文章总结: 本文详细介绍了某友APP的逆向分析过程,作者通过Java层和SO层两步分析,成功逆向了该APP的sig签名生成机制。在Java层使用jadx定位到sig参数的生成位置,发现它由so层函数处理;在SO层使用IDA和Fridahook技术,最终确定sig是通过MD5算法对特定参数组合加密生成的。文章提供了完整的分析思路和工具使用方法,是安卓逆向学习的优质案例。
综合评分: 91
文章分类: 逆向分析,移动安全,二进制安全,漏洞分析,实战经验
安卓逆向 — 某友APP案例分析
buluo533
逆向有你
2025年12月12日 11:21
河南
本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关.本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责
为了给即将结束的学生生涯留下印记,把学校用的所有APP全部分析一遍,进行一个记录。这个样本可以作为so层的入门教程进行参考学习。
一、样本基本信息
接口信息:https://*****/330000/v8/circle/feed/list
样本信息:
逆向核心参数:sig
其中还包括大批量的设备指纹信息,也可以作为一个入门阶段的学习,非常优质的样本
二、逆向思路
1、java层分析
样本app无壳,直接拖入jadx,搜索https://*****/330000/v8/circle/feed/list接口信息(脱敏一下,大佬们抓包可以看到整个接口信息)
用的是okhttp框架,继续进去分析
这里我们可以看到请求接口传入的headers和params参数,我们利用快捷键x查询C0函数引用位置
、
对照入参我们知道,第一个是headers,第二个是params,我们需要处理的核心参数sig就在headers当中。
a10是c0289a.a()产生,直接跟进去看看
这里有大量的指纹生成,但是不是我们分析的核心,大佬们感兴趣可以试试,非常优质的样本。
这里就找到一个sig的生成位置,跟进去看看,这里我们可以看到第二个参数是null,这里可以作为一个过滤点,方便我们定位需要的入参,以及后续的分析
然后我们就可以找到so文件加载,明显知道是一个so层的加密,先hook一下入参情况
function hook_socall() { Java.perform(function () { let a = Java.use("sa.a"); var TreeMap = Java.use('java.util.TreeMap'); a["cscd130065c407"].implementation = function (treeMap, str) { if (str == null) { console.log(`a.a is called: treeMap=${treeMap}`); let result = this["cscd130065c407"](treeMap, str); console.log(`a.a result=${result}`); return result; } }; });}function main() { hook_socall()}setImmediate(main)// frida -Uf com.sohu.sohuhy -l .\hy_hook.js
从整体来看,第一个treemap是前面存入的一些请求头校验信息,同时也包含了token参数,返回值是一个32位的参数,猜测是md5,可以将参数丢进标准算法中和返回值对比
应该是在so层对入参进行了一些处理,我们丢进ida进行so层的逻辑处理
2、so层分析
拖入ida进行分析,先在导出函数表确定是动态注册函数还是静态注册函数,搜索java,可以发现是一个静态注册函数
点击跳转到对应的地址
通过快捷键tab或者f5进入到伪c界面
修改jni函数入参方便分析,修改后通过f5刷新伪c代码,这样就可以清晰看到jni函数的调用
已经写了一部分的注释,可以参考
通过代码分析,可以看到这段伪c代码不断对treemap入参进行处理,包括追加,同时判断了一个data参数是否为空,在java层我们可以知道,这里的data很明确是空值,我们就可以确定这个判断的走向
之后持续对reale_str进行追加,同时只有一个地方调用了这个参数入参追加结果,可以怀疑这是一个加密入口,将他改名留一个记录,进入函数查看分析
这里的话可以看到返回值是a1,从a1往上推导,在备注rucan这个函数有唯一的调用,同时也是唯一的函数,进入其中继续分析
这里的话也只有一个函数调用,已经被我改名了,是通过ai分析得到是一个标准的md5算法
既然这里可能是加密的核心,我们来做一个参数的hook分析,看看情况。找到函数的偏移,6A8CC
function print_arg(addr){ var module = Process.findRangeByAddress(addr); if(module != null) return hexdump(addr) + "\n"; return ptr(addr) + "\n";}function hook_native_addr(funcPtr, paramsNum){ var module = Process.findModuleByAddress(funcPtr); Interceptor.attach(funcPtr, { onEnter: function(args){ this.logs = []; this.params = []; this.logs.push("call " + module.name + "!" + ptr(funcPtr).sub(module.base) + "\n"); for(let i = 0; i < paramsNum; i++){ this.params.push(args[i]); this.logs.push("this.args" + i + " onEnter: " + print_arg(args[i])); } }, onLeave: function(retval){ for(let i = 0; i < paramsNum; i++){ this.logs.push("this.args" + i + " onLeave: " + print_arg(this.params[i])); } this.logs.push("retval onLeave: " + print_arg(retval) + "\n"); console.log(this.logs); } });}function so_hook() { let base_addr = Process.findModuleByName("libCtaApiJni.so").base let func_addr = base_addr.add(0x6A8CC) hook_native_addr(func_addr, 2)}
我们打印出日志信息
这里我们发现dump出非常可疑的数据,和我们的入参非常相似,我们修改一下代码,直接打印成字符串形式
function hook_native_addr(funcPtr, paramsNum) { console.log("hook_native_addr") var module = Process.findModuleByAddress(funcPtr); Interceptor.attach(funcPtr, { onEnter: function (args) { console.log('so层函数调用====>') console.log(args[1].readCString()) }, onLeave: function (retval) { } });}
so层函数调用====>
S-CID=011332370515867896192S-PID=932773080366004480S-PPID=1556925024278454272@sohu.comapp_key_vs=6.12.1appid=330000circle_id=799434391037358592count=10exposed_circle_pos_feed_id=exposed_hot_feed_ids=extras=1flyer=1759066923374list_type=2log_user_id=932773080366004480score=-1.759066143423E12stpl=1,2,3,4,7,9,11,12tpl=1,3,24,26,27,29withTop=163a000NqP3011J32
这样我们就得到md5实现的一个加密,同时在java层和so层hook,对比参数
a.a is called: treeMap={S-CID=011332370515867896192, S-PID=932773080366004480, [email protected], app_key_vs=6.12.1, appid=330000, circle_id=799434391037358592, count=10, exposed_circle_pos_feed_id=, exposed_hot_feed_ids=, extras=1, flyer=1759067087855, list_type=2, log_user_id=932773080366004480, score=-1.759063282077E12, stpl=1,2,3,4,7,9,11,12, tpl=1,3,24,26,27,29, withTop=1}
so层函数调用====>
S-CID=011332370515867896192S-PID=932773080366004480S-PPID=1556925024278454272@sohu.comapp_key_vs=6.12.1appid=330000circle_id=799434391037358592count=10exposed_circle_pos_feed_id=exposed_hot_feed_ids=extras=1flyer=1759067087855list_type=2log_user_id=932773080366004480score=-1.759063282077E12stpl=1,2,3,4,7,9,11,12tpl=1,3,24,26,27,29withTop=163a000NqP3011J32
a.a result=e33814fd5ef620fa619b8ea466a6cd0c
这样发现找到了,入参在so层进行了重新处理,愉快的结束了这个简单so层样本的分析
本文内容来自网络,如有侵权请联系删除
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:逆向有你 buluo533《安卓逆向 — 某友APP案例分析》