开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 432|回复: 5
收起左侧

[技术文章] JD sign分析过程

[复制链接]
结帖率:0% (0/1)
发表于 2024-5-13 16:54:35 | 显示全部楼层 |阅读模式   湖北省武汉市
前言:
京东sign有三种算法,这次讲解的是最简单的一个分支。打通任意一个分支都可以拿到正确的、可以请求的Sign
目标样本版本12.2.2(最新版地址可能会发生偏移以及变化)

Jadx打开样本 开始定位sign的生成逻辑
采用搜索
x-api-eid-token的方
法来定位
发现在此处进行引用,从函数功能可以分析出,这是在组包,并返回组装完的字符串
按经验来说,组装成字符串之后就要加密了,我们按x 查找函数上一层引用
发现上一层函数也在组包,返回的也是str类型
继续网上寻找,发现同上
继续向上寻找:
最终找到加密位置
[JavaScript] 纯文本查看 复制代码
    try {
            String signature = JDHttpTookit.getEngine().getSignatureHandlerImpl().signature(JDHttpTookit.getEngine().getApplicationContext(), queryParameter, str, deviceUUID, property, versionName);
            if (OKLog.D) {
                OKLog.d("Signature", "native signature sucess " + signature);
            }
            if (TextUtils.isEmpty(signature) || (urlParams = getUrlParams(signature)) == null || urlParams.isEmpty()) {
                return;
            }
            for (String str8 : urlParams.keySet()) {
                builder.addQueryParameter(str8, urlParams.get(str8));
            }
        } catch (Exception unused) {
        }
发现加密的是一个接口
我们要找实现这个类型的方法
implements ISignatureHandler
搜索不到
所以我们直接搜索 ISignatureHandler
发现在这个类里有一定线索
在初始化时传入了
查找调用此函数的位置的方法
在initapp中传入了,我们往上跟入
进入方法查看
原来是使用new创建的 所以下次搜索可以使用
[JavaScript] 纯文本查看 复制代码
new ISignatureHandler
来搜索定位
定位到关键函数,接下来进行hook 并主动调用:
[JavaScript] 纯文本查看 复制代码
function call(){
    Java.perform(function () {
        let BitmapkitUtils = Java.use("com.jingdong.common.utils.BitmapkitUtils");

        let context = Java.use("android.app.ActivityThread").currentApplication().getApplicationContext();
        let str = "wareBusiness";
        let str2 ='{"abTest800":true,"acceptPrivacy":true,"avoidLive":false,"bbtf":"","brand":"Redmi","businessType":"","bybt":"","cityCode":72,"cityId":0,"cpsNoTuan":null,"darkModelEnum":3,"districtId":0,"euaf":false,"eventId":"MyHistory_Product","fromType":0,"isDesCbc":true,"isFromOpenApp":true,"latitude":"0.0","lego":true,"longitude":"0.0","model":"Redmi Note 11T Pro","ocrFlag":false,"oneboxChannel":false,"oneboxKeyword":"","oneboxSource":"","openSimilarFlag":"","overseas":0,"pdVersion":"1","personas":null,"pluginVersion":101050,"plusClickCount":0,"plusLandedFatigue":0,"popBusinessType":"","poplayer":false,"productJdv":"-1|kong|t_1000210271_502774|zssc|d36d13b9-61c4-4fdf-b7f2-11dbc28d14dd-p_1999-pr_100746-at_502774-tg_ext_0-00-0-tgx-5050508-3935-20231110|1699610674","provinceId":"0","prstate":"0","refreshMe":null,"searchWareflag":"","selfDelivery":"0","skuId":"48905840961","source_type":"wojing_history","source_value":"","townId":0,"uAddrId":"0","utmMedium":null,"wareInnerSource":"extra.inner.source.init","yrqNew":"1"}'
        let str3 = "789e43b8e08521ee";
        let str4 = "android";
        let str5 = "12.2.2";

        let result = BitmapkitUtils.getSignFromJni(context, str, str2, str3, str4, str5);
        console.log("BitmapkitUtils.getSignFromJni result = " + result);
    });
}
发现疑似是hash函数
hook dlsym函数,得知函数加载的so
libjdbitmapkit.so
定位到要分析的函数,由于位数疑似md5,所以使用龙哥的findhash插件,进行寻找
熟悉的朋友应该认出了,这个就是md5运算部分,我们寻找上层引用
再次寻找上层引用
发现调用位置就在我们目标分析的函数里(如果没跟到的兄弟可以打印堆栈)
我们进行hook来分析入参
[JavaScript] 纯文本查看 复制代码
(function () {

    // @ts-ignore
    function print_arg(addr) {
        try {
            var module = Process.findRangeByAddress(addr);
            if (module != null) return "\n"+hexdump(addr) + "\n";
            return ptr(addr) + "\n";
        } catch (e) {
            return addr + "\n";
        }
    }

    // @ts-ignore
    function hook_native_addr(funcPtr, paramsNum) {
        var module = Process.findModuleByAddress(funcPtr);
        try {
            Interceptor.attach(funcPtr, {
                onEnter: function (args) {
                    this.logs = "";
                    this.params = [];
                    // @ts-ignore
                    this.logs=this.logs.concat("So: " + module.name + "  Method: sub_25E0 offset: " + ptr(funcPtr).sub(module.base) + "\n");
                    for (let i = 0; i < paramsNum; i++) {
                        this.params.push(args);
                        this.logs=this.logs.concat("this.args" + i + " onEnter: " + print_arg(args));
                    }
                }, onLeave: function (retval) {
                    for (let i = 0; i < paramsNum; i++) {
                        this.logs=this.logs.concat("this.args" + i + " onLeave: " + print_arg(this.params));
                    }
                    this.logs=this.logs.concat("retval onLeave: " + print_arg(retval) + "\n");
                    console.log(this.logs);
                }
            });
        } catch (e) {
            console.log(e);
        }
    }
    // @ts-ignore
    hook_native_addr(Module.findBaseAddress("libjdbitmapkit.so").add(0x25e0), 0x3);
})();

发现入参是一段base64,解密后是乱码
在md5前,明文进行了额外处理:
v39是我们要分析的密文,
继续往上跟踪v39生成的位置
经过hook可知
密文由sub_18c9c计算而来
其中两个参数是rand随机生成的
在这里决定了sign由哪个函数进行加密
今天我们分析case2里面的加密函数,也是最简单的,后面我会分析剩下两个算法的计算方法
算法肉眼可见的可以复现,所以我们进行hook入参和出参进行分析
[JavaScript] 纯文本查看 复制代码
(function () {

    // @ts-ignore
    function print_arg(addr) {
        try {
            var module = Process.findRangeByAddress(addr);
            if (module != null) return "\n"+hexdump(addr) + "\n";
            return ptr(addr) + "\n";
        } catch (e) {
            return addr + "\n";
        }
    }

    // @ts-ignore
    function hook_native_addr(funcPtr, paramsNum) {
        var module = Process.findModuleByAddress(funcPtr);
        try {
            Interceptor.attach(funcPtr, {
                onEnter: function (args) {
                    this.logs = "";
                    this.params = [];
                    // @ts-ignore
                    this.logs=this.logs.concat("So: " + module.name + "  Method: sub_6858 offset: " + ptr(funcPtr).sub(module.base) + "\n");
                    for (let i = 0; i < paramsNum; i++) {
                        this.params.push(args);
                        if (i==0){
                            // this.logs=this.logs.concat("this.args" + i + " onEnter: " +args.readCString());
                        }
                        else if(i==3){
                            this.logs=this.logs.concat("this.args" + i + " onEnter: " +hexdump(args[3]));
                        }
                        else {
                            this.logs=this.logs.concat("this.args" + i + " onEnter: " + print_arg(args));

                        }
                    }
                }, onLeave: function (retval) {
                    for (let i = 0; i < paramsNum; i++) {
                        this.logs=this.logs.concat("this.args" + i + " onLeave: " + print_arg(this.params));
                    }
                    this.logs=this.logs.concat("retval onLeave: " + print_arg(retval) + "\n");
                    console.log(this.logs);
                }
            });
        } catch (e) {
            console.log(e);
        }
    }
    // @ts-ignore
    hook_native_addr(Module.findBaseAddress("libjdbitmapkit.so").add(0x1882C), 0x4);
})();
不是所有的call都能触发这个分支,得多call几次
我们可以看到明文数据了
[JavaScript] 纯文本查看 复制代码
(function () {

    // @ts-ignore
    function print_arg(addr) {
        try {
            var module = Process.findRangeByAddress(addr);
            if (module != null) return "\n"+hexdump(addr) + "\n";
            return ptr(addr) + "\n";
        } catch (e) {
            return addr + "\n";
        }
    }

    // @ts-ignore
    function hook_native_addr(funcPtr, paramsNum) {
        var module = Process.findModuleByAddress(funcPtr);
        try {
            Interceptor.attach(funcPtr, {
                onEnter: function (args) {
                    this.logs = "";
                    this.params = [];
                    // @ts-ignore
                    this.logs=this.logs.concat("So: " + module.name + "  Method: sub_6858 offset: " + ptr(funcPtr).sub(module.base) + "\n");
                    for (let i = 0; i < paramsNum; i++) {
                        this.params.push(args);
                        if (i==1){
                            this.logs=this.logs.concat("this.args" + i + " onEnter: " +args.readCString());
                        }
                        else if(i==3){
                            this.logs=this.logs.concat("this.args" + i + " onEnter: " +hexdump(args[3]));
                        }
                        else {
                            this.logs=this.logs.concat("this.args" + i + " onEnter: " + print_arg(args));

                        }
                    }
                }, onLeave: function (retval) {
                    for (let i = 0; i < paramsNum; i++) {
                        this.logs=this.logs.concat("this.args" + i + " onLeave: " + print_arg(this.params));
                    }
                    this.logs=this.logs.concat("retval onLeave: " + print_arg(retval) + "\n");
                    console.log(this.logs);
                }
            });
        } catch (e) {
            console.log(e);
        }
    }
    // @ts-ignore
    hook_native_addr(Module.findBaseAddress("libjdbitmapkit.so").add(0x1882C), 0x4);
})();
修改脚本 拿到arg1的key

afcb2afb1f349bed06555aef7fd47cecbec115c6083eafa51f608df10bdd350bab2a21cb1ffb6cb7df2b9dea43cf07ccaaf12ffd1b378cf126678edb57840d1ebbcb2184c52ca2ee265595e144cf35c4aff728cb08ef5ee11f658f9a088435f66bf03ef931275eb9df4382dc7bd335f66bf031cb0c2991f2284586e873840dcc6b82eefa1c2da0a1f7134ba430c5401ea2d12bfc08ed76b6ef1d4bdb47de5013adb0e688f7ed9ff728bfb4cc43cb41cc63fc31c437ef5eeb1e63b0c57dce7c368efc31c5c5c56f93df55b6eb42d4400dbddf20baddf358a122668ede309c790b95c12184c520a2e42b6596dc309c3517a2de15cb1f2aaef814419be772df7a1e....省略

使用C语言进行复现,发现结果一致,接下来把结果from hex 再base64
把base64进行md5加密 即可得到JD的sign
[Java] 纯文本查看 复制代码
void TenSeattosEncrypt(char* input, int input_len)

{

    int v4, v5;

    char v6;

    const char* TenSeattos_key = "80306f4370b39fd5630ad0529f77adb6";

    unsigned char table[0x10] = { 0x37, 0x92, 0x44, 0x68, 0xA5, 0x3D, 0xCC, 0x7F, 0xBB, 0xF, 0xD9, 0x88, 0xEE, 0x9A, 0xE9, 0x5A };

    for (int i = 0; i != input_len; ++i) {

        v4 = i & 7;

        v5 = table[i & 0xF];

        v6 = (v5 + (*(unsigned char*)(input + i) ^ *(unsigned char*)(TenSeattos_key + v4) ^ table[i & 0xF])) ^ table[i & 0xF];

        *(unsigned char*)(input + i) = v6;

        *(unsigned char*)(input + i) = *(unsigned char*)(TenSeattos_key + v4) ^ v6;

    }

}
至此,我们已经完成了最容易的一个分支的京东sign的计算
下一篇文章将分析另外的两个加密过程,涉及到unidbg/unicorn的使用,记录算法还原的过程






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
结帖率:0% (0/1)

签到天数: 6 天

 楼主| 发表于 2024-5-13 17:31:45 | 显示全部楼层   湖北省武汉市
交流群:528582295
回复 支持 反对

使用道具 举报

结帖率:0% (0/1)

签到天数: 6 天

 楼主| 发表于 6 天前 | 显示全部楼层   湖北省武汉市
111111111
回复 支持 反对

使用道具 举报

签到天数: 2 天

发表于 2024-5-17 18:14:19 | 显示全部楼层   北京市北京市
回复 支持 反对

使用道具 举报

结帖率:100% (5/5)

签到天数: 28 天

发表于 2024-5-13 19:01:39 | 显示全部楼层   广东省深圳市
那么然后了
回复 支持 反对

使用道具 举报

结帖率:100% (6/6)

签到天数: 28 天

发表于 2024-5-13 17:51:27 | 显示全部楼层   河南省郑州市
避开或者突破计算机信息系统安全保护措施
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 诚聘英才| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 800073686,邮箱:800073686@b.qq.com
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表