android 显示gpu 竖条 安卓启用gpu调试层 | 您所在的位置:网站首页 › 启用gpu调试层的作用 › android 显示gpu 竖条 安卓启用gpu调试层 |
学习到的内容 — 1、在java层,对容器类的对象进行hook来进行快速定位 2、ida的findcrypt插件对so层的算法快速识别 3、文章分析简单,就是记录了一次新的hook思路,没有新的套路,就当作练手了,有一个字段没有分析出来,之后知道了会补上的 算法逆向过程 — APP登陆界面: 数据包(请求和相应)如下: POST /api/v1/auth/login/sms HTTP/1.1Content-Type: application/jsonConnection: closeCharset: UTF-8User-Agent: Dalvik/2.1.0 (Linux; U; Android 8.1.0; Pixel Build/OPM1.171019.011)Host: api.taozuiredian.comAccept-Encoding: gzipContent-Length: 464{"code":"9500","device_id":"1f37638fd87cb9056801c785e040957f","channel":"aliapp","sign":"850da5bdfd60c42cc1dbc027884c85325e4145a8","getui_push_id":"6c6d6b7b7c1a7d6990cbcb17a27d55ee","nonce":"ecoxul1604389882104","mac":"AC:37:43:4F:22:9D","imei2":"null","device_name":"google Pixel","imei1":"359906070277673","system":"1","phone":"19817353426","app_ver":"53","device_udid":"6992562083e7f7b8ed1ed6e285c5dce9","from":"app","os_ver_code":"27","timestamp":"1604389882"}HTTP/1.1 200 OKServer: nginx/1.12.2Date: Tue, 03 Nov 2020 07:51:50 GMTContent-Type: application/jsonContent-Length: 187Connection: closeCache-Control: no-cache, privateAccess-Control-Allow-Origin: *Vary: Origin{"code":0,"success":true,"data":{"token":{"token":"03c24bI23Od8BcPkyEsgTxPjvGqMhRmUmEsAGSEjgR73m3s2H3BmHmCydn6Y8yqa","expired_at":1604476310,"refresh_expired_at":1606981910},"smfk":true}}对java层直接进行hook,初步分析内容如下: code:验证码 device_id:md5(imei1) sign:不知道,但是可以看到签名值为40个字符,应该也就是sha1了 getui_push_id:不知道 nonce:随机6个字符 + timestamp device_udid:md5(ffffffff-ec38-7ce6-0000-0000495241ed) 小提醒:ffffffff-ec38-7ce6-0000-0000495241ed这个值每个手机都是不同的,uuid md5(imei1 + mac) =》 a59a6b16b9053a50c64805a5256bf113,不知道是啥 进行快速定位,这次用到方法是一个新的思路,来对java中容器类来进行hook,常用的都有HashMap类 ArrayList类 StringBuiler类 实现的代码: var hashMap = Java.use("java.util.HashMap"); hashMap.put.implementation = function (key, value) { if (value == 'XXXX' || value == 'XXXX' || value == 'XXXX' || key == 'username' || key == 'user' || key == 'password' || key == 'pass' || key == 'sign') { send(key + " " + value); showStacks(); } return this.put(key, value); send("======================================"); }; var arrayList = Java.use("java.util.ArrayList"); arrayList.add.overload("java.lang.Object").implementation = function (value) { if (value == 'XXXX' || value == 'XXXX' || value == 'XXXX') { send(value); showStacks(); } return this.add(value); send("======================================"); }; var stringBuilder = Java.use("java.lang.StringBuilder"); stringBuilder.append.overload("java.lang.String").implementation = function (value) { if (value == '19817353426' || value == 'a12345678' || value == 'e10adc3949ba59abbe56e057f20f883e') { send(value); showStacks(); } return this.append(value); send("======================================"); };通过分析函数调用栈来到sign的地方,然后进行了动态调试,感觉能动态调试的话比写代码方便多了 两个断点分别读取到的p0(v4)对应的值 VM> readvar v4 string"app_ver=53&captcha_id=&captcha_value=&channel=aliapp&device_id=75e908ea96987513c2a884591adb8a93&device_udid=b11785ed41cdef913e41b7b95796e7b4&from=app&mac=02:00:00:00:00:00&nonce=rxks7r1604403451122&os_ver_code=22&phone=19817353426&system=1×tamp=1604403451"VM> readvar v4 string"1fe0b02e4d0affbbde831618c73a065dafe80db7"分析sign的生成 最终是加载了libtre.so文件中静态注册的导出函数sign 该函数为静态注册的函数,命名如下: 分析的注释如下: 这里可以使用ida中的findctypt插件,可以帮助我们快速定位,之前说了sign是40个字符的,那么这个插件也能通过特征码(算法初始化常量)来匹配出对应的算法 最后模拟sign测试: 1、将如下的数据进行base64加密 app_ver=53&captcha_id=&captcha_value=&channel=aliapp&device_id=75e908ea96987513c2a884591adb8a93&device_udid=b11785ed41cdef913e41b7b95796e7b4&from=app&mac=02:00:00:00:00:00&nonce=rxks7r1604403451122&os_ver_code=22&phone=19817353426&system=1×tamp=1604403451b2qKgtaW4,9z9D`Fmst?K5JZbLYOY]NP6ssGf2U~;zk9oCNgoytV!}wW7ia+`w9g2、将base64编码的结果进行sha1加密 最后有一个字段没有分析出来,之后再补上吧,分析过程: getui_push_id,这边可以从登陆按钮产生的调用栈来观察,结果如下: D:\ATTACK\Android\Frida\myHook>D:/python38/python.exe d:/ATTACK/Android/Frida/myHook/frida-demo.py[*] java.lang.Throwable at com.maihan.tredian.net.MhRequestUtil.a(Native Method) at com.maihan.tredian.net.MhNetworkUtil$1.run(MhNetworkUtil.java:76) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:818)发现Util.g会先判断LocalValue.g的值是否存在,存在则将LocalValue作为getui_push_id的值 默认LocalValue.g是一个静态属性 com.maihan.tredian.util.LocalValue通过wallbreaker插件(Objection插件)对这个对象结构进行打印观察,发现g已经被赋值了,所以这个应该是程序开启的时候就已经被初始化了 plugin wallbreaker classdump com.maihan.tredian.util.LocalValue继续对该g属性进行交叉索引 来到如下的地方,Hook该方法的调用栈,代码实现如下: 会发现是从这个意图类中进行获取的clientId的值 最终只能看到这里,因为上一层就是系统的函数了无法查看,系统dispatchMessage给这个函数进行调用,这个函数是用来处理消息队列中的消息的,目前技术不行,也没研究深入... |
CopyRight 2018-2019 实验室设备网 版权所有 |