1、网页 js 逆向分析( v_jstools )
From:https://mp.weixin.qq/s/LisYhDKK_6ddF-19m1gvzg
爬虫工具篇:Chrome 插件
油叉:https://greasyfork/zh-CN/scripts
油猴脚本 搜索:hook、console、控制台、加密、解密、逆向、绕过、anti、debug、调试
- EditThisCookie 是一个 Cookie 管理器,可以很方便的添加,删除,编辑,搜索,锁定和屏蔽 Cookies。可以将登录后的 Cookies 先保存到本地,借助 cookielib 库,直接爬取登录后的数据。避免了抓包和模拟登录,帮助我们快速地进行爬虫。
- Web Scraper 是一款免费的、适用于任何人,包含没有任何编程基础的爬虫工具。操作简单,只需要鼠标点击和简单的配置,就能快速的爬取 Web 端的数据。它支持复杂的网站结构,数据支持文本、连接、数据块、下拉加载数据块等各种数据类型。此外,还能将爬取的数据导出到 CSV 文件中。
- Xpath Helper / XpathHelperPlus 都是结构化网页元素选择器,可以快速地定位网页元素,重点是 "会实时显示匹配的数目和对应的位置"。 Xpath 比 Beautiful Soup 网页元素查找性能更有优势,Xpath 比正则表达式编写更方便。XpathHelper / XpathHelperPlus / ( https://blog.csdn/weixin_43411585/article/details/131208719 ) XPathHelperWizard 插件功能特点:可以先看看 xpath-helper插件使用,掌握点基础xpath语法知识;更推荐 XpathHelperPlus,其次 XPathHelperWizard。xpath-helper-plus 是在 xpath-helper 插件上做了升级功能,精简xpath规则,能复制css,而且操作更容易,并且一直在持续更新。xpath-helper-plus:https://github/mic1on/xpath-helper-plus
- Toggle JavaScript 插件可以用来检测当前网页哪些元素是通过 AJAX 动态加载的。使用它可以快速在容许加载 JS 、禁止加载 JS 两种模式中切换。
- User-Agent Switcher for Chrome 插件可以很方便的修改浏览器的 User-Agent。可以模拟不同的浏览器、客户端,包含 Android、IOS 去模拟请求。对于一些特殊网站,切换 User-Agent 可以更方便地进行数据爬取。
- JSON-handle 是一款功能强大的 JSON 数据解析 Chrome 插件。它以简单清晰的树形图样式展现 JSON 文档,并可实时编辑。针对数据量大的场景,可以做局部选取分析。
- 前端助手:功能和JSON-handle 差不多。但是功能更强大
- ReRes、ReRes、URLRedirector、XSwitch:重定向 URL。可以把请求的 js 文件重定向本地的 js,方便进行调试。
- Console Importer:用一个命令,从控制台导入 JavaScript 和 CSS 资源。
jQuery-hook 用于快速定位使用jQuery绑定到DOM元素上的事件的代码的真实位置,辅助逆向分析:https://github/JSREI/jQuery-hook
下载、安装 v_jstools 插件
v_jstools 是可以进行 web hook的浏览器插件。地址:https://github/cilame/v_jstools
浏览器打开上面的网站后,点击 code 按钮,选择 Download ZIP 选项,将文件下载下来,然后解压,会看到一个 v_jstools-main 的文件夹。
安装插件
- 谷歌浏览器地址栏输入:chrome://extensions/ 打开扩展程序页面,并打开开发者模式。如果是其他浏览器,请使用菜单栏打开。
- 打开后,点击左上角的 加载已解压的扩展程序 按钮,然后选择 v_jstools-main 文件夹,插件就已经加载进来了。
插件功能
在扩展程序中,打开该插件,看看支持哪些功能:
打开配置页面后,来到这里:
可以看到,有三个功能。
dom对象hook
第一个功能是 dom对象hook ,它内置了很多常见方法的hook,如eval,cookie,Function等,想hook哪个方法,直接打钩即可,非常的方便。有了这个,再也不用写油猴脚本啦。
ast hook替换
第二个功能是 ast hook替换,顾名思义,就是拦截某个js代码,通过ast处理后,再返回ast处理后的代码,让混淆代码见鬼去吧。
它给的示例代码是这个:
function fetch_hook(code, url) {
var ast = parser.parse(code);
function removedebugger(path) {
path.replaceWith(t.identifier("/*debugger*/"))
}
traverse(ast, {
DebuggerStatement: removedebugger
});
var {code} = generator(ast, {
jsescOption: {
minimal: true,
}
});
return code
}
这里简单说一下, fetch_hook 函数 接受2个参数,可以不用理会,如果你想hook特定的url,可以在函数的首行加入这样一段代码:
if (url.indexOf("https://www.xxx/xxx.js") == -1)
{
return code // 检测到不是这个 url 就直接返回原始代码
}
再就是编写 ast 插件了,按照这样下就好:
function removedebugger(path) {
path.replaceWith(t.identifier("/*debugger*/"))
}
traverse(ast, {DebuggerStatement: removedebugger});
先写方法,再遍历,也可以按照我星球里的方式进行编写,都是一样的。
不过在我使用了几次以后,还是觉得线下处理混淆代码香,当然要看你的使用场景了。
AST 的解密混淆
第三个功能是一些 AST的解密混淆,如图:
把混淆代码复制到上面的白色框中,点击对应的按钮即可解混淆,也是非常的方便。这里能解混淆的有 sojson,ob混淆,jsfuck以及压缩代码等,都是比较常用的功能。
试用了一番,可以还原最新版的ob混淆,效果还是很棒的。当然一些修改特征了的代码无法还原,这个要做到通杀确实有些难度。
v_jstools 补环境
点击 打开配置按钮:
按图进行如下设置:
实战案例 1:知乎搜索
实战:https://www.zhihu/search?type=content&q=python
抓包,查看 请求参数
需要的加密参数:
等网站加载完毕后,我们再点开这个插件,选择 生成临时环境 命令:
点击后,会有个弹框提示已复制到剪切板。这样,临时环境就帮我们生成好了,新建一个js文件 v.js, 将生成的环境复制过来进来并保存。我们再将这个参数加密的代码也复制进来,保存到一起,具体请参考这篇文章:https://blog.csdn/qq523176585/article/details/123814707
在加密函数处打上断点,记录实参和结果。
实参: '7861d84e110af123f2fc8c05ff38601f';
结果: 'a8O0QQuy28xYcR28f0NBkQe0kXtYUuY0mLxq66L0S7Yp'
在v.js中构造好实参,并打印结果:console.log(b('7861d84e110af123f2fc8c05ff38601f'));
保存后,运行结果
经过仔细比对后可以发现,和网页上面的结果是一模一样的。非常的 nice。
基本就靠一些CV操作,就把结果弄出来了,可以说非常的简单。
如果你不想打印上面的日志,可以将这个函数进行改写:var v_console_log = function(){{}}
这个插件试用了几天,已经解决了很多网站的加密,几乎可以说js逆向有手就行,当然,你需要一些js逆向分析的功底。毕竟它只是帮你补环境。注意,这个并不是万能的,因此有效网站如果不行的话,可能需要想其他的办法了哈。
实战案例 2:同花顺
- :https://blog.csdn/weixin_43411585/article/details/132440165
- :https://blog.csdn/qiulin_wu/article/details/133909883
实战:https://q.10jqka/
反爬参数如图
知识点:cookie 一般是两种,要么服务器生成,要么 js 生成,可通过如下方式判断
为啥要补环境:英文我们知道这个js文件代码内容会生成我们想要的参数,但是放到本地 nodejs 环境下运行不出结果,因为缺少浏览器环境特有的一些window/document/navigator/localstorage等参数,所以我们需要把这些缺少的浏览器环境补上,让这份js代码在本地nodejs环境下也能运行出结果来。请看这个图10秒钟
补环境分三部分:上、中、下。
- 在最上面放好你补的环境参数,
- 中间部分放好js代码,
- 最下面部分放生成的目标参数,
补环境的好处:就是可以完全不用考虑内部的算法逻辑,让它能正常跑起来输出就行
详细分析流程
-
1.先点击打开如下两个开关,然后打开配置页面
- 2. 如下插件配置详情,勾选上总开关,DOM开关,以及常用的挂钩,然后关掉该配置页面
- 3.直接看视频-缺啥补啥的方法补环境:https://www.bilibili/video/BV1FN4y1d7av/ 或者星球文章 后,我们知道生成 cookie 的 js 代码,如图 hook 到了cookie,然后堆栈回溯查看定位到具体的 js 文件内容
对比 cookie,发现 cookie 一致,说明找的位置正确。
- 4. 在 vscode 里面新建一个js文件,把 js 代码和希望输出的函数写好。还是3部分:
第 1 部分:待补的环境,把插件生成的临时环境放过来。后面
第 2 部分:复制 js 代码,也就是生成 cookie 的 js 文件。
第3部分:调用生成 cookie 的函数,生成 cookie
现在开始 "第1部分:待补的环境",使用插件生成临时环境
- 继续回到浏览器里面,先清掉缓存 cookie
- 然后刷新网页 ( 可以把所有断点全部删除 ),在滑动鼠标下滚下,防止无法正常生成临时环境,如下弹出,代表环境参数已经生成好
- 回到 vscode 里面,在刚才新建的 js 文件里面 ctrl+v 粘贴刚刚生成的临时环境,放在最上方
- 接下来,运行已经补好环境的 js 文件,最后发现可能会出现如下几种情况:
1. 生成的补环境,函数之间调用正常,可以直接使用;
2. 已经能生成正常cookie,但是不能用;例如:一直是固定的。
3. 完全生成不出 cookie 结果值;
下面针对两种情况进行分析:
- 一种是直接能用的,
- 一种是需要调试才能出结果的情况
方法 1:本案例操作流程之-生成临时环境-直接可以用的情况
1. 我们还是按之前的步骤清掉缓存,打开插件的勾选项,然后这里唯一要注意的点就是需要勾选script断点,然后用它生成的临时环境
2.刷新网页后,跳到目标生成cookie的js文件被断住的js后,我们取消script断点,直接下一步调试过去
3. 这时候点击插件的生成临时环境,可能会报错如下,生成的临时环境无法保存至剪贴板
4. 多点击几次生成临时环境就可以了,我们把它复制到本地js文件里面
5. ctrl+v粘贴到本地js文件中,运行能生成正常cookie,但是程序处于卡死无法退出状态
6.ctrl+s保存文件后,再次运行,这个时候已经能正常生成cookie值了,但是同样出现了我们上一篇文章介绍的虽然出来了cookie值,但是无法中断程序退出的现象,就是run后不能自动停掉程序,这时候我们可以尝试将setInterval()定时函数给置空试试,这是因为setinterval不会清除定时器队列,每重复执行1次都会导致定时器叠加,最终卡死你的网页(具体的大家可以调试看看)
7.我们在js代码的最上方的位置添加setInterval = function(){}将定时器置空即可,这时候能正常生成cookie了,并且把日志输出置空var v_console_log = function(){{}}
8.接下来我们验证下这份通过插件补的环境,与js代码生成的cookie最终能不能用,用python调用js文件试试,如下我们调用js生成的cookie验证,发现能成功拿到cookie,这说明我们用插件补环境也能用,而上面插件补环境我们只做了两个操作置空定时器,把日志输出关掉即可,接下来分析调试过程中,可能你生成的临时环境不能用的解决方法
方法 2:本案例操作流程之-生成临时环境-不可以直接用,需要调试补下
1.勾选Caught Exceptions,即使所发生运行时异常的代码在 try/catch 范围内,Chrome 开发者工具也能够在错误代码处停住,这里就不详细介绍了,大概思路如下
文章与视频
- 原文文章
- 十一姐b站视频
- 时光漫漫星球
JS hook 脚本
hook 又称钩子,可以在调用系统函数之前, 先执行我们的函数. 例如, hook eval
eval_ = eval; // 先保存系统的eval函数
eval = function(s){
console.log(s);
debugger;
return eval_(s);
}
eval()
// 可能会被检测到, 用这种方案来进行
eval.toString = function(){return 'function eval() { [native code] }'}
对 Function 的 hook, 主要为了解决无限 debugger
var qiaofu_function_constructor = (function(){}).__proto__.constructor;
(function(){}).__proto__.constructor = function(arg){
console.log("我爱你大大");
if(arg ==='debugger'){
return function(){}
} else {
return new qiaofu_function_constructor(arg);
}
}
上面都是 hook 的系统函数. 但有时, 我们需要hook某个属性. 此时应该怎么办?
var v;
Object.defineProperty(document, "cookie", {
set: function(val) {
console.log("有人来存cookie了");
v = val;
debugger;
return val;
},
get() {
console.log("有人提取cookie了∂
debugger;
return v;
}
});
在逆向时, 常用的主要有: hook eval 、hook Function 、hook JSON.stringify、JSON.parse 、hook cookie、hook window对象
Js 代码 替换
JS逆向|JavaScript代码线上替换(js 逆向 系列文章):https://blog.csdn/qq523176585/article/details/126258689
有的网站在用 debuger 调试之后,每一步都变得非常卡顿非常影响效率和心情,项目经过webpack处理了,请问这种有什么好的办法吗?
答案是:可以把源码保存到本地,然后用fiddler的atuo response替换线上的js调试
方法 1:使用谷歌浏览器自带的替换功能
Chrome 的 local overrides:https://zhuanlan.zhihu/p/36677472
方法 2:使用 fiddler 的 auto response 替换功能
fiddler 本地资源替换线上文件:https://wwwblogs/shichangchun/p/10731297.html
方法 3:使用 reres 插件进行替换
Github地址:https://github/annnhan/ReRes
使用方法:找不到变量生成的位置?让插件来帮你轻松定位:https://blog.csdn/qq523176585/article/details/109508013
方法 4:使用 Netify 插件进行替换
插件下载地址:https://chrome.google/webstore/detail/netify/mdafhjaillpdogjdigdkmnoddeoegblj
使用方法:工具分析 | Akamai2.0 还原后的js线上替换方案分享:https://blog.csdn/qq523176585/article/details/125093543
方法 5:v_jstools 插件进行替换
使用方法:AST实战技巧|使用v神插件动态替换AST还原后的代码:https://blog.csdn/qq523176585/article/details/124395678
2、jshook ( 安卓上用Js实现Hook )
频道: https://t.me/jshookapp
交流群: https://t.me/jshookgroup
安 装
- Frida 是一款跨平台的动态二进制注入工具,它可以在程序运行时监视并修改程序的执行。并且提供了 JavaScript API ,只要会 js 就可以快速实现 hook (支持 java层和native层)。
- JsHook 可以把 Frida 注入到目标应用中。frida 注入后,通过 JavaScript 代码可以完全访问内存中信息。JsHook 扩展并丰富了 Frida 的 api,例如:常用的文件操作、数据加解密、IMGUI悬浮窗UI、设备信息、视图操作、模拟点击、内核驱动内存读写...
在 root 环境下推荐安装 jshook 的 Magisk 模块,免 root 环境下使用 Lspatch 或者虚拟机。
jshook 相关文件下载地址:https://github/JsHookApp/Download
官网文档:https://doc.jshook/#/README
真机 root 环境 激活
手机已经拥有root权限,并且已经安装以下任意一种 root 框架
- magisk:https://github/topjohnwu/Magisk
- kernelsu:https://github/tiann/KernelSU
- apatch:https://github/bmax121/APatch
模块依赖 zygisk/riru,还需要安装以下任意模块用于支持激活 jshook
- zygisk (推荐):https://github/Dr-TSNG/ZygiskNext
- riru (已停止更新):https://github/RikkaApps/Riru
以上准备就绪后打开 jshook.apk 点击安装 Magisk/kernelSU 模块按钮选择,选择 zygisk 版本的 jshook 模块进行安装,安装后重启手机即可完成激活
使用 vmos 或者 光速虚拟机 等类似产品进行安装激活操作,同root环境激活方式
在模拟器中安装时,需要下载 MagiskDelta,再按照上面root环境激活的方式继续操作
真机 免root 环境 激活
如果手机无法root,可以尝试使用 lspatch https://github/LSPosed/LSPatch
lspatch 激活xp模块的方式是给目标应用进行修补过签名验证并修改程序入口,入口处会加入注入xposed框架以及调用lsp相关服务
安装 lspatch 后 jshook 会显示激活
安装完lspatch后你需要先将原应用
提取成apk文件
,可以使用mt管理器
进行操作,lspatch中点击管理
右下角+号
新建修补,选择apk文件,修补完成后,用mt管理器找到修补后的apk文件,并安装,安装完成后在lspatch的管理中即可看到被修补成功的应用,点击这个应用,会出现菜单,选择模块作用域
,勾选jshook即可完成激活
常见问题
目前加密脚本只能使用 fridamod 框架运行。
部分机型实时注入脚本会直接发生闪退情况,可以先关闭hook服务再启动应用,等待几秒后在开启hook服务会途中开始注入,在测试之前先取消勾选脚本,排除脚本原因
frida-server如何连接
jshook 提供的 frida-server 默认端口号为 28042 / 28043
#端口转发
adb forward tcp:28042 tcp:28042#spawn
frida -H 127.0.0.1:28042 -f com.android.xxx -l test.js
#attach
frida -H 127.0.0.1:28042 -n com.android.xxx -l test.js
frida-gadget 与 frida-server 一样更改了端口
#端口转发
adb forward tcp:28042 tcp:28042
#attach
frida -H 127.0.0.1:28042 Gadget -l test.js
渲染增强指不依赖android系统的情况下直接使用底层api进行渲染,android系统无法感知存在,所以在增强模式下性能最好,且屏幕录制和截屏无法获取到渲染数据。
没有开启渲染增强则使用android系统的api创建渲染试图,性能会有损失,且受系统管控,屏幕录制和截屏可以获取到渲染数据
连接 计算机
可以使用Visual Studio Code 实时推送脚本到手机,或者从手机获取脚本到电脑。下载 vscode 插件: https://marketplace.visualstudio/items?itemName=JsonET.jshook-vscode-extension
安装后在js文件右键或者快捷键操作
Shift+Alt+D: 推送脚本
Shift+Alt+C: 获取脚本
Shift+Alt+F: 清空日志
Shift+Alt+G: 查看日志,自动刷新
同步脚本时(脚本名+相对路径)与手机上一致即可,使用插件时需要jshook设置中启用服务端,使用快捷键后会出现输入ip的对话框,让电脑与手机在同一个wifi网络下。
启用服务端可以关闭jshook,不用保持在后台运行
基础 使用 教程
JsHook基础使用教程:http://blog.wutongliran.top/jshook基础使用教程/
实战分析&LSPosed+Xposed模块Hook&JsHook 过某60加固:https://bbs.binmt/thread-125074-1-1.html
环境 配置
前提:手机已经通过 Magisk 获取 ROOT 权限
演示环境:Magisk(面具)、JsHook、倒数日(要破解的软件)
打开 Magisk,在设置里勾选 Zygisk。
安装 JsHook
安装 JsHook 后,此时打开会提示未激活,需要下载 Magisk 模块 (下载 zygisk 版本)。
安装下载的模块,重启手机
显示已激活即为成功
安装 Frida 框架
点击框架管理,安装 frida 框架,这里选择 FridaMod 框架。
导入 frida hook js 脚本
点击脚本管理,点右上角导入脚本
脚本内容:
/**
* vip
*/
function hookTest1() {
let User = Java.use("com.lezhi.meitubao.Infos.User");
User["getVip"].implementation = function () {
return true;
};
}
/**
* 到期时间
*/
function hookTest2() {
let User = Java.use("com.lezhi.meitubao.Infos.User");
User["getVipExpireDate"].implementation = function () {
let ret = this.getVipExpireDate();
return ret= "天荒地老";
};
}
function main() {
Java.perform(function () {
hookTest1();
hookTest2();
});
}
setImmediate(main);
选择 目标 app 开始 hook
然后到应用列表里点目标 APP、勾选启动 Hook、框架选择默认(FridaMod 就是默认)、启动脚本(记得点右上角保存)
最后,重启目标 APP,脚本生效,解锁高级版
jshook 脚本 仓库
:https://github/bcmdy/JsHook-Script-Repo
新版仓库(V1.1.5+) 订阅地址:
- github(一般情况下需爬墙):https://raw.githubusercontent/bcmdy/JsHook-Script-Repo/master/Store-new.json
- CDN解析地址(一般情况下国内正常访问):https://gh-proxy/https://raw.githubusercontent/bcmdy/JsHook-Script-Repo/master/Store-new-cdn.json
API 说明
global (全局函数)
可以全局任何地方调用的函数。
- toast(message) 参数:message: string
- alert(message) 参数:message: string
- confirm(message,callback) 参数:message: string、callback: function
confirm('is ok?', { ok: function () { //... }, cancel: function () { //... } })
- uuid() 返回 string 类型的 32位小写 uuid
runtime (运行时相关信息)
用于获取当前hook运行时相关基础信息
- runtime.appInfo 返回值: ApplicationInfo
- runtime.packageName 返回值: string
- runtime.processName 返回值: string
- runtime.classLoader 返回值: ClassLoader
- runtime.isKernel 是否在内核模式中。返回值: boolean
- runtime.coreVersionCode 获取当前jshook的版本号。返回值: int
- runtime.modVersion 获取当前firamod的版本。返回值: string
- runtime.modVersionCode 获取当前firamod的版本号。返回值: int
app (当前app基本信息)
用于获取当前hook应用的基本信息
- app.isAppSystem() 判断 App 是否是系统应用。返回值: boolean
- app.isAppForeground() 判断 App 是否处于前台。返回值: boolean
- app.exitApp() 关闭应用
- app.getAppInfo() 获取 App 信息。返回值: object
- app.openUrl(url) 打开指定网址。参数: url: string 网址
- app.startActivity(activity) 启动 Activity。参数:activity: Activity
- app.getActivityList() 获取 Activity 栈链表。返回值: List
- app.finishActivity(activity) 结束 Activity。参数:activity: Activity
- app.finishToActivity(activity) 结束到指定 Activity。参数:activity: Activity
- app.startHomeActivity() 回到桌面
- app.dpToPx(value) dp转px。参数: value: float。返回值: int
- app.pxToDp(value) px转dp。参数:value: float。返回值: int
- app.getInternalAppDataPath() 获取内存应用数据路径。返回值: string
- app.getExternalAppDataPath() 获取外存应用数据路径。返回值: string
- app.getExternalAppObbPath() 获取外存应用 OBB 路径。返回值: string
- app.getExternalStoragePath() 获取外存路径。返回值: string
base64 (base64编码解码)
- base64.encode(data) 参数:data: string。返回值: string
- base64.encodeBytes(data) 参数:data: byte[]。返回值: byte[]
- base64.decode(data) 参数:data: string。返回值: string
- base64.decodeBytes(data) 参数:data: byte[]。返回值: byte[]
media (播放音乐)
用于播放音乐
- media.create(data) 参数:data: url 地址或者文件base64值。返回值: 实例。调用后默认会自动播放,无需调用start
- [实例].start() 开始播放
- [实例].pause() 暂停播放
- [实例].stop() 停止播放
- [实例].loop(state) 参数:state: boolean。是否循环播放,默认音乐只播放一次
- media.closeAll() 关闭所有实例
crypto (字符串加密解密)
-
crypto.encrypt(key,data,enctype,transformation)
参数:
key: string
data: string
enctype: CRYPTO_AES | CRYPTO_DES
transformation: 转换的名称 例如 DES/CBC/PKCS5Padding
返回值: string -
crypto.encryptBytes(key,data,enctype,transformation)
参数:
key: byte[]
data: byte[]
enctype: CRYPTO_AES | CRYPTO_DES
transformation: 转换的名称 例如 DES/CBC/PKCS5Padding
返回值: byte[] -
crypto.decrypt(key,data,enctype,transformation)
参数:
key: string
data: string
enctype: CRYPTO_AES | CRYPTO_DES
transformation: 转换的名称 例如 DES/CBC/PKCS5Padding
返回值: string -
crypto.decryptBytes(key,data,enctype,transformation)
参数:
key: byte[]
data: byte[]
enctype: CRYPTO_AES | CRYPTO_DES
transformation: 转换的名称 例如 DES/CBC/PKCS5Padding
返回值: byte[] -
crypto.rc4Encrypt(key,data)
参数:
key: string
data: string
返回值: string -
crypto.rc4EncryptBytes(key,data)
参数:
key: byte[]
data: byte[]
返回值: byte[] -
crypto.rc4Decrypt(key,data)
参数:
key: string
data: string
返回值: string -
crypto.rc4DecryptBytes(key,data)
参数:
key: byte[]
data: byte[]
返回值: byte[] -
crypto.md5(data)
参数:data: string
返回值: string -
crypto.md5Bytes(data)
参数:data: byte[]
返回值: string -
crypto.sha1(data)
参数:data: string
返回值: string -
crypto.sha1Bytes(data)
参数:data: byte[]
返回值: string -
crypto.sha256(data)
参数:data: string
返回值: string -
crypto.sha256Bytes(data)
参数:data: byte[]
返回值: string
device
- device.isAdbEnabled()
- device.getSDKVersionName()
- device.getSDKVersionCode()
- device.getAndroidID()
- device.getMacAddress()
- device.getManufacturer()
- device.getModel()
- device.getABIs()
- device.isTablet()
- device.isDevelopmentSettingsEnabled()
- device.getScreenWidth()
- device.getScreenHeight()
- device.getScreenDensity()
- device.getScreenDensityDpi()
- device.isLandscape()
- device.isPortrait()
- device.screenShot(activity)
- device.setClipboard(data)
- device.getClipboard()
file
- file.isFile(path)
- file.isDir(path)
- file.isExists(path)
- file.read(path)
- file.readBytes(path)
- file.write(path,content)
- file.writeBytes(path,content)
- file.append(path,content)
- file.appendBytes(path,content)
- file.copy(path,topath)
- file.move(path,topath)
- file.rename(path,newname)
- file.delete(path)
- file.getName(path)
- file.getSize(path)
- file.zip(path,topath,passwd)
- file.zip(path,topath)
- file.unzip(path,topath,passwd)
- file.unzip(path,topath)
http
- http.get(url,headers,function)
- http.post(url,data,headers,function)
- 注意事项
curl
- curl(url,method,headers,body,function)
json
- json.toGsonString(data)
- json.gsonStringToClass(data,class)
- json.toJSONString(data)
- json.parseObject(data)
- json.parseArray(data)
modmenu (mod菜单)
- modmenu.create(title,options,function)
- 自定义控件id
- 多个tab实例
- [实例].close()
- [实例].state()
- [实例].size(width,height)
- [实例].position(type,x,y)
- [实例].icon(img)
- [实例].edgeHiden(enable)
- [实例].update(id,value)
- modmenu.closeAll()
moddraw (底层绘制)
- moddraw.create(function)
- [实例].close()
- moddraw.closeAll()
- 注意事项
kernel
- kernel.getModuleBase(libname)
- kernel.readDword(address)
- kernel.readFloat(address)
- kernel.writeDword(address,value)
- kernel.writeFloat(address,value)
- 示例脚本
memory
- memory.getModuleBase(libname)
- memory.readDword(address)
- memory.readFloat(address)
- memory.writeDword(address,value)
- memory.writeFloat(address,value)
- 示例脚本
storage
- storage.get(key)
- storage.set(key,data)
- storage.del(key)
- storage.clear()
convert
- convert.stringToByte(data)
- convert.byteToString(data)
- convert.hexStringToByte(data)
- convert.byteToHexString(data)
- convert.byteToBitmap(data)
- convert.bitmapToByte(data)
- convert.byteToDrawable(data)
- convert.drawableToByte(data)
- convert.byteToInputStream(data)
- convert.inputStreamToByte(data)
- convert.byteToOutputStream(data)
- convert.outputStreamToByte(data)
dialog
- dialog.input(title,callback,content)
view
- view.findViewByText(text)
- view.getPosition(view)
- view.findViewPositionByText(text)
- view.runOnUiThread(function)
keys
- keys.click(x,y)
- keys.swipe(x,y,tox,toy,time)
- keys.back()
- keys.home()
- keys.enter()
- keys.del()
- keys.text(text)
colors
- colors.toString(color)
- colors.red(color)
- colors.green(color)
- colors.blue(color)
- colors.alpha(color)
- colors.rgb(red,green,blue)
- colors.argb(alpha,red,green,blue)
- colors.parseColor(color)
canvas
- canvas.create(function)
- [实例].close()
- [实例].maxfps(fps)
- canvas.closeAll()
- frida简单示例
3、免 root 框架:神之手
神之手:https://download.csdn/download/freeking101/89349747
文件下载: http://route.lozn.top:88/lozn/ lozn后面要加/否则404
LSPatch(已停止更新) 是免 root 的 Xposed 框架,NPatch 是基于 LSPatch 开发的免root 框架,都是以 LSPosed 为基础的免 root 的 Xposed 框架,不需要 Root 就可以使用 LSPosed 框架,原理是通过在目标 APK 中插入 dex 等来集成 Xposed API。神之手也是通过改造手机上已经安装的或者本地app,然后植入钩子框架代码,使被改造的app在启动时自动加载钩子,从而执行 hook 代码。
"免 root 框架" 非常适合没有 root 的但是又想使用 LSPosed 功能的手机。
神之手
"超度应用" 就是在目标 APK 中插入 dex 等来集成 Xposed API,通过这个 dex 可以 hook
场景:一种无root抓包方法
:https://www.52pojie/thread-1773022-1-1.html
当你尝试抓包某个软件时是否遇到过
但你又没有 root,那么这时候你就需要三大法宝:抓包组合拳
首先打开 jshook(开启无root模式),找到你要抓包的应用,启用 hook 服务,选择相应框架,再点击 LSPatch 注入 hook 服务,安装应用。
如果软件签名校验较强,加固较强比如4x90加固undefined,就别想了,还是乖乖root或者放弃吧。这就是这个方法的限制
安装完成后在jshook找到软件,在最下方启用xp模块,选择算法助手
启用 算法助手。
然后打开算法助手,开启相应功能,例如你要抓包,就开启这三个功能,然后把后台全部划掉。
重新打开jshook、算法助手(施法过程),注意,使用过程保持这两个应用程序后台。
尝试抓包,成功解决抓包断网问题
4、算法助手
算法助手是一款运行在Android平台上基于Xposed的安卓调试工具,配合Xposed(需要Root或者沙盒环境),通过一系列反射操作,进行应用的安全测试,调试分析,代码定位,是一款不错的调试工具。开发者:军哥(757456456@qq)。主要功能:
- 1、Md5,Sha等信息摘要算法(MessageDigest类)
- 2、AES、DES,RSA等秘钥算法(Cipher类)
- 3、Hmac等含有秘钥的哈希算法(Mac类)
- 4、对话框的定位(Dialog类)
- 5、Log捕获(LOG类)
- 7、拦截程序退出(System以及其他类)
- 8、justTrustMe升级版(可高效自动定位混淆后的okhttp)
- 9、文件访问记录(File类)
- 10、自定义Hook,可自行定义hook类,可设置返回值,可拦截执行
- 11、webViewDebug(使webView可调试)
- 12、shell命令行纪录
- 13、……后续会不断进行增加
算法助手Pro版本下载:https://www.123pan/s/7G8aTd-g3T4H.html 提取码:u7Zn
算法助手使用教程:https://bbs.kanxue/thread-268565.htm
算法助手使用教程:https://blog.csdn/u014645251/article/details/119030982
【初级教程】算法助手简单教程:https://bbs.binmt/forum.php?mod=viewthread&tid=64273
5、hookui
hookui 是什么
hookui 是一款 xposed 插件,必须依赖 xposed 框架环境
- root 环境有 xposed framework、edposed、LSxposed。
- 非root 有 virtual app 以及类似多开平行空间的一些软件。
- 基于 app 直接修改,然后植入 xposed framework 的有 太极,神之手 goodhand文档 ,它能快速跟踪一些行为从而找到破解的思路,就像 window 破解一样,也有类似的,如 hook window api 的某些函数,hook io 文件打开,注册表行为。而这个 hookui 也类似行为,可以对一些敏感行为可进行追踪拦截,可追踪调用堆栈。
可以做什么
通过 HOOKUI 做了很多不可告人的事情,常用的爆破策略是 追踪点击,布局事件,敏感字符串的源头来针对性的做 hook 功能。破解一些没什么验证的收费 SE 直播,倒计时自动关闭视频直接拦截对方法进行屏蔽的操作。也通过它直接改手机余额,来告诉那些拜金女小心骗子。
hook、字段编辑
支持自定义填写要hook的类,支持方法参数调用,支持批量修改列表数据,支持修改字段,实例,内存漫游字段修改,支持字符串,触摸事件,窗口创建,布局设置堆栈追踪打印. 支持开启web服务,下载任意应用内数据,支持web端做一些hook操作(此功能是移植inspect,不过兼容没有root的手机
支持 webview 注入,显示 webview hook 菜单(调用js,查看源码) 支持 activity 序列化保存,
下载、使用
官网:https://hookui.lozn.top/#/?id=main
下载:https://github/Xposed-Modules-Repo/lozn.hookui
常见的更新地址如下: qq群(不稳定容易被封), telegram(需要翻墙)。不可使用本软件进行诈骗从事违法行为等行为,仅供学习使用!触发法律后果自负!软件使用的时候协议上也一再强调禁止用于违法用途!切记切记。群主非本人 [qq群 659119840]群若提示不存在,请加入电报群以便获得新群,请悉知。qq 35068264 的qq空间可以翻找说说,有时会会把加群图片放在QQ空间
- 电报 : https://t.me/qssq666
- 简书 https://www.jianshu/u/9b0768e66d01
- 博客 http://lozn.top/
电报有一些使用的视频教程,而简书有一些图文的教程,其它的只能问问群里人了
微信公众号:情迁说科技。抖音:lozn00/。快手:吉凶以情迁
B站:https://space.bilibili/101043764
文件下载: http://route.lozn.top:88/lozn/ lozn 后面要加 / 否则404
下载安装完成后,首先需要在 LSPosed 中启用模块,然后选择在哪些 app 上生效。
在 LSPosed 的 hookui 模块中点击设置,打开 hookui (也可以直接通过点击 hookui app 打开)。
打开对应 app
如果 "其它应用中" 没有 彩色渐变图标,这基本代表你在 hookui 界面所进行的一些功能都是无法正常生效的,可能你用 logcat 也看不到 hookui 关键词的一些堆栈调用 等数据。解决方法:
- 1. 如果其它应用中没有图标,确保 hookui 是最新版。
- 2. 确保在 hookui 中勾选开启了总开关,在激活应用选项卡中确保勾选了 该应用
- 3. 会使用 hook 框架,以及正确激活一个 xposed 插件,毕竟 hookui 也是一个xposed插件
- 4. 上面确保的情况下,可以把 hookui 界面的其它选项勾选全部关闭。再试试是否正常。
- 5. 不要随意开启一些功能,可能会造成非常卡顿。比如延迟启动,这个主要是用于调试用的,比如你需要断点调试so,那么这个时机就很重要。字符串调用更不要随意开启,这是非常非常频繁的功能.
点击 "彩色渐变图标",图标内菜单界面功能如图:
案例教程
逆向与安全 系列:https://www.jianshu/nb/15035584
精彩连接之HOOKUI-hook字符串
精品教程之HOOKUI-hook点击事件
精彩连接之HOOKUI-内存搜索
精品教程之HOOKUI-activity字段编辑
精彩连接之HOOKUI-Web服务器
精品教程之HOOKUI-文件访问
精品教程之HOOKUI-ui分析
精品教程之HOOKUI-dump文件
精品教程之HOOKUI-延迟启动应用脱壳
install 是 xx.apk 的文件,
uninstall 是这个apk文件里面具体存在的包名。
adb shell pm list packages 列出手机中所有安装包的包名
adb shell pm list packages
adb uninstall com.xx.xx
adb -s xxxx uninstall com.xx.xx 多个设备时,-s 可以指定设备
adb -s xxxx uninstall -k com.xx.xx 卸载应用但是保留配置和缓存文件。
HOOKUI --- hook字符串
hookui 逆向 xposed 神器 之 字符串hook跟踪逆向分析。不用抓包工具也能抓http :https://www.jianshu/p/474a60fe194a
安卓JAVA内存漫游、字段替换:https://bbs.pediy/thread-269107-1.htm
hook字符串有两种方式一种是在应用启动之后在界面里面设置,另外一种则是在app启动的时候就记录。
第一种:启动就抓取
第二种:在应用界面里面设置。
打开 要 hook 的应用,点击 应用上的 hookui 图层。如下,点击红色图标。
达到了类似 frida 的效果。 (还有很多功能没做,比如动态编写 js代码,实时 hook 监听)
这里面有3个选项,第一个是 hook 字符串api,后面两个是拼接类的调用了。
选择 hook 就会开始 hook,这个时候可能 app 会有点卡,因为字符串他比较多,"关键字设置" 就是匹配到关键词就会打印堆栈信息。"启用关键字替换" 如果填写了,那么匹配到关键词就会替换成你需要的文字内容。选择 hook 后,不会有任何提示(懂的人都知道,提示也会调用字符串,这会导致一个死循环)
HOOKUI --- hook点击事件
HOOKUI --- 内存搜索
HOOKUI --- activity字段编辑
HOOKUI --- Web服务器
HOOKUI --- 文件访问
HOOKUI --- ui分析
HOOKUI --- dump文件
HOOKUI --- 延迟启动应用脱壳
1、网页 js 逆向分析( v_jstools )
From:https://mp.weixin.qq/s/LisYhDKK_6ddF-19m1gvzg
爬虫工具篇:Chrome 插件
油叉:https://greasyfork/zh-CN/scripts
油猴脚本 搜索:hook、console、控制台、加密、解密、逆向、绕过、anti、debug、调试
- EditThisCookie 是一个 Cookie 管理器,可以很方便的添加,删除,编辑,搜索,锁定和屏蔽 Cookies。可以将登录后的 Cookies 先保存到本地,借助 cookielib 库,直接爬取登录后的数据。避免了抓包和模拟登录,帮助我们快速地进行爬虫。
- Web Scraper 是一款免费的、适用于任何人,包含没有任何编程基础的爬虫工具。操作简单,只需要鼠标点击和简单的配置,就能快速的爬取 Web 端的数据。它支持复杂的网站结构,数据支持文本、连接、数据块、下拉加载数据块等各种数据类型。此外,还能将爬取的数据导出到 CSV 文件中。
- Xpath Helper / XpathHelperPlus 都是结构化网页元素选择器,可以快速地定位网页元素,重点是 "会实时显示匹配的数目和对应的位置"。 Xpath 比 Beautiful Soup 网页元素查找性能更有优势,Xpath 比正则表达式编写更方便。XpathHelper / XpathHelperPlus / ( https://blog.csdn/weixin_43411585/article/details/131208719 ) XPathHelperWizard 插件功能特点:可以先看看 xpath-helper插件使用,掌握点基础xpath语法知识;更推荐 XpathHelperPlus,其次 XPathHelperWizard。xpath-helper-plus 是在 xpath-helper 插件上做了升级功能,精简xpath规则,能复制css,而且操作更容易,并且一直在持续更新。xpath-helper-plus:https://github/mic1on/xpath-helper-plus
- Toggle JavaScript 插件可以用来检测当前网页哪些元素是通过 AJAX 动态加载的。使用它可以快速在容许加载 JS 、禁止加载 JS 两种模式中切换。
- User-Agent Switcher for Chrome 插件可以很方便的修改浏览器的 User-Agent。可以模拟不同的浏览器、客户端,包含 Android、IOS 去模拟请求。对于一些特殊网站,切换 User-Agent 可以更方便地进行数据爬取。
- JSON-handle 是一款功能强大的 JSON 数据解析 Chrome 插件。它以简单清晰的树形图样式展现 JSON 文档,并可实时编辑。针对数据量大的场景,可以做局部选取分析。
- 前端助手:功能和JSON-handle 差不多。但是功能更强大
- ReRes、ReRes、URLRedirector、XSwitch:重定向 URL。可以把请求的 js 文件重定向本地的 js,方便进行调试。
- Console Importer:用一个命令,从控制台导入 JavaScript 和 CSS 资源。
jQuery-hook 用于快速定位使用jQuery绑定到DOM元素上的事件的代码的真实位置,辅助逆向分析:https://github/JSREI/jQuery-hook
下载、安装 v_jstools 插件
v_jstools 是可以进行 web hook的浏览器插件。地址:https://github/cilame/v_jstools
浏览器打开上面的网站后,点击 code 按钮,选择 Download ZIP 选项,将文件下载下来,然后解压,会看到一个 v_jstools-main 的文件夹。
安装插件
- 谷歌浏览器地址栏输入:chrome://extensions/ 打开扩展程序页面,并打开开发者模式。如果是其他浏览器,请使用菜单栏打开。
- 打开后,点击左上角的 加载已解压的扩展程序 按钮,然后选择 v_jstools-main 文件夹,插件就已经加载进来了。
插件功能
在扩展程序中,打开该插件,看看支持哪些功能:
打开配置页面后,来到这里:
可以看到,有三个功能。
dom对象hook
第一个功能是 dom对象hook ,它内置了很多常见方法的hook,如eval,cookie,Function等,想hook哪个方法,直接打钩即可,非常的方便。有了这个,再也不用写油猴脚本啦。
ast hook替换
第二个功能是 ast hook替换,顾名思义,就是拦截某个js代码,通过ast处理后,再返回ast处理后的代码,让混淆代码见鬼去吧。
它给的示例代码是这个:
function fetch_hook(code, url) {
var ast = parser.parse(code);
function removedebugger(path) {
path.replaceWith(t.identifier("/*debugger*/"))
}
traverse(ast, {
DebuggerStatement: removedebugger
});
var {code} = generator(ast, {
jsescOption: {
minimal: true,
}
});
return code
}
这里简单说一下, fetch_hook 函数 接受2个参数,可以不用理会,如果你想hook特定的url,可以在函数的首行加入这样一段代码:
if (url.indexOf("https://www.xxx/xxx.js") == -1)
{
return code // 检测到不是这个 url 就直接返回原始代码
}
再就是编写 ast 插件了,按照这样下就好:
function removedebugger(path) {
path.replaceWith(t.identifier("/*debugger*/"))
}
traverse(ast, {DebuggerStatement: removedebugger});
先写方法,再遍历,也可以按照我星球里的方式进行编写,都是一样的。
不过在我使用了几次以后,还是觉得线下处理混淆代码香,当然要看你的使用场景了。
AST 的解密混淆
第三个功能是一些 AST的解密混淆,如图:
把混淆代码复制到上面的白色框中,点击对应的按钮即可解混淆,也是非常的方便。这里能解混淆的有 sojson,ob混淆,jsfuck以及压缩代码等,都是比较常用的功能。
试用了一番,可以还原最新版的ob混淆,效果还是很棒的。当然一些修改特征了的代码无法还原,这个要做到通杀确实有些难度。
v_jstools 补环境
点击 打开配置按钮:
按图进行如下设置:
实战案例 1:知乎搜索
实战:https://www.zhihu/search?type=content&q=python
抓包,查看 请求参数
需要的加密参数:
等网站加载完毕后,我们再点开这个插件,选择 生成临时环境 命令:
点击后,会有个弹框提示已复制到剪切板。这样,临时环境就帮我们生成好了,新建一个js文件 v.js, 将生成的环境复制过来进来并保存。我们再将这个参数加密的代码也复制进来,保存到一起,具体请参考这篇文章:https://blog.csdn/qq523176585/article/details/123814707
在加密函数处打上断点,记录实参和结果。
实参: '7861d84e110af123f2fc8c05ff38601f';
结果: 'a8O0QQuy28xYcR28f0NBkQe0kXtYUuY0mLxq66L0S7Yp'
在v.js中构造好实参,并打印结果:console.log(b('7861d84e110af123f2fc8c05ff38601f'));
保存后,运行结果
经过仔细比对后可以发现,和网页上面的结果是一模一样的。非常的 nice。
基本就靠一些CV操作,就把结果弄出来了,可以说非常的简单。
如果你不想打印上面的日志,可以将这个函数进行改写:var v_console_log = function(){{}}
这个插件试用了几天,已经解决了很多网站的加密,几乎可以说js逆向有手就行,当然,你需要一些js逆向分析的功底。毕竟它只是帮你补环境。注意,这个并不是万能的,因此有效网站如果不行的话,可能需要想其他的办法了哈。
实战案例 2:同花顺
- :https://blog.csdn/weixin_43411585/article/details/132440165
- :https://blog.csdn/qiulin_wu/article/details/133909883
实战:https://q.10jqka/
反爬参数如图
知识点:cookie 一般是两种,要么服务器生成,要么 js 生成,可通过如下方式判断
为啥要补环境:英文我们知道这个js文件代码内容会生成我们想要的参数,但是放到本地 nodejs 环境下运行不出结果,因为缺少浏览器环境特有的一些window/document/navigator/localstorage等参数,所以我们需要把这些缺少的浏览器环境补上,让这份js代码在本地nodejs环境下也能运行出结果来。请看这个图10秒钟
补环境分三部分:上、中、下。
- 在最上面放好你补的环境参数,
- 中间部分放好js代码,
- 最下面部分放生成的目标参数,
补环境的好处:就是可以完全不用考虑内部的算法逻辑,让它能正常跑起来输出就行
详细分析流程
-
1.先点击打开如下两个开关,然后打开配置页面
- 2. 如下插件配置详情,勾选上总开关,DOM开关,以及常用的挂钩,然后关掉该配置页面
- 3.直接看视频-缺啥补啥的方法补环境:https://www.bilibili/video/BV1FN4y1d7av/ 或者星球文章 后,我们知道生成 cookie 的 js 代码,如图 hook 到了cookie,然后堆栈回溯查看定位到具体的 js 文件内容
对比 cookie,发现 cookie 一致,说明找的位置正确。
- 4. 在 vscode 里面新建一个js文件,把 js 代码和希望输出的函数写好。还是3部分:
第 1 部分:待补的环境,把插件生成的临时环境放过来。后面
第 2 部分:复制 js 代码,也就是生成 cookie 的 js 文件。
第3部分:调用生成 cookie 的函数,生成 cookie
现在开始 "第1部分:待补的环境",使用插件生成临时环境
- 继续回到浏览器里面,先清掉缓存 cookie
- 然后刷新网页 ( 可以把所有断点全部删除 ),在滑动鼠标下滚下,防止无法正常生成临时环境,如下弹出,代表环境参数已经生成好
- 回到 vscode 里面,在刚才新建的 js 文件里面 ctrl+v 粘贴刚刚生成的临时环境,放在最上方
- 接下来,运行已经补好环境的 js 文件,最后发现可能会出现如下几种情况:
1. 生成的补环境,函数之间调用正常,可以直接使用;
2. 已经能生成正常cookie,但是不能用;例如:一直是固定的。
3. 完全生成不出 cookie 结果值;
下面针对两种情况进行分析:
- 一种是直接能用的,
- 一种是需要调试才能出结果的情况
方法 1:本案例操作流程之-生成临时环境-直接可以用的情况
1. 我们还是按之前的步骤清掉缓存,打开插件的勾选项,然后这里唯一要注意的点就是需要勾选script断点,然后用它生成的临时环境
2.刷新网页后,跳到目标生成cookie的js文件被断住的js后,我们取消script断点,直接下一步调试过去
3. 这时候点击插件的生成临时环境,可能会报错如下,生成的临时环境无法保存至剪贴板
4. 多点击几次生成临时环境就可以了,我们把它复制到本地js文件里面
5. ctrl+v粘贴到本地js文件中,运行能生成正常cookie,但是程序处于卡死无法退出状态
6.ctrl+s保存文件后,再次运行,这个时候已经能正常生成cookie值了,但是同样出现了我们上一篇文章介绍的虽然出来了cookie值,但是无法中断程序退出的现象,就是run后不能自动停掉程序,这时候我们可以尝试将setInterval()定时函数给置空试试,这是因为setinterval不会清除定时器队列,每重复执行1次都会导致定时器叠加,最终卡死你的网页(具体的大家可以调试看看)
7.我们在js代码的最上方的位置添加setInterval = function(){}将定时器置空即可,这时候能正常生成cookie了,并且把日志输出置空var v_console_log = function(){{}}
8.接下来我们验证下这份通过插件补的环境,与js代码生成的cookie最终能不能用,用python调用js文件试试,如下我们调用js生成的cookie验证,发现能成功拿到cookie,这说明我们用插件补环境也能用,而上面插件补环境我们只做了两个操作置空定时器,把日志输出关掉即可,接下来分析调试过程中,可能你生成的临时环境不能用的解决方法
方法 2:本案例操作流程之-生成临时环境-不可以直接用,需要调试补下
1.勾选Caught Exceptions,即使所发生运行时异常的代码在 try/catch 范围内,Chrome 开发者工具也能够在错误代码处停住,这里就不详细介绍了,大概思路如下
文章与视频
- 原文文章
- 十一姐b站视频
- 时光漫漫星球
JS hook 脚本
hook 又称钩子,可以在调用系统函数之前, 先执行我们的函数. 例如, hook eval
eval_ = eval; // 先保存系统的eval函数
eval = function(s){
console.log(s);
debugger;
return eval_(s);
}
eval()
// 可能会被检测到, 用这种方案来进行
eval.toString = function(){return 'function eval() { [native code] }'}
对 Function 的 hook, 主要为了解决无限 debugger
var qiaofu_function_constructor = (function(){}).__proto__.constructor;
(function(){}).__proto__.constructor = function(arg){
console.log("我爱你大大");
if(arg ==='debugger'){
return function(){}
} else {
return new qiaofu_function_constructor(arg);
}
}
上面都是 hook 的系统函数. 但有时, 我们需要hook某个属性. 此时应该怎么办?
var v;
Object.defineProperty(document, "cookie", {
set: function(val) {
console.log("有人来存cookie了");
v = val;
debugger;
return val;
},
get() {
console.log("有人提取cookie了∂
debugger;
return v;
}
});
在逆向时, 常用的主要有: hook eval 、hook Function 、hook JSON.stringify、JSON.parse 、hook cookie、hook window对象
Js 代码 替换
JS逆向|JavaScript代码线上替换(js 逆向 系列文章):https://blog.csdn/qq523176585/article/details/126258689
有的网站在用 debuger 调试之后,每一步都变得非常卡顿非常影响效率和心情,项目经过webpack处理了,请问这种有什么好的办法吗?
答案是:可以把源码保存到本地,然后用fiddler的atuo response替换线上的js调试
方法 1:使用谷歌浏览器自带的替换功能
Chrome 的 local overrides:https://zhuanlan.zhihu/p/36677472
方法 2:使用 fiddler 的 auto response 替换功能
fiddler 本地资源替换线上文件:https://wwwblogs/shichangchun/p/10731297.html
方法 3:使用 reres 插件进行替换
Github地址:https://github/annnhan/ReRes
使用方法:找不到变量生成的位置?让插件来帮你轻松定位:https://blog.csdn/qq523176585/article/details/109508013
方法 4:使用 Netify 插件进行替换
插件下载地址:https://chrome.google/webstore/detail/netify/mdafhjaillpdogjdigdkmnoddeoegblj
使用方法:工具分析 | Akamai2.0 还原后的js线上替换方案分享:https://blog.csdn/qq523176585/article/details/125093543
方法 5:v_jstools 插件进行替换
使用方法:AST实战技巧|使用v神插件动态替换AST还原后的代码:https://blog.csdn/qq523176585/article/details/124395678
2、jshook ( 安卓上用Js实现Hook )
频道: https://t.me/jshookapp
交流群: https://t.me/jshookgroup
安 装
- Frida 是一款跨平台的动态二进制注入工具,它可以在程序运行时监视并修改程序的执行。并且提供了 JavaScript API ,只要会 js 就可以快速实现 hook (支持 java层和native层)。
- JsHook 可以把 Frida 注入到目标应用中。frida 注入后,通过 JavaScript 代码可以完全访问内存中信息。JsHook 扩展并丰富了 Frida 的 api,例如:常用的文件操作、数据加解密、IMGUI悬浮窗UI、设备信息、视图操作、模拟点击、内核驱动内存读写...
在 root 环境下推荐安装 jshook 的 Magisk 模块,免 root 环境下使用 Lspatch 或者虚拟机。
jshook 相关文件下载地址:https://github/JsHookApp/Download
官网文档:https://doc.jshook/#/README
真机 root 环境 激活
手机已经拥有root权限,并且已经安装以下任意一种 root 框架
- magisk:https://github/topjohnwu/Magisk
- kernelsu:https://github/tiann/KernelSU
- apatch:https://github/bmax121/APatch
模块依赖 zygisk/riru,还需要安装以下任意模块用于支持激活 jshook
- zygisk (推荐):https://github/Dr-TSNG/ZygiskNext
- riru (已停止更新):https://github/RikkaApps/Riru
以上准备就绪后打开 jshook.apk 点击安装 Magisk/kernelSU 模块按钮选择,选择 zygisk 版本的 jshook 模块进行安装,安装后重启手机即可完成激活
使用 vmos 或者 光速虚拟机 等类似产品进行安装激活操作,同root环境激活方式
在模拟器中安装时,需要下载 MagiskDelta,再按照上面root环境激活的方式继续操作
真机 免root 环境 激活
如果手机无法root,可以尝试使用 lspatch https://github/LSPosed/LSPatch
lspatch 激活xp模块的方式是给目标应用进行修补过签名验证并修改程序入口,入口处会加入注入xposed框架以及调用lsp相关服务
安装 lspatch 后 jshook 会显示激活
安装完lspatch后你需要先将原应用
提取成apk文件
,可以使用mt管理器
进行操作,lspatch中点击管理
右下角+号
新建修补,选择apk文件,修补完成后,用mt管理器找到修补后的apk文件,并安装,安装完成后在lspatch的管理中即可看到被修补成功的应用,点击这个应用,会出现菜单,选择模块作用域
,勾选jshook即可完成激活
常见问题
目前加密脚本只能使用 fridamod 框架运行。
部分机型实时注入脚本会直接发生闪退情况,可以先关闭hook服务再启动应用,等待几秒后在开启hook服务会途中开始注入,在测试之前先取消勾选脚本,排除脚本原因
frida-server如何连接
jshook 提供的 frida-server 默认端口号为 28042 / 28043
#端口转发
adb forward tcp:28042 tcp:28042#spawn
frida -H 127.0.0.1:28042 -f com.android.xxx -l test.js
#attach
frida -H 127.0.0.1:28042 -n com.android.xxx -l test.js
frida-gadget 与 frida-server 一样更改了端口
#端口转发
adb forward tcp:28042 tcp:28042
#attach
frida -H 127.0.0.1:28042 Gadget -l test.js
渲染增强指不依赖android系统的情况下直接使用底层api进行渲染,android系统无法感知存在,所以在增强模式下性能最好,且屏幕录制和截屏无法获取到渲染数据。
没有开启渲染增强则使用android系统的api创建渲染试图,性能会有损失,且受系统管控,屏幕录制和截屏可以获取到渲染数据
连接 计算机
可以使用Visual Studio Code 实时推送脚本到手机,或者从手机获取脚本到电脑。下载 vscode 插件: https://marketplace.visualstudio/items?itemName=JsonET.jshook-vscode-extension
安装后在js文件右键或者快捷键操作
Shift+Alt+D: 推送脚本
Shift+Alt+C: 获取脚本
Shift+Alt+F: 清空日志
Shift+Alt+G: 查看日志,自动刷新
同步脚本时(脚本名+相对路径)与手机上一致即可,使用插件时需要jshook设置中启用服务端,使用快捷键后会出现输入ip的对话框,让电脑与手机在同一个wifi网络下。
启用服务端可以关闭jshook,不用保持在后台运行
基础 使用 教程
JsHook基础使用教程:http://blog.wutongliran.top/jshook基础使用教程/
实战分析&LSPosed+Xposed模块Hook&JsHook 过某60加固:https://bbs.binmt/thread-125074-1-1.html
环境 配置
前提:手机已经通过 Magisk 获取 ROOT 权限
演示环境:Magisk(面具)、JsHook、倒数日(要破解的软件)
打开 Magisk,在设置里勾选 Zygisk。
安装 JsHook
安装 JsHook 后,此时打开会提示未激活,需要下载 Magisk 模块 (下载 zygisk 版本)。
安装下载的模块,重启手机
显示已激活即为成功
安装 Frida 框架
点击框架管理,安装 frida 框架,这里选择 FridaMod 框架。
导入 frida hook js 脚本
点击脚本管理,点右上角导入脚本
脚本内容:
/**
* vip
*/
function hookTest1() {
let User = Java.use("com.lezhi.meitubao.Infos.User");
User["getVip"].implementation = function () {
return true;
};
}
/**
* 到期时间
*/
function hookTest2() {
let User = Java.use("com.lezhi.meitubao.Infos.User");
User["getVipExpireDate"].implementation = function () {
let ret = this.getVipExpireDate();
return ret= "天荒地老";
};
}
function main() {
Java.perform(function () {
hookTest1();
hookTest2();
});
}
setImmediate(main);
选择 目标 app 开始 hook
然后到应用列表里点目标 APP、勾选启动 Hook、框架选择默认(FridaMod 就是默认)、启动脚本(记得点右上角保存)
最后,重启目标 APP,脚本生效,解锁高级版
jshook 脚本 仓库
:https://github/bcmdy/JsHook-Script-Repo
新版仓库(V1.1.5+) 订阅地址:
- github(一般情况下需爬墙):https://raw.githubusercontent/bcmdy/JsHook-Script-Repo/master/Store-new.json
- CDN解析地址(一般情况下国内正常访问):https://gh-proxy/https://raw.githubusercontent/bcmdy/JsHook-Script-Repo/master/Store-new-cdn.json
API 说明
global (全局函数)
可以全局任何地方调用的函数。
- toast(message) 参数:message: string
- alert(message) 参数:message: string
- confirm(message,callback) 参数:message: string、callback: function
confirm('is ok?', { ok: function () { //... }, cancel: function () { //... } })
- uuid() 返回 string 类型的 32位小写 uuid
runtime (运行时相关信息)
用于获取当前hook运行时相关基础信息
- runtime.appInfo 返回值: ApplicationInfo
- runtime.packageName 返回值: string
- runtime.processName 返回值: string
- runtime.classLoader 返回值: ClassLoader
- runtime.isKernel 是否在内核模式中。返回值: boolean
- runtime.coreVersionCode 获取当前jshook的版本号。返回值: int
- runtime.modVersion 获取当前firamod的版本。返回值: string
- runtime.modVersionCode 获取当前firamod的版本号。返回值: int
app (当前app基本信息)
用于获取当前hook应用的基本信息
- app.isAppSystem() 判断 App 是否是系统应用。返回值: boolean
- app.isAppForeground() 判断 App 是否处于前台。返回值: boolean
- app.exitApp() 关闭应用
- app.getAppInfo() 获取 App 信息。返回值: object
- app.openUrl(url) 打开指定网址。参数: url: string 网址
- app.startActivity(activity) 启动 Activity。参数:activity: Activity
- app.getActivityList() 获取 Activity 栈链表。返回值: List
- app.finishActivity(activity) 结束 Activity。参数:activity: Activity
- app.finishToActivity(activity) 结束到指定 Activity。参数:activity: Activity
- app.startHomeActivity() 回到桌面
- app.dpToPx(value) dp转px。参数: value: float。返回值: int
- app.pxToDp(value) px转dp。参数:value: float。返回值: int
- app.getInternalAppDataPath() 获取内存应用数据路径。返回值: string
- app.getExternalAppDataPath() 获取外存应用数据路径。返回值: string
- app.getExternalAppObbPath() 获取外存应用 OBB 路径。返回值: string
- app.getExternalStoragePath() 获取外存路径。返回值: string
base64 (base64编码解码)
- base64.encode(data) 参数:data: string。返回值: string
- base64.encodeBytes(data) 参数:data: byte[]。返回值: byte[]
- base64.decode(data) 参数:data: string。返回值: string
- base64.decodeBytes(data) 参数:data: byte[]。返回值: byte[]
media (播放音乐)
用于播放音乐
- media.create(data) 参数:data: url 地址或者文件base64值。返回值: 实例。调用后默认会自动播放,无需调用start
- [实例].start() 开始播放
- [实例].pause() 暂停播放
- [实例].stop() 停止播放
- [实例].loop(state) 参数:state: boolean。是否循环播放,默认音乐只播放一次
- media.closeAll() 关闭所有实例
crypto (字符串加密解密)
-
crypto.encrypt(key,data,enctype,transformation)
参数:
key: string
data: string
enctype: CRYPTO_AES | CRYPTO_DES
transformation: 转换的名称 例如 DES/CBC/PKCS5Padding
返回值: string -
crypto.encryptBytes(key,data,enctype,transformation)
参数:
key: byte[]
data: byte[]
enctype: CRYPTO_AES | CRYPTO_DES
transformation: 转换的名称 例如 DES/CBC/PKCS5Padding
返回值: byte[] -
crypto.decrypt(key,data,enctype,transformation)
参数:
key: string
data: string
enctype: CRYPTO_AES | CRYPTO_DES
transformation: 转换的名称 例如 DES/CBC/PKCS5Padding
返回值: string -
crypto.decryptBytes(key,data,enctype,transformation)
参数:
key: byte[]
data: byte[]
enctype: CRYPTO_AES | CRYPTO_DES
transformation: 转换的名称 例如 DES/CBC/PKCS5Padding
返回值: byte[] -
crypto.rc4Encrypt(key,data)
参数:
key: string
data: string
返回值: string -
crypto.rc4EncryptBytes(key,data)
参数:
key: byte[]
data: byte[]
返回值: byte[] -
crypto.rc4Decrypt(key,data)
参数:
key: string
data: string
返回值: string -
crypto.rc4DecryptBytes(key,data)
参数:
key: byte[]
data: byte[]
返回值: byte[] -
crypto.md5(data)
参数:data: string
返回值: string -
crypto.md5Bytes(data)
参数:data: byte[]
返回值: string -
crypto.sha1(data)
参数:data: string
返回值: string -
crypto.sha1Bytes(data)
参数:data: byte[]
返回值: string -
crypto.sha256(data)
参数:data: string
返回值: string -
crypto.sha256Bytes(data)
参数:data: byte[]
返回值: string
device
- device.isAdbEnabled()
- device.getSDKVersionName()
- device.getSDKVersionCode()
- device.getAndroidID()
- device.getMacAddress()
- device.getManufacturer()
- device.getModel()
- device.getABIs()
- device.isTablet()
- device.isDevelopmentSettingsEnabled()
- device.getScreenWidth()
- device.getScreenHeight()
- device.getScreenDensity()
- device.getScreenDensityDpi()
- device.isLandscape()
- device.isPortrait()
- device.screenShot(activity)
- device.setClipboard(data)
- device.getClipboard()
file
- file.isFile(path)
- file.isDir(path)
- file.isExists(path)
- file.read(path)
- file.readBytes(path)
- file.write(path,content)
- file.writeBytes(path,content)
- file.append(path,content)
- file.appendBytes(path,content)
- file.copy(path,topath)
- file.move(path,topath)
- file.rename(path,newname)
- file.delete(path)
- file.getName(path)
- file.getSize(path)
- file.zip(path,topath,passwd)
- file.zip(path,topath)
- file.unzip(path,topath,passwd)
- file.unzip(path,topath)
http
- http.get(url,headers,function)
- http.post(url,data,headers,function)
- 注意事项
curl
- curl(url,method,headers,body,function)
json
- json.toGsonString(data)
- json.gsonStringToClass(data,class)
- json.toJSONString(data)
- json.parseObject(data)
- json.parseArray(data)
modmenu (mod菜单)
- modmenu.create(title,options,function)
- 自定义控件id
- 多个tab实例
- [实例].close()
- [实例].state()
- [实例].size(width,height)
- [实例].position(type,x,y)
- [实例].icon(img)
- [实例].edgeHiden(enable)
- [实例].update(id,value)
- modmenu.closeAll()
moddraw (底层绘制)
- moddraw.create(function)
- [实例].close()
- moddraw.closeAll()
- 注意事项
kernel
- kernel.getModuleBase(libname)
- kernel.readDword(address)
- kernel.readFloat(address)
- kernel.writeDword(address,value)
- kernel.writeFloat(address,value)
- 示例脚本
memory
- memory.getModuleBase(libname)
- memory.readDword(address)
- memory.readFloat(address)
- memory.writeDword(address,value)
- memory.writeFloat(address,value)
- 示例脚本
storage
- storage.get(key)
- storage.set(key,data)
- storage.del(key)
- storage.clear()
convert
- convert.stringToByte(data)
- convert.byteToString(data)
- convert.hexStringToByte(data)
- convert.byteToHexString(data)
- convert.byteToBitmap(data)
- convert.bitmapToByte(data)
- convert.byteToDrawable(data)
- convert.drawableToByte(data)
- convert.byteToInputStream(data)
- convert.inputStreamToByte(data)
- convert.byteToOutputStream(data)
- convert.outputStreamToByte(data)
dialog
- dialog.input(title,callback,content)
view
- view.findViewByText(text)
- view.getPosition(view)
- view.findViewPositionByText(text)
- view.runOnUiThread(function)
keys
- keys.click(x,y)
- keys.swipe(x,y,tox,toy,time)
- keys.back()
- keys.home()
- keys.enter()
- keys.del()
- keys.text(text)
colors
- colors.toString(color)
- colors.red(color)
- colors.green(color)
- colors.blue(color)
- colors.alpha(color)
- colors.rgb(red,green,blue)
- colors.argb(alpha,red,green,blue)
- colors.parseColor(color)
canvas
- canvas.create(function)
- [实例].close()
- [实例].maxfps(fps)
- canvas.closeAll()
- frida简单示例
3、免 root 框架:神之手
神之手:https://download.csdn/download/freeking101/89349747
文件下载: http://route.lozn.top:88/lozn/ lozn后面要加/否则404
LSPatch(已停止更新) 是免 root 的 Xposed 框架,NPatch 是基于 LSPatch 开发的免root 框架,都是以 LSPosed 为基础的免 root 的 Xposed 框架,不需要 Root 就可以使用 LSPosed 框架,原理是通过在目标 APK 中插入 dex 等来集成 Xposed API。神之手也是通过改造手机上已经安装的或者本地app,然后植入钩子框架代码,使被改造的app在启动时自动加载钩子,从而执行 hook 代码。
"免 root 框架" 非常适合没有 root 的但是又想使用 LSPosed 功能的手机。
神之手
"超度应用" 就是在目标 APK 中插入 dex 等来集成 Xposed API,通过这个 dex 可以 hook
场景:一种无root抓包方法
:https://www.52pojie/thread-1773022-1-1.html
当你尝试抓包某个软件时是否遇到过
但你又没有 root,那么这时候你就需要三大法宝:抓包组合拳
首先打开 jshook(开启无root模式),找到你要抓包的应用,启用 hook 服务,选择相应框架,再点击 LSPatch 注入 hook 服务,安装应用。
如果软件签名校验较强,加固较强比如4x90加固undefined,就别想了,还是乖乖root或者放弃吧。这就是这个方法的限制
安装完成后在jshook找到软件,在最下方启用xp模块,选择算法助手
启用 算法助手。
然后打开算法助手,开启相应功能,例如你要抓包,就开启这三个功能,然后把后台全部划掉。
重新打开jshook、算法助手(施法过程),注意,使用过程保持这两个应用程序后台。
尝试抓包,成功解决抓包断网问题
4、算法助手
算法助手是一款运行在Android平台上基于Xposed的安卓调试工具,配合Xposed(需要Root或者沙盒环境),通过一系列反射操作,进行应用的安全测试,调试分析,代码定位,是一款不错的调试工具。开发者:军哥(757456456@qq)。主要功能:
- 1、Md5,Sha等信息摘要算法(MessageDigest类)
- 2、AES、DES,RSA等秘钥算法(Cipher类)
- 3、Hmac等含有秘钥的哈希算法(Mac类)
- 4、对话框的定位(Dialog类)
- 5、Log捕获(LOG类)
- 7、拦截程序退出(System以及其他类)
- 8、justTrustMe升级版(可高效自动定位混淆后的okhttp)
- 9、文件访问记录(File类)
- 10、自定义Hook,可自行定义hook类,可设置返回值,可拦截执行
- 11、webViewDebug(使webView可调试)
- 12、shell命令行纪录
- 13、……后续会不断进行增加
算法助手Pro版本下载:https://www.123pan/s/7G8aTd-g3T4H.html 提取码:u7Zn
算法助手使用教程:https://bbs.kanxue/thread-268565.htm
算法助手使用教程:https://blog.csdn/u014645251/article/details/119030982
【初级教程】算法助手简单教程:https://bbs.binmt/forum.php?mod=viewthread&tid=64273
5、hookui
hookui 是什么
hookui 是一款 xposed 插件,必须依赖 xposed 框架环境
- root 环境有 xposed framework、edposed、LSxposed。
- 非root 有 virtual app 以及类似多开平行空间的一些软件。
- 基于 app 直接修改,然后植入 xposed framework 的有 太极,神之手 goodhand文档 ,它能快速跟踪一些行为从而找到破解的思路,就像 window 破解一样,也有类似的,如 hook window api 的某些函数,hook io 文件打开,注册表行为。而这个 hookui 也类似行为,可以对一些敏感行为可进行追踪拦截,可追踪调用堆栈。
可以做什么
通过 HOOKUI 做了很多不可告人的事情,常用的爆破策略是 追踪点击,布局事件,敏感字符串的源头来针对性的做 hook 功能。破解一些没什么验证的收费 SE 直播,倒计时自动关闭视频直接拦截对方法进行屏蔽的操作。也通过它直接改手机余额,来告诉那些拜金女小心骗子。
hook、字段编辑
支持自定义填写要hook的类,支持方法参数调用,支持批量修改列表数据,支持修改字段,实例,内存漫游字段修改,支持字符串,触摸事件,窗口创建,布局设置堆栈追踪打印. 支持开启web服务,下载任意应用内数据,支持web端做一些hook操作(此功能是移植inspect,不过兼容没有root的手机
支持 webview 注入,显示 webview hook 菜单(调用js,查看源码) 支持 activity 序列化保存,
下载、使用
官网:https://hookui.lozn.top/#/?id=main
下载:https://github/Xposed-Modules-Repo/lozn.hookui
常见的更新地址如下: qq群(不稳定容易被封), telegram(需要翻墙)。不可使用本软件进行诈骗从事违法行为等行为,仅供学习使用!触发法律后果自负!软件使用的时候协议上也一再强调禁止用于违法用途!切记切记。群主非本人 [qq群 659119840]群若提示不存在,请加入电报群以便获得新群,请悉知。qq 35068264 的qq空间可以翻找说说,有时会会把加群图片放在QQ空间
- 电报 : https://t.me/qssq666
- 简书 https://www.jianshu/u/9b0768e66d01
- 博客 http://lozn.top/
电报有一些使用的视频教程,而简书有一些图文的教程,其它的只能问问群里人了
微信公众号:情迁说科技。抖音:lozn00/。快手:吉凶以情迁
B站:https://space.bilibili/101043764
文件下载: http://route.lozn.top:88/lozn/ lozn 后面要加 / 否则404
下载安装完成后,首先需要在 LSPosed 中启用模块,然后选择在哪些 app 上生效。
在 LSPosed 的 hookui 模块中点击设置,打开 hookui (也可以直接通过点击 hookui app 打开)。
打开对应 app
如果 "其它应用中" 没有 彩色渐变图标,这基本代表你在 hookui 界面所进行的一些功能都是无法正常生效的,可能你用 logcat 也看不到 hookui 关键词的一些堆栈调用 等数据。解决方法:
- 1. 如果其它应用中没有图标,确保 hookui 是最新版。
- 2. 确保在 hookui 中勾选开启了总开关,在激活应用选项卡中确保勾选了 该应用
- 3. 会使用 hook 框架,以及正确激活一个 xposed 插件,毕竟 hookui 也是一个xposed插件
- 4. 上面确保的情况下,可以把 hookui 界面的其它选项勾选全部关闭。再试试是否正常。
- 5. 不要随意开启一些功能,可能会造成非常卡顿。比如延迟启动,这个主要是用于调试用的,比如你需要断点调试so,那么这个时机就很重要。字符串调用更不要随意开启,这是非常非常频繁的功能.
点击 "彩色渐变图标",图标内菜单界面功能如图:
案例教程
逆向与安全 系列:https://www.jianshu/nb/15035584
精彩连接之HOOKUI-hook字符串
精品教程之HOOKUI-hook点击事件
精彩连接之HOOKUI-内存搜索
精品教程之HOOKUI-activity字段编辑
精彩连接之HOOKUI-Web服务器
精品教程之HOOKUI-文件访问
精品教程之HOOKUI-ui分析
精品教程之HOOKUI-dump文件
精品教程之HOOKUI-延迟启动应用脱壳
install 是 xx.apk 的文件,
uninstall 是这个apk文件里面具体存在的包名。
adb shell pm list packages 列出手机中所有安装包的包名
adb shell pm list packages
adb uninstall com.xx.xx
adb -s xxxx uninstall com.xx.xx 多个设备时,-s 可以指定设备
adb -s xxxx uninstall -k com.xx.xx 卸载应用但是保留配置和缓存文件。
HOOKUI --- hook字符串
hookui 逆向 xposed 神器 之 字符串hook跟踪逆向分析。不用抓包工具也能抓http :https://www.jianshu/p/474a60fe194a
安卓JAVA内存漫游、字段替换:https://bbs.pediy/thread-269107-1.htm
hook字符串有两种方式一种是在应用启动之后在界面里面设置,另外一种则是在app启动的时候就记录。
第一种:启动就抓取
第二种:在应用界面里面设置。
打开 要 hook 的应用,点击 应用上的 hookui 图层。如下,点击红色图标。
达到了类似 frida 的效果。 (还有很多功能没做,比如动态编写 js代码,实时 hook 监听)
这里面有3个选项,第一个是 hook 字符串api,后面两个是拼接类的调用了。
选择 hook 就会开始 hook,这个时候可能 app 会有点卡,因为字符串他比较多,"关键字设置" 就是匹配到关键词就会打印堆栈信息。"启用关键字替换" 如果填写了,那么匹配到关键词就会替换成你需要的文字内容。选择 hook 后,不会有任何提示(懂的人都知道,提示也会调用字符串,这会导致一个死循环)