Featured image of post 某直聘app逆向分析

某直聘app逆向分析

样本地址: aHR0cHM6Ly93d3cud2FuZG91amlhLmNvbS9hcHBzLzYyMDIyMjIvaGlzdG9yeV92MTMxNDExMA==

抓包分析

我的 Charles 不知道怎么抽风了,抓包不对劲,又去换了个 burpsuite 来抓包

随便找一个包,发现请求参数又 sp 和 sig 两个加密参数,返回值是加密状态,同时通过多次抓包,发现 sig 中的 V3.0 是固定的,sp 中的 zwp 是固定的 接着看一下 app 有没有加固

没加固,继续往下面看

静态分析

看 sig 和 sp 这两个参数,常规的搜索肯定不太好找,hook hashmap 这个方式应该好一点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
function hook_map() {
    console.log("hook hashMap")
    var hashMap = Java.use("java.util.HashMap");
    hashMap.put.implementation = function (a, b) {
        if (a!=null&&a.equals("sp")) {
            console.log('输出-->', a, b)
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
        }
        if (a!=null&&a.equals("sig")) {
            console.log('输出-->', a, b)
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
        }
        return this.put(a, b)
    }
}

hook 之后的结果如下:

发现 sp 和 sig 都是在 dc0.b.r 中生成的,去 jadx 中跟一下

发现也就是 put 进去了两个参数,大概率 put 进去就是 sp 和 sig,hook 一下

1
2
3
4
5
var C34104b = Java.use("dc0.b");
C34104b["r"].implementation = function (str, str2) {
	console.log(`C34104b.m116030r is called: str=${str}, str2=${str2}`);
	this["r"](str, str2);
};


好吧,看一下交叉引用,看一下是谁调用了这个函数,然后把加密参数放进去的

这两个也好跟,跟到后面就发现了

sp 主要是由 nativeEncodeRequest 这个 native 函数生成的
sig 主要是由 nativeSignature 这个 native 函数生成的
hook 一下这两个函数,看一下参数是什么?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// sp参数的生成
var JavaString = Java.use("java.lang.String");
var StandardCharsets = Java.use("java.nio.charset.StandardCharsets");
var YZWG = Java.use("com.twl.signer.YZWG");
YZWG["nativeEncodeRequest"].implementation = function (bArr, str) {
	var utf8String = JavaString.$new(bArr, StandardCharsets.UTF_8.value);
	console.log("以下是sp参数生成的开始::")
	console.log("参数1::", utf8String)
	console.log("参数2::", str)
	let result = this["nativeEncodeRequest"](bArr, str);
	console.log(`YZWG.nativeEncodeRequest result=${result}`);
	console.log("sp参数生成完毕")
	return result;
};
// sig参数的生成
YZWG["nativeSignature"].implementation = function (bArr, str) {
	var utf8String = JavaString.$new(bArr, StandardCharsets.UTF_8.value);
	console.log("以下是sig参数生成的开始::")
	console.log("参数1::", utf8String)
	console.log("参数2::", str)
	let result = this["nativeSignature"](bArr, str);
	var result_string = JavaString.$new(result, StandardCharsets.UTF_8.value);
	console.log(`YZWG.nativeSignature result=${result_string}`);
	console.log("sig参数生成完毕")
	return result;
};

生成的日志如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
以下是sp参数生成的开始::
参数1:: client_info=%7B%22version%22%3A%2210%22%2C%22os%22%3A%22Android%22%2C%22start_time%22%3A%221772188217563%22%2C%22resume_time%22%3A%221772188217563%22%2C%22channel%22%3A%2228%22%2C%22model%22%3A%22google%7C%7CPixel+2%22%2C%22dzt%22%3A0%2C%22loc_per%22%3A0%2C%22uniqid%22%3A%22809b4bb9-33e9-4d7c-b59b-0a7d6f0ef0ee%22%2C%22oaid%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22oaid_honor%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22did%22%3A%22DUlRWq6jQRU_Glo4HL5qAwwsy7zpPrAM1600RFVsUldxNmpRUlVfR2xvNEhMNXFBd3dzeTd6cFByQU0xNjAwc2h1%22%2C%22tinker_id%22%3A%22Prod-arm64-v8a-release-13.141.1314110_0812-10-06-09%22%2C%22is_bg_req%22%3A0%2C%22network%22%3A%22wifi%22%2C%22operator%22%3A%22UNKNOWN%22%2C%22abi%22%3A1%7D&curidentity=0&data=%5B%7B%22action%22%3A%22app-active%22%2C%22time%22%3A1772188217717%2C%22p4%22%3A%22%22%2C%22p5%22%3A%221%22%2C%22p9%22%3A%22Prod-arm64-v8a-release-13.141.1314110_0812-10-06-09%22%7D%5D&req_time=1772188217741&uniqid=809b4bb9-33e9-4d7c-b59b-0a7d6f0ef0ee&v=13.141
参数2:: null
YZWG.nativeEncodeRequest result=zwp_NCTRJTSwi3DewMDkHB6GvU2BAYbyceqJ44s9CxuyL65jv20XaVYg1XpFLNVaF7LolNJtanuLr-ARNMt36qI3RFO3xe8JyDZtt-TQVeh_TOtTgNw-LeFjEs8hx0tJoj7v9ncKmYZWKNui4mO4EMBKqCp54Wi6L8MQyX1JatkuDl9Ec4gZFqDhg7Z1SBl0Q5EvXDZ9Hpb4hZrrp1qpTkEGTjmODhup8HF6VZa0VcxsMFLprFD40lIaRNgU9G7mUIMTy2f0MKwht_lGzm2bw9GnXzCQyGB8Lr9XYvIqmMmmQ8DHWVid8LshMJ0kV52zxZ2rg44Dxcb_cjVfYQd3k5ucb_MgYgZLVJLM4QfkktgfBS3MfS4m3TyKtzi7q5zNIHc52z2fsjpoSrdhmQzh6Bu6-ZMzHJWJ_nbibMppOwVp0HgqJSYdAgYwSwgrTFyUbxw15pDCp830uxCbGNwcHSQjXxi2QgRWAPNLA5ueAa07KMmuMDBrn66vKAqzehxbIFtE4CcoTGstb34UnWCQZ9CHK-DZwfQSrZu_B5i2KIvvFqQG5Fq-ycwEKSZhUmhQJuvLzl5vd6wwh08SdOWSVXsdhHdJaBhEITwc3qRr9K--K8P1fbqdFwd92GQtBdMYqXao5TbaeXuTB0nPAKVcLm67Itr35_UjlCnqciQ_D1gHezlwHiz9xMIosw5DE4hmRLXi_2s6Qm-ohQH9ooezUsQlaPNOPcYqGYA7kqAwhU1qnbISOAhNHjNNCrD-KeWeWb1UJPyg1CE5GJ5KPfTztHGY6zfoJWP7ZKkxM9aOiLMEueJjsCVuE3BpE8h-EMCAeXo_4EXFkeLihAkaNhC9wsphUwZIIS6wTUNQ8yYBBw~~
sp参数生成完毕
以下是sig参数生成的开始::
参数1:: /api/zpCommon/batch/unloginStatisticsclient_info=%7B%22version%22%3A%2210%22%2C%22os%22%3A%22Android%22%2C%22start_time%22%3A%221772188217563%22%2C%22resume_time%22%3A%221772188217563%22%2C%22channel%22%3A%2228%22%2C%22model%22%3A%22google%7C%7CPixel+2%22%2C%22dzt%22%3A0%2C%22loc_per%22%3A0%2C%22uniqid%22%3A%22809b4bb9-33e9-4d7c-b59b-0a7d6f0ef0ee%22%2C%22oaid%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22oaid_honor%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22did%22%3A%22DUlRWq6jQRU_Glo4HL5qAwwsy7zpPrAM1600RFVsUldxNmpRUlVfR2xvNEhMNXFBd3dzeTd6cFByQU0xNjAwc2h1%22%2C%22tinker_id%22%3A%22Prod-arm64-v8a-release-13.141.1314110_0812-10-06-09%22%2C%22is_bg_req%22%3A0%2C%22network%22%3A%22wifi%22%2C%22operator%22%3A%22UNKNOWN%22%2C%22abi%22%3A1%7D&curidentity=0&data=%5B%7B%22action%22%3A%22app-active%22%2C%22time%22%3A1772188217717%2C%22p4%22%3A%22%22%2C%22p5%22%3A%221%22%2C%22p9%22%3A%22Prod-arm64-v8a-release-13.141.1314110_0812-10-06-09%22%7D%5D&req_time=1772188217741&uniqid=809b4bb9-33e9-4d7c-b59b-0a7d6f0ef0ee&v=13.141
参数2:: null
YZWG.nativeSignature result=V3.0f709c133cb9964973c96a2b036376fad
sig参数生成完毕

等会儿就拿这些参数值来进行模拟 接着又继续往下面看,看到了返回值的解密函数

返回值主要是由 nativeDecodeContent 这个 native 函数进行解密的,参数 1 就是返回值的字节数组,只不过我们看到的是字节数组转成的字符串的样子,参数 2 是 null,参数 3 是 0,参数 4 是 1,参数 5 是 0
同时,这三个 native 加载的 so 都是 libyzwg.so

unidbg 模拟

先一个一个来吧,首先是 sp,先用 unidbg 搭个架子吧

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.boss;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.file.FileResult;
import com.github.unidbg.file.IOResolver;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.AbstractJni;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.memory.Memory;

import java.io.File;
//必须继承AbstractJni
public class YZWG extends AbstractJni implements IOResolver {
    public static AndroidEmulator emulator;  // 静态属性,以后对象和类都可以直接使用
    public static Memory memory;
    public static VM vm;
    public static Module module;
    // 1 构造方法--》用来初始化
    public YZWG(){
        // 1.创建设备(32位或64位模拟器), 具体看so文件在哪个目录。 在armeabi-v7a就选择32位
        // 传进设备时,如果是32位,后面so文件就要用32位,同理需要用64位的
        // 这个名字可以随便写,一般写成app的包名    以后可能会动
        emulator = AndroidEmulatorBuilder.for64Bit().setProcessName("com.hpbr.bosszhipin").build();

        // 2.获取内存对象(可以操作内存)
        memory = emulator.getMemory();

        //3.设置安卓sdk版本(只支持19、23)
        memory.setLibraryResolver(new AndroidResolver(23));

        // 4.创建虚拟机(运行安卓代码需要虚拟机,就想运行py代码需要python解释器一样)    以后会动
        vm = emulator.createDalvikVM(new File("apks/boss/boss.apk"));
        vm.setJni(this); // 后期补环境会用,把要补的环境,写在当前这个类中,执行这个代码即可,但是必须继承AbstractJni
        vm.setVerbose(true); //是否展示调用过程的细节

        // 5.加载so文件
        DalvikModule dm = vm.loadLibrary("yzwg", true);   // 以后会动
        dm.callJNI_OnLoad(emulator); // jni开发动态注册,会执行JNI_OnLoad,如果是动态注册,需要执行一下这个,如果静态注册,这个不需要执行,车智赢案例是静态注册

        // 6.dm代表so文件,dm.getModule()得到module对象,基于module对象可以访问so中的成员。
        module = dm.getModule(); // 把so文件加载到内存后,后期可以获取基地址,偏移量等,该变量代指so文件
    }

    //2 sign 成员方法--》主要用来解密
    public void get_sp(){

    }

    // 3 main方法---》右键直接运行
    public static void main(String[] args) {
        YZWG yzwg=new YZWG();
    }

    @Override
    public FileResult resolve(Emulator emulator, String pathname, int oflags) {
        System.out.println("pathname open:"+pathname);
        return null;
    }
}

运行,发现直接报错了

1
2
3
4
java.lang.UnsupportedOperationException: com/twl/signer/YZWG->gContext:Landroid/content/Context;
	at com.github.unidbg.linux.android.dvm.AbstractJni.getStaticObjectField(AbstractJni.java:103)
	at com.github.unidbg.linux.android.dvm.AbstractJni.getStaticObjectField(AbstractJni.java:53)
	at com.github.unidbg.linux.android.dvm.DvmField.getStaticObjectField(DvmField.java:106)

这种,直接补,返回一个 context 实例

1
2
3
4
5
6
7
8
9
@Override
public DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {
    switch (signature){
        case "com/twl/signer/YZWG->gContext:Landroid/content/Context;":{
            return vm.resolveClass("android/content/Context").newObject(null);
        }
    }
    return super.getStaticObjectField(vm, dvmClass, signature);
}

补上之后,又报错

1
2
3
4
java.lang.UnsupportedOperationException: android/content/pm/PackageManager->getPackagesForUid(I)[Ljava/lang/String;
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethod(AbstractJni.java:933)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethod(AbstractJni.java:867)
	at com.github.unidbg.linux.android.dvm.DvmMethod.callObjectMethod(DvmMethod.java:69)

这个方法接收一个 UID,返回该 UID 对应的所有报名列表(通常是当前应用的包名),返回值还是返回一个数组类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@Override
public DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
	switch (signature) {
		case "android/content/pm/PackageManager->getPackagesForUid(I)[Ljava/lang/String;": {
			int arg = varArg.getIntArg(0);
			System.out.println("uid==>" + arg);
			return new ArrayObject(new StringObject(vm, vm.getPackageName()));
		}
	}
	return super.callObjectMethod(vm, dvmObject, signature, varArg);
}

接着,报错

1
2
3
4
java.lang.UnsupportedOperationException: java/lang/String->hashCode()I
	at com.github.unidbg.linux.android.dvm.AbstractJni.callIntMethod(AbstractJni.java:965)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callIntMethod(AbstractJni.java:938)
	at com.github.unidbg.linux.android.dvm.DvmMethod.callIntMethod(DvmMethod.java:129)

直接补就行了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Override
public int callIntMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
	switch (signature){
		case "java/lang/String->hashCode()I":{
			String str = (String)dvmObject.getValue();
			return str.hashCode();
		}
	}
	return super.callIntMethod(vm, dvmObject, signature, varArg);
}

接着,就没报错了,开始调用参数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public void get_sp() {
	ArrayList<Object> list = new ArrayList<>(10);
	list.add(vm.getJNIEnv());
	list.add(0);
	String arg1 = "client_info=%7B%22version%22%3A%2210%22%2C%22os%22%3A%22Android%22%2C%22start_time%22%3A%221772188217563%22%2C%22resume_time%22%3A%221772188217563%22%2C%22channel%22%3A%2228%22%2C%22model%22%3A%22google%7C%7CPixel+2%22%2C%22dzt%22%3A0%2C%22loc_per%22%3A0%2C%22uniqid%22%3A%22809b4bb9-33e9-4d7c-b59b-0a7d6f0ef0ee%22%2C%22oaid%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22oaid_honor%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22did%22%3A%22DUlRWq6jQRU_Glo4HL5qAwwsy7zpPrAM1600RFVsUldxNmpRUlVfR2xvNEhMNXFBd3dzeTd6cFByQU0xNjAwc2h1%22%2C%22tinker_id%22%3A%22Prod-arm64-v8a-release-13.141.1314110_0812-10-06-09%22%2C%22is_bg_req%22%3A0%2C%22network%22%3A%22wifi%22%2C%22operator%22%3A%22UNKNOWN%22%2C%22abi%22%3A1%7D&curidentity=0&data=%5B%7B%22action%22%3A%22app-active%22%2C%22time%22%3A1772188217717%2C%22p4%22%3A%22%22%2C%22p5%22%3A%221%22%2C%22p9%22%3A%22Prod-arm64-v8a-release-13.141.1314110_0812-10-06-09%22%7D%5D&req_time=1772188217741&uniqid=809b4bb9-33e9-4d7c-b59b-0a7d6f0ef0ee&v=13.141";
	ByteArray byteArray = new ByteArray(vm, arg1.getBytes(StandardCharsets.UTF_8));
	list.add(vm.addLocalObject(byteArray));
	list.add(vm.addLocalObject(null));
	Number number = module.callFunction(emulator, 0x209a4, list.toArray());
	String result = vm.getObject(number.intValue()).getValue().toString();
	System.out.println(result);
}

public void get_sig() {
	ArrayList<Object> list = new ArrayList<>(10);
	list.add(vm.getJNIEnv());
	list.add(0);
	String arg1 = "/api/zpCommon/batch/unloginStatisticsclient_info=%7B%22version%22%3A%2210%22%2C%22os%22%3A%22Android%22%2C%22start_time%22%3A%221772188217563%22%2C%22resume_time%22%3A%221772188217563%22%2C%22channel%22%3A%2228%22%2C%22model%22%3A%22google%7C%7CPixel+2%22%2C%22dzt%22%3A0%2C%22loc_per%22%3A0%2C%22uniqid%22%3A%22809b4bb9-33e9-4d7c-b59b-0a7d6f0ef0ee%22%2C%22oaid%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22oaid_honor%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22did%22%3A%22DUlRWq6jQRU_Glo4HL5qAwwsy7zpPrAM1600RFVsUldxNmpRUlVfR2xvNEhMNXFBd3dzeTd6cFByQU0xNjAwc2h1%22%2C%22tinker_id%22%3A%22Prod-arm64-v8a-release-13.141.1314110_0812-10-06-09%22%2C%22is_bg_req%22%3A0%2C%22network%22%3A%22wifi%22%2C%22operator%22%3A%22UNKNOWN%22%2C%22abi%22%3A1%7D&curidentity=0&data=%5B%7B%22action%22%3A%22app-active%22%2C%22time%22%3A1772188217717%2C%22p4%22%3A%22%22%2C%22p5%22%3A%221%22%2C%22p9%22%3A%22Prod-arm64-v8a-release-13.141.1314110_0812-10-06-09%22%7D%5D&req_time=1772188217741&uniqid=809b4bb9-33e9-4d7c-b59b-0a7d6f0ef0ee&v=13.141";
	ByteArray byteArray = new ByteArray(vm, arg1.getBytes(StandardCharsets.UTF_8));
	list.add(vm.addLocalObject(byteArray));
	list.add(vm.addLocalObject(null));
	Number number = module.callFunction(emulator, 0x21864, list.toArray());
	DvmObject<?> retObj = vm.getObject(number.intValue());
	byte[] resultBytes = (byte[]) retObj.getValue();
	String result = new String(resultBytes, StandardCharsets.UTF_8);
	System.out.println("结果: " + result);

}

public void decodeContent() {
	byte[] encryptedData = new byte[]{
			-10, 114, 76, 25, 44, -37, 100, 101, -124, -69, 64, -18, -101, -32, -119, 121, -125, -10, -36, 42, 125, 34, -68, -48, 102, 107, 91, 107, 88, -42, -125, -19, 69, -95, 90, -127, 56, -28, -108, -69, -101, -78, 1, -2, -70, -84, 12, -91, -106, 98, 27, 89, 71, -37, -87, -37, 71, 110, 111, -65, -22, 71, -16, 15, 111, -106, -30, -1, 8, 31, 46, -60, 38, -110, -21, 71, 126, 34, -16, 62, -106, -40, 16, -107, 2, 64, -65, -56, 71, -36, 85, 40, -3, 69, -71, -65, 24, -20, 4, 125, -114, -112, 126, 17, -28, -63, -100, 61, 58, -24, 6, -55, 87, -59, 124, -112, -26, 50, -41, 26, 25, -9, 33, -48, 80, 22, 46, -119, 112, 78, 5, 24, 96, -86, 36, 68, -71, -7, -90, -71, 111, 76, 87, 116, 56, -19, 2
	};
	ArrayList<Object> list = new ArrayList<>(10);
	list.add(vm.getJNIEnv());
	list.add(0);
	ByteArray dataArray = new ByteArray(vm, encryptedData);
	list.add(vm.addLocalObject(dataArray));

	list.add(null);
	list.add(0);
	list.add(1);
	list.add(0);
	Number number = module.callFunction(emulator, 0x24dc8, list.toArray()); // 替换实际地址
	DvmObject<?> retObj = vm.getObject(number.intValue());
	byte[] resultBytes = (byte[]) retObj.getValue();
	String result = new String(resultBytes, StandardCharsets.UTF_8);
	System.out.println("解密结果: " + result);
}

发现直接就能够出调用的结果了

跟 hook 的结果是一样的
所有的代码如下:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package com.boss;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.file.FileResult;
import com.github.unidbg.file.IOResolver;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.array.ArrayObject;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.memory.Memory;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;

//必须继承AbstractJni
public class YZWG extends AbstractJni implements IOResolver {
    public static AndroidEmulator emulator;  // 静态属性,以后对象和类都可以直接使用
    public static Memory memory;
    public static VM vm;
    public static Module module;

    // 1 构造方法--》用来初始化
    public YZWG() {
        // 1.创建设备(32位或64位模拟器), 具体看so文件在哪个目录。 在armeabi-v7a就选择32位
        // 传进设备时,如果是32位,后面so文件就要用32位,同理需要用64位的
        // 这个名字可以随便写,一般写成app的包名    以后可能会动
        emulator = AndroidEmulatorBuilder.for64Bit().setProcessName("com.hpbr.bosszhipin").build();

        // 2.获取内存对象(可以操作内存)
        memory = emulator.getMemory();

        //3.设置安卓sdk版本(只支持19、23)
        memory.setLibraryResolver(new AndroidResolver(23));

        // 4.创建虚拟机(运行安卓代码需要虚拟机,就想运行py代码需要python解释器一样)    以后会动
        vm = emulator.createDalvikVM(new File("apks/boss/boss.apk"));
        vm.setJni(this); // 后期补环境会用,把要补的环境,写在当前这个类中,执行这个代码即可,但是必须继承AbstractJni
        vm.setVerbose(true); //是否展示调用过程的细节

        // 5.加载so文件
        DalvikModule dm = vm.loadLibrary("yzwg", true);   // 以后会动
        dm.callJNI_OnLoad(emulator); // jni开发动态注册,会执行JNI_OnLoad,如果是动态注册,需要执行一下这个,如果静态注册,这个不需要执行,车智赢案例是静态注册

        // 6.dm代表so文件,dm.getModule()得到module对象,基于module对象可以访问so中的成员。
        module = dm.getModule(); // 把so文件加载到内存后,后期可以获取基地址,偏移量等,该变量代指so文件
    }


    @Override
    public DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {
        switch (signature) {
            case "com/twl/signer/YZWG->gContext:Landroid/content/Context;": {
                return vm.resolveClass("android/content/Context").newObject(null);
            }
        }
        return super.getStaticObjectField(vm, dvmClass, signature);
    }

    @Override
    public DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
        switch (signature) {
            case "android/content/pm/PackageManager->getPackagesForUid(I)[Ljava/lang/String;": {
                int arg = varArg.getIntArg(0);
                System.out.println("uid==>" + arg);
                System.out.println("包名==>" + vm.getPackageName());
                return new ArrayObject(new StringObject(vm, vm.getPackageName()));
            }
        }
        return super.callObjectMethod(vm, dvmObject, signature, varArg);
    }

    @Override
    public int callIntMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
        switch (signature) {
            case "java/lang/String->hashCode()I": {
                String str = (String) dvmObject.getValue();
                return str.hashCode();
            }
        }
        return super.callIntMethod(vm, dvmObject, signature, varArg);
    }
    
    //2 sign 成员方法--》主要用来解密
    public void get_sp() {
        ArrayList<Object> list = new ArrayList<>(10);
        list.add(vm.getJNIEnv());
        list.add(0);
        String arg1 = "client_info=%7B%22version%22%3A%2210%22%2C%22os%22%3A%22Android%22%2C%22start_time%22%3A%221772188217563%22%2C%22resume_time%22%3A%221772188217563%22%2C%22channel%22%3A%2228%22%2C%22model%22%3A%22google%7C%7CPixel+2%22%2C%22dzt%22%3A0%2C%22loc_per%22%3A0%2C%22uniqid%22%3A%22809b4bb9-33e9-4d7c-b59b-0a7d6f0ef0ee%22%2C%22oaid%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22oaid_honor%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22did%22%3A%22DUlRWq6jQRU_Glo4HL5qAwwsy7zpPrAM1600RFVsUldxNmpRUlVfR2xvNEhMNXFBd3dzeTd6cFByQU0xNjAwc2h1%22%2C%22tinker_id%22%3A%22Prod-arm64-v8a-release-13.141.1314110_0812-10-06-09%22%2C%22is_bg_req%22%3A0%2C%22network%22%3A%22wifi%22%2C%22operator%22%3A%22UNKNOWN%22%2C%22abi%22%3A1%7D&curidentity=0&data=%5B%7B%22action%22%3A%22app-active%22%2C%22time%22%3A1772188217717%2C%22p4%22%3A%22%22%2C%22p5%22%3A%221%22%2C%22p9%22%3A%22Prod-arm64-v8a-release-13.141.1314110_0812-10-06-09%22%7D%5D&req_time=1772188217741&uniqid=809b4bb9-33e9-4d7c-b59b-0a7d6f0ef0ee&v=13.141";
        ByteArray byteArray = new ByteArray(vm, arg1.getBytes(StandardCharsets.UTF_8));
        list.add(vm.addLocalObject(byteArray));
        list.add(vm.addLocalObject(null));
        Number number = module.callFunction(emulator, 0x209a4, list.toArray());
        String result = vm.getObject(number.intValue()).getValue().toString();
        System.out.println(result);
    }

    public void get_sig() {
        ArrayList<Object> list = new ArrayList<>(10);
        list.add(vm.getJNIEnv());
        list.add(0);
        String arg1 = "/api/zpCommon/batch/unloginStatisticsclient_info=%7B%22version%22%3A%2210%22%2C%22os%22%3A%22Android%22%2C%22start_time%22%3A%221772188217563%22%2C%22resume_time%22%3A%221772188217563%22%2C%22channel%22%3A%2228%22%2C%22model%22%3A%22google%7C%7CPixel+2%22%2C%22dzt%22%3A0%2C%22loc_per%22%3A0%2C%22uniqid%22%3A%22809b4bb9-33e9-4d7c-b59b-0a7d6f0ef0ee%22%2C%22oaid%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22oaid_honor%22%3A%2200000000-0000-0000-0000-000000000000%22%2C%22did%22%3A%22DUlRWq6jQRU_Glo4HL5qAwwsy7zpPrAM1600RFVsUldxNmpRUlVfR2xvNEhMNXFBd3dzeTd6cFByQU0xNjAwc2h1%22%2C%22tinker_id%22%3A%22Prod-arm64-v8a-release-13.141.1314110_0812-10-06-09%22%2C%22is_bg_req%22%3A0%2C%22network%22%3A%22wifi%22%2C%22operator%22%3A%22UNKNOWN%22%2C%22abi%22%3A1%7D&curidentity=0&data=%5B%7B%22action%22%3A%22app-active%22%2C%22time%22%3A1772188217717%2C%22p4%22%3A%22%22%2C%22p5%22%3A%221%22%2C%22p9%22%3A%22Prod-arm64-v8a-release-13.141.1314110_0812-10-06-09%22%7D%5D&req_time=1772188217741&uniqid=809b4bb9-33e9-4d7c-b59b-0a7d6f0ef0ee&v=13.141";
        ByteArray byteArray = new ByteArray(vm, arg1.getBytes(StandardCharsets.UTF_8));
        list.add(vm.addLocalObject(byteArray));
        list.add(vm.addLocalObject(null));
        Number number = module.callFunction(emulator, 0x21864, list.toArray());
        DvmObject<?> retObj = vm.getObject(number.intValue());
        byte[] resultBytes = (byte[]) retObj.getValue();
        String result = new String(resultBytes, StandardCharsets.UTF_8);
        System.out.println("结果: " + result);

    }

    public void decodeContent() {
        byte[] encryptedData = new byte[]{
                -10, 114, 76, 25, 44, -37, 100, 101, -124, -69, 64, -18, -101, -32, -119, 121, -125, -10, -36, 42, 125, 34, -68, -48, 102, 107, 91, 107, 88, -42, -125, -19, 69, -95, 90, -127, 56, -28, -108, -69, -101, -78, 1, -2, -70, -84, 12, -91, -106, 98, 27, 89, 71, -37, -87, -37, 71, 110, 111, -65, -22, 71, -16, 15, 111, -106, -30, -1, 8, 31, 46, -60, 38, -110, -21, 71, 126, 34, -16, 62, -106, -40, 16, -107, 2, 64, -65, -56, 71, -36, 85, 40, -3, 69, -71, -65, 24, -20, 4, 125, -114, -112, 126, 17, -28, -63, -100, 61, 58, -24, 6, -55, 87, -59, 124, -112, -26, 50, -41, 26, 25, -9, 33, -48, 80, 22, 46, -119, 112, 78, 5, 24, 96, -86, 36, 68, -71, -7, -90, -71, 111, 76, 87, 116, 56, -19, 2
        };
        ArrayList<Object> list = new ArrayList<>(10);
        list.add(vm.getJNIEnv());
        list.add(0);
        ByteArray dataArray = new ByteArray(vm, encryptedData);
        list.add(vm.addLocalObject(dataArray));

        list.add(null);
        list.add(0);
        list.add(1);
        list.add(0);
        Number number = module.callFunction(emulator, 0x24dc8, list.toArray());
        DvmObject<?> retObj = vm.getObject(number.intValue());
        byte[] resultBytes = (byte[]) retObj.getValue();
        String result = new String(resultBytes, StandardCharsets.UTF_8);
        System.out.println("解密结果: " + result);
    }

    // 3 main方法---》右键直接运行
    public static void main(String[] args) {
        YZWG yzwg = new YZWG();
        yzwg.get_sp();
        yzwg.get_sig();
        yzwg.decodeContent();
    }

    @Override
    public FileResult resolve(Emulator emulator, String pathname, int oflags) {
        System.out.println("pathname open:" + pathname);
        return null;
    }
}

// zwp_NCTRJTSwi3DewMDkHB6GvU2BAYbyceqJ44s9CxuyL65jv20XaVYg1XpFLNVaF7LolNJtanuLr-ARNMt36qI3RFO3xe8JyDZtt-TQVeh_TOtTgNw-LeFjEs8hx0tJoj7v9ncKmYZWKNui4mO4EMBKqCp54Wi6L8MQyX1JatkuDl9Ec4gZFqDhg7Z1SBl0Q5EvXDZ9Hpb4hZrrp1qpTkEGTjmODhup8HF6VZa0VcxsMFLprFD40lIaRNgU9G7mUIMTy2f0MKwht_lGzm2bw9GnXzCQyGB8Lr9XYvIqmMmmQ8DHWVid8LshMJ0kV52zxZ2rg44Dxcb_cjVfYQd3k5ucb_MgYgZLVJLM4QfkktgfBS3MfS4m3TyKtzi7q5zNIHc52z2fsjpoSrdhmQzh6Bu6-ZMzHJWJ_nbibMppOwVp0HgqJSYdAgYwSwgrTFyUbxw15pDCp830uxCbGNwcHSQjXxi2QgRWAPNLA5ueAa07KMmuMDBrn66vKAqzehxbIFtE4CcoTGstb34UnWCQZ9CHK-DZwfQSrZu_B5i2KIvvFqQG5Fq-ycwEKSZhUmhQJuvLzl5vd6wwh08SdOWSVXsdhHdJaBhEITwc3qRr9K--K8P1fbqdFwd92GQtBdMYqXao5TbaeXuTB0nPAKVcLm67Itr35_UjlCnqciQ_D1gHezlwHiz9xMIosw5DE4hmRLXi_2s6Qm-ohQH9ooezUsQlaPNOPcYqGYA7kqAwhU1qnbISOAhNHjNNCrD-KeWeWb1UJPyg1CE5GJ5KPfTztHGY6zfoJWP7ZKkxM9aOiLMEueJjsCVuE3BpE8h-EMCAeXo_4EXFkeLihAkaNhC9wsphUwZIIS6wTUNQ8yYBBw~~
// zwp_NCTRJTSwi3DewMDkHB6GvU2BAYbyceqJ44s9CxuyL65jv20XaVYg1XpFLNVaF7LolNJtanuLr-ARNMt36qI3RFO3xe8JyDZtt-TQVeh_TOtTgNw-LeFjEs8hx0tJoj7v9ncKmYZWKNui4mO4EMBKqCp54Wi6L8MQyX1JatkuDl9Ec4gZFqDhg7Z1SBl0Q5EvXDZ9Hpb4hZrrp1qpTkEGTjmODhup8HF6VZa0VcxsMFLprFD40lIaRNgU9G7mUIMTy2f0MKwht_lGzm2bw9GnXzCQyGB8Lr9XYvIqmMmmQ8DHWVid8LshMJ0kV52zxZ2rg44Dxcb_cjVfYQd3k5ucb_MgYgZLVJLM4QfkktgfBS3MfS4m3TyKtzi7q5zNIHc52z2fsjpoSrdhmQzh6Bu6-ZMzHJWJ_nbibMppOwVp0HgqJSYdAgYwSwgrTFyUbxw15pDCp830uxCbGNwcHSQjXxi2QgRWAPNLA5ueAa07KMmuMDBrn66vKAqzehxbIFtE4CcoTGstb34UnWCQZ9CHK-DZwfQSrZu_B5i2KIvvFqQG5Fq-ycwEKSZhUmhQJuvLzl5vd6wwh08SdOWSVXsdhHdJaBhEITwc3qRr9K--K8P1fbqdFwd92GQtBdMYqXao5TbaeXuTB0nPAKVcLm67Itr35_UjlCnqciQ_D1gHezlwHiz9xMIosw5DE4hmRLXi_2s6Qm-ohQH9ooezUsQlaPNOPcYqGYA7kqAwhU1qnbISOAhNHjNNCrD-KeWeWb1UJPyg1CE5GJ5KPfTztHGY6zfoJWP7ZKkxM9aOiLMEueJjsCVuE3BpE8h-EMCAeXo_4EXFkeLihAkaNhC9wsphUwZIIS6wTUNQ8yYBBw~~

算法分析

首先,trace 一份日志,管他用不用的上,用不上最好,分析不出来了,就看日志

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public void traceCode() {
	String traceFile = "unidbg-android/src/test/java/com/boss/traceCode.log"; // 输出的路径
	PrintStream traceStream = null; // 打印流
	try {
		traceStream = new PrintStream(new FileOutputStream(traceFile), true);
	} catch (FileNotFoundException e) {
		throw new RuntimeException(e);
	}
	// traceCode 对代码进行监控
	emulator.traceCode(module.base, module.base + module.size).setRedirect(traceStream);
}

参数sig

首先先来一个简单的参数吧, V3.0f709c133cb9964973c96a2b036376fad 其中 V3.0 是固定的,后面拼接了一个 32 位的字符串,有极大概率就是一个 md5 算法

他返回的是一个字节数组,跳转到 0x21fdc

最后调用 SetByteArrayRegion 返回数组,回顾一下 JNI 的语法

  • jbyteArray javaArray = (*env)->NewByteArray(env, len); 创建字节数组
  • (*env)->SetByteArrayRegion(env, javaArray, 0, len, (jbyte*)result); 将 C 数据复制到 Java 数组
  • GetByteArrayRegion 获取 Java 数组的数据到 C

所以,在这儿就可以看出: v29 是源数据, v27 是复制到的索引/长度, v4 是目标数组
所以就需要看 v29 是哪儿来的?v29 由 v27 赋值, v27sub_1C38C 函数的返回值,所以就需要 hook 一下这个子函数了

1
emulator.attach().addBreakPoint(module.base+0x1C38C);

结果如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
mx0

>-----------------------------------------------------------------------------<
[09:28:54 820]x0=RW@0x123d13c8[libyzwg.so]0x3d13c8, md5=432ae95099f42e1e651cece1e929145a, hex=56332e30000000004241534536345f53495a45203d205b25645d2c20436f6e74656e744c656e203d205b25645d00000000000000000000004465636f64654f7574707574206d616c6c6f63206661696c21000000000000004e6f7420737570706f727420656e6372797074696f6e2074
size: 112
0000: 56 33 2E 30 00 00 00 00 42 41 53 45 36 34 5F 53    V3.0....BASE64_S
0010: 49 5A 45 20 3D 20 5B 25 64 5D 2C 20 43 6F 6E 74    IZE = [%d], Cont
0020: 65 6E 74 4C 65 6E 20 3D 20 5B 25 64 5D 00 00 00    entLen = [%d]...
0030: 00 00 00 00 00 00 00 00 44 65 63 6F 64 65 4F 75    ........DecodeOu
0040: 74 70 75 74 20 6D 61 6C 6C 6F 63 20 66 61 69 6C    tput malloc fail
0050: 21 00 00 00 00 00 00 00 4E 6F 74 20 73 75 70 70    !.......Not supp
0060: 6F 72 74 20 65 6E 63 72 79 70 74 69 6F 6E 20 74    ort encryption t
^-----------------------------------------------------------------------------^
mx1

>-----------------------------------------------------------------------------<
[09:28:59 041]x1=RW@0x12713060, md5=6621f88cccba6b7d2442b768b59782f3, hex=66373039633133336362393936343937336339366132623033363337366661640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
size: 112
0000: 66 37 30 39 63 31 33 33 63 62 39 39 36 34 39 37    f709c133cb996497
0010: 33 63 39 36 61 32 62 30 33 36 33 37 36 66 61 64    3c96a2b036376fad
0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
^-----------------------------------------------------------------------------^

x0 我看不出来是个什么东西,x1 我知道就是最后生成的 sig 中 V3.0 后面拼接的字符串,所以,需要分析的就是 x1 寄存器,即 v24 是在哪儿生成的了
v24 是由上面的 sub_1C714 这个子函数生成的,继续 hook 这个子函数
x0 是地址,那么 x1 肯定就是代表 x0 这个寄存器数据的长度了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
mx0 0x433

>-----------------------------------------------------------------------------<
[09:42:01 665]x0=RW@0x12719000, hex=2f6170692f7a70436f6d6d6f6e2f62617463682f756e6c6f67696e53746174697374696373636c69656e745f696e666f3d25374225323276657273696f6e25323225334125323231302532322532432532326f73253232253341253232416e64726f696425323225324325323273746172745f74696d6525323225334125323231373732313838323137353633253232253243253232726573756d655f74696d65253232253341253232313737323138383231373536332532322532432532326368616e6e656c25323225334125323232382532322532432532326d6f64656c253232253341253232676f6f676c65253743253743506978656c2b32253232253243253232647a74253232253341302532432532326c6f635f70657225323225334130253243253232756e6971696425323225334125323238303962346262392d333365392d346437632d623539622d3061376436663065663065652532322532432532326f61696425323225334125323230303030303030302d303030302d303030302d303030302d3030303030303030303030302532322532432532326f6169645f686f6e6f7225323225334125323230303030303030302d303030302d303030302d303030302d30303030303030303030303025323225324325323264696425323225334125323244556c525771366a5152555f476c6f34484c35714177777379377a705072414d3136303052465673556c64784e6d7052556c5666523278764e45684d4e5846426433647a6554643663464279515530784e6a41776332683125323225324325323274696e6b65725f696425323225334125323250726f642d61726d36342d7638612d72656c656173652d31332e3134312e313331343131305f303831322d31302d30362d303925323225324325323269735f62675f726571253232253341302532432532326e6574776f726b253232253341253232776966692532322532432532326f70657261746f72253232253341253232554e4b4e4f574e25323225324325323261626925323225334131253744266375726964656e746974793d3026646174613d253542253742253232616374696f6e2532322533412532326170702d61637469766525323225324325323274696d65253232253341313737323138383231373731372532432532327034253232253341253232253232253243253232703525323225334125323231253232253243253232703925323225334125323250726f642d61726d36342d7638612d72656c656173652d31332e3134312e313331343131305f303831322d31302d30362d3039253232253744253544267265715f74696d653d3137373231383832313737343126756e697169643d38303962346262392d333365392d346437632d623539622d30613764366630656630656526763d31332e3134316133303866333632386233663339663764333563646562656236393230653231, md5=f709c133cb9964973c96a2b036376fad
size: 1075
0000: 2F 61 70 69 2F 7A 70 43 6F 6D 6D 6F 6E 2F 62 61    /api/zpCommon/ba
0010: 74 63 68 2F 75 6E 6C 6F 67 69 6E 53 74 61 74 69    tch/unloginStati
0020: 73 74 69 63 73 63 6C 69 65 6E 74 5F 69 6E 66 6F    sticsclient_info
0030: 3D 25 37 42 25 32 32 76 65 72 73 69 6F 6E 25 32    =%7B%22version%2
0040: 32 25 33 41 25 32 32 31 30 25 32 32 25 32 43 25    2%3A%2210%22%2C%
0050: 32 32 6F 73 25 32 32 25 33 41 25 32 32 41 6E 64    22os%22%3A%22And
0060: 72 6F 69 64 25 32 32 25 32 43 25 32 32 73 74 61    roid%22%2C%22sta
0070: 72 74 5F 74 69 6D 65 25 32 32 25 33 41 25 32 32    rt_time%22%3A%22
0080: 31 37 37 32 31 38 38 32 31 37 35 36 33 25 32 32    1772188217563%22
0090: 25 32 43 25 32 32 72 65 73 75 6D 65 5F 74 69 6D    %2C%22resume_tim
00A0: 65 25 32 32 25 33 41 25 32 32 31 37 37 32 31 38    e%22%3A%22177218
00B0: 38 32 31 37 35 36 33 25 32 32 25 32 43 25 32 32    8217563%22%2C%22
00C0: 63 68 61 6E 6E 65 6C 25 32 32 25 33 41 25 32 32    channel%22%3A%22
00D0: 32 38 25 32 32 25 32 43 25 32 32 6D 6F 64 65 6C    28%22%2C%22model
00E0: 25 32 32 25 33 41 25 32 32 67 6F 6F 67 6C 65 25    %22%3A%22google%
00F0: 37 43 25 37 43 50 69 78 65 6C 2B 32 25 32 32 25    7C%7CPixel+2%22%
0100: 32 43 25 32 32 64 7A 74 25 32 32 25 33 41 30 25    2C%22dzt%22%3A0%
0110: 32 43 25 32 32 6C 6F 63 5F 70 65 72 25 32 32 25    2C%22loc_per%22%
0120: 33 41 30 25 32 43 25 32 32 75 6E 69 71 69 64 25    3A0%2C%22uniqid%
0130: 32 32 25 33 41 25 32 32 38 30 39 62 34 62 62 39    22%3A%22809b4bb9
0140: 2D 33 33 65 39 2D 34 64 37 63 2D 62 35 39 62 2D    -33e9-4d7c-b59b-
0150: 30 61 37 64 36 66 30 65 66 30 65 65 25 32 32 25    0a7d6f0ef0ee%22%
0160: 32 43 25 32 32 6F 61 69 64 25 32 32 25 33 41 25    2C%22oaid%22%3A%
0170: 32 32 30 30 30 30 30 30 30 30 2D 30 30 30 30 2D    2200000000-0000-
0180: 30 30 30 30 2D 30 30 30 30 2D 30 30 30 30 30 30    0000-0000-000000
0190: 30 30 30 30 30 30 25 32 32 25 32 43 25 32 32 6F    000000%22%2C%22o
01A0: 61 69 64 5F 68 6F 6E 6F 72 25 32 32 25 33 41 25    aid_honor%22%3A%
01B0: 32 32 30 30 30 30 30 30 30 30 2D 30 30 30 30 2D    2200000000-0000-
01C0: 30 30 30 30 2D 30 30 30 30 2D 30 30 30 30 30 30    0000-0000-000000
01D0: 30 30 30 30 30 30 25 32 32 25 32 43 25 32 32 64    000000%22%2C%22d
01E0: 69 64 25 32 32 25 33 41 25 32 32 44 55 6C 52 57    id%22%3A%22DUlRW
01F0: 71 36 6A 51 52 55 5F 47 6C 6F 34 48 4C 35 71 41    q6jQRU_Glo4HL5qA
0200: 77 77 73 79 37 7A 70 50 72 41 4D 31 36 30 30 52    wwsy7zpPrAM1600R
0210: 46 56 73 55 6C 64 78 4E 6D 70 52 55 6C 56 66 52    FVsUldxNmpRUlVfR
0220: 32 78 76 4E 45 68 4D 4E 58 46 42 64 33 64 7A 65    2xvNEhMNXFBd3dze
0230: 54 64 36 63 46 42 79 51 55 30 78 4E 6A 41 77 63    Td6cFByQU0xNjAwc
0240: 32 68 31 25 32 32 25 32 43 25 32 32 74 69 6E 6B    2h1%22%2C%22tink
0250: 65 72 5F 69 64 25 32 32 25 33 41 25 32 32 50 72    er_id%22%3A%22Pr
0260: 6F 64 2D 61 72 6D 36 34 2D 76 38 61 2D 72 65 6C    od-arm64-v8a-rel
0270: 65 61 73 65 2D 31 33 2E 31 34 31 2E 31 33 31 34    ease-13.141.1314
0280: 31 31 30 5F 30 38 31 32 2D 31 30 2D 30 36 2D 30    110_0812-10-06-0
0290: 39 25 32 32 25 32 43 25 32 32 69 73 5F 62 67 5F    9%22%2C%22is_bg_
02A0: 72 65 71 25 32 32 25 33 41 30 25 32 43 25 32 32    req%22%3A0%2C%22
02B0: 6E 65 74 77 6F 72 6B 25 32 32 25 33 41 25 32 32    network%22%3A%22
02C0: 77 69 66 69 25 32 32 25 32 43 25 32 32 6F 70 65    wifi%22%2C%22ope
02D0: 72 61 74 6F 72 25 32 32 25 33 41 25 32 32 55 4E    rator%22%3A%22UN
02E0: 4B 4E 4F 57 4E 25 32 32 25 32 43 25 32 32 61 62    KNOWN%22%2C%22ab
02F0: 69 25 32 32 25 33 41 31 25 37 44 26 63 75 72 69    i%22%3A1%7D&curi
0300: 64 65 6E 74 69 74 79 3D 30 26 64 61 74 61 3D 25    dentity=0&data=%
0310: 35 42 25 37 42 25 32 32 61 63 74 69 6F 6E 25 32    5B%7B%22action%2
0320: 32 25 33 41 25 32 32 61 70 70 2D 61 63 74 69 76    2%3A%22app-activ
0330: 65 25 32 32 25 32 43 25 32 32 74 69 6D 65 25 32    e%22%2C%22time%2
0340: 32 25 33 41 31 37 37 32 31 38 38 32 31 37 37 31    2%3A177218821771
0350: 37 25 32 43 25 32 32 70 34 25 32 32 25 33 41 25    7%2C%22p4%22%3A%
0360: 32 32 25 32 32 25 32 43 25 32 32 70 35 25 32 32    22%22%2C%22p5%22
0370: 25 33 41 25 32 32 31 25 32 32 25 32 43 25 32 32    %3A%221%22%2C%22
0380: 70 39 25 32 32 25 33 41 25 32 32 50 72 6F 64 2D    p9%22%3A%22Prod-
0390: 61 72 6D 36 34 2D 76 38 61 2D 72 65 6C 65 61 73    arm64-v8a-releas
03A0: 65 2D 31 33 2E 31 34 31 2E 31 33 31 34 31 31 30    e-13.141.1314110
03B0: 5F 30 38 31 32 2D 31 30 2D 30 36 2D 30 39 25 32    _0812-10-06-09%2
03C0: 32 25 37 44 25 35 44 26 72 65 71 5F 74 69 6D 65    2%7D%5D&req_time
03D0: 3D 31 37 37 32 31 38 38 32 31 37 37 34 31 26 75    =1772188217741&u
03E0: 6E 69 71 69 64 3D 38 30 39 62 34 62 62 39 2D 33    niqid=809b4bb9-3
03F0: 33 65 39 2D 34 64 37 63 2D 62 35 39 62 2D 30 61    3e9-4d7c-b59b-0a
0400: 37 64 36 66 30 65 66 30 65 65 26 76 3D 31 33 2E    7d6f0ef0ee&v=13.
0410: 31 34 31 61 33 30 38 66 33 36 32 38 62 33 66 33    141a308f3628b3f3
0420: 39 66 37 64 33 35 63 64 65 62 65 62 36 39 32 30    9f7d35cdebeb6920
0430: 65 32 31                                           e21
^-----------------------------------------------------------------------------^

他在明文后面拼接了一个字符串,你说这个会不会是 md5 算法的盐值,这完全有可能啊,可以去测试一下

我去,还真是,我经过不断的测试发现这个盐值还是固定的,那就不用继续往里面跟了
总结: sig=V3.0+hashlib.md5(明文+a308f3628b3f39f7d35cdebeb6920e21)

参数 sp

sig 的部分看完了,下面就来看 sp 这个参数,回到 unidbg 最后生成的代码逻辑中

来到 0x21020 这个偏移

发现最后返回的是 v23 这个字符串,v23 最开始是分配了 v19 长度的字节空间,经过了 sub_29E90sub_1CEB8 这两个子函数,得到了最终的结果,那么这两个子函数就很可疑了,它在里面做了什么就很有探究的必要了
首先来看一下 sub_29E90 这个子函数

在这儿看到了码表,这很有可能就是一个 base64 编码啊,可以去验证一下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
emulator.attach().addBreakPoint(module.base+0x29E90);

debugger break at: 0x12029e90 @ Runnable|Function64 address=0x120209a4, arguments=[unidbg@0xfffe1640, 0, 1332668132, 0]
>>> x0=0x1271e000 x1=0x12719000 x2=0x28f x3=0x12702ae0 x4=0x12606000 x5=0x1 x6=0x0 x7=0x0 x8=0x0 x9=0xaaaaaaaaaaaaaaab x10=0x0 x11=0x12702260 x12=0x0 x13=0x0 x14=0x1
>>> x15=0x8 x16=0x9 x17=0x0 x18=0x1e x19=0x449e509f x20=0x0 x21=0xfffe1640 x22=0x4f6ee6e4 x23=0xdb13f0ef x24=0x13dbc278 x25=0x32c11dfa x26=0xe4fff708 x27=0x7a1d9687 x28=0x36d fp=0x1271e000
>>> q0=0x1300000000000000130(1.5E-321, 1.5E-321) q1=0x50000000000000004000(8.0948E-320, 1.01185E-319) q2=0x0(0.0) q3=0x70000000000000006(3.0E-323, 3.5E-323) q4=0x10000000000000001(4.9E-324, 4.9E-324) q5=0x40000000000000004(2.0E-323, 2.0E-323) q6=0x20000000000000002(1.0E-323, 1.0E-323) q7=0x1310000000000000131(1.507E-321, 1.507E-321) q8=0x0(0.0) q9=0x0(0.0) q10=0x0(0.0) q11=0x0(0.0) q12=0x0(0.0) q13=0x0(0.0) q14=0x0(0.0) q15=0x0(0.0)
>>> q16=0x51310000000000004131(8.2455E-320, 1.0269E-319) q17=0x0(0.0) q18=0x51310000000000004131(8.2455E-320, 1.0269E-319) q19=0xfdf1c3ced3ceced9(-4.647269563198482E298) q20=0x7d71434e534e4e59(1.7640457944868906E296) q21=0x0(0.0) q22=0x0(0.0) q23=0x0(0.0) q24=0x0(0.0) q25=0x0(0.0) q26=0x0(0.0) q27=0x0(0.0) q28=0x0(0.0) q29=0x0(0.0) q30=0x0(0.0) q31=0x0(0.0)
LR=RX@0x12020ff8[libyzwg.so]0x20ff8
SP=0xe4fff4f0
PC=RX@0x12029e90[libyzwg.so]0x29e90
nzcv: N=1, Z=0, C=0, V=0, EL0, use SP_EL0
    [libyzwg.so 0x029e8c] [c0035fd6] 0x12029e8c: "ret"
=> *[libyzwg.so*0x029e90]*[ffc302d1]*0x12029e90:*"sub sp, sp, #0xb0"
    [libyzwg.so 0x029e94] [fc6f05a9] 0x12029e94: "stp x28, x27, [sp, #0x50]"
    [libyzwg.so 0x029e98] [fa6706a9] 0x12029e98: "stp x26, x25, [sp, #0x60]"
    [libyzwg.so 0x029e9c] [f85f07a9] 0x12029e9c: "stp x24, x23, [sp, #0x70]"
    [libyzwg.so 0x029ea0] [f65708a9] 0x12029ea0: "stp x22, x21, [sp, #0x80]"
    [libyzwg.so 0x029ea4] [f44f09a9] 0x12029ea4: "stp x20, x19, [sp, #0x90]"
    [libyzwg.so 0x029ea8] [fd7b0aa9] 0x12029ea8: "stp x29, x30, [sp, #0xa0]"
    [libyzwg.so 0x029eac] [48080051] 0x12029eac: "sub w8, w2, #2"
    [libyzwg.so 0x029eb0] [e27f0229] 0x12029eb0: "stp w2, wzr, [sp, #0x10]"
    [libyzwg.so 0x029eb4] [e80f00b9] 0x12029eb4: "str w8, [sp, #0xc]"
    [libyzwg.so 0x029eb8] [391d00f0] 0x12029eb8: "adrp x25, #0x123d0000"
    [libyzwg.so 0x029ebc] [3a1d00f0] 0x12029ebc: "adrp x26, #0x123d0000"
    [libyzwg.so 0x029ec0] [39db43f9] 0x12029ec0: "ldr x25, [x25, #0x7b0]"
    [libyzwg.so 0x029ec4] [5a6344f9] 0x12029ec4: "ldr x26, [x26, #0x8c0]"
    [libyzwg.so 0x029ec8] [ea03024b] 0x12029ec8: "neg w10, w2"
    [libyzwg.so 0x029ecc] [f00300aa] 0x12029ecc: "mov x16, x0"

mx0

>-----------------------------------------------------------------------------<
[18:18:49 893]x0=RW@0x1271e000, md5=c20019258ca235d2408334dfbc5e67e3, hex=00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
size: 112
0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
^-----------------------------------------------------------------------------^
mx1 0x28f

>-----------------------------------------------------------------------------<
[18:19:02 219]x1=RW@0x12719000, md5=e216af4d82acea61f6ec959b5dc2a25a, hex=cf0a7f3424d12534b08b70dec0c0e41c1e86bd4d810186f271ea89e38b3d0b1bb22fae63bf6d17695620d57a452cd55a17b2e894d26d6a7b8bafe01134cb77eaa2374453b7c5ef09c8366db7e4d055e87f4ceb5380dc3e2de16312cf21c74b49a23eeff6770a99865628dba2e263b810c04aa82a79e168ba2fc310c97d496ad92e0e5f4473881916a0e183b67548197443912f5c367d1e96f8859aeba75aa94e41064e398e0e1ba9f0717a5596b455cc6c3052e9ac50f8d2521a44d814f46ee6508313cb67f430ac21b7f946ce6d9bc3d1a75f3090c8607c2ebf5762f22a98c9a643c0c759589df0bb21309d24579db3c59dab838e03c5c6ff72355f610777939b9c6ff32062064b5492cce107e492d81f052dcc7d2e26dd3c8ab738bbab9ccd207739db3d9fb23a684ab761990ce1e81bbaf993331c9589fe76e26cca693b0569d0782a25261d0206304b082b4c5c946f1c35e690c2a7cdf4bb109b18dc1c1d24235f18b642045600f34b039b9e01ad3b28c9ae30306b9faeaf280ab37a1c5b205b44e027284c6b2d6f7e149d609067d0872be0d9c1f412ad9bbf0798b6288bef16a406e45abec9cc0429266152685026ebcbce5e6f77ac30874f1274e592557b1d847749681844213c1cdea46bf4afbe2bc3f57dba9d17077dd8642d05d318a976a8e536da797b930749cf00a55c2e6ebb22daf7e7f5239429ea72243f0f58077b39701e2cfdc4c228b30e4313886644b5e2ff6b3a426fa88501fda287b352c42568f34e3dc62a19803b92a030854d6a9db21238084d1e334d0ab0fe29e59e59bd5424fca0d42139189e4a3df4f3b47198eb37e82563fb64a93133d68e88b304b9e263b0256e13706913c87e10c080797a3fe045c591e2e284091a3610bdc2ca61530648212eb04d4350f3260107
size: 655
0000: CF 0A 7F 34 24 D1 25 34 B0 8B 70 DE C0 C0 E4 1C    ...4$.%4..p.....
0010: 1E 86 BD 4D 81 01 86 F2 71 EA 89 E3 8B 3D 0B 1B    ...M....q....=..
0020: B2 2F AE 63 BF 6D 17 69 56 20 D5 7A 45 2C D5 5A    ./.c.m.iV .zE,.Z
0030: 17 B2 E8 94 D2 6D 6A 7B 8B AF E0 11 34 CB 77 EA    .....mj{....4.w.
0040: A2 37 44 53 B7 C5 EF 09 C8 36 6D B7 E4 D0 55 E8    .7DS.....6m...U.
0050: 7F 4C EB 53 80 DC 3E 2D E1 63 12 CF 21 C7 4B 49    .L.S..>-.c..!.KI
0060: A2 3E EF F6 77 0A 99 86 56 28 DB A2 E2 63 B8 10    .>..w...V(...c..
0070: C0 4A A8 2A 79 E1 68 BA 2F C3 10 C9 7D 49 6A D9    .J.*y.h./...}Ij.
0080: 2E 0E 5F 44 73 88 19 16 A0 E1 83 B6 75 48 19 74    .._Ds.......uH.t
0090: 43 91 2F 5C 36 7D 1E 96 F8 85 9A EB A7 5A A9 4E    C./\6}.......Z.N
00A0: 41 06 4E 39 8E 0E 1B A9 F0 71 7A 55 96 B4 55 CC    A.N9.....qzU..U.
00B0: 6C 30 52 E9 AC 50 F8 D2 52 1A 44 D8 14 F4 6E E6    l0R..P..R.D...n.
00C0: 50 83 13 CB 67 F4 30 AC 21 B7 F9 46 CE 6D 9B C3    P...g.0.!..F.m..
00D0: D1 A7 5F 30 90 C8 60 7C 2E BF 57 62 F2 2A 98 C9    .._0..`|..Wb.*..
00E0: A6 43 C0 C7 59 58 9D F0 BB 21 30 9D 24 57 9D B3    .C..YX...!0.$W..
00F0: C5 9D AB 83 8E 03 C5 C6 FF 72 35 5F 61 07 77 93    .........r5_a.w.
0100: 9B 9C 6F F3 20 62 06 4B 54 92 CC E1 07 E4 92 D8    ..o. b.KT.......
0110: 1F 05 2D CC 7D 2E 26 DD 3C 8A B7 38 BB AB 9C CD    ..-.}.&.<..8....
0120: 20 77 39 DB 3D 9F B2 3A 68 4A B7 61 99 0C E1 E8     w9.=..:hJ.a....
0130: 1B BA F9 93 33 1C 95 89 FE 76 E2 6C CA 69 3B 05    ....3....v.l.i;.
0140: 69 D0 78 2A 25 26 1D 02 06 30 4B 08 2B 4C 5C 94    i.x*%&...0K.+L\.
0150: 6F 1C 35 E6 90 C2 A7 CD F4 BB 10 9B 18 DC 1C 1D    o.5.............
0160: 24 23 5F 18 B6 42 04 56 00 F3 4B 03 9B 9E 01 AD    $#_..B.V..K.....
0170: 3B 28 C9 AE 30 30 6B 9F AE AF 28 0A B3 7A 1C 5B    ;(..00k...(..z.[
0180: 20 5B 44 E0 27 28 4C 6B 2D 6F 7E 14 9D 60 90 67     [D.'(Lk-o~..`.g
0190: D0 87 2B E0 D9 C1 F4 12 AD 9B BF 07 98 B6 28 8B    ..+...........(.
01A0: EF 16 A4 06 E4 5A BE C9 CC 04 29 26 61 52 68 50    .....Z....)&aRhP
01B0: 26 EB CB CE 5E 6F 77 AC 30 87 4F 12 74 E5 92 55    &...^ow.0.O.t..U
01C0: 7B 1D 84 77 49 68 18 44 21 3C 1C DE A4 6B F4 AF    {..wIh.D!<...k..
01D0: BE 2B C3 F5 7D BA 9D 17 07 7D D8 64 2D 05 D3 18    .+..}....}.d-...
01E0: A9 76 A8 E5 36 DA 79 7B 93 07 49 CF 00 A5 5C 2E    .v..6.y{..I...\.
01F0: 6E BB 22 DA F7 E7 F5 23 94 29 EA 72 24 3F 0F 58    n."....#.).r$?.X
0200: 07 7B 39 70 1E 2C FD C4 C2 28 B3 0E 43 13 88 66    .{9p.,...(..C..f
0210: 44 B5 E2 FF 6B 3A 42 6F A8 85 01 FD A2 87 B3 52    D...k:Bo.......R
0220: C4 25 68 F3 4E 3D C6 2A 19 80 3B 92 A0 30 85 4D    .%h.N=.*..;..0.M
0230: 6A 9D B2 12 38 08 4D 1E 33 4D 0A B0 FE 29 E5 9E    j...8.M.3M...)..
0240: 59 BD 54 24 FC A0 D4 21 39 18 9E 4A 3D F4 F3 B4    Y.T$...!9..J=...
0250: 71 98 EB 37 E8 25 63 FB 64 A9 31 33 D6 8E 88 B3    q..7.%c.d.13....
0260: 04 B9 E2 63 B0 25 6E 13 70 69 13 C8 7E 10 C0 80    ...c.%n.pi..~...
0270: 79 7A 3F E0 45 C5 91 E2 E2 84 09 1A 36 10 BD C2    yz?.E.......6...
0280: CA 61 53 06 48 21 2E B0 4D 43 50 F3 26 01 07       .aS.H!..MCP.&..
^-----------------------------------------------------------------------------^

x0 就是缓冲区,用于存放结果的地方,x1 应该就是明文数据,x2 是明文的长度,去 cyberchef 里面验证一下:

确实能够得到结果,但是貌似跟我们 unidbg 模拟出来的结果不太一样啊

感觉是码表改变了,但是我确实在 sub_29E90 这个函数中发现的就是标准的 base64 编码的字符串啊,那是为什么,或许是不是它是将编码进行替换是在其他函数中
继续运行 sub_29E90 这个函数

发现他确实是标准的 base64 编码,那么很有可能就是在 sub_1CEB8 子函数中做了处理
进去 sub_1CEB8 发现它做了一些单字节的替换
总之,结合上面文本比对的情况,可以推断出:

1
2
3
/ ==> _
+ ==> -
= ==> ~

也就是说,我可以将码表进行替换能达到同样的效果:
码表就可以替换成 A-Za-z0-9-_~,接着,就需要知道 base64 编码中的明文是什么了,这就需要向上进行追溯

发现 sub_2E91C 在对这个参数进行操作,hook 一下这个地址,看一下它做了哪些操作

1
emulator.attach().addBreakPoint(module.base+0x2E91C);

第一个参数

第二个参数,第三个参数(这两个参数是一样的)

第四个参数是长度,接着我看一下返回值是啥
这个也确实是 base64 编码的明文数据,所以说这个地方是对的,需要分析一下这个函数干了什么
跟进 sub_2E91C ,发现有点像 rc4 算法,先来看一下标准的 rc4 算法缓缓:

1
2
3
4
5
6
7
def _prga(self):
	"""伪随机生成算法(生成一个字节)"""
	self.i = (self.i + 1) % 256
	self.j = (self.j + self.S[self.i]) % 256
	self.S[self.i], self.S[self.j] = self.S[self.j], self.S[self.i]
	t = (self.S[self.i] + self.S[self.j]) % 256
	return self.S[t]

去源码看到的对应关系如下:
反正有极大概率可以推断出这个就是一个 rc4 的加密算法,rc4 算法,加密/解密是一样的,可能返回值解密的话也会走这个逻辑说不定
既然知道了这个一个 rc4 算法,就需要去找 S 盒和密钥,S 盒不知道有没有魔改,或者说是如何进行魔改的,回到函数外
sub_2E680 这个函数也会处理 S 盒,也许它就是 S 盒的初始化函数,那另外一个 s 这个参数呢?密钥一般是跟 S 盒一起的,v53 应该就是密钥的长度,姑且就论 S 盒没有魔改,s 就是密钥,v53 就是密钥的长度,后面去验证一下就知道了
我去,这个不就是之前 sig 这个参数 md5 的盐值吗?这能一样吗?验证一下就知道了

没毛病,就是这个,好的,还需要继续找这个明文是从哪儿来的,找 text 的交叉引用

来到 sub_1D444 这个子函数,v47 不知道是个啥,这里的 text 才分配内存,进去应该啥都没有,是缓冲区,用于存放结果,v49 应该就是这个明文的长度,size 不知道是啥,目前先猜测这些东西

1
emulator.attach().addBreakPoint(module.base+0x1D444);

先看一下第一个参数,是明文

第二个参数确实是缓冲区,用于存放结果

第三个参数是明文的长度
第四个参数未知,它也是一个长度值,但是不知道是什么的长度,加密之后结果的长度?这个还需要去进行验证才知道
继续往上面看

size 是经过 LZ4_compressBound 方法,将 v49 也就是明文的长度传进去,这个是做了什么事情啊,而且 LZ4_compressBound 看起来像个压缩算法,这个算法是什么啊,没见过,可以问下 ai,去查一下

所以说这个函数就是给压缩后的数据分配空间的,进去看一下它是什么逻辑
说白了,也就是给明文扩展长度,用于压缩后的数据,既然知道了它的用途,接下来就应该去 sub_1D444 这个子函数中分析一下,但是暂时先按下不表,先看一下标准的 lz4 压缩算法,跟这个 app 得到的压缩算法生成的有什么不同

发现 app 魔改了头部的 24 个字节的数据,其实后面是一样的,如果时间充足的话可以慢慢比对,我目测是一样的
也就是说 sub_1D444 这个子函数魔改了头部的 24 个字节的数据,接下来可以去看看这个子函数的逻辑了

那现在唯一的问题就是需要去看一下 LZ4_compress_limitedOutput 这个函数干了什么,进去之后就变成了 LZ4_compress_fast 这个函数
但是也不是说非要进去看是什么逻辑,我已经猜了是压缩处理后数据的长度,那么我只需要验证就可以了啊

hook 之后,发现是 0x277,转换成十进制就是 631,总的压缩长度是 655,减去单独处理的 24 个字节,剩下的刚好就是 631,即 0x277,所以,sp 所有的逻辑就全都分析完了
下面来总结一下:

  • 明文数据通过魔改的 lz4(魔改了头部的 24 个字节),得到压缩后的数据
  • 将压缩后的数据经过 rc4 加密,密钥是上面 sig 参数,md5 算法的盐值,得到加密后的数据
  • 在将加密后的数据进行 base64 编码(码表是进行魔改的),通过这样编码之后就得到了最终的 sp 参数的数据

返回值解密

返回值在打印数据之前调用的 JNI 函数是 GetByteArrayElements,这个函数好像不能像 NewStringUTF 一样对结果进行定位

但是之前好像 trace 了一份日志还没用啊,在日志里面搜肯定搜不到中文的字符串,只能搜到 16 进制的一些东西,改一下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
>-----------------------------------------------------------------------------<
[11:49:51 464]解密结果, md5=8f22bf8315b3a293b593bc54c3f72d79, hex=7b22636f6465223a343030302c226d657373616765223a22e794b1e4ba8ee682a8e79a84e8b4a6e58fb7e6b689e5ab8ce8bf9de8a784e6938de4bd9cefbc8ce5bd93e5898de8aebee5a487e69a82e4b88de694afe68c81e4bdbfe794a8e38082e5a682e69c89e79691e997aeefbc8ce8afb7e68ba8e68993203430302d3036352d35373939222c227a7044617461223a7b7d7d
size: 147
0000: 7B 22 63 6F 64 65 22 3A 34 30 30 30 2C 22 6D 65    {"code":4000,"me
0010: 73 73 61 67 65 22 3A 22 E7 94 B1 E4 BA 8E E6 82    ssage":"........
0020: A8 E7 9A 84 E8 B4 A6 E5 8F B7 E6 B6 89 E5 AB 8C    ................
0030: E8 BF 9D E8 A7 84 E6 93 8D E4 BD 9C EF BC 8C E5    ................
0040: BD 93 E5 89 8D E8 AE BE E5 A4 87 E6 9A 82 E4 B8    ................
0050: 8D E6 94 AF E6 8C 81 E4 BD BF E7 94 A8 E3 80 82    ................
0060: E5 A6 82 E6 9C 89 E7 96 91 E9 97 AE EF BC 8C E8    ................
0070: AF B7 E6 8B A8 E6 89 93 20 34 30 30 2D 30 36 35    ........ 400-065
0080: 2D 35 37 39 39 22 2C 22 7A 70 44 61 74 61 22 3A    -5799","zpData":
0090: 7B 7D 7D                                           {}}
^-----------------------------------------------------------------------------^
解密结果: {"code":4000,"message":"由于您的账号涉嫌违规操作,当前设备暂不支持使用。如有疑问,请拨打 400-065-5799","zpData":{}}

但是上面的结果包含了 sp 和 sig 的逻辑,这个很不方便我查找,需要把 get_sig 和 get_sp 的代码逻辑个给注释掉,重新 trace 一份日志,直接搜索字符串,很快就能够定位到相关位置:

跳转到 0x02e9bc

就到这儿了,回忆一下,这个就是之前的 rc4 算法的加密分析过的啊

可以解密一下: 应该算是完成了吧