zhaoboy666 发表于 2020-9-27 12:20:27

ic*app的native层算法破解

Nic*app的native层算法破解 原文链接Nic*app的native层算法破解
案例:就不放了
抓包分析
这里抓包分析的过程不详细说了
可以看到主要有两个参数
sign和signV1//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/355bb19b65fe4766a191d12260bcf9ad~tplv-k3u1fbpfcp-zoom-1.image//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d6717468f3944ef99fa95bfde4db05ae~tplv-k3u1fbpfcp-zoom-1.image
反编译1、 sign破解
搜索关键词定位以及跳转到声明之后,最后就是一个md5,用objection看看就完事了//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/87861ec0d24f4631ae0af34d9e5f89c6~tplv-k3u1fbpfcp-zoom-1.image//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e60df6fbc7f447aea36972d3b584bb7d~tplv-k3u1fbpfcp-zoom-1.image//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/36e8416f8e1642af94026e68234a7e4d~tplv-k3u1fbpfcp-zoom-1.image//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/804cc143602844e083723ff51e6bb70a~tplv-k3u1fbpfcp-zoom-1.image这是java层的sign破解,完事。
2、*-sign-v1破解
这个算法主要是在native层,这里借助了frida进行破解,最后换成cpp代码。
这里定位到这个,刚开始我也不知道这里,就瞎找,分析到这里。//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/36b4fe00b8e54557bf125339df257b21~tplv-k3u1fbpfcp-zoom-1.image最后确定到这两个方法,用objection确定下,最后native走的那个方法//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c4aaecc5128249ebb568e7110c606e3a~tplv-k3u1fbpfcp-zoom-1.image可以看到最后走的是getSignRequest这个方法,并且根据上图,就可以看到so是libsalt.so。//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ec6fb207ede3477491477034ec235853~tplv-k3u1fbpfcp-zoom-1.image
2.1 分析so[*]导入jni头文件,这里没有jni_onload,就是静态注册的。
在Java_com_*_main_helpers_utils_*SignUtils_getSignRequest找到一个加密的函数,追下去看看。//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c1839d1c76be45918ebf532b0d2d0526~tplv-k3u1fbpfcp-zoom-1.image看到这么多函数,根据名字就猜测一下了,md5操作,看看是不是导出函数。//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/303134135b6f4a8ba703ccc9108bc406~tplv-k3u1fbpfcp-zoom-1.image//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/61983884055a4f6492741776f8281368~tplv-k3u1fbpfcp-zoom-1.image//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2fe306c52b8d45998697ce9adcd26bbb~tplv-k3u1fbpfcp-zoom-1.image果然是导出函数,直接frida就去Hook一下导出函数。Interceptor.attach(Module.findExportByName("libsalt.so", "*_md5"), {
    onEnter: function (args) {
        console.log("*_md5 onEnter", Memory.readCString(args))
    },
    onLeave: function (retvalue) {
        console.log("*_md5 onLeave", Memory.readCString(retvalue))
    }
})
Hook之后得到这么多//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/92f23dd1cd214c8aa7a31067abff8847~tplv-k3u1fbpfcp-zoom-1.image其实a4698cf0eea7a9b92a0194618079aba9是did2a0194618079aba9a4698cf0eea7a9b9中间进行切割,然后交换位置。
5nhrec75lf3drenb09a349366a5b7eda4ee99d7a104fb38b8a5f746c1c9c99c0b458e1ed510845e5
是随机字符串+md5(a4698cf0eea7a9b92a0194618079aba9)+8a5f746c1c9c99c0b458e1ed510845e5的结果8a5f746c1c9c99c0b458e1ed510845e5是固定值,随机字符串是java层算法。
python这一部分的实现
did = '2a0194618079aba9a4698cf0eea7a9b9'
    rstr = 'yqkdfs6y4d2ci8wm'  # 随机字did[:符串
    new_did = did + len(did) // 2]
    did_md5 = get_md5(new_did)
    sss = rstr + did_md5 + '8a5f746c1c9c99c0b458e1ed510845e5'
    dest = get_md5(sss)
cpp实现:
string did = "2a0194618079aba9a4698cf0eea7a9b9";
    string ranstr = "28npqz4cpmw6ifpc";
    string new_did = getStringSubs(did);
    string did_md5 = getMd5(new_did);
    string sss = ranstr + did_md5 + "8a5f746c1c9c99c0b458e1ed510845e5";
    string dest = getStringSubs(getMd5(sss));
上边的dest是新字符串拼接需要的//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5f0c92c3c52842eb89d4d2aab011a55c~tplv-k3u1fbpfcp-zoom-1.image这里有一个json的操作,其实刚开始我也不知道干了什么,最后我用frida-trac 就轻松解决了。
frida-trace -FU -i "strlen"//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f678f60b5c6b440a9eb5a57feb417740~tplv-k3u1fbpfcp-zoom-1.imagefilearray = buffer & 0xF0 | buffer & 0xF;
这个是对字符串进行了高低位的操作,也就是这个app的signV3唯一个非标准算法。
拿到高低位操作之后的字符串之后,拼接了之前的dest(我自己写的那个),然后进行sha1操作。
sha1之后取了第8位到最后的字符串,然后又中间进行切割,然后交换位置,最后生成的就是signV3的结果。
cpp最后实现的算法:
string getMd5(const string &message) {    return MD5(message).toStr();
}
string getSha1(const string &message) {
    SHA1 checksum;
    checksum.update(message);
    const string hash = checksum.final();    return hash;
}
string getStringSubs(const string &message) {
    string string1 = message.substr(0, message.length() / 2);
    string string2 = message.substr(message.length() / 2);    return string2 + string1;
}void SignV3() {
    string did = "2a0194618079aba9a4698cf0eea7a9b9";
    string ranstr = "28npqz4cpmw6ifpc";
    string new_did = getStringSubs(did);
    string did_md5 = getMd5(new_did);
    string sss = ranstr + did_md5 + "8a5f746c1c9c99c0b458e1ed510845e5";
    string dest = getStringSubs(getMd5(sss));
    string arr = "aid=fbef33334c2388ccee5757dc2dbb0b45&comments_sort=asc&isnewsession=false&mark_read_sid=361595316249559936&mcc=&mnc=&nextkey=&timestamp=1592463682&ua=Mozilla/5.0 (Linux; Android 8.1.0; AOSP on msm8996 Build/OPM4.171019.021.D1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36"; const char *buffer = "aid=fbef33334c2388ccee5757dc2dbb0b45&comments_sort=asc&isnewsession=false&mark_read_sid=361595316249559936&mcc=&mnc=&nextkey=&timestamp=1592463682&ua=Mozilla/5.0 (Linux; Android 8.1.0; AOSP on msm8996 Build/OPM4.171019.021.D1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36";
    int i = 0;
//这里的算法可以看看ida的图 自己实现呐
   string new_sss = arr.substr(0, i) + dest;
    string sha1Res = getSha1(new_sss).substr(8);
    string sign_v3 = getStringSubs(sha1Res);
    cout << "_sign_v3=" << sign_v3;
}
int main() {
    SignV3();    return 0;
}算法检验
//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4d1dc157b34f4a52aaf0c33c258d45f7~tplv-k3u1fbpfcp-zoom-1.image至于为什么最后不放python算法,实在是因为,还原成python之后,高低位操作的时候,部分数据不对了。。就只有cpp了
此文章仅用于学习交流,请勿商业用途和传播。

Nic*app的native层算法破解 原文链接



Damn7Kx 发表于 2020-9-27 16:19:39

tql 前排留名
页: [1]
查看完整版本: ic*app的native层算法破解