案例 车智赢 的hook 脚本 和 总体的java逻辑的提取

hook的逻辑还原


function UpgradeBlock() {
    var UpgradeAppBean = Java.use('com.che168.autotradercloud.upgradeapp.UpgradeAppBean');
        // Hook isForce 方法
    UpgradeAppBean.isForce.implementation = function () {
        send('Hooked isForce');
        return false;  // 强制返回 false,跳过强制更新
    };

    // Hook isLatestVersion 方法
    UpgradeAppBean.isLatestVersion.implementation = function () {
        send('Hooked isLatestVersion');
        return true;  // 强制返回 true,表示已是最新版本
    };

}



// 把最开始的 登陆的参数的 给 hook 出来.
// 通过  tradercloud/sealed/login/login.ashx 这个 URI  搜索的到内部的加密算法的位置  loginByPassword()  函数中的 最后的一个参数加密的位置.  encodeMD5()
// 密码 被 MD5 重新加密了.
function encodeMD5() {
    var SecurityUtil = Java.use("com.autohome.ahkit.utils.SecurityUtil");
    SecurityUtil.encodeMD5.implementation = function ( str ){
        console.log("md5 加密, 明文--->  ", str);
        var result = this.encodeMD5(str);
        console.log(" md5 加密后的秘闻 是---> ",result);
        return result;
    };
}






// 把最开始的 登陆的参数的 给 hook 出来.
// 通过  tradercloud/sealed/login/login.ashx 这个 URI  搜索的到内部的加密算法的位置  loginByPassword()
function loginByPassword_bakcup() {

    let UserModel = Java.use("com.che168.autotradercloud.user.model.UserModel");
    UserModel["loginByPassword"].implementation = function (str, str2, str3, responseCallback) {
        console.log("tradercloud/sealed/login/login.ashx 验证密码登陆 是否可通过 \n");
        console.log(`UserModel.loginByPassword is called: str=${str}, str2=${str2}, str3=${str3}, responseCallback=${responseCallback}`);
         // 调用原方法并捕获返回值
        var result = this.loginByPassword(str, str2, str3, responseCallback);
        // 执行后打印结果
        console.log(`After Execution: result=${result}`);
        // 返回原方法的结果
        return result;
    };
}


function loginByPassword() {
    let UserModel = Java.use("com.che168.autotradercloud.user.model.UserModel");

        // 指定的手机号和密码
        const TARGET_PHONE = "13541722917";
        const TARGET_PASSWORD = "aA.11111";

        // Hook the loginByPassword method
        UserModel.loginByPassword.implementation = function (str, str2, str3, responseCallback) {
            console.log("tradercloud/sealed/login/login.ashx 验证密码登陆 是否可通过 \n");

            // 打印原始参数
            console.log(`原始参数: str=${str}, str2=${str2}, str3=${str3}, responseCallback=${responseCallback}`);

            // 强制替换为指定的手机号和密码
            str2 = TARGET_PHONE;
            str3 = TARGET_PASSWORD;

            console.log(`强制替换后的参数: str=${str}, str2=${str2}, str3=${str3}, responseCallback=${responseCallback}`);

            // 调用原方法并捕获返回值
            var result = this.loginByPassword(str, str2, str3, responseCallback);

            // 打印原方法的返回值
            console.log(`After Execution: result=${result}`);

            // 返回原方法的结果
            return result;
        };

        console.log("[*] UserModel.loginByPassword hook installed successfully!");

    // let UserModel = Java.use("com.che168.autotradercloud.user.model.UserModel");
    //     // 指定的手机号和密码
    //     const TARGET_PHONE = "13541722917";
    //     const TARGET_PASSWORD = "aA.11111";
    //     // Hook the loginByPassword method
    //     UserModel.loginByPassword.implementation = function (str, str2, str3, responseCallback) {
    //         console.log("tradercloud/sealed/login/login.ashx 验证密码登陆 是否可通过 \n");
    //         console.log(`UserModel.loginByPassword is called: str=${str}, str2=${str2}, str3=${str3}, responseCallback=${responseCallback}`);
    //
    //         // 检查是否匹配指定的手机号和密码
    //         if (str2 === TARGET_PHONE && str3 === TARGET_PASSWORD) {
    //             console.log(`匹配到指定的手机号和密码: Phone=${str2}, Password=${str3}`);
    //             console.log("直接返回指定的手机号和密码,不调用原始方法。");
    //             // 直接返回指定的手机号和密码
    //             return { phone: str2, password: str3 };
    //         }
    //
    //         // 如果不匹配,调用原始方法并捕获返回值
    //         console.log("未匹配到指定的手机号和密码,继续调用原始方法。");
    //         var result = this.loginByPassword(str, str2, str3, responseCallback);
    //
    //         // 打印原方法的返回值
    //         console.log(`After Execution: result=${result}`);
    //
    //         // 返回原方法的结果
    //         return result;
    //     };
    //     console.log("[*] UserModel.loginByPassword hook installed successfully!");
}

// UserModel.loginByPassword is called: str=com.che168.autotradercloud.user.LoginActivity@4ea788e, str2=18881121153, str3=123123, responseCallback=[object Object]


// 这里的 3 个重载[函数名相同--> 参数个数不同,或者类型不同.] 的方法并没有生效 , 也就是说, 我们并没有找对地方.
// toSigndMap(context, treemap)
// toSigndMap(context, treeMap , str)
// toSignedMap(context, z, treeMap)
// 不是这个地方,位置找错了 <--------------- [目标检测 _Sign 参数的位置]
function toSign() {
    var AHAPIHelper = Java.use("com.autohome.ahkit.AHAPIHelper");
    // 在这里, 没有hook 到数据, 证明位置有问题.  重新换个地方,就可以找到了.
    AHAPIHelper.toSign.implementation = function (context, map){

        console.log("请求来了-->")
        console.log("map的值是: ", map);

        // 执行原来的方法
        var res = this.toSign(context, map);
        console.log("sign的签名 ---> ", res);
        return res;
    };
}



function treemap_display() {
    Java.perform(function () {
        var TreeMap = Java.use('java.util.TreeMap');

        // Hook the put method of TreeMap
        TreeMap.put.implementation = function (key, value) {
            // Check if the key is "data"
            if (key == "data") {
                console.log("[*] TreeMap.put called with key: " + key + ", value: " + value);
            }

            // Call the original put method
            var result = this.put(key, value);

            // Return the result of the original put method
            return result;
        };

        console.log("[*] TreeMap.put hook installed successfully!");
    });
}

// Call the function to install the hook
treemap_display();

function encode3des() {
    var SecurityUtil = Java.use("com.autohome.ahkit.utils.SecurityUtil");
    SecurityUtil.encode3Des.implementation = function(ctx,arg){
        console.log("拼接后的第二个参数:", arg);
        var res = this.encode3Des(ctx,arg);  // 别人如果有返回值,那么就直接 先 res 接收一下,再 return  一下。
                                             // 如果原函数没有 返回值,直接 this.encode3Des(ctx,arg) 当前的这个函数继续让她执行走!
        console.log("UDID的值:",res);
        return res;
        // return  "305eb636305eb636305eb636305eb636305eb636305eb636";
    };
}


function SignManager_signByType() {
    Java.perform(function () {
        var SignManager = Java.use("com.che168.atclibrary.base.SignManager");

        // Hook the signByType method
        SignManager.signByType.implementation = function (i, TreeMap) {
            console.log("执行了, 参数 i = ", i);
            console.log("执行了, 参数 Treemap = ", TreeMap.toString());

            // 执行原来的方法并获取返回值
            var res = this.signByType(i, TreeMap);
            console.log("执行了, 返回值:", res);

            // 返回原始方法的返回值
            return res;
        };

        console.log("[*] SignManager.signByType hook installed successfully!");
    });
}




// 寻找的路径---> 通过上一个, toSign---> 三个重载的函数, 并没有任何的输出,所以位置不对.
// --> 再次搜索到,, -----> public static final String KEY_SIGN = "_sign";
// --------------------> 右键查找   KEY_SIGN 的被引用的位置.
// --------------------->找到了,  lambda$initRequestCommonParams$0 , 包含了 channelid,AppVersion,Udid,UserKey,以及包含的 sign的引用, 所以,推测是这里,hook 一下就明白是否是这里.
// ---------------------> 最后的, treeMap.put(KEY_SIGN, SignManager.INSTANCE.signByType(i, treeMap) ); --------> 这里面的算法,就是 登陆加密协议的重要实现都在这里.这是一个
function appid_channelid_UDID_userkey_KEY_SIGN() {
    var LaunchModel = Java.use("com.che168.autotradercloud.launch.model.LaunchModel");

    // hook 替换的位置
    LaunchModel.lambda$initRequestCommonParams$0.implementation = function (i, treeMap) {
        console.log(`lambda$initRequestCommonParam执行了参数---前面,参数 i=${i}, \n treeMap= ${treeMap.toString}`);

        // 执行原来的方法
        var res = this.lambda$initRequestCommonParams$0(i, treeMap);

        console.log("lambda$initRequestCommonParam执行后, ---> 后面----> 返回值是---->\n", res.toString());
        return res;
    };
}
// 个推相关
// 登录时,未携带或携带固定的20期是否可以正常运行
// 注册设备,返回格式错误。
function push_deviceID_RegDevice() {
    var PushModel = Java.use("com.che168.autotradercloud.base.push.model.PushModel");
    PushModel.regDevice.implementation = function(str){
        console.log(" 个推相关--push_deviceID_RegDevice ---> 注册前  " + str);
        var result = this.regDevice(str);
        console.log("个推相关--push_deviceID_RegDevice--注册结果 " + result);
        return result
        // this.regDevice("");
    };
}


function Des3_Serious_liucheng() {
    // Hook the getDesKey method in AHAPIHelper
    var AHAPIHelper = Java.use('com.autohome.ahkit.AHAPIHelper');
    AHAPIHelper.getDesKey.implementation = function (context) {
        console.log("[*] AHAPIHelper.getDesKey called with context: " + context);
        var result = this.getDesKey(context);
        console.log("[*] AHAPIHelper.getDesKey returned: " + result);
        return result;
    };

    // Hook the getSignKey method in AHAPIHelper
    AHAPIHelper.getSignKey.implementation = function (context) {
        console.log("[*] AHAPIHelper.getSignKey called with context: " + context);
        var result = this.getSignKey(context);
        console.log("[*] AHAPIHelper.getSignKey returned: " + result);
        return result;
    };

    // Hook the getSignDesKey method in AHAPIHelper
    AHAPIHelper.getSignDesKey.implementation = function (context) {
        console.log("[*] AHAPIHelper.getSignDesKey called with context: " + context);
        this.getSignDesKey(context);
    };

    // Hook the get3desKey method in CheckSignUtil
    var CheckSignUtil = Java.use('com.autohome.ahkit.jni.CheckSignUtil');
    CheckSignUtil.get3desKey.implementation = function (context) {
        console.log("[*] CheckSignUtil.get3desKey called with context: " + context);
        var result = this.get3desKey(context);
        console.log("[*] CheckSignUtil.get3desKey returned: " + result);
        return result;
    };
}

// 寻找的路径---> 通过上一个, toSign---> 三个重载的函数, 并没有任何的输出,所以位置不对.
// --> 再次搜索到,, -----> public static final String KEY_SIGN = "_sign";
// --------------------> 右键查找   KEY_SIGN 的被引用的位置.
// --------------------->找到了,  lambda$initRequestCommonParams$0 , 包含了 channelid,AppVersion,Udid,UserKey,以及包含的 sign的引用, 所以,推测是这里,hook 一下就明白是否是这里.
// ---------------------> 最后的, treeMap.put(KEY_SIGN, SignManager.INSTANCE.signByType(i, treeMap) ); --------> 这里面的算法,就是 登陆加密协议的重要实现都在这里.
// hook _sign算法
// 终于找到这个位置了,接下来就可以围绕此处的代码来进行逆向 `udid` 和 `_sign` 的算法了。
// 重要的结构,   _sign ----->等于 ---> KEY_SIGN,----> 依赖, SignManager.INSTANCE.signByType(i, treeMap)---> 所以包含 TreeMap, 其中包括了 UDID.
// 通过 这个函数 lambda$initRequestCommonParams$0 中的一句话, treeMap.put(UDID, AppUtils.getUDID(ContextProvider.getContext()))
// ----> 通过摸瓜找到了,  getUDID 这个函数, ----> 函数内部调用了 3DES 函数 . 那么通过守株待兔, hook ,就能够等到 参数加密前,和参数 加密后.
function encode3Des() {
    var SecurityUtil = Java.use("com.autohome.ahkit.utils.SecurityUtil");
    SecurityUtil.encode3Des.implementation = function(ctx,str){
        console.log("3DES 的输入数据---> ", str);
        var res = this.encode3Des(ctx,str);
        console.log("3DES 的加密结果---> ", res);
        return res;
    };
}

// public static String getUDID(Context context) {
//     return SecurityUtil.encode3Des(
//         context, getIMEI(context) +   // ------> getIMEI ---> 本地读取 xml 文件.  最后, 根据 uuid 生成.-->getIMEIByAndroidIDandUUID ( context )--> UUID.randomUUID().toString()
//         HiAnalyticsConstant.REPORT_VAL_SEPARATOR +
//         System.nanoTime() +
//         HiAnalyticsConstant.REPORT_VAL_SEPARATOR +
//         SPUtils.getDeviceId()         // -----> getDeviceID() --> saveDeviceId()---> 他们是成对的出现.-
//                                           ----> 发现只去XML文件中读取,那么一定会有人先在XML中设置,此处才能读取到。
//     );                                   -----> 接下来,可以去hook `saveDeviceId`,这个大概率是设置的位置,通过hook此方法可以看到【值 + 调用栈 】。
// }
function SPUtils_saveDeviceId_getDeviceId_saveIMEI_getIMEI() {   // 设备注册 --->相关联的.
    // 包.类
    var SPUtils = Java.use("com.che168.autotradercloud.util.SPUtils");

     // Hook,替换
    SPUtils.saveDeviceId.implementation = function (str) {
        console.log("来设置device_id了___SPUtils_saveDeviceId(), 参数 str     ----> \n", str);
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); // 打印调用栈

        // 执行原来的方法
        var res = this.saveDeviceId(str);
        console.log("SPUtils_saveDeviceId()最后输出的结果是 ----->\n", res);
        return res;
    };

    // 获取设备 ID  --- 设别注册
    SPUtils.getDeviceId.implementation = function(){
        var res = this.getDeviceId();
        console.log("获取 DeviceId ",res);
        return res;
    };

    // getIMEI
    SPUtils.getIMEI.implementation = function(){
        var res = this.getIMEI();
        console.log(" 获取IMEI ",res);
        return res;
    };

    // saveIMEI
    SPUtils.saveIMEI.implementation = function (str) {
        console.log("来设置  SPUtils_saveIMEI(), 参数 str     ----> \n", str);
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); // 打印调用栈

        // 执行原来的方法
        var res = this.saveIMEI(str);
        console.log("SPUtils_saveIMEI()最后输出的结果是 ----->\n", res);
        return res;
        };
}

//  又回到了, 最开始请求的地方.  Loginbypassword 的地方.
// 这里, 回到了  encode3DES 的加密函数.   找到  python 版本的 3DES 的 代码, 直接整合,就可以拿到他的逻辑.

function SharedPreferencesUtil_saveString_getString() {
    var SharedPreferencesUtil = Java.use("com.che168.atclibrary.utils.SharedPreferencesUtil")
    SharedPreferencesUtil.saveString.implementation = function (str, str2) {
        console.log(" SharedPreferencesUtil.saveString  ----> ", str, str2);
        var res = this.saveString(str, str2);
        console.log("SharedPreferencesUtil.saveString 最后输出的结果是 ----->\n", res);
        return res;
    }
    SharedPreferencesUtil.getString.implementation = function (str, str2) {
        console.log(" SharedPreferencesUtil.getString  ----> ", str, str2);
        var res = this.getString(str, str2);
        console.log("SharedPreferencesUtil.getString 最后输出的结果是 ----->\n", res);
        return res;
    }
}

function getUDID_getIMEI() {
    var  AppUtils = Java.use("com.che168.autotradercloud.util.AppUtils");
    AppUtils.getUDID.implementation = function (context) {
        console.log("SecurityUtil.encode3Des(context, getIMEI(context) + HiAnalyticsConstant.REPORT_VAL_SEPARATOR + System.nanoTime() + HiAnalyticsConstant.REPORT_VAL_SEPARATOR + SPUtils.getDeviceId());\n");
        console.log("  Hook,替换  getUDID 的值 ---> ", context);
        var res = this.getUDID(context);
        console.log(" 返回 getUDID 的值是:   --->", res );
        // return "305eb636-eb15-4e24-a29d-9fd60fbc91bf";  // 通过替换测试是否可以 通过  ???
        return res;
    }
    AppUtils.getIMEI.implementation = function (context) {
        console.log("getIMEI 输入值是一下---> ", context);
        var res = this.getIMEI(context);
        console.log("getIMEI 最后的值是  --->", res );
        return res;
    }
}


Java.perform(function () {
    UpgradeBlock();  // 屏蔽升级

    // md5加密  +
    encodeMD5();
    // tradercloud/sealed/login/login.ashx 验证密码登陆 是否可通过
    loginByPassword();

    // 处理请求体中的  _Sign 的来源  ==处理 3个重载的 函数调用的 Sign是否会走这里 ?
    // toSign(); // 最后不走这里

    // Des3_Serious_liucheng();
    // SignManager_signByType();
    // SharedPreferencesUtil_saveString_getString();
    // SPUtils_saveDeviceId_getDeviceId_saveIMEI_getIMEI();  // 设备指纹注册 和 保存 XML 验证
    //
    // push_deviceID_RegDevice();  // 设备注册 ==> 没有输出!!!
    // // getUDID = encode3Des(getIMEI() + | + NanoTime() + | + getDeviceId())
    // encode3Des();// getUDID 通过这里加密
    // getUDID_getIMEI();
    //
    //
    // _sign 算法=============
    // 分析 KEY_SIGN 是怎样来的
    // appid + channelid + UDID + userkey =>最后 通过 signByType 加密
    // com.che168.autotradercloud.launch.model.LaunchModel.lambda$initRequestCommonParams$0 treeMap把他们全部都集中起来了.
    // appid_channelid_UDID_userkey_KEY_SIGN();
    //
    // treemap_display();
});

//7bt6kLQ la3esZnRfXjvfVT0LtaJh+pXd48wnstT7whH0lhA+I39s5/wJIBJz oRTMVwV67Xe6DCTnZPr7wEn0cg==
//udi     la3esZnRfXjvfVT0LtaJh+pXd48wnstT7whH0lhA+I39s5/wJIBJz oRTMVwV67Xe6DCTnZPr7wEn0cg==

//  adb -s e265872e install '/home/calleng/桌面/xinyue/season5/车智赢-v2.8.2.apk'
//  adb -s e265872e  shell pm clear com.che168.autotradercloud
//  adb -s e265872e push '/home/calleng/桌面/old_Desktop/新月部分/逆向课程笔记和代码(第10期)/day03-抓包和f编译/软件roid-arm64/frida-server-16.1.3-android-arm64'  /data/local/tmp/
//  /home/calleng/桌面/old_Desktop/新月部分/逆向课程笔记和代码(第11期)/day13-JNI开发/软件/ida相关/jni-include/include/
//  以上是JNI 的 头文件 .

// frida -D 10.10.10.200:5555 -f com.che168.autotradercloud -l '/home/calleng/p9/Mikrom2.0/JS_editor/com_che168_autotradercloud_hook_获取设备注册.js'
// frida -D 9B011FFAZ00E06   -f  com.che168.autotradercloud   -l /home/calleng/p9/Mikrom2.0/JS_editor/com_che168_autotradercloud_hook_获取设备注册.js
// frida -D 9B011FFAZ00E06   -F  -l /home/calleng/p9/Mikrom2.0/JS_editor/com_che168_autotradercloud_hook_获取设备注册.js



// frida -D e265872e -F -l  JS_editor/com_che168_autotradercloud_hook_md5.js

// frida -D 9B011FFAZ00E06   -f  com.che168.autotradercloud   -l '/home/calleng/p9/Mikrom2.0/JS_editor/com_che168_autotradercloud_hook_md5.js'


// Spawned `com.che168.autotradercloud`. Resuming main thread!
// [AOSP on flame::com.che168.autotradercloud]-> [*] TreeMap.put hook installed successfully!
// [*] SignManager.signByType hook installed successfully!
// 执行了, 参数 i =  0
// 执行了, 参数 Treemap =  {_appid=atc.android, appversion=2.8.2, channelid=csy, udid=fU1LJm2NAdHKtoF5qqPjlKsTKP6y9oPl}
// 执行了, 返回值: BA2991D1F6629B83AFA96C8D37869C86
// 执行了, 参数 i =  0
// 执行了, 参数 Treemap =  {_appid=atc.android, appversion=2.8.2, channelid=csy, specid=58532,101784,1014248, udid=V6RGSxwRGumecbnKDiFB5ZXQrA5vkDHRfWSpstj8WUVrtnAb1r1x7MDKCgxC nTPm1f/0ybB+2Pk=}
// 执行了, 返回值: E2D512057453EE3EBFBB99DF4D23DB4F
// 执行了, 参数 i =  0
// 执行了, 参数 Treemap =  {_appid=atc.android, appversion=2.8.2, channelid=csy, udid=V6RGSxwRGumecbnKDiFB5ZXQrA5vkDHRfWSpstj8WUVrtnAb1r1x7FAuLVsp zkoX+taZbYwxKtE=}
// 执行了, 返回值: D15611755A3C1048974735CD963F38E8
// 执行了, 参数 i =  0
// 执行了, 参数 Treemap =  {_appid=atc.android, appversion=2.8.2, channelid=csy, type=1, udid=V6RGSxwRGumecbnKDiFB5ZXQrA5vkDHRfWSpstj8WUVrtnAb1r1x7N8yMvBU y3p2qgQ2e2LMfsY=}
// 执行了, 返回值: 3248B54CDB51B3C45A671172EBBEBDAB
// 执行了, 参数 i =  0
// 执行了, 参数 Treemap =  {_appid=atc.android, appversion=2.8.2, buildcode=243, channelid=csy, plaform=atc.android.csy, udid=V6RGSxwRGumecbnKDiFB5ZXQrA5vkDHRfWSpstj8WUVrtnAb1r1x7K0Uoa/T UIPgWP7IjOAWO4c=, version=2.8.2}
// 执行了, 返回值: C3C3536BB1A539FA9F38AD364C938E16
// message: {'type': 'send', 'payload': 'Hooked isForce'} data: None
// 执行了, 参数 i =  1
// 执行了, 参数 Treemap =  {_appid=atc.android, appversion=2.8.2, channelid=csy, pwd=4297f44b13955235245b2497399d7a93, udid=V6RGSxwRGumecbnKDiFB5ZXQrA5vkDHRfWSpstj8WUVyWcnmYdRgeUF8JohF uFK6iXPgdZJbKw4=, username=18881121153}
// 执行了, 返回值: 0A4F2B1E33437DEC1605B5E73A60EE57
// [*] TreeMap.put hook installed successfully!
// [*] AHAPIHelper.getDesKey called with context: com.che168.autotradercloud.ATCApplication@78e67d7
// [*] AHAPIHelper.getDesKey returned: appapiche168comappapiche168comap
// [*] TreeMap.put hook installed successfully!
// [AOSP on flame::com.che168.autotradercloud]-> md5 加密, 明文--->   123123
//  md5 加密后的秘闻 是--->  4297f44b13955235245b2497399d7a93
// md5 加密, 明文--->   W@oC!AH_6Ew1f6%8_appidatc.androidappversion2.8.2channelidcsypwd4297f44b13955235245b2497399d7a93udidV6RGSxwRGumecbnKDiFB5ZXQrA5vkDHRfWSpstj8WUX3GzVf37U56tAWRxCg etzsajcP9Ccoh1M=username18881121153W@oC!AH_6Ew1f6%8
//  md5 加密后的秘闻 是--->  b106ef85a0f2bdac47557f322287eb8d
// [*] TreeMap.put hook installed successfully!
// UserModel.loginByPassword is called: str=com.che168.autotradercloud.user.LoginActivity@4ea788e, str2=18881121153, str3=123123, responseCallback=[object Object]
// After Execution: result=undefined
// [*] TreeMap.put hook installed successfully!
// tradercloud/sealed/login/login.ashx 验证密码登陆 是否可通过
//
// UserModel.loginByPassword is called: str=com.che168.autotradercloud.user.LoginActivity@4ea788e, str2=18881121153, str3=123123, responseCallback=[object Object]
// After Execution: result=undefined
// [*] TreeMap.put hook installed successfully!
// [*] TreeMap.put hook installed successfully!
// [*] AHAPIHelper.getDesKey called with context: com.che168.autotradercloud.ATCApplication@78e67d7
// [*] AHAPIHelper.getDesKey returned: appapiche168comappapiche168comap
// [*] TreeMap.put hook installed successfully!
// [*] SignManager.signByType hook installed successfully!
// 执行了, 参数 i =  1
// 执行了, 参数 Treemap =  {_appid=atc.android, appversion=2.8.2, channelid=csy, pwd=4297f44b13955235245b2497399d7a93, udid=V6RGSxwRGumecbnKDiFB5ZXQrA5vkDHRfWSpstj8WUVWB13GOdAnQl0Zvwii lBJLvnUy3hDEIho=, username=18881121153}
// 执行了, 返回值: 9ABDF3B8071D5E0E39FFF3C457E47CAF
// [*] TreeMap.put hook installed successfully!
//  SharedPreferencesUtil.getString  ---->  imei
// SharedPreferencesUtil.getString 最后输出的结果是 ----->
//  f5001045-faf3-3136-8188-f2144ede22b4
//  SharedPreferencesUtil.getString  ---->  KEY_DEVICE_ID
// SharedPreferencesUtil.getString 最后输出的结果是 ----->
//
//  SharedPreferencesUtil.getString  ---->  loginUserInfo
// SharedPreferencesUtil.getString 最后输出的结果是 ----->
//
// [*] TreeMap.put hook installed successfully!
//  获取IMEI  f5001045-faf3-3136-8188-f2144ede22b4
// 获取 DeviceId
// [*] TreeMap.put hook installed successfully!
// [*] TreeMap.put hook installed successfully!
// [*] TreeMap.put hook installed successfully!
// 3DES 的输入数据--->  f5001045-faf3-3136-8188-f2144ede22b4|3190170556808|
// 3DES 的加密结果--->  V6RGSxwRGumecbnKDiFB5ZXQrA5vkDHRfWSpstj8WUV3NalWSKr2e+yO6mX9 kmYzEl8H8X1q/Kg=
// [*] TreeMap.put hook installed successfully!
// SecurityUtil.encode3Des(context, getIMEI(context) + HiAnalyticsConstant.REPORT_VAL_SEPARATOR + System.nanoTime() + HiAnalyticsConstant.REPORT_VAL_SEPARATOR + SPUtils.getDeviceId());
//
//   Hook,替换  getUDID 的值 --->  com.che168.autotradercloud.ATCApplication@78e67d7
// getIMEI 输入值是一下--->  com.che168.autotradercloud.ATCApplication@78e67d7
// getIMEI 最后的值是  ---> f5001045-faf3-3136-8188-f2144ede22b4
//  返回 getUDID 的值是:   ---> V6RGSxwRGumecbnKDiFB5ZXQrA5vkDHRfWSpstj8WUVgrCf3T4GHtv6lh3KZ qeJyHHXpj0rckEw=
// [*] TreeMap.put hook installed successfully!
// lambda$initRequestCommonParam执行了参数---前面,参数 i=1,
//  treeMap= function e() {
//     [native code]
// }
// lambda$initRequestCommonParam执行后, ---> 后面----> 返回值是---->
//  {_appid=atc.android, _sign=BEA52BCACBE799C9D1A3753CC230CF68, appversion=2.8.2, channelid=csy, pwd=4297f44b13955235245b2497399d7a93, udid=V6RGSxwRGumecbnKDiFB5ZXQrA5vkDHRfWSpstj8WUUZfhUr/q0z1fxqk/LW qlicLHVqDaCcNwk=, username=18881121153}

 

 

反编译,Java的逻辑提取

 

public class 车智赢 {
}

// ============================用户名  和  密码 =================================
public class com.che168.autotradercloud.user.model.UserModel extends BaseModel {
    public static final String LOGIN_URL = "/tradercloud/sealed/login/login.ashx";

    public static void loginByPassword(String str, String str2, String str3, ResponseCallback<UserBean> responseCallback) {
        HttpUtil.Builder builder = new HttpUtil.Builder();

        builder.tag(str)   // 设置请求标记
                .method(HttpUtil.Method.POST)     // 请求方式为 post
                .signType(1)     // 使用签名类型
                .url(LOGIN_URL)   // 指定登陆的 URL
                .param("username", str2) // 添加用户名参数
                .param("pwd", SecurityUtil.encodeMD5(str3)); // 添加密码参数,进过 md5 加密

        doRequest(builder, responseCallback, new TypeToken<BaseResult<UserBean>>() {/* class com.che168.autotradercloud.user.model.UserModel.AnonymousClass5 */}.getType());  // 发起请求
        //  调用 doRequest 方法, 发起http请求
    }

}


public class com.autohome.ahkit.utils.SecurityUtil {
    private static final String encoding = "UTF-8";
    private static final String iv = "appapich";
    private static final char[] legalChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();

    public static String encode3Des (Context context, String str){
        String desKey = AHAPIHelper.getDesKey(context);
        byte[] bArr = null;
        if (TextUtils.isEmpty(desKey)) {
            return null;
        }
        try {
            SecretKey generateSecret = SecretKeyFactory.getInstance("desede").generateSecret(new DESedeKeySpec(desKey.getBytes()));
            Cipher instance = Cipher.getInstance("desede/CBC/PKCS5Padding");
            instance.init(1, generateSecret, new IvParameterSpec(iv.getBytes()));
            bArr = instance.doFinal(str.getBytes("UTF-8"));
        } catch (Exception unused) {
        }
        return encode(bArr).toString();
    }

    public static String decode3Des (Context context, String str){
        String desKey = AHAPIHelper.getDesKey(context);
        if (TextUtils.isEmpty(desKey)) {
            return null;
        }
        try {
            SecretKey generateSecret = SecretKeyFactory.getInstance("desede").generateSecret(new DESedeKeySpec(desKey.getBytes()));
            Cipher instance = Cipher.getInstance("desede/CBC/PKCS5Padding");
            instance.init(2, generateSecret, new IvParameterSpec(iv.getBytes()));
            return new String(instance.doFinal(decode(str)), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static final String encodeMD5 (String str){ // 定义一个静态的 encodeMD5 方法,接收一个字符串作为参数
        char[] cArr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; // 定义一个字符数组,用于存储十六进制字符
        try {
            byte[] bytes = str.getBytes(); // 将输入的字符串转换为字节数组
            MessageDigest instance = MessageDigest.getInstance("MD5"); // 获取 MD5 的 MessageDigest 实例
            instance.update(bytes); // 将字节数组更新到 MessageDigest 中
            byte[] digest = instance.digest(); // 计算消息摘要,返回 MD5 哈希值的字节数组
            int length = digest.length; // 获取 MD5 哈希值字节数组的长度
            char[] cArr2 = new char[(length * 2)]; // 定义一个字符数组,用于存储转换后的十六进制字符
            int i = 0; // 初始化索引 i
            for (byte b : digest) { // 遍历每一个字节
                int i2 = i + 1; // 计算下一个索引值
                cArr2[i] = cArr[(b >>> 4) & 15]; // 取当前字节的高 4 位,转换为对应的十六进制字符
                i = i2 + 1; // 更新索引值
                cArr2[i2] = cArr[b & 15]; // 取当前字节的低 4 位,转换为对应的十六进制字符
            }
            return new String(cArr2).toLowerCase(); // 将字符数组转换为字符串并转换为小写后返回
        } catch (Exception e) { // 捕获异常
            e.printStackTrace(); // 打印异常堆栈信息
            return null; // 返回 null 表示处理失败
        }
    }
}


public class com.autohome.ahkit.jni.CheckSignUtil {

    public static native String get3desKey(Context context);  //  =================> 第 三点五 步
    static {
        System.loadLibrary("native-lib");
    }
}


public class com.autohome.ahkit.AHAPIHelper {

    public static final String APP_ID = "2scapp.android";
    private static final String PARAM_APPID = "_appid";
    private static final String PARAM_APPVERSION = "appversion";
    private static final String PARAM_CHANNELID = "channelid";
    private static final String PARAM_SIGN = "_sign";
    private static final String PARAM_UDID = "udid";
    private static final String PARAM_USERKEY = "userkey";
    public static final String[] URL_FILTER_USEDKEY_UDID = {"apirnappusc.che168.com"};
    private static String mDesKey = "";
    private static String mSignKey = "";

    public static String getDesKey(Context context) {   // =================> 第一步
        if (TextUtils.isEmpty(mDesKey)) {
            getSignDesKey(context);
        }
        return mDesKey;    //  =================> 第四步
    }

    public static String getSignKey(Context context) {
        if (TextUtils.isEmpty(mSignKey)) {
            getSignDesKey(context);       //  =================> 第二步
        }
        return mSignKey;
    }

    private static void getSignDesKey(Context context) {    //  =================> 第三步
        mDesKey = CheckSignUtil.get3desKey(context);
    }

    public static TreeMap<String, String> toSigndMap(Context context, TreeMap<String, String> treeMap) {  // 重载 方法 1
        if (treeMap == null) {
            return null;
        }
        appendPublicParam(context, treeMap);
        appendUserKey(context, treeMap);
        appendUdid(context, treeMap);
        treeMap.put("_sign", toSign(context, treeMap));
        return treeMap;
    }

    public static TreeMap<String, String> toSigndMap(Context context, TreeMap<String, String> treeMap, String str) {   // 重载 方法 2
        if (treeMap == null) {
            return null;
        }
        appendPublicParam(context, treeMap);
        if (isAddUsedkeyAndUdid(str)) {
            appendUserKey(context, treeMap);
            appendUdid(context, treeMap);
        }
        treeMap.put("_sign", toSign(context, treeMap));
        return treeMap;
    }

    public static TreeMap<String, String> toSignedMap(Context context, boolean z, TreeMap<String, String> treeMap) {    // 重载 方法 3
        if (treeMap == null) {
            return null;
        }
        appendPublicParam(context, treeMap);
        if (z) {
            appendUdid(context, treeMap);
        }
        treeMap.put("_sign", toSign(context, treeMap));
        return treeMap;
    }

    private static void appendPublicParam(Context context, Map<String, String> map) {
        map.put("_appid", APP_ID);
        map.put("channelid", AHAppInfoUtil.getUMSChannelId(context));
        map.put("appversion", AHAppInfoUtil.getAppVersionName(context));
    }

    public static void appendUdid(Context context, Map<String, String> map) {
        map.put("udid", getUDID(context));
    }

    public static synchronized String getUDID(Context context) {
        String encode3Des;
        synchronized (AHAPIHelper.class) {
            encode3Des = SecurityUtil.encode3Des(context, AHDeviceUtil.getDeviceId(context) + HiAnalyticsConstant.REPORT_VAL_SEPARATOR + System.nanoTime() + HiAnalyticsConstant.REPORT_VAL_SEPARATOR + ((long) UserInfoUtil.getUserDeviceId(context)));
        }
        return encode3Des;
    }

    public static String toSign(Context context, Map<String, String> map) {    // 最后的方法, 最后没有走到这里...   ===> 最后的担心的事情, 却是没有走这里!!
        if (map == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        sb.append(getSignKey(context));
        for (Map.Entry<String, String> entry : map.entrySet()) {
            sb.append(entry.getKey() + entry.getValue());
        }
        sb.append(getSignKey(context));
        return SecurityUtil.encodeMD5(sb.toString()).toUpperCase();
    }
}

public class com.che168.autotradercloud.launch.model.LaunchModel extends BaseModel {

    public static final String KEY_SIGN = "_sign";

    static /* synthetic */ TreeMap lambda$initRequestCommonParams$0 ( int i, TreeMap treeMap){    // 传入一个map, 在 map中 put Appid
        if (!treeMap.containsKey(KEY_APP_ID)) {
            treeMap.put(KEY_APP_ID, Constants.APP_ID);
        }
        if (!treeMap.containsKey("channelid")) {
            treeMap.put("channelid", AppUtils.getChannelId(ContextProvider.getContext()));
        }
        if (!treeMap.containsKey(KEY_APP_VERSION)) {
            treeMap.put(KEY_APP_VERSION, SystemUtil.getAppVersionName(ContextProvider.getContext()));
        }
        if (!treeMap.containsKey("udid")) {
            treeMap.put("udid", AppUtils.getUDID(ContextProvider.getContext()));
        }
        String userKey = UserModel.getUserKey();
        if (!ATCEmptyUtil.isEmpty((CharSequence) userKey)) {
            treeMap.put("userkey", userKey);
        }
        checkNullParams(treeMap);
        treeMap.put(KEY_SIGN, SignManager.INSTANCE.signByType(i, treeMap));
        return treeMap;
    }
}


public final class com.che168.atclibrary.base.SignManager { // 定义一个名为 SignManager 的最终公共类。
    public static final SignManager INSTANCE = new SignManager(); // 创建一个名为 INSTANCE 的公共静态最终 SignManager 实例。
    public static final String KEY_AUTOHOME = "@7U$aPOE@$"; // 定义一个名为 KEY_AUTOHOME 的公共静态最终字符串,值为 "@7U$aPOE@$"。
    public static final String KEY_SHARE = "moc.861ehc.relaed.bup.wyfv"; // 定义一个名为 KEY_SHARE 的公共静态最终字符串,值为 "moc.861ehc.relaed.bup.wyfv"。
    public static final String KEY_V1 = "com.che168.www"; // 定义一个名为 KEY_V1 的公共静态最终字符串,值为 "com.che168.www"。
    public static final String KEY_V2 = "W@oC!AH_6Ew1f6%8"; // 定义一个名为 KEY_V2 的公共静态最终字符串,值为 "W@oC!AH_6Ew1f6%8"。------------------------------

    private SignManager() { // 定义一个私有的 SignManager 构造函数,防止外部实例化。
    }

    public final String signByType(@SignType int i, TreeMap<String, String> paramMap) { // 定义一个名为 signByType 的公共最终方法,接受一个 @SignType 注释的整数和一个 TreeMap<String, String> 作为参数,返回一个字符串。-----------------
        Intrinsics.checkParameterIsNotNull(paramMap, "paramMap"); // 检查 paramMap 是否为空,如果为空则抛出异常。
        StringBuilder sb = new StringBuilder(); // 创建一个 StringBuilder 对象来构建签名字符串。
        String str = KEY_V1; // 初始化一个字符串变量 str 为 KEY_V1。
        if (i != 0) { // 检查 i 是否不等于 0。
            if (i == 1) { // 如果 i 等于 1,将 str 设置为 KEY_V2。
                str = KEY_V2;
            } else if (i == 2) { // 如果 i 等于 2,将 str 设置为 KEY_SHARE。
                str = KEY_SHARE;
            } else if (i == 3) { // 如果 i 等于 3,将 str 设置为 KEY_AUTOHOME。
                str = KEY_AUTOHOME;
            }
        }
        sb.append(str); // 将 str 追加到 StringBuilder。   ------前面加上这个玩意儿---定义一个名为 KEY_V2 的公共静态最终字符串,值为 "W@oC!AH_6Ew1f6%8"。-------------
        for (String str2 : paramMap.keySet()) { // 遍历 paramMap 的键集。-----------------
            sb.append(str2); // 将每个键追加到 StringBuilder。---------------
            sb.append(paramMap.get(str2)); // 将每个键对应的值追加到 StringBuilder。-------------
        }
        sb.append(str); // 再次将 str 追加到 StringBuilder。   -----再次将这个放到末尾 定义一个名为 KEY_V2 的公共静态最终字符串,值为 "W@oC!AH_6Ew1f6%8"。-----------------
        String encodeMD5 = SecurityUtil.encodeMD5(sb.toString()); // 使用 SecurityUtil.encodeMD5 方法对 StringBuilder 的内容进行 MD5 编码,并将结果存储在 encodeMD5 中。--将内容再次MD5运算------------
        if (encodeMD5 != null) { // 检查 encodeMD5 是否不为空。
            Locale locale = Locale.ROOT; // 获取默认的 Locale。
            Intrinsics.checkExpressionValueIsNotNull(locale, "Locale.ROOT"); // 检查 locale 是否不为空,如果为空则抛出异常。
            if (encodeMD5 == null) { // 再次检查 encodeMD5 是否为空,如果为空则抛出类型转换异常。
                throw new TypeCastException("null cannot be cast to non-null type java.lang.String");
            }
            String upperCase = encodeMD5.toUpperCase(locale); // 将 encodeMD5 转换为大写,并将结果存储在 upperCase 中。---------------------
            Intrinsics.checkExpressionValueIsNotNull(upperCase, "(this as java.lang.String).toUpperCase(locale)"); // 检查 upperCase 是否不为空,如果为空则抛出异常。
            if (upperCase != null) { // 再次检查 upperCase 是否不为空,如果不为空则返回 upperCase。
                return upperCase;// 变成 大写-----------------------------
            }
        }
        return ""; // 如果 encodeMD5 为空或 upperCase 为空,则返回一个空字符串。
    }
}




public class com.che168.autotradercloud.util.AppUtils {

    public static String getIMEI (Context context){
        String str;
        if (!PermissionsCheckerUtil.hasReadPhoenStatePermission(context)) {
            return "sssss";
        }
        String imei = SPUtils.getIMEI();     // 1, 本地 xml中 读取
        if (imeiIsNull(imei)) {
            imei = ((TelephonyManager) context.getSystemService("phone")).getDeviceId();   // 2, 读取设备  id
            if (imeiIsNull(imei)) {
                String macAddress = ((WifiManager) context.getSystemService(NetworkUtil.NETWORK_TYPE_WIFI)).getConnectionInfo().getMacAddress();  // 3, 读取 Mac 地址
                if (macAddress != null) {
                    try {
                        if (macAddress.length() > 0 && !isInBlackList(macAddress)) {
                            str = UUID.nameUUIDFromBytes(macAddress.getBytes("utf8")).toString();
                            imei = str;
                        }
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                        str = getIMEIbyAndroidIDandUUID(context);
                    }
                }
                str = getIMEIbyAndroidIDandUUID(context);       // 4, 根据  uuid 生成
                imei = str;
            }
            if (!imeiIsNull(imei)) {
                SPUtils.saveIMEI(imei);
            }
        }
        return imei;
    }

    private static String getIMEIbyAndroidIDandUUID (Context context){
        String string = Settings.Secure.getString(context.getContentResolver(), SocializeProtocolConstants.PROTOCOL_KEY_ANDROID_ID);
        if (imeiIsNull(string)) {
            return UUID.randomUUID().toString();     //  生成 UUID这个值
        }
        try {
            return UUID.nameUUIDFromBytes(string.getBytes("utf8")).toString();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return string;
        }
    }

    public static String getUDID (Context context){
        return SecurityUtil.encode3Des(context, getIMEI(context) + HiAnalyticsConstant.REPORT_VAL_SEPARATOR + System.nanoTime() + HiAnalyticsConstant.REPORT_VAL_SEPARATOR + SPUtils.getDeviceId());
    }
}



public class com.che168.autotradercloud.util.SPUtils {

    public static void saveDeviceId(String str) {
        getSpUtil().saveString(KEY_DEVICE_ID, str);
    }
    public static String getDeviceId() {
        return getSpUtil().getString(KEY_DEVICE_ID, "");
    }
    public static void saveIMEI(String str) {
        if (!ATCEmptyUtil.isEmpty((CharSequence) str)) {
            getSpUtil().saveString("imei", str);
        }
    }
    public static String getIMEI() {
        return getSpUtil().getString("imei", "");
    }
}


public class com.che168.atclibrary.utils.SharedPreferencesUtil {

    public void saveString(String str, String str2) {
        SharedPreferences sharedPreferences = this.mPreferences;
        if (sharedPreferences != null) {
            SharedPreferences.Editor edit = sharedPreferences.edit();
            edit.putString(str, str2);
            edit.commit();
        }
    }
    public String getString(String str, String str2) {
        SharedPreferences sharedPreferences = this.mPreferences;
        return sharedPreferences != null ? sharedPreferences.getString(str, str2) : str2;
    }
}




public class com.che168.autotradercloud.base.push.model.PushModel extends BaseModel {
    private static final String REG_DEVICE_URL = "/tradercloud/v100/push/regdevice.ashx";

    public static void regDevice(String str) {
        HttpUtil.Builder builder = new HttpUtil.Builder();

        builder.url(REG_DEVICE_URL)
                                    .method(HttpUtil.Method.POST)
                                    // 固定参数
                                    .param("pid", "")
                                    .param("cid", "")
                                    // 动态参数
                                    .param(ai.a, str)      // 设备注册, 个推 参数
                                    // 设备信息
                                    .param("syssn", SystemUtil.getModel())
                                    .param("sysversion", SystemUtil.getOSVersion(ContextProvider.getContext()))
                                    .param("manufacturer", SystemUtil.getBrand())
                                    // 应用信息
                                    .param("appname", SystemUtil.getAppName());

        doRequest(builder, new ResponseCallback<RegDeviceResult>() {
            /* class com.che168.autotradercloud.base.push.model.PushModel.AnonymousClass1 */

            public void success(RegDeviceResult regDeviceResult) {
                if (regDeviceResult != null && !ATCEmptyUtil.isEmpty((CharSequence) regDeviceResult.deviceid)) {
                    SPUtils.saveDeviceId(regDeviceResult.deviceid);
                    PushModel.regPush();
                }
            }

            @Override // com.che168.autotradercloud.base.httpNew.ResponseCallback
            public void failed(int i, ApiException apiException) {
                LogUtil.e(PushModel.TAG, apiException.toString());
            }
        }, new TypeToken<BaseResult<RegDeviceResult>>() {
            /* class com.che168.autotradercloud.base.push.model.PushModel.AnonymousClass2 */
        }.getType());
        LogUtil.d(TAG, "regDevice invoke...");
    }
}


public class com.che168.autotradercloud.base.push.ReceivePushService extends GTIntentService {   // 个推相关
    private static final int MAX_COUNT = 10;
    private static final String TAG = "ReceivePushService";
    private static int sRequestCode;

    @Override // com.igexin.sdk.GTIntentService
    public void onReceiveClientId (Context context, String str){
        String clientId = SPUtils.getClientId();
        if (ATCEmptyUtil.isEmpty((CharSequence) clientId) || !clientId.equals(str)) {
            SPUtils.saveClientId(str);
        }
        PushModel.regDevice(str);
        LogUtil.d(TAG, "onReceiveClientId:" + str);
    }
}