某某新闻 app sign逆向
某新闻app sign逆向
本文仅用于技术交流
前言
app:6L6+5bed{beihai_delete}6KeC5a+fIDEuMg==
环境:pixel2 android10
正文
抓包脱壳
抓一下登录的包,使用postern结合抓包工具
发现存在sign值
下面来分析这sign的生成过程
先分析sign
直接反编译apk,发现加了数字壳

尝试使用fundex脱壳

脱出的dex文件在/data/data/com.dachaun.news下
把这几个dex拉下来再全部拖到jadx中反编译

java层
搜索了一下字符串sign,没有发现有什么结果,搜索"sign"。好在搜出的结果不多
排除了明显的sdk包,像是什么阿里巴巴,腾讯,魅族的,在剩下的里面看了一下,就找到可疑的位置

顺着this.sign往上看,发现了getSign

进入getSign

继续跟进

进入SignManager,发现就已经追到了jni函数了

hook一下
代码如下:
function hook_getSign() {
Java.perform(
function () {
var SignManager = Java.use(\"cn.thecover.lib.common.manager.SignManager\");
SignManager.getSign.overload('java.lang.String','java.lang.String','java.lang.String').implementation = function (a,b,c) {
console.log(\"a========>\", a);
console.log(\"b========>\", b);
console.log(\"c========>\", c);
var ret = this.getSign(a,b,c);
console.log(\"ret========>\", ret);
return ret;
}
}
)
}可以发现这个位置是正确的,第一个参数是account,第二个是空,第三个是时间戳
貌似这个account每次都会变

回头查看很容易就找到了account和时间戳的生成位置,同时也可看到第二个参数是token,因为上面没有登录所以是空的

UUID.randomUUID().toString()
生成一个新的 UUID(通用唯一标识符)字符串。UUID 是一种 128 位的标识符,用于确保唯一性。String.valueOf(System.currentTimeMillis())
用来获取当前的时间戳并将其转换为字符串
native层
参数都ok了,下面来看看getSign里面具体是怎么进行处理的
用ida反编译wtf库
搜索一手getSign,直接就找到了

源码逻辑并不复杂,大致步骤是
首先查找LogShutDown类。然后尝试获取getAppSign静态方法的ID,如果成功,则调用该方法,获取应用的签名字符串。最后将返回的Java字符串转换为C++中的UTF字符串,存储在__s中
获取到的字符串通过MD5加密,生成src。然后,将src转换为大写,生成appsignMd5result

接着是拼接字符串,顺序是appsignMd5result+account+token+timestamp

对拼接后的字符串再次进行MD5加密,得到最终的签名result。然后将结果转换为大写。

这个结果将转为jstring最后返回出来
可以通过hook update的参数和返回值来佐证分析
进行md5::update函数,通过点击视图->打开子视图->详细地址来查看md5::update的偏移


找到偏移之后就可以写hook代码了,打印第二个参数input就行了,使用frida api中的readCString读取C风格的字符串(以\0结尾的字符序列)
function hook_md5_update(){
let soBaseAddr = Module.findBaseAddress(\"libwtf.so\")
let md5_ptr = soBaseAddr.add(0x43834)
Interceptor.attach(md5_ptr, {
onEnter: function (args) {
console.log(\"args========>\", args[1].readCString());
},
onLeave: function (retval) {
}
})
}通过结果可以看出,确实是像前面分析的一样进行了拼接
逻辑清楚了,接着来看看getAppSign函数
cn.thecover.lib.common.utils.LogShutDown.getAppSign

编写hook代码打印返回值
function hook_getAppSign(){
Java.perform(
function () {
var SignManager = Java.use(\"cn.thecover.lib.common.utils.LogShutDown\");
SignManager.getAppSign.implementation = function () {
var ret = this.getAppSign();
console.log(\"ret========>\", ret);
return ret;
}
}
)
}观察结果发现好像是固定的
下面尝试手动复现处理逻辑
以前面的为例,getAppSign返回的是A262FA6ED59F60E49FD49E205F68426D,account为2d5c37ea-c2ef-4453-a87a-103610a90b53,token为空,timestamp为1735787896808

先将A262FA6ED59F60E49FD49E205F68426D进行md5加密得到32位大写结果F2FD87D83151721B48E869DBFF113AC8,再将结果和其他字符串拼接进行第二次加密并取大写
最终结果和sign比对发现一致,说明前面的分析正确

于是,sign生成的分析到此就完成了