免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
内容参考于:图灵Python学院
本人写的内容纯属胡编乱造,全都是合成造假,仅仅只是为了娱乐,请不要盲目相信。
工具下载:
链接:https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd=6tw3
提取码:6tw3
复制这段内容后打开百度网盘手机App,操作更方便哦
上一个内容:16.安卓逆向-frida基础-HOOK类方法2
然后接着继续Frida HOOK,现在的技术的叫Frida调试,Frida调试原理就是把所有方法全部HOOK然后逐个分析
首先连接adb shell,然后运行frida server(f14)
HOOK排序算法
有的app它会把参数进行一个封装(整合)丢到一个算法里去加密,加密算法如MD5、sha、mac等,然后在加密之前会把参数进行一个处理。
然后加密算法的特点:第一点明文不一样,加密的结果也不同(MD5、sha),第二点没有解密的钥匙加密完的结果不可逆,第三点加密完的结果长度一致
在app里面对参数加密时,会先对数据进行排序,加密的原因由于结果不可逆,服务端需要接收数据复现算法来对比加密结果,排序算法可以保证不会因为参数乱序而导致结果不同
然后开始,首先双击打开 jadx-gui-1.4.7.exe并且把apk文件拖到jadx-gui-1.4.7.exe里
然后Firda HOOK脚本代码
function showStacks(){console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new() )); } function paixusuanfa(){ var Collections = Java.use('java.util.Collections'); // Hook sort() 方法 Collections.sort.overload("java.util.List").implementation = function(list) {console.log('Hooked Collections.sort()'); console.log('List: ' + list.toString()); // 可在此处对参数进行修改或记录 // 使用 Java.cast 进行类型转换 将list转换成ArrayList类型 var res = Java.cast(list,Java.use("java.util.ArrayList"))if(res.toString().includes("userPwd")){showStacks()} console.log('List list-->',res) // 调用原始的 sort() 方法 return this.sort(list); }Collections.sort.overload("java.util.List","java.util.Comparator").implementation = function(a,b) {console.log("Hooked Collections.sort()22222");var res = Java.cast(a, Java.use("java.util.ArrayList"))if(res.toString().includes("userPwd")){showStacks()}console.log('Comparator list-->',res)return this.sort(a,b); }}Java.perform(function (){ paixusuanfa()})
效果图:然后根据打印的栈信息,去jadx-gui-1.4.7.exe里找
首先根据栈信息得到它调用了一个onClick方法,然后就从onClick方法入手
然后点击下图红框位置
搜索 LoginActivity类,通过栈可以看出onClick方法在LoginActivity类中,所以通过搜索 LoginActivity类名来找onClikck
如下图找的类
然后双击下图红框位置
进入类中
然后找onClick方法,如下图onClick方法,然后开始分析它
通过Firda hook脚本知道onClick里面调用了login方法,如下图源码也确实调用了,然后鼠标左键双击下图红框里的login进入login方法里
然后在login方法中调用了,下图红框的方法发送了登录请求,然后再进入requestNetwork方法里
然后下图蓝框可以看到它重写的响应处理
然后通过Frida hook看出入参是在红框里组装的
然后
然后,可以看出通过排序也是可以找到入参的
然后另一个栈,可以看出与上面的栈一样
hook string字符串
很多app在参数加密的时候会把字符串转成字节,一般stirng离着加密最近,也就是说stirng的内容是已经处理好的,所以在stirng的位置往上找,会找到一些蛛丝马迹
Frida hook脚本代码
function showStacks(){console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); } function hookString(){var StringClass = Java.use('java.lang.String');// Hook String 类的构造函数StringClass.getBytes.overload().implementation = function () {console.log('Original Value');// 可在此处修改传入的字符串参数var res = this.getBytes();var newString = StringClass.$new(res)// 输出修改后的值console.log('Modified Value: ' + newString);return res;}}Java.perform(function (){ hookString()})
效果图:
打印堆栈的写法
function showStacks(){console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); } function hookString(){var StringClass = Java.use('java.lang.String');// Hook String 类的构造函数StringClass.getBytes.overload().implementation = function () {console.log('Original Value');// 可在此处修改传入的字符串参数var res = this.getBytes();var newString = StringClass.$new(res)// 输出修改后的值console.log('Modified Value: ' + newString);if (newString.toString().includes('username')){// 字符串中包含 username 就打印堆栈showStacks()}return res;}}Java.perform(function (){ hookString()})
分析栈
通过上方的栈看源码,下图红框位置是md5加密
然后进入md5方法,可以看到下图红框位置它调用了getBytes方法,在加密之前获取了字符串的字节(或者说是字符),基本上所有md5的都会这样写,md5要的参数就是字节,对于安全方面来说下图中的md5的写法需要改一下,自己实现字节转换,不要用它提供好的方法,避免被人用上方的Frida hook脚本拦截
Stirng还有一个静态的getByte方法,如下图红框
function showStacks(){console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); } function hookString(){var StringClass = Java.use('java.lang.String');// Hook String 类的构造函数StringClass.getBytes.overload().implementation = function () {console.log('Original Value');// 可在此处修改传入的字符串参数var res = this.getBytes();var newString = StringClass.$new(res)// 输出修改后的值console.log('Modified Value: ' + newString);if (newString.toString().includes('username')){// 字符串中包含 username 就打印堆栈showStacks()}return res;}// Hook String 类的静态方法StringClass.getBytes.overload('java.lang.String').implementation = function(obj) {console.log('Hooked String.valueOf()');// 可在此处修改传入的对象参数showStacks()var res = this.getBytes(obj);var newString = StringClass.$new(res,obj)// 输出修改后的结果console.log('getBytes: ' + newString)return res}}Java.perform(function (){ hookString()})
效果图:可以看到它也是可以hook到请求入参的
hook StringBuilder字符串
StringBuilder也是一种数据存放的容器
Frida HOOK脚本代码
function showStacks(){console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new() )); } function d(){ // 获取 StringBuilder 类并定义需要 Hook 的方法名 var stringBuilderClass = Java.use("java.lang.StringBuilder"); stringBuilderClass.toString.implementation = function (){var res = this.toString.apply(this,arguments)if (res == ""){showStacks()console.log('tostring is called ',res)}console.log('tostring is called ',res)return res }}Java.perform(function (){ d()})
效果图:注意下图红框接口返回的是加密的数据(密文)现在它是明文,这样通过打印栈信息可以找到它解密的代码
然后还可以看到请求入参的明文和响应的密文,可以发现StringBuilder也可以覆盖很多东西,所以直接把所有方法所有类全HOOK掉就一定可以找到漏洞
HOOK点击按钮进行定位
Andriod sdk里有一个工具叫做 uiautomatorviewer.bat,如下图红框
双击上图红框里文件运行之后,会出现下图中的内容,然后点击下图红框里的按钮,会出错
下图出错的原因是,安装了多个Android SDK当前目录未配置环境变量,意思就是找错目录了
需要用环境变量里的那个目录,如下图是Path的环境变量的内容,需要在这里面打开 uiautomatorviewer.bat才行
然后下图的错是因为,uiautomatorviewer.bat不维护了正常版本的会有问题,网上有大神修改了,需要下载修改的uiautomatorviewer.bat才行,已经放到百度网盘了
如下图:下载下图红框里的东西
上图红框里的东西下载完,然后把里面的tool进行复制,然后把原本Android SDK里的tool删了(一定要删了或者改个名)然后把复制的tool粘贴过去,如下图
然后再次双击 uiautomatorviewer.bat 运行
然后再点下图红框按钮连接手机就可以了,它可以看组件的id,如何使用继续往下看
然后鼠标点击,下图红框位置后,就可以在下图蓝框位置看到它的id(下图也就是输入框组件的id)
主要是看它按钮的id,如下图按钮的id是btn_login,找到了它的id就可以对它进行hook
Frida Hook脚本代码:它是通过hook绑定事件的setOnClickListener方法来实现,它只能通过Frida重启app的方式来拦截
function showStacks(){console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); } function d(){ var btn_login_id = Java.use("com.dodonew.online.R$id").btn_login.value;console.log('id:',btn_login_id)var View = Java.use('android.view.View');View.setOnClickListener.implementation = function(listener) {console.log(this.getId(),"22222222222")if (this.getId() === btn_login_id){showStacks()console.log("view.id-->" + this.getId())}// 调用原始的setOnClickListener方法return this.setOnClickListener(listener);};}Java.perform(function (){ d()})
下图通过红框里绑定了点击事件,处理点击事件的函数是通过实现下图蓝框里的接口来的,也就是setOnClickListener方法绑定的是当前类(this就是当前类)
然后在下图中可以看出 OnClickListener 接口只有一个onClick方法,所以源码中 LoginActivity类就一定会实现onClick方法并且在点击空间的时候会执行onClick方法
也就是会执行下图红框的代码,这就是通过id来hook看源码的思路
强制重启hook的Frida命令:frida -Uf com.dodonew.online -l ./xxx/js,也就是使用 spawn 模式,执行之后app会关闭重启,重启时会处于卡死状态,需要输入 %resume 让app运行起来
执行的指令
效果图: