首页
社区
课程
招聘
68
[分享]某内容分享平台最新shield字段分析
发表于: 2025-3-9 17:08 5502

[分享]某内容分享平台最新shield字段分析

2025-3-9 17:08
5502

协议抓包

先看下协议
图片描述

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
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
@Override
public DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {
    switch (signature) {
        case "com/xingin/shield/http/ContextHolder->sLogger:Lcom/xingin/shield/http/ShieldLogger;":
            return vm.resolveClass("com/xingin/shield/http/ShieldLogger").newObject(null);
        case "com/xingin/shield/http/ContextHolder->sDeviceId:Ljava/lang/String;":
            return new StringObject(vm, "0d7eee2c-5d77-3c26-99f8-a5a2c9e08aeb");
    }
    //throw new UnsupportedOperationException(signature);
    return super.getStaticObjectField(vm,dvmClass,signature);
}
  
@Override
public void callVoidMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
    switch (signature) {
        case "com/xingin/shield/http/ShieldLogger->nativeInitializeStart()V":
            return;
        case "com/xingin/shield/http/ShieldLogger->nativeInitializeEnd()V":
            return;
        case "com/xingin/shield/http/ShieldLogger->buildSourceStart()V":
            return;
        case "com/xingin/shield/http/ShieldLogger->buildSourceEnd()V":
            return;
        case "com/xingin/shield/http/ShieldLogger->initializeStart()V":
            return;
        case "com/xingin/shield/http/ShieldLogger->initializedEnd()V":
            return;
        case "com/xingin/shield/http/ShieldLogger->calculateStart()V":
            return;
        case "com/xingin/shield/http/ShieldLogger->calculateEnd()V":
            return;
        case "okhttp3/RequestBody->writeTo(Lokio/BufferedSink;)V":
            BufferedSink bufferedSink = (BufferedSink) vaList.getObjectArg(0).getValue();
            RequestBody requestBody = (RequestBody) dvmObject.getValue();
            if (requestBody != null) {
                try {
                    requestBody.writeTo(bufferedSink);
                } catch (IOException e) {
                    System.out.println(e);
                }
            }
            return;
    }
    super.callVoidMethodV(vm,dvmObject,signature,vaList);
}
  
@Override
public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
    switch (signature) {
        case "java/nio/charset/Charset->defaultCharset()Ljava/nio/charset/Charset;":
            return vm.resolveClass("java/nio/charset/Charset").newObject(Charset.defaultCharset());
        case "com/xingin/shield/http/Base64Helper->decode(Ljava/lang/String;)[B":
            String input = vaList.getObjectArg(0).getValue().toString();
            return new ByteArray(vm, Base64.decodeBase64(input));
    }
    //throw new UnsupportedOperationException(signature);
 return super.callStaticObjectMethodV(vm, dvmClass, signature, vaList);
}
  
@Override
public int callIntMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
    if (signature.equals("okhttp3/Headers->size()I")) {
        Headers headers = (Headers) dvmObject.getValue();
        return headers.size();
    }
    if (signature.equals("okio/Buffer->read([B)I")) {
        Buffer buffer = (Buffer) dvmObject.getValue();
        return buffer.read((byte[]) vaList.getObjectArg(0).getValue());
    }
    if (signature.equals("okhttp3/Response->code()I")) {
        return 200;
    }
    return super.callIntMethodV(vm, dvmObject, signature, vaList);
}
  
@Override
public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
    switch (signature) {
        case "okhttp3/Interceptor$Chain->request()Lokhttp3/Request;":
            return vm.resolveClass("okhttp3/Request").newObject(request);
        case "okhttp3/Request->url()Lokhttp3/HttpUrl;":
            return vm.resolveClass("okhttp3/HttpUrl").newObject(request.url());
        case "okhttp3/HttpUrl->encodedPath()Ljava/lang/String;":
            return new StringObject(vm, request.url().encodedPath());
        case "okhttp3/HttpUrl->encodedQuery()Ljava/lang/String;":
            if (request.url().encodedQuery() != null) {
                return new StringObject(vm, request.url().encodedQuery());
            }
            return new StringObject(vm, "");
        case "okhttp3/Request->body()Lokhttp3/RequestBody;":
            return vm.resolveClass("okhttp3/RequestBody").newObject(request.body());
        case "okhttp3/Request->headers()Lokhttp3/Headers;":
            return vm.resolveClass("okhttp3/Headers").newObject(request.headers());
        case "okio/Buffer->writeString(Ljava/lang/String;Ljava/nio/charset/Charset;)Lokio/Buffer;":
            Buffer buffer = (Buffer) dvmObject.getValue();
            buffer.writeString(vaList.getObjectArg(0).getValue().toString(), (Charset) vaList.getObjectArg(1).getValue());
            // return dvmObject;
            return ProxyDvmObject.createObject(vm,buffer);
        case "okio/Buffer->clone()Lokio/Buffer;":
            Buffer bufferc = (Buffer) dvmObject.getValue();
            return vm.resolveClass("okio/Buffer").newObject(bufferc.clone());
        case "okhttp3/Headers->name(I)Ljava/lang/String;":
            Headers headers = (Headers) dvmObject.getValue();
            return new StringObject(vm, headers.name(vaList.getIntArg(0)));
        case "okhttp3/Headers->value(I)Ljava/lang/String;":
            Headers headersValue = (Headers) dvmObject.getValue();
            return new StringObject(vm, headersValue.value(vaList.getIntArg(0)));
        case "okhttp3/Request$Builder->header(Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Request$Builder;":
            okhttp3.Request.Builder builder = (okhttp3.Request.Builder)dvmObject.getValue();
            String para1 = (String)vaList.getObjectArg(0).getValue();
            String para2 = (String)vaList.getObjectArg(1).getValue();
            return vm.resolveClass("okhttp3/Request$Builder").newObject(builder.header(para1, para2));
        case "android/content/Context->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;":
            String xmlName =  vaList.getObjectArg(0).getValue().toString();
            System.out.println("xmlName : " + xmlName);
            return vm.resolveClass("android.content.SharedPreferences")
                    .newObject(null); //.newObject(vaList.getObjectArg(0).getValue().toString());
        case "android/content/SharedPreferences->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;":
            String key = vaList.getObjectArg(0).getValue().toString();
            System.out.println("get key:"+key);
            switch (key){
                case "main":{
                    return new StringObject(vm, "");
                }
                case "main_hmac":{
                    return new StringObject(vm, "2s/EPZ9Xnk4cCZd5weXEd0DqcudY1yJwoQRV2cESN9+9HEVLiu6C72X5YfPYhiESrmuWLXe9U1BGSCIq7/DiMEWjsKmdlUEEbJGkmfTMN7xRJvuw2uqNpAewis/HKAQk");
                }
            }
        case "okhttp3/Request->newBuilder()Lokhttp3/Request$Builder;":
            Request request = (Request) dvmObject.getValue();
            return vm.resolveClass("okhttp3/Request$Builder").newObject(request.newBuilder());
        case "okhttp3/Request$Builder->build()Lokhttp3/Request;":
            Request.Builder builderr = (Request.Builder) dvmObject.getValue();
            Request requestr = builderr.build();
            return vm.resolveClass("okhttp3/Request").newObject(requestr);
        case "okhttp3/Interceptor$Chain->proceed(Lokhttp3/Request;)Lokhttp3/Response;": {
            return vm.resolveClass("okhttp3/Response").newObject(null);
        }
    }
    return super.callObjectMethodV(vm, dvmObject, signature, vaList);
}
 
@Override
public int getStaticIntField(BaseVM vm, DvmClass dvmClass, String signature) {
    switch (signature){
        case"com/xingin/shield/http/ContextHolder->sAppId:I":{
            return -319115519;
        }
    }
    return super.getStaticIntField(vm, dvmClass, signature);
}
  
@Override
public DvmObject<?> newObjectV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
    switch (signature){
        case "okio/Buffer-><init>()V":
            return dvmClass.newObject(new Buffer());
    }
    return super.newObjectV(vm, dvmClass, signature, vaList);
}
  
public void call_initializeNative() {
    List<Object> params = new ArrayList<>();
    params.add(vm.getJNIEnv());
    params.add(0);
    Number number = module.callFunction(emulator, 0xbd8bc, params.toArray());
}
  
public long call_initialize() {
    List<Object> params = new ArrayList<>();
    params.add(vm.getJNIEnv());
    params.add(0);
    params.add(vm.addLocalObject(new StringObject(vm,"main")));
    Number number = module.callFunction(emulator, 0xbc3c8, params.toArray());
    return number.longValue();
}
  
public void call_intercept(long cPtr) {
    List<Object> params = new ArrayList<>();
    params.add(vm.getJNIEnv());
    params.add(0);
  
    DvmObject<?> chain = vm.resolveClass("okhttp3/Interceptor$Chain").newObject(null);
    params.add(vm.addLocalObject(chain));
    params.add(cPtr);
    Number number = module.callFunction(emulator, 0xbc6b4, params.toArray());
    Object result = vm.getObject(number.intValue()).getValue();
}
  
public static void main(String[] args) {
    request = new Request.Builder()
            .url("https://edith.xiaohongshu.com/api/sns/v6/message/detect")
            .addHeader("xy-direction", "49")
            .addHeader("xy-common-params","fid=1722182473106fc84899565e2acf00656ae05a78764b&device_fingerprint=2023122411004376bd379fe6f54e6dc5ca0b0cf8d24dd601dc85661f97571b&device_fingerprint1=2023122411004376bd379fe6f54e6dc5ca0b0cf8d24dd601dc85661f97571b&cpu_name=Qualcomm+Technologies%2C+Inc+SDM845&gid=7c7ea0a5b61c5590cec3770efa9cfec6e81b439947359eeb775b6fc4&device_model=phone&launch_id=1722617914&tz=Asia%2FShanghai&channel=Guanfang&versionName=8.42.0&overseas_channel=0&deviceId=0d7eee2c-5d77-3c26-99f8-a5a2c9e08aeb&platform=android&sid=session.1722182426050852896201&identifier_flag=4&t=1722617846&project_id=ECFAAF&build=8420294&x_trace_page_current=&lang=zh-Hans&app_id=ECFAAF01&uis=light&teenager=0")
            .build();
    fuckxhs fkxhs = new fuckxhs();
    fkxhs.call_initializeNative();
    long cPtr = fkxhs.call_initialize();
    fkxhs.call_intercept(cPtr);
}

运行起来后

1
2
3
4
5
6
7
8
9
10
11
JNIEnv->CallIntMethodV(okio.Buffer@5622fdf, read([B@7d9d1a19) => 0x302) was called from RX@0x40013d54[libshield.so]0x13d54
JNIEnv->GetByteArrayElements(false) => [B@7d9d1a19 was called from RX@0x40016048[libshield.so]0x16048
JNIEnv->CallIntMethodV(okio.Buffer@5622fdf, read([B@39c0f4a) => 0xffffffff) was called from RX@0x40013d54[libshield.so]0x13d54
JNIEnv->NewStringUTF("XYAAAAAQAAAAEAAABTAAAAUzUWEe0xG1IbD9/c+qCLOlKGmTtFa+lG434KfuFUTalCkYPly+NlH539q+dYz8N53st+2KtkGAwfFDSKN7Kh3CMx07Yvb5gnynhyIN/gbMnm9OPb") was called from RX@0x400bcf2c[libshield.so]0xbcf2c
JNIEnv->CallVoidMethodV(com.xingin.shield.http.ShieldLogger@5315b42e, calculateEnd()) was called from RX@0x40014354[libshield.so]0x14354
JNIEnv->CallObjectMethodV(okhttp3.Request@2b98378d, newBuilder() => okhttp3.Request$Builder@42e26948) was called from RX@0x40013bf4[libshield.so]0x13bf4
JNIEnv->CallObjectMethodV(okhttp3.Request$Builder@42e26948, header("shield", "XYAAAAAQAAAAEAAABTAAAAUzUWEe0xG1IbD9/c+qCLOlKGmTtFa+lG434KfuFUTalCkYPly+NlH539q+dYz8N53st+2KtkGAwfFDSKN7Kh3CMx07Yvb5gnynhyIN/gbMnm9OPb") => okhttp3.Request$Builder@57baeedf) was called from RX@0x40013bf4[libshield.so]0x13bf4
JNIEnv->CallObjectMethodV(okhttp3.Request$Builder@42e26948, header("xy-platform-info", "platform=android&build=8420294&deviceId=0d7eee2c-5d77-3c26-99f8-a5a2c9e08aeb") => okhttp3.Request$Builder@343f4d3d) was called from RX@0x40013bf4[libshield.so]0x13bf4
JNIEnv->CallObjectMethodV(okhttp3.Request$Builder@42e26948, build() => okhttp3.Request@53b32d7) was called from RX@0x40013bf4[libshield.so]0x13bf4
JNIEnv->CallObjectMethodV(okhttp3.Interceptor$Chain@4b9e13df, proceed(okhttp3.Request@53b32d7) => okhttp3.Response@5442a311) was called from RX@0x40013bf4[libshield.so]0x13bf4
JNIEnv->CallIntMethodV(okhttp3.Response@5442a311, code() => 0xc8) was called from RX@0x40013d54[libshield.so]0x13d54

从日志可以看出shield字段,我们挑最上面的“JNIEnv->NewStringUTF”的执行地址0xbcf2c开始定位debugger.addBreakPoint(module.base + 0xbcf2c)
图片描述
继续emulator.traceWrite(0x40461018,0x40461018+134)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[23:37:28 675] Memory WRITE at 0x4046101a, data size = 8, data value = 0x4141514141414141, PC=RX@0x4028c1f8[libc.so]0x1c1f8, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 675] Memory WRITE at 0x40461022, data size = 8, data value = 0x5442414141454141, PC=RX@0x4028c1f8[libc.so]0x1c1f8, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 675] Memory WRITE at 0x40461022, data size = 8, data value = 0x5442414141454141, PC=RX@0x4028c220[libc.so]0x1c220, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 675] Memory WRITE at 0x4046102a, data size = 8, data value = 0x57557a5541414141, PC=RX@0x4028c220[libc.so]0x1c220, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 675] Memory WRITE at 0x40461032, data size = 8, data value = 0x6249314778306545, PC=RX@0x4028c224[libc.so]0x1c224, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 675] Memory WRITE at 0x4046103a, data size = 8, data value = 0x4c43712b632f3944, PC=RX@0x4028c224[libc.so]0x1c224, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 675] Memory WRITE at 0x40461042, data size = 8, data value = 0x4674546d474b6c4f, PC=RX@0x4028c228[libc.so]0x1c228, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 675] Memory WRITE at 0x4046104a, data size = 8, data value = 0x4b343334476c2b61, PC=RX@0x4028c228[libc.so]0x1c228, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 676] Memory WRITE at 0x40461052, data size = 8, data value = 0x436c615455467566, PC=RX@0x4028c22c[libc.so]0x1c22c, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 676] Memory WRITE at 0x4046105a, data size = 8, data value = 0x6c4e2b796c50596b, PC=RX@0x4028c22c[libc.so]0x1c22c, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 676] Memory WRITE at 0x40461062, data size = 8, data value = 0x59642b7139333548, PC=RX@0x4028c17c[libc.so]0x1c17c, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 676] Memory WRITE at 0x4046106a, data size = 8, data value = 0x2b747333354e387a, PC=RX@0x4028c17c[libc.so]0x1c17c, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 676] Memory WRITE at 0x40461072, data size = 8, data value = 0x667741476b744b32, PC=RX@0x4028c184[libc.so]0x1c184, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 676] Memory WRITE at 0x4046107a, data size = 8, data value = 0x684b374e4b534446, PC=RX@0x4028c184[libc.so]0x1c184, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 676] Memory WRITE at 0x40461082, data size = 8, data value = 0x76593730784d4333, PC=RX@0x4028c18c[libc.so]0x1c18c, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 676] Memory WRITE at 0x4046108a, data size = 8, data value = 0x79686e796e673562, PC=RX@0x4028c18c[libc.so]0x1c18c, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 676] Memory WRITE at 0x4046108e, data size = 8, data value = 0x672f4e4979686e79, PC=RX@0x4028c1a4[libc.so]0x1c1a4, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 676] Memory WRITE at 0x40461096, data size = 8, data value = 0x62504f396d6e4d62, PC=RX@0x4028c1a4[libc.so]0x1c1a4, LR=RX@0x4009f0f0[libshield.so]0x9f0f0
[23:37:28 676] Memory WRITE at 0x4046109e, data size = 1, data value = 0x00, PC=RX@0x4009f038[libshield.so]0x9f038, LR=RX@0x4009f120[libshield.so]0x9f120
[23:37:28 676] Memory WRITE at 0x40461018, data size = 2, data value = 0x5958, PC=RX@0x4028c1cc[libc.so]0x1c1cc, LR=RX@0x4009f78c[libshield.so]0x9f78c

根据地址定位到
图片描述
在此处下断点多调试几次,不难发现应该是memcpy函数
debugger.addBreakPoint(module.base+0x9f0e8)
图片描述
找到地址后继续trace一下emulator.traceWrite(0x4059a018,0x4059a018+134)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[09:38:33 900] Memory WRITE at 0x4059a09d, data size = 1, data value = 0x00, PC=RX@0x4009d04c[libshield.so]0x9d04c, LR=RX@0x4009d030[libshield.so]0x9d030
[09:38:33 900] Memory WRITE at 0x4059a018, data size = 1, data value = 0x41, PC=RX@0x4004bfac[libshield.so]0x4bfac, LR=RX@0x40049b98[libshield.so]0x49b98
[09:38:33 900] Memory WRITE at 0x4059a01b, data size = 1, data value = 0x41, PC=RX@0x4004bfc4[libshield.so]0x4bfc4, LR=RX@0x40049b98[libshield.so]0x49b98
[09:38:33 900] Memory WRITE at 0x4059a019, data size = 1, data value = 0x41, PC=RX@0x4004bfc8[libshield.so]0x4bfc8, LR=RX@0x40049b98[libshield.so]0x49b98
[09:38:33 900] Memory WRITE at 0x4059a01a, data size = 1, data value = 0x41, PC=RX@0x4004bfcc[libshield.so]0x4bfcc, LR=RX@0x40049b98[libshield.so]0x49b98
[09:38:33 900] Memory WRITE at 0x4059a01c, data size = 1, data value = 0x41, PC=RX@0x4004bfac[libshield.so]0x4bfac, LR=RX@0x40049b98[libshield.so]0x49b98
[09:38:33 901] Memory WRITE at 0x4059a01f, data size = 1, data value = 0x41, PC=RX@0x4004bfc4[libshield.so]0x4bfc4, LR=RX@0x40049b98[libshield.so]0x49b98
[09:38:33 901] Memory WRITE at 0x4059a01d, data size = 1, data value = 0x51, PC=RX@0x4004bfc8[libshield.so]0x4bfc8, LR=RX@0x40049b98[libshield.so]0x49b98
...
[09:38:33 905] Memory WRITE at 0x4059a096, data size = 1, data value = 0x6e, PC=RX@0x4004bfcc[libshield.so]0x4bfcc, LR=RX@0x40049b98[libshield.so]0x49b98
[09:38:33 905] Memory WRITE at 0x4059a098, data size = 1, data value = 0x39, PC=RX@0x4004bfac[libshield.so]0x4bfac, LR=RX@0x40049b98[libshield.so]0x49b98
[09:38:33 905] Memory WRITE at 0x4059a09b, data size = 1, data value = 0x62, PC=RX@0x4004bfc4[libshield.so]0x4bfc4, LR=RX@0x40049b98[libshield.so]0x49b98
[09:38:33 905] Memory WRITE at 0x4059a099, data size = 1, data value = 0x4f, PC=RX@0x4004bfc8[libshield.so]0x4bfc8, LR=RX@0x40049b98[libshield.so]0x49b98
[09:38:33 905] Memory WRITE at 0x4059a09a, data size = 1, data value = 0x50, PC=RX@0x4004bfcc[libshield.so]0x4bfcc, LR=RX@0x40049b98[libshield.so]0x49b98
[09:38:33 906] Memory WRITE at 0x4059a09c, data size = 1, data value = 0x00, PC=RX@0x4004c080[libshield.so]0x4c080, LR=RX@0x40049b98[libshield.so]0x49b98
[09:38:33 906] Memory WRITE at 0x4059a09c, data size = 1, data value = 0x00, PC=RX@0x4009f038[libshield.so]0x9f038, LR=RX@0x40049bbc[libshield.so]0x49bbc

根据调用地址0x4bfac定位到函数sub_4BF44
图片描述
打断点看下表debugger.addBreakPoint(module.base + 0x4bfb0)
图片描述
标准的base64表,拿到网站换算一下
图片描述
能正确转换,继续往上分析下sub_4BF44的入参
图片描述
断点看一下入参情况 debugger.addBreakPoint(module.base + 0x49b94)
图片描述
继续emulator.traceWrite(0x40456098,0x40456098 + 99)分析下会发现也是memcpy,找到源地址后emulator.traceWrite(0x40593000,0x40593000 + 99)

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
[08:42:02 756] Memory WRITE at 0x40593000, data size = 1, data value = 0x00, PC=RX@0x4004972c[libshield.so]0x4972c, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x40593001, data size = 1, data value = 0x00, PC=RX@0x40049734[libshield.so]0x49734, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x40593002, data size = 1, data value = 0x00, PC=RX@0x40049740[libshield.so]0x49740, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x40593003, data size = 1, data value = 0x01, PC=RX@0x40049748[libshield.so]0x49748, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x40593004, data size = 1, data value = 0x00, PC=RX@0x40049750[libshield.so]0x49750, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x40593005, data size = 1, data value = 0x00, PC=RX@0x40049758[libshield.so]0x49758, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x40593006, data size = 1, data value = 0x00, PC=RX@0x40049764[libshield.so]0x49764, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x40593007, data size = 1, data value = 0x01, PC=RX@0x4004976c[libshield.so]0x4976c, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x40593008, data size = 1, data value = 0x00, PC=RX@0x40049774[libshield.so]0x49774, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x40593009, data size = 1, data value = 0x00, PC=RX@0x4004977c[libshield.so]0x4977c, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x4059300a, data size = 1, data value = 0x00, PC=RX@0x40049788[libshield.so]0x49788, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x4059300b, data size = 1, data value = 0x53, PC=RX@0x40049790[libshield.so]0x49790, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x4059300c, data size = 1, data value = 0x00, PC=RX@0x40049798[libshield.so]0x49798, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x4059300d, data size = 1, data value = 0x00, PC=RX@0x400497a0[libshield.so]0x497a0, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 756] Memory WRITE at 0x4059300e, data size = 1, data value = 0x00, PC=RX@0x400497ac[libshield.so]0x497ac, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 757] Memory WRITE at 0x4059300f, data size = 1, data value = 0x53, PC=RX@0x400497b4[libshield.so]0x497b4, LR=RX@0x400496e4[libshield.so]0x496e4
[08:42:02 757] Memory WRITE at 0x40593010, data size = 8, data value = 0x1b521b31ed111635, PC=RX@0x4028c220[libc.so]0x1c220, LR=RX@0x400497dc[libshield.so]0x497dc
[08:42:02 757] Memory WRITE at 0x40593018, data size = 8, data value = 0x523a8ba0fadcdf0f, PC=RX@0x4028c220[libc.so]0x1c220, LR=RX@0x400497dc[libshield.so]0x497dc
[08:42:02 757] Memory WRITE at 0x40593020, data size = 8, data value = 0xe346e96b453b9986, PC=RX@0x4028c224[libc.so]0x1c224, LR=RX@0x400497dc[libshield.so]0x497dc
[08:42:02 757] Memory WRITE at 0x40593028, data size = 8, data value = 0x42a94d54e17e0a7e, PC=RX@0x4028c224[libc.so]0x1c224, LR=RX@0x400497dc[libshield.so]0x497dc
[08:42:02 757] Memory WRITE at 0x40593030, data size = 8, data value = 0x9d1f65e3cbe58391, PC=RX@0x4028c228[libc.so]0x1c228, LR=RX@0x400497dc[libshield.so]0x497dc
[08:42:02 757] Memory WRITE at 0x40593038, data size = 8, data value = 0xde79c3cf58e7abfd, PC=RX@0x4028c228[libc.so]0x1c228, LR=RX@0x400497dc[libshield.so]0x497dc
[08:42:02 757] Memory WRITE at 0x40593040, data size = 8, data value = 0x1f0c1864abd87ecb, PC=RX@0x4028c22c[libc.so]0x1c22c, LR=RX@0x400497dc[libshield.so]0x497dc
[08:42:02 757] Memory WRITE at 0x40593048, data size = 8, data value = 0x23dca1b2378a3414, PC=RX@0x4028c22c[libc.so]0x1c22c, LR=RX@0x400497dc[libshield.so]0x497dc
[08:42:02 757] Memory WRITE at 0x40593050, data size = 8, data value = 0xca27986f2fb6d331, PC=RX@0x4028c18c[libc.so]0x1c18c, LR=RX@0x400497dc[libshield.so]0x497dc
[08:42:02 757] Memory WRITE at 0x40593058, data size = 8, data value = 0xe6c96ce0df207278, PC=RX@0x4028c18c[libc.so]0x1c18c, LR=RX@0x400497dc[libshield.so]0x497dc
[08:42:02 757] Memory WRITE at 0x40593053, data size = 8, data value = 0x207278ca27986f2f, PC=RX@0x4028c1a4[libc.so]0x1c1a4, LR=RX@0x400497dc[libshield.so]0x497dc
[08:42:02 757] Memory WRITE at 0x4059305b, data size = 8, data value = 0xdbe3f4e6c96ce0df, PC=RX@0x4028c1a4[libc.so]0x1c1a4, LR=RX@0x400497dc[libshield.so]0x497dc

可以明显看到数据分为两部分,先看第一部分

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
void __usercall sub_49650(__int64 *a1@<X0>, __int64 a2@<X8>)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
 
  v42 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
  v4 = *a1;
  v3 = (unsigned int *)a1[1];
  if ( v3 )
  {
    v5 = v3 + 2;
    if ( pthread_create_ptr )
    {
      do
        v6 = __ldaxr(v5);
      while ( __stlxr(v6 + 1, v5) );
    }
    else
    {
      ++*v5;
    }
  }
  v7 = *(_DWORD *)(v4 + 16);
  v8 = (int)(v7 + 16);
  if ( v8 < 0 )
    v9 = -1LL;
  else
    v9 = (int)(v7 + 16);
  v10 = (_BYTE *)sub_12490(v9);
  sub_129A0(v10, 0LL, v9);
  if ( v3 )
  {
    v11 = v3 + 2;
    if ( pthread_create_ptr )
    {
      do
        v12 = __ldaxr(v11);
      while ( __stlxr(v12 + 1, v11) );
    }
    else
    {
      ++*v11;
    }
  }
  if ( v7 <= 0xFFFFFFEF )
  {
    *v10 = *(_BYTE *)(v4 + 11); //赋值位置
    v10[1] = *(_WORD *)(v4 + 10);
    v10[2] = BYTE1(*(_DWORD *)(v4 + 8));
    v10[3] = *(_DWORD *)(v4 + 8);
    v10[4] = *(_BYTE *)(v4 + 15);
    v10[5] = *(_WORD *)(v4 + 14);
    v10[6] = BYTE1(*(_DWORD *)(v4 + 12));
    v10[7] = *(_DWORD *)(v4 + 12);
    v10[8] = *(_BYTE *)(v4 + 19);
    v10[9] = *(_WORD *)(v4 + 18);
    v10[10] = BYTE1(*(_DWORD *)(v4 + 16));
    v10[11] = *(_DWORD *)(v4 + 16);
    v10[12] = *(_BYTE *)(v4 + 23);
    v10[13] = *(_WORD *)(v4 + 22);
    v10[14] = BYTE1(*(_DWORD *)(v4 + 20));
    v10[15] = *(_DWORD *)(v4 + 20);
    if ( *(_DWORD *)(v4 + 16) + 16 <= (unsigned int)v8 )
...

可以很明显看到是a1中获取数据进行填充的,打断点看一下debugger.addBreakPoint(module.base+0x49650)
图片描述
取地址0x40453190
图片描述
trace跟踪一下emulator.traceWrite(0x40453196,40453196 + 16)

1
2
3
4
[23:30:45 903] Memory WRITE at 0x40453198, data size = 4, data value = 0x00000001, PC=RX@0x400492f0[libshield.so]0x492f0, LR=RX@0x400492ec[libshield.so]0x492ec
[23:30:45 903] Memory WRITE at 0x4045319c, data size = 4, data value = 0x00000001, PC=RX@0x400492f0[libshield.so]0x492f0, LR=RX@0x400492ec[libshield.so]0x492ec
[23:30:45 903] Memory WRITE at 0x404531a4, data size = 4, data value = 0x00000053, PC=RX@0x4004930c[libshield.so]0x4930c, LR=RX@0x400492ec[libshield.so]0x492ec
[23:30:45 920] Memory WRITE at 0x404531a0, data size = 4, data value = 0x00000053, PC=RX@0x40049574[libshield.so]0x49574, LR=RX@0x40049570[libshield.so]0x49570

根据地址定位下
图片描述
可以看到前八个字节固定为1,接着看下第一个0x53,断一下a1,debugger.addBreakPoint(module.base+0x4926c)
图片描述
v7 = *(_DWORD *)(*a1 + 20LL) + *(_DWORD *)(*a1 + 24LL) + *(_DWORD *)(*a1 + 28LL) + 24;
0x7+0x24+0x10+0x18=0x53
接着我们在继续trace一下emulator.traceWrite(0x4058e024,0x4058e024+9)

1
2
3
[00:18:21 012] Memory WRITE at 0x4058e024, data size = 4, data value = 0x00000007, PC=RX@0x40049138[libshield.so]0x49138, LR=RX@0x40049128[libshield.so]0x49128
[00:18:21 013] Memory WRITE at 0x4058e028, data size = 4, data value = 0x00000024, PC=RX@0x40049154[libshield.so]0x49154, LR=RX@0x40049140[libshield.so]0x49140
[00:18:21 013] Memory WRITE at 0x4058e02c, data size = 4, data value = 0x00000010, PC=RX@0x40049160[libshield.so]0x49160, LR=RX@0x4004915c[libshield.so]0x4915c

图片描述
断一下4908c后查看一下各个地址
*(_QWORD *)(*a2 - 24LL)
图片描述
*(_QWORD *)(*a5 - 24LL)
图片描述
很明显是build跟deviceid的长度,稍微修改下字符串,验证下就可以得出来
在看下0x10的来源,这个直接打开trace文件,根据汇编代码往上找就好
图片描述
trace一下emulator.traceWrite(0x40453120,0x40453120+4)

1
[10:06:27 070] Memory WRITE at 0x40453120, data size = 8, data value = 0x0000000000000010, PC=RX@0x4009ce2c[libshield.so]0x9ce2c, LR=RX@0x4009cdb4[libshield.so]0x9cdb4

根据trace文件定位一下
图片描述
可以看到w2是固定值0x10,传给函数0x9cd08,直接看下伪C代码更加明显一点
图片描述
现在接续看②剩下的83个字节,根据之前的trace日志可以定位到memcpy函数,继续emulator.traceWrite(0x4045e060,0x4045e060 + 83)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[12:48:28 084] Memory WRITE at 0x4045e060, data size = 1, data value = 0x35, PC=RX@0x4005126c[libshield.so]0x5126c, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 085] Memory WRITE at 0x4045e061, data size = 1, data value = 0x16, PC=RX@0x400512ac[libshield.so]0x512ac, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 085] Memory WRITE at 0x4045e062, data size = 1, data value = 0x11, PC=RX@0x400512ec[libshield.so]0x512ec, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 085] Memory WRITE at 0x4045e063, data size = 1, data value = 0xed, PC=RX@0x4005132c[libshield.so]0x5132c, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 085] Memory WRITE at 0x4045e064, data size = 1, data value = 0x31, PC=RX@0x4005136c[libshield.so]0x5136c, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 085] Memory WRITE at 0x4045e065, data size = 1, data value = 0x1b, PC=RX@0x400513ac[libshield.so]0x513ac, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 085] Memory WRITE at 0x4045e066, data size = 1, data value = 0x52, PC=RX@0x400513ec[libshield.so]0x513ec, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 086] Memory WRITE at 0x4045e067, data size = 1, data value = 0x1b, PC=RX@0x40051424[libshield.so]0x51424, LR=RX@0x40049570[libshield.so]0x49570
...
[12:48:28 089] Memory WRITE at 0x4045e0ab, data size = 1, data value = 0xdf, PC=RX@0x4005132c[libshield.so]0x5132c, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 089] Memory WRITE at 0x4045e0ac, data size = 1, data value = 0xe0, PC=RX@0x4005136c[libshield.so]0x5136c, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 089] Memory WRITE at 0x4045e0ad, data size = 1, data value = 0x6c, PC=RX@0x400513ac[libshield.so]0x513ac, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 089] Memory WRITE at 0x4045e0ae, data size = 1, data value = 0xc9, PC=RX@0x400513ec[libshield.so]0x513ec, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 089] Memory WRITE at 0x4045e0af, data size = 1, data value = 0xe6, PC=RX@0x40051424[libshield.so]0x51424, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 089] Memory WRITE at 0x4045e0b0, data size = 1, data value = 0xf4, PC=RX@0x40051490[libshield.so]0x51490, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 089] Memory WRITE at 0x4045e0b1, data size = 1, data value = 0xe3, PC=RX@0x400514d8[libshield.so]0x514d8, LR=RX@0x40049570[libshield.so]0x49570
[12:48:28 090] Memory WRITE at 0x4045e0b2, data size = 1, data value = 0xdb, PC=RX@0x40051520[libshield.so]0x51520, LR=RX@0x40049570[libshield.so]0x49570

可以定位到sub_511E0函数,应为是伪c代码,没看到熟悉算法的明显特征,但是可以肯定的是算法的加密流程并不复杂,我们对着汇编代码译一下

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
_DWORD *__fastcall sub_511E0(_DWORD *result, unsigned int a2, _BYTE *a3, _BYTE *a4)
...
  LODWORD(v5) = *result;                        // v5=result[0]=0 v6=result[1]=0
  LODWORD(v6) = result[1];
  if ( a2 >> 3 )
  {
    v7 = 8LL * (v4 - 1) + 8;                    // v7=0x50
    v8 = &a3[v7];
    v9 = -v4;
    out = a4;
    do
    {
      v11 = result + 2;                         // v11=&result[8]
      v12 = 4LL * (unsigned __int8)(v5 + 1);    // v12=4
      v13 = *(_DWORD *)((char *)result + v12 + 8);// v13=result[0xc]=0x2e
      ++v9;
      v14 = v13 + v6;                           // v14=result[0xc]=0x2e
      v15 = v14;                                // v15=v14<<2    //v15=result[0xc]<<2=0x2e<<2=0xb8
      v16 = result[v15 + 2];                    // v16=v11[v15]        //v16=v11[result[0xc]<<2]=result[8+0xb8]=result[0xc0]=0x68
      *(_DWORD *)((char *)v11 + v12) = v16;     // result[&result[8] + 4] = result[0xc] = 0x68
      v11[v15] = v13;                           // result[8+0xb8]=result[0xc0]=v13=0x2e
      v17 = (unsigned __int8)(v5 + 2);          // v17=v5<<2 = 0x8
      *out = *a3 ^ result[(unsigned __int8)(v16 + v13) + 2];// *out=*a3 ^ result[(v16 + v13) << 2] = *a3 ^ result[(0xb8 + 0x2e) << 2] = *a3 ^result[0x96 << 2] = 0x35
      LODWORD(v12) = result[v17 + 2];           // v12=result[8 + v17] // result[8 + 8] = result[0xf]=0xe
      v18 = v12 + v14;                          // v18= 0x2e +0xe = 0x3c
      v19 = v18;
      v20 = result[v19 + 2];                    // v20=result[8 + v19 << 2] //result[8 + 0x3c<<2]=result[8 + 0xf0]=0x37
      v11[v17] = v20;                           // result[8 + 8] = result[0xf] = 0x37
      v11[v19] = v12;                           // v11[v19]=result[8+v19<<2] //result[8+0xf0]=result[0xf8] = 0xe
      v21 = (unsigned __int8)(v5 + 3);
      out[1] = a3[1] ^ result[(unsigned __int8)(v20 + v12) + 2];
...

第一轮 result[0xc]与 result[0xc0]交换,第二轮 result[0xf]与 result[0xf0]交换,每一轮还有异或,result内存好像是256个字节
结合以上看上去就像RC4,result就是s盒,肯定还是需要往上找一下key的
图片描述
不难发现sub_51698就是RC4的初始化函数,qword_10B508应该就是key,找出来拿到网站试算一下
图片描述
分析完,继续看下sub_511e0的加密入参
图片描述
方便观看,我们拆分一下

1
2
3
4
5
1.   00 00 00 01
2.   EC FA AF 01 -->app_id
3.   00 00 00 02 00 00 00 07 00 00 00 24 00 00 00 10
4.   38 34 32 30 32 39 34 30 64 37 65 65 65 32 63 2D 35 64 37 37 2D 33 63 32 36 2D 39 39 66 38 2D 61 35 61 32 63 39 65 30 38 61 65 62 -->deviceId
5.   BA BE E4 F8 68 C3 E3 C9 4B 9B 57 81 B0 D7 14 60

①我们直接trace跟踪一下会发现是固定值,②很明显是app_id,③trace跟踪会发现02是固定值,07,24,10就是前面分析过的字符串长度跟固定值,④是deviceId,后面着重追下⑤
emulator.traceWrite(0x4045e043,0x4045e043 + 16)

1
2
[21:56:03 245] Memory WRITE at 0x4045e043, data size = 8, data value = 0xc9e3c368f8e4beba, PC=RX@0x4028c18c[libc.so]0x1c18c, LR=RX@0x40049498[libshield.so]0x49498
[21:56:03 245] Memory WRITE at 0x4045e04b, data size = 8, data value = 0x6014d7b081579b4b, PC=RX@0x4028c18c[libc.so]0x1c18c, LR=RX@0x40049498[libshield.so]0x49498

结合IDA与trace分析,会发现有memcpy函数,接着trace
emulator.traceWrite(0x40453138,0x40453138 + 16)

1
2
[22:05:14 255] Memory WRITE at 0x40453138, data size = 8, data value = 0xc9e3c368f8e4beba, PC=RX@0x4028c18c[libc.so]0x1c18c, LR=RX@0x4009cdb4[libshield.so]0x9cdb4
[22:05:14 255] Memory WRITE at 0x40453140, data size = 8, data value = 0x6014d7b081579b4b, PC=RX@0x4028c18c[libc.so]0x1c18c, LR=RX@0x4009cdb4[libshield.so]0x9cdb4

分析后会发现也是memcpy,定位IDA继续往前会找到sub_9cd08的入参a2,debugger.addBreakPoint(module.base+0x9cd08)
图片描述
结合trace可以找到sub_4afec
图片描述
一直往下找可以定位到sub_54600
图片描述
加密函数位于sub539dc中,函数很长,我们截取一段看下
图片描述
第一眼反正是没有看出是什么算法,找下特征看下上图中的v3,v4,v5,v6一直在循环里面使用,找trace记录搜一下

1
2
3
4
5
6
7
8
9
10
[23:08:19 711][libshield.so 0x0539fc] [0a744129] 0x400539fc: "ldp w10, w29, [x0, #8]" w10=0x0 w29=0xbffff390 x0=0x40469000 => w10=0xefcdab89 w29=0x67452301
[23:08:19 711][libshield.so 0x0539fc] [0a744129] 0x400539fc: "ldp w10, w29, [x0, #8]" w10=0x0 w29=0xbffff390 x0=0x40469000 => w10=0xefcdab89 w29=0x67452301
[23:08:19 863][libshield.so 0x0539fc] [0a744129] 0x400539fc: "ldp w10, w29, [x0, #8]" w10=0x0 w29=0xbffff390 x0=0x40469180 => w10=0xefcdab89 w29=0x67452301
[23:08:19 863][libshield.so 0x0539fc] [0a744129] 0x400539fc: "ldp w10, w29, [x0, #8]" w10=0x0 w29=0xbffff390 x0=0x40469180 => w10=0xefcdab89 w29=0x67452301
[23:08:21 699][libshield.so 0x0539fc] [0a744129] 0x400539fc: "ldp w10, w29, [x0, #8]" w10=0x0 w29=0xbffff450 x0=0x40469300 => w10=0x4241d083 w29=0xe47da01e
[23:08:21 699][libshield.so 0x0539fc] [0a744129] 0x400539fc: "ldp w10, w29, [x0, #8]" w10=0x0 w29=0xbffff450 x0=0x40469300 => w10=0x4241d083 w29=0xe47da01e
[23:08:21 903][libshield.so 0x0539fc] [0a744129] 0x400539fc: "ldp w10, w29, [x0, #8]" w10=0x0 w29=0xbffff3c0 x0=0x40469300 => w10=0x1ccfa223 w29=0xbec4ba48
[23:08:21 903][libshield.so 0x0539fc] [0a744129] 0x400539fc: "ldp w10, w29, [x0, #8]" w10=0x0 w29=0xbffff3c0 x0=0x40469300 => w10=0x1ccfa223 w29=0xbec4ba48
[23:08:21 941][libshield.so 0x0539fc] [0a744129] 0x400539fc: "ldp w10, w29, [x0, #8]" w10=0x0 w29=0xbffff3c0 x0=0x40469300 => w10=0x9bdae578 w29=0xa7783828
[23:08:21 941][libshield.so 0x0539fc] [0a744129] 0x400539fc: "ldp w10, w29, [x0, #8]" w10=0x0 w29=0xbffff3c0 x0=0x40469300 => w10=0x9bdae578 w29=0xa7783828

其中w10=0xefcdab89 w29=0x67452301,这个很熟悉,md5标准幻数,一般找到了算法,我们都要先看看是不是标准的加密函数的,所以一定会hook加密前后的数据,这里会发现这个加密一共调用了五次,我这边整理了下贴在下面,总共打印了三段,次数序号,输入参数1,输入参数2,以及输出的结果

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
1.
^0x36  md5
76 54 32 10 FE DC BA 98 89 AB CD EF 01 23 45 67
 
0000: 6F 7E 82 CD 2F DE 22 B8 CD 40 C8 A3 D9 6B 4B 9B    o~../."..@...kK.
0010: 47 01 C7 0C 9E 88 85 70 D5 0C 5D 08 34 DD 9A 5B    G......p..].4..[
0020: 62 1E 70 24 1F 46 FD FF 5A F4 79 F5 85 4E F8 D6    b.p$.F..Z.y..N..
0030: 53 D1 32 2C 06 A7 03 97 6C 2B B6 B0 19 A9 8B ED    S.2,....l+......
0040: 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36    6666666666666666
0050: 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36    6666666666666666
0060: 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36    6666666666666666
 
AF 9C BE 39 E7 24 85 73 83 D0 41 42 1E A0 7D E4
 
2.
^0x5c md5
76 54 32 10 FE DC BA 98 89 AB CD EF 01 23 45 67
 
0000: 05 14 E8 A7 45 B4 48 D2 A7 2A A2 C9 B3 01 21 F1    ....E.H..*....!.
0010: 2D 6B AD 66 F4 E2 EF 1A BF 66 37 62 5E B7 F0 31    -k.f.....f7b^..1
0020: 08 74 1A 4E 75 2C 97 95 30 9E 13 9F EF 24 92 BC    .t.Nu,..0....$..
0030: 39 BB 58 46 6C CD 69 FD 06 41 DC DA 73 C3 E1 87    9.XFl.i..A..s...
0040: 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C    \\\\\\\\\\\\\\\\
0050: 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C    \\\\\\\\\\\\\\\\
0060: 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C 5C    \\\\\\\\\\\\\\\\
 
2E 78 E6 70 7D 75 49 16 78 E5 DA 9B 28 38 78 A7
 
3.
AF 9C BE 39 E7 24 85 73 83 D0 41 42 1E A0 7D E4          ---1 md5
 
0000: 2F 61 70 69 2F 73 6E 73 2F 76 36 2F 6D 65 73 73    /api/sns/v6/mess
0010: 61 67 65 2F 64 65 74 65 63 74 66 69 64 3D 31 37    age/detectfid=17
0020: 32 32 31 38 32 34 37 33 31 30 36 66 63 38 34 38    22182473106fc848
0030: 39 39 35 36 35 65 32 61 63 66 30 30 36 35 36 61    99565e2acf00656a
0040: 65 30 35 61 37 38 37 36 34 62 26 64 65 76 69 63    e05a78764b&devic
0050: 65 5F 66 69 6E 67 65 72 70 72 69 6E 74 3D 32 30    e_fingerprint=20
0060: 32 33 31 32 32 34 31 31 30 30 34 33 37 36 62 64    23122411004376bd
 
E3 A1 BA DA 5E EC 8C 5A 23 A2 CF 1C 48 BA C4 BE
 
4.
E3 A1 BA DA 5E EC 8C 5A 23 A2 CF 1C 48 BA C4 BE          --->3 md5
 
0000: 65 62 80 00 00 00 00 00 00 00 00 00 00 00 00 00    eb..............
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 10 1A 00 00 00 00 00 00    ................
0040: 02 00 00 00 56 B7 C9 E9 79 A4 1B D7 DB 81 10 24    ....V...y......$
0050: D9 88 10 68 AF F7 14 9B B1 5B 1F FF BE D7 1C 88    ...h.....[......
0060: 22 61 66 66 93 61 66 F6 9E 63 19 A6 21 09 14 49    "aff.af..c..!..I
 
FF 13 AB 61 58 BD D6 19 53 CD AB 36 15 38 43 AE
 
5.
2E 78 E6 70 7D 75 49 16 78 E5 DA 9B 28 38 78 A7          --->2  md5
 
0000: FF 13 AB 61 58 BD D6 19 53 CD AB 36 15 38 43 AE    ...aX...S..6.8C--->4 md5
0010: 80 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 80 02 00 00 00 00 00 00    ................
0040: 10 00 00 00 56 B7 C9 E9 79 A4 1B D7 DB 81 10 24    ....V...y......$
0050: D9 88 10 68 AF F7 14 9B B1 5B 1F FF BE D7 1C 88    ...h.....[......
0060: 22 61 66 66 93 61 66 F6 9E 63 19 A6 21 09 14 49    "aff.af..c..!..I
 
BA BE E4 F8 68 C3 E3 C9 4B 9B 57 81 B0 D7 14 60

明显看到了0x36和0x5c的标记,这个大概率是hmac md5了,我们先看下标准的hmac md5流程
(1) 在密钥key后面添加0来创建一个长为B(64字节)的字符串(str)。
(2) 将上一步生成的字符串(str)与ipad(0x36)做异或运算,形成结果字符串(istr)。
(3) 将数据流data附加到第二步的结果字符串(istr)的末尾。
(4) 做md5运算于第三步生成的数据流(istr)。
(5) 将第一步生成的字符串(str)与opad(0x5c)做异或运算,形成结果字符串(ostr)。
(6) 再将第四步的结果(istr)附加到第五步的结果字符串(ostr)的末尾。
(7) 做md5运算于第六步生成的数据流(ostr),输出最终结果(out)。
再对着看下我整理的数据
(1)对istr做md5运算
(2)对ostr做md5运算
(3)对数据流data做md5运算
(4)对第三次的结果做md5运算
仔细对比会发现其实已经魔改的很多了,hmac流程看完了,我们再看下魔改的md5算法
正常的md5算法,主要就是这四个线性函数
图片描述
图片描述
主要是四轮运算,每组十六次,不熟悉的可以找个文档熟悉一下,再看下伪c下我的注释代码

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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
HIDWORD(v26) = ((c ^ d) & b ^ d) + a + v7 + result[23];//11 a b c d
LODWORD(v26) = HIDWORD(v26);
v27_a = (v26 >> 26) + b;
HIDWORD(v26) = v8 + d + result[24] + (v27_a & (b ^ c) ^ c);//2 d a b c
LODWORD(v26) = HIDWORD(v26);
v28_d = (v26 >> 19) + v27_a;
v29 = ((unsigned __int16)(a2[20] | (a2[21] << 8)) | (a2[22] << 16)) & 0xFFFFFF | (a2[23] << 24);
HIDWORD(v26) = v10 + c + result[25] + (v28_d & (v27_a ^ b) ^ b);//3 c d a b
LODWORD(v26) = HIDWORD(v26);
v30 = v29 + v28_d + result[28];
v31_c = (v26 >> 15) + v28_d;
v151 = result[66] + v12;
v172 = result[81] + v12;
HIDWORD(v26) = v25 + (v31_c & (v28_d ^ v27_a) ^ v27_a);//4 b c d a
LODWORD(v26) = HIDWORD(v26);
v32_b = (v26 >> 11) + v31_c;
HIDWORD(v26) = v171 + v27_a + result[27] + (v32_b & (v31_c ^ v28_d) ^ v28_d);//5 a b c d
LODWORD(v26) = HIDWORD(v26);
v33_a = (v26 >> 25) + v32_b;
HIDWORD(v26) = v30 + (v33_a & (v32_b ^ v31_c) ^ v31_c);//6 d a b c
LODWORD(v26) = HIDWORD(v26);
v34_d = (v26 >> 20) + v33_a;
HIDWORD(v26) = v12 + v31_c + result[29] + (v34_d & (v33_a ^ v32_b) ^ v32_b);//7 c d a b
LODWORD(v26) = HIDWORD(v26);
v35_c = (v26 >> 15) + v34_d;
v156 = result[79] + v16;
v36 = result[56] + v16;
v37 = v16 + v33_a + result[31];
v38 = result[50] + v16;
HIDWORD(v26) = v11 + v32_b + result[30] + (v35_c & (v34_d ^ v33_a) ^ v33_a);//8 b c d a
LODWORD(v26) = HIDWORD(v26);
v39_b = (v26 >> 12) + v35_c;
HIDWORD(v26) = v37 + (v39_b & (v35_c ^ v34_d) ^ v34_d);//9 a b c d
LODWORD(v26) = HIDWORD(v26);
v40_a = (v26 >> 25) + v39_b;
HIDWORD(v26) = v17 + v34_d + result[32] + (v40_a & (v39_b ^ v35_c) ^ v35_c);//10 d a b c
LODWORD(v26) = HIDWORD(v26);
v41_d = (v26 >> 20) + v40_a;
v42 = v35_c + v14 + result[33];
v43 = v22 + v39_b;
HIDWORD(v26) = v42 + (v41_d & (v40_a ^ v39_b) ^ v39_b);//11 c d a b
LODWORD(v26) = HIDWORD(v26);
v44_c = (v26 >> 16) + v41_d;
v45 = v152 + v40_a;
HIDWORD(v26) = v43 + (v44_c & (v41_d ^ v40_a) ^ v40_a);//12 b c d a
LODWORD(v26) = HIDWORD(v26);
v46_b = (v26 >> 10) + v44_c;
v47 = result[36] + v20 + v41_d;
HIDWORD(v26) = v45 + (v46_b & (v44_c ^ v41_d) ^ v41_d);//13 a b c d
LODWORD(v26) = HIDWORD(v26);
v48_a = (v26 >> 25) + v46_b;
v49 = v155 + v44_c;
HIDWORD(v26) = v47 + (v48_a & (v46_b ^ v44_c) ^ v44_c);//14 d a b c
LODWORD(v26) = HIDWORD(v26);
v50_d = (v26 >> 19) + v48_a;
v51 = v15 + result[38] + v46_b;
HIDWORD(v26) = v49 + (v50_d & (v48_a ^ v46_b) ^ v46_b);//15 c d a b
LODWORD(v26) = HIDWORD(v26);
v52_c = (v26 >> 15) + v50_d;
v53 = (result[39] & 0xFF00FF00) + v8 + v48_a;
HIDWORD(v26) = v51 + (v52_c & (v50_d ^ v48_a) ^ v48_a);//16 b c d a
LODWORD(v26) = HIDWORD(v26);
v54_b = (v26 >> 10) + v52_c;
v55 = v21 + v50_d;
HIDWORD(v26) = v53 + ((v54_b ^ v52_c) & v50_d ^ v52_c);// 21 a b c d
LODWORD(v26) = HIDWORD(v26);
v56_a = (v26 >> 27) + v54_b;
v57 = v23 + v52_c;
HIDWORD(v26) = v55 + ((v56_a ^ v54_b) & v52_c ^ v54_b);// 2 d a b c 
LODWORD(v26) = HIDWORD(v26);
v58_d = (v26 >> 23) + v56_a;
v59 = v159 + v54_b;
HIDWORD(v26) = v57 + ((v58_d ^ v56_a) & v54_b ^ v56_a);// 3 c d a b
LODWORD(v26) = HIDWORD(v26);
v60_c = (v26 >> 18) + v58_d;
v61 = result[43] + v29 + v56_a;
HIDWORD(v26) = v59 + ((v60_c ^ v58_d) & v56_a ^ v58_d);// 4 b c d a
LODWORD(v26) = HIDWORD(v26);
v62_b = (v26 >> 12) + v60_c;
v63 = result[44] + v14 + v58_d;
HIDWORD(v26) = v61 + ((v62_b ^ v60_c) & v58_d ^ v60_c);// 5 a b c d
LODWORD(v26) = HIDWORD(v26);
v64_a = (v26 >> 27) + v62_b;
v65 = result[45] + v15 + v60_c;
HIDWORD(v26) = v63 + ((v64_a ^ v62_b) & v60_c ^ v62_b);// 6 d a b c
LODWORD(v26) = HIDWORD(v26);
v66_d = (v26 >> 23) + v64_a;
v67 = result[46] + v171 + v62_b;
HIDWORD(v26) = v65 + ((v66_d ^ v64_a) & v62_b ^ v64_a);// 7 c d a b
LODWORD(v26) = HIDWORD(v26);
v68_c = (v26 >> 18) + v66_d;
v69 = result[47] + v17 + v64_a;
HIDWORD(v26) = v67 + ((v68_c ^ v66_d) & v64_a ^ v66_d);// 8 b c d a
LODWORD(v26) = HIDWORD(v26);
v70_b = (v26 >> 12) + v68_c;
v71 = v161 + v66_d;
HIDWORD(v26) = v69 + ((v70_b ^ v68_c) & v66_d ^ v68_c);// 9 a b c d
LODWORD(v26) = HIDWORD(v26);
v72_a = (v26 >> 27) + v70_b;
v73 = v24 + v68_c;
HIDWORD(v26) = v71 + ((v72_a ^ v70_b) & v68_c ^ v70_b);// 10 d a b c
LODWORD(v26) = HIDWORD(v26);
v74_d = (v26 >> 23) + v72_a;
v75 = v38 + v70_b;
HIDWORD(v26) = v73 + ((v74_d ^ v72_a) & v70_b ^ v72_a);// 11 c d a b 
LODWORD(v26) = HIDWORD(v26);
v76_c = (v26 >> 18) + v74_d;
v77 = result[51] + v20 + v72_a;
HIDWORD(v26) = v75 + ((v76_c ^ v74_d) & v72_a ^ v74_d);// 12 b c d a 
LODWORD(v26) = HIDWORD(v26);
v78_b = (v26 >> 12) + v76_c;
v79 = v150 + v74_d;
HIDWORD(v26) = v77 + ((v78_b ^ v76_c) & v74_d ^ v76_c);// 13 a b c d
LODWORD(v26) = HIDWORD(v26);
v80_a = (v26 >> 27) + v78_b;
v81 = result[53] + v11 + v76_c;
HIDWORD(v26) = v79 + ((v80_a ^ v78_b) & v76_c ^ v78_b);// 14 d a b c
LODWORD(v26) = HIDWORD(v26);
v82_d = (v26 >> 23) + v80_a;
v83 = v162 + v78_b;
HIDWORD(v26) = v81 + ((v82_d ^ v80_a) & v78_b ^ v80_a);// 15 c d a b
LODWORD(v26) = HIDWORD(v26);
v84_c = (v26 >> 18) + v82_d;
v85 = result[55] + v29 + v80_a;
HIDWORD(v26) = v83 + ((v84_c ^ v82_d) & v80_a ^ v82_d);// 16 b c d a
LODWORD(v26) = HIDWORD(v26);
v86_b = (v26 >> 12) + v84_c;
v87 = v36 + v82_d;
HIDWORD(v26) = v85 + (v84_c ^ v82_d ^ v86_b);// 31 a b c d
LODWORD(v26) = HIDWORD(v26);
v88_a = (v26 >> 28) + v86_b;
v89 = v153 + v84_c;
HIDWORD(v26) = v87 + (v86_b ^ v84_c ^ v88_a);// 2 d a b c
LODWORD(v26) = HIDWORD(v26);
v90 = v165 + v86_b;
v91_d = (v26 >> 21) + v88_a;
HIDWORD(v26) = v89 + (v88_a ^ v86_b ^ v91_d);// 3 c d a b
LODWORD(v26) = HIDWORD(v26);
v92_c = (v26 >> 16) + v91_d;
v93 = v160 + v88_a;
HIDWORD(v26) = v90 + (v91_d ^ v88_a ^ v92_c);// 4 b c d a
LODWORD(v26) = HIDWORD(v26);
v94_b = (v26 >> 9) + v92_c;
v95 = result[62] + v14 + v94_b;
v96 = result[60] + v171 + v91_d;
HIDWORD(v26) = v93 + (v92_c ^ v91_d ^ v94_b);// 5 a b c d
LODWORD(v26) = HIDWORD(v26);
v97 = result[61] + v11 + v92_c;
v98_a = (v26 >> 28) + v94_b;
HIDWORD(v26) = v96 + (v94_b ^ v92_c ^ v98_a);// 6 d a b c 
LODWORD(v26) = HIDWORD(v26);
v99_d = (v26 >> 21) + v98_a;
v100 = result[63] + v20 + v98_a;
HIDWORD(v26) = v97 + (v98_a ^ v94_b ^ v99_d);// 7 c d a b
LODWORD(v26) = HIDWORD(v26);
v101_c = (v26 >> 16) + v99_d;
HIDWORD(v26) = v100 + (v99_d ^ v94_b ^ v101_c);// 8 a c d b
LODWORD(v26) = HIDWORD(v26);
v102_a = (v26 >> 28) + v94_b;
HIDWORD(v26) = v95 + (v101_c ^ v99_d ^ v102_a);// 9 b c d a
LODWORD(v26) = HIDWORD(v26);
v103 = v154 + v101_c;
v104_b = (v26 >> 9) + v101_c;
HIDWORD(v26) = v103 + (v102_a ^ v99_d ^ v104_b);// 10 c d a b
LODWORD(v26) = HIDWORD(v26);
--a3;
a2 += 64;
v105 = v168 + v99_d;
v106_c = (v26 >> 16) + v99_d;
v107 = v151 + v104_b;
HIDWORD(v26) = v105 + (v104_b ^ v102_a ^ v106_c);// 11 d a b c
LODWORD(v26) = HIDWORD(v26);
v108 = result[67] + v17 + v102_a;
v109_d = (v26 >> 21) + v102_a;
HIDWORD(v26) = v107 + (v106_c ^ v102_a ^ v109_d);// 12 b c d a
LODWORD(v26) = HIDWORD(v26);
v110 = v166 + v109_d;
v111_b = (v26 >> 9) + v106_c;
HIDWORD(v26) = v108 + (v109_d ^ v106_c ^ v111_b);// 13 a b c d
LODWORD(v26) = HIDWORD(v26);
v112 = result[69] + v15 + v106_c;
v113_a = (v26 >> 28) + v111_b;
HIDWORD(v26) = v110 + (v111_b ^ v106_c ^ v113_a);// 14 d a b c 
LODWORD(v26) = HIDWORD(v26);
v114 = v157 + v111_b;
v115_d = (v26 >> 21) + v113_a;
HIDWORD(v26) = v112 + (v113_a ^ v111_b ^ v115_d);// 15 c d a b
LODWORD(v26) = HIDWORD(v26);
v116 = v173 + v113_a;
v117_c = (v26 >> 16) + v115_d;
HIDWORD(v26) = v114 + (v115_d ^ v113_a ^ v117_c);// 16 b c d a
LODWORD(v26) = HIDWORD(v26);
v118_b = (v26 >> 9) + v117_c;
v119 = result[72] + v11 + v115_d;
HIDWORD(v26) = v116 + ((v118_b | ~v115_d) ^ v117_c);//41 a b c d
LODWORD(v26) = HIDWORD(v26);
v120_a = (v26 >> 26) + v118_b;
v121 = v169 + v117_c;
HIDWORD(v26) = v119 + ((v120_a | ~v117_c) ^ v118_b);// 2 d a b c
LODWORD(v26) = HIDWORD(v26);
v122_d = (v26 >> 22) + v120_a;
v123 = result[74] + v29 + v118_b;
HIDWORD(v26) = v121 + ((v122_d | ~v118_b) ^ v120_a);// 3 c d a b 
LODWORD(v26) = HIDWORD(v26);
v124_c = (v26 >> 17) + v122_d;
v125 = v170 + v120_a;
HIDWORD(v26) = v123 + ((v124_c | ~v120_a) ^ v122_d);// 4 b c d a
LODWORD(v26) = HIDWORD(v26);
v126_b = (v26 >> 11) + v124_c;
v127 = v158 + v122_d;
HIDWORD(v26) = v125 + ((v126_b | ~v122_d) ^ v124_c);// 5 a b c d
LODWORD(v26) = HIDWORD(v26);
v128_a = (v26 >> 26) + v126_b;
v129 = result[77] + v14 + v124_c;
HIDWORD(v26) = v127 + ((v128_a | ~v124_c) ^ v126_b);// 6 d a b c
LODWORD(v26) = HIDWORD(v26);
v130_d = (v26 >> 22) + v128_a;
v131 = v167 + v126_b;
HIDWORD(v26) = v129 + ((v130_d | ~v126_b) ^ v128_a);// 7 c d a b  
LODWORD(v26) = HIDWORD(v26);
v132_c = (v26 >> 17) + v130_d;
v133 = v156 + v128_a;
HIDWORD(v26) = v131 + ((v132_c | ~v128_a) ^ v130_d);// 8 b c d a
LODWORD(v26) = HIDWORD(v26);
v134_b = (v26 >> 11) + v132_c;
v135 = result[80] + v15 + v130_d;
HIDWORD(v26) = v133 + ((v134_b | ~v130_d) ^ v132_c);// 9 a b c d 
LODWORD(v26) = HIDWORD(v26);
v136_a = (v26 >> 26) + v134_b;
v137 = v172 + v132_c;
HIDWORD(v26) = v135 + ((v136_a | ~v132_c) ^ v134_b);// 10 d a b c
LODWORD(v26) = HIDWORD(v26);
v138_d = (v26 >> 22) + v136_a;
v139 = result[82] + v20 + v134_b;
HIDWORD(v26) = v137 + ((v138_d | ~v134_b) ^ v136_a);// 11 c d a b
LODWORD(v26) = HIDWORD(v26);
v140_c = (v26 >> 17) + v138_d;
v141 = result[83] + v171 + v136_a;
HIDWORD(v26) = v139 + ((v140_c | ~v136_a) ^ v138_d);// 12 b c d a
LODWORD(v26) = HIDWORD(v26);
v142_b = (v26 >> 11) + v140_c;
v143 = v164 + v138_d;
HIDWORD(v26) = v141 + ((v142_b | ~v138_d) ^ v140_c);// 13 a b c d 
LODWORD(v26) = HIDWORD(v26);
v144_a = (v26 >> 26) + v142_b;
v145 = v163 + v140_c;
HIDWORD(v26) = v143 + ((v144_a | ~v140_c) ^ v142_b);// 14 d a b c
LODWORD(v26) = HIDWORD(v26);
v146_d = (v26 >> 22) + v144_a;
v147 = result[86] + v17 + v142_b;
HIDWORD(v26) = v145 + ((v146_d | ~v142_b) ^ v144_a);// 15 c d a b 
LODWORD(v26) = HIDWORD(v26);
v148_c = (v26 >> 17) + v146_d;
a = v144_a + *result;
v149 = v148_c + result[1];
HIDWORD(v26) = v147 + ((v148_c | ~v144_a) ^ v146_d);// 16 b c d a
LODWORD(v26) = HIDWORD(v26);
d = v146_d + result[3];
c = v148_c + result[2];
b = v149 + (v26 >> 11);
result[2] = c;
result[3] = d;
*result = a;
result[1] = b;

加上注释看其实就很明显了,对着标准的算法扣汇编就行了,主要流程其实都没变,只是魔改了一些参数跟顺序而已,看下最后的实现代码,怕被恶意利用,关键代码就不公布了

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
...
#第一次md5
data="6F7E82CD2FDE22B8CD40C8A3D96B4B9B4701C70C9E888570D50C5D0834DD9A5B621E70241F46FDFF5AF479F5854EF8D653D1322C06A703976C2BB6B019A98BED"
context1=md5_m1(bytes.fromhex(data), False, 0x10325476, 0x98badcfe, 0xefcdab89, 0x67452301)
print(context1)
# AF9CBE39E724857383D041421EA07DE4
print("AF9CBE39E724857383D041421EA07DE4")
 
#第二次md5
data="0514E8A745B448D2A72AA2C9B30121F12D6BAD66F4E2EF1ABF6637625EB7F03108741A4E752C9795309E139FEF2492BC39BB58466CCD69FD0641DCDA73C3E187"
context2=md5_m1(bytes.fromhex(data), False, 0x10325476, 0x98badcfe, 0xefcdab89, 0x67452301)
print(context2)
# 2E78E6707D75491678E5DA9B283878A7
print("2E78E6707D75491678E5DA9B283878A7")
 
#第三MD5
val = struct.unpack('<4I', bytes.fromhex(context1))
print(hex(val[0]))
print(hex(val[1]))
print(hex(val[2]))
print(hex(val[3]))
str = "/api/sns/v6/message/detectfid=1722182473106fc84899565e2acf00656ae05a78764b&device_fingerprint=2023122411004376bd379fe6f54e6dc5ca0b0cf8d24dd601dc85661f97571b&device_fingerprint1=2023122411004376bd379fe6f54e6dc5ca0b0cf8d24dd601dc85661f97571b&cpu_name=Qualcomm+Technologies%2C+Inc+SDM845&gid=7c7ea0a5b61c5590cec3770efa9cfec6e81b439947359eeb775b6fc4&device_model=phone&launch_id=1722617914&tz=Asia%2FShanghai&channel=Guanfang&versionName=8.42.0&overseas_channel=0&deviceId=0d7eee2c-5d77-3c26-99f8-a5a2c9e08aeb&platform=android&sid=session.1722182426050852896201&identifier_flag=4&t=1722617846&project_id=ECFAAF&build=8420294&x_trace_page_current=&lang=zh-Hans&app_id=ECFAAF01&uis=light&teenager=0"
str = str + "49" #xy-direction
str = str + "platform=android&build=8420294&deviceId=0d7eee2c-5d77-3c26-99f8-a5a2c9e08a"
print(str)
print(len(str))
data = str.encode('utf-8').hex()
print(md5_m1(bytes.fromhex(data), False, val[0], val[1], val[2], val[3]))
print("E3A1BADA5EEC8C5A23A2CF1C48BAC4BE")
 
#第三四次MD5一起(满512与不满512加padding)
str = str+"eb"
print(str)
data = str.encode('utf-8').hex()
data4=md5_m1(bytes.fromhex(data), True, val[0], val[1], val[2], val[3])
print(data4)
 
#第五次MD5
val = struct.unpack('<4I', bytes.fromhex(context2))
result=md5_m1(bytes.fromhex(data4), True, val[0], val[1], val[2], val[3])
print("=================================")
print(result)
print("BABEE4F868C3E3C94B9B5781B0D71460")

运行结果
图片描述
后面接着要找下hmac md5的key值了,debugger.addBreakPoint(module.base+0x539DC)
图片描述
根据trace文件往上找,最终会找到赋值的汇编处理代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[08:31:33 382][libshield.so 0x053158] [6042c23c] 0x40053158: "ldur q0, [x19, #0x24]" x19=0x40466000 //原始数据 0x24偏移
[08:31:33 382][libshield.so 0x05315c] [6142c33c] 0x4005315c: "ldur q1, [x19, #0x34]" x19=0x40466000 //原始数据 0x34偏移
[08:31:33 383][libshield.so 0x053160] [c2e6014f] 0x40053160: "movi v2.16b, #0x36"    //异或值
[08:31:33 383][libshield.so 0x053164] [e10314aa] 0x40053164: "mov x1, x20" x20=0x40105a40 => x1=0x40105a40
[08:31:33 383][libshield.so 0x053168] [001c226e] 0x40053168: "eor v0.16b, v0.16b, v2.16b" //异或0x36
[08:31:33 383][libshield.so 0x05316c] [211c226e] 0x4005316c: "eor v1.16b, v1.16b, v2.16b" //异或0x36
[08:31:33 424][libshield.so 0x053170] [e00700ad] 0x40053170: "stp q0, q1, [sp]" sp=0xbffff3a0 //存储
[08:31:33 424][libshield.so 0x053174] [6042c43c] 0x40053174: "ldur q0, [x19, #0x44]" x19=0x40466000 //修改偏移地址继续...
[08:31:33 425][libshield.so 0x053178] [6142c53c] 0x40053178: "ldur q1, [x19, #0x54]" x19=0x40466000 //修改偏移地址继续...
[08:31:33 425][libshield.so 0x05317c] [001c226e] 0x4005317c: "eor v0.16b, v0.16b, v2.16b"
[08:31:33 425][libshield.so 0x053180] [211c226e] 0x40053180: "eor v1.16b, v1.16b, v2.16b"
[08:31:33 425][libshield.so 0x053184] [e00701ad] 0x40053184: "stp q0, q1, [sp, #0x20]" sp=0xbffff3a0
[08:31:33 425][libshield.so 0x053188] [6042c63c] 0x40053188: "ldur q0, [x19, #0x64]" x19=0x40466000
[08:31:33 425][libshield.so 0x05318c] [6142c73c] 0x4005318c: "ldur q1, [x19, #0x74]" x19=0x40466000
[08:31:33 425][libshield.so 0x053190] [001c226e] 0x40053190: "eor v0.16b, v0.16b, v2.16b"
[08:31:33 425][libshield.so 0x053194] [211c226e] 0x40053194: "eor v1.16b, v1.16b, v2.16b"
[08:31:33 426][libshield.so 0x053198] [e00702ad] 0x40053198: "stp q0, q1, [sp, #0x40]" sp=0xbffff3a0
[08:31:33 426][libshield.so 0x05319c] [6042c83c] 0x4005319c: "ldur q0, [x19, #0x84]" x19=0x40466000
[08:31:33 426][libshield.so 0x0531a0] [6142c93c] 0x400531a0: "ldur q1, [x19, #0x94]" x19=0x40466000
[08:31:33 426][libshield.so 0x0531a4] [001c226e] 0x400531a4: "eor v0.16b, v0.16b, v2.16b"
[08:31:33 426][libshield.so 0x0531a8] [211c226e] 0x400531a8: "eor v1.16b, v1.16b, v2.16b"
[08:31:33 426][libshield.so 0x0531ac] [e00703ad] 0x400531ac: "stp q0, q1, [sp, #0x60]" sp=0xbffff3a0

加上断点看下原始数据debugger.addBreakPoint(module.base+0x53158)
图片描述
继续找赋值的地方,中间trace跟踪的方法跟之前的一样,具体步骤就省略了,我们直接到最后一次emulator.traceWrite(0x4045e010,0x4045e010 + 64)

1
2
3
4
5
6
7
[11:14:28 321] Memory WRITE at 0x4045e010, data size = 8, data value = 0x8e14e819fbb44859, PC=RX@0x40052a6c[libshield.so]0x52a6c, LR=RX@0x40052998[libshield.so]0x52998
[11:14:28 322] Memory WRITE at 0x4045e018, data size = 8, data value = 0xad7d5def95fe76fb, PC=RX@0x40052a6c[libshield.so]0x52a6c, LR=RX@0x40052998[libshield.so]0x52998
[11:14:28 322] Memory WRITE at 0x4045e020, data size = 8, data value = 0x46b3bea83af13771, PC=RX@0x40052a6c[libshield.so]0x52a6c, LR=RX@0x40052998[libshield.so]0x52998
[11:14:28 322] Memory WRITE at 0x4045e028, data size = 8, data value = 0x6daceb023e6b3ae3, PC=RX@0x40052a6c[libshield.so]0x52a6c, LR=RX@0x40052998[libshield.so]0x52998
[11:14:28 322] Memory WRITE at 0x4045e030, data size = 8, data value = 0xc9cb702912462854, PC=RX@0x40052a6c[libshield.so]0x52a6c, LR=RX@0x40052998[libshield.so]0x52998
[11:14:28 322] Memory WRITE at 0x4045e038, data size = 8, data value = 0xe0ce78b3c34fc26c, PC=RX@0x40052a6c[libshield.so]0x52a6c, LR=RX@0x40052998[libshield.so]0x52998
[11:14:28 322] Memory WRITE at 0x4045e040, data size = 8, data value = 0xa13591301a04e765, PC=RX@0x40052a6c[libshield.so]0x52a6c, LR=RX@0x40052998[libshield.so]0x52998

定位到IDA函数我们看下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
__int64 __fastcall sub_51868(__int64 result, _OWORD *a2, unsigned __int64 a3, __int64 a4, _OWORD *a5, int a6)
...
    result = ((__int64 (__fastcall *)(__int64, char *, __int64, __int64, _OWORD *, __int64 (__fastcall *)()))v79)( //__int64 __fastcall sub_522F4(unsigned __int8 *a1, _BYTE *a2, _DWORD *a3)
               v53,
               v82,
               a4,
               a4,
               a5,
               v18);
...
    do
    {
      v65 = *(_OWORD *)(v53 + v64);
      v54[v64 / 0x10] = veorq_s8((int8x16_t)a5[v64 / 0x10], *(int8x16_t *)&v82[v64]);//异或后赋值处
      a5[v64 / 0x10] = v65;
      v64 += 16LL;//偏移长度
    }
    while ( (-v80 & 0xFFFFFFFFFFFFFFF0LL) != v64 );
...

进去先看看加密函数,截取一部分看一下
图片描述
代码比较多,先到里面找特征值分析一下先,经过一番查找,最后定在debugger.addBreakPoint(module.base+0x52580)
图片描述
图片描述
图片描述
非常明显是个AES查表法的逆S盒,逆S盒我们一般用于AES解密函数,S盒采用于AES加密函数,我们结合trace跟后面异或的赋值流程看下调用次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[libshield.so 0x052988] [e2a341a9] 0x40052988: "ldp x2, x8, [sp, #0x18]" x2=0x60 x8=0xffffffffffffffa0 sp=0xbffff280 => x2=0xbffff350 x8=0x400522f4
[libshield.so 0x052994] [00013fd6] 0x40052994: "blr x8" x8=0x400522f4 //1 解密调用
[libshield.so 0x052a6c] [a06aaa3c] 0x40052a6c: "str q0, [x21, x10]" x21=0x4045e000 x10=0x0 //1 异或后赋值
[libshield.so 0x052988] [e2a341a9] 0x40052988: "ldp x2, x8, [sp, #0x18]" x2=0x2b x8=0xffffffffffffffb0 sp=0xbffff280 => x2=0xbffff350 x8=0x400522f4
[libshield.so 0x052994] [00013fd6] 0x40052994: "blr x8" x8=0x400522f4 //2
[libshield.so 0x052a6c] [a06aaa3c] 0x40052a6c: "str q0, [x21, x10]" x21=0x4045e010 x10=0x0 //2
[libshield.so 0x052988] [e2a341a9] 0x40052988: "ldp x2, x8, [sp, #0x18]" x2=0xa9 x8=0xffffffffffffffc0 sp=0xbffff280 => x2=0xbffff350 x8=0x400522f4
[libshield.so 0x052994] [00013fd6] 0x40052994: "blr x8" x8=0x400522f4//3
[libshield.so 0x052a6c] [a06aaa3c] 0x40052a6c: "str q0, [x21, x10]" x21=0x4045e020 x10=0x0 //3
[libshield.so 0x052988] [e2a341a9] 0x40052988: "ldp x2, x8, [sp, #0x18]" x2=0xb2 x8=0xffffffffffffffd0 sp=0xbffff280 => x2=0xbffff350 x8=0x400522f4
[libshield.so 0x052994] [00013fd6] 0x40052994: "blr x8" x8=0x400522f4 //4
[libshield.so 0x052a6c] [a06aaa3c] 0x40052a6c: "str q0, [x21, x10]" x21=0x4045e030 x10=0x0 // 4
[libshield.so 0x052988] [e2a341a9] 0x40052988: "ldp x2, x8, [sp, #0x18]" x2=0x6a x8=0xffffffffffffffe0 sp=0xbffff280 => x2=0xbffff350 x8=0x400522f4
[libshield.so 0x052994] [00013fd6] 0x40052994: "blr x8" x8=0x400522f4 //5
[libshield.so 0x052a6c] [a06aaa3c] 0x40052a6c: "str q0, [x21, x10]" x21=0x4045e040 x10=0x0 //5
[libshield.so 0x052988] [e2a341a9] 0x40052988: "ldp x2, x8, [sp, #0x18]" x2=0x45 x8=0xfffffffffffffff0 sp=0xbffff280 => x2=0xbffff350 x8=0x400522f4
[libshield.so 0x052994] [00013fd6] 0x40052994: "blr x8" x8=0x400522f4 //6
[libshield.so 0x052a6c] [a06aaa3c] 0x40052a6c: "str q0, [x21, x10]" x21=0x4045e050 x10=0x0 //6

总共6次,每次都是aes解密后进行异或赋值,我们简述下aes cbc的算法解密流程
1.对密文数据块进行解密
2.对解密结果与IV进行异或
3.对下一个密文数据库进行解密
4.对解密数据与上一个密文块进行异或
5.重复3,4完成解密流程
对比着看就很明显了
算法明确了,下一步就是找下iv了,就是解密后的第一次异或debugger.addBreakPoint(module.base+0x52a64)
图片描述
往上定位IV出处会找到
图片描述
紧接着我们要找key了,接着sub_522f4中的a3往上找
图片描述
继续往上找
图片描述
结合下uibdbg日志就可以定位到key了
图片描述
最后就要找下加密数据的出处了debugger.addBreakPoint(module.base+0x51868)
图片描述
往上找可以定位到
图片描述
在结合unibdbg日志
图片描述
很明显就能看出来是获取main_hmac的SharedPreference在进行base64的解码了
现在加密数据,key,iv都拿到了,当我们拿到网站试算会发现无法匹配,很明显aes算法是魔改了,截取部分aes解密函数看下
图片描述
正常的aes加解密一般也就四个表,但是这个魔改的解密函数整出来了十个表,因为魔改太严重,我这边就没去细致分析了,直接对着汇编跟伪C扣出来算法我个人觉得可能花的时间还少一些
图片描述
运行结果
图片描述

总结

整个算法的难度跟工作量还是不小,不但魔改了hmac,连md5也一起魔改了,最后的aes更是魔改的很彻底,基本让人无法清晰看出算法结构只能被迫使去扣汇编,整体时间是耗费掉不少。

样本

https://pan.quark.cn/s/28c1a4d0d49e

参考链接

https://www.jianshu.com/p/067f9eb6b252
https://zhuanlan.zhihu.com/p/702060967
https://www.cnblogs.com/kentle/p/15529251.html

警告:本文章相关代码与分析流程仅用于技术学习与提升,切勿用于非法用途,否则后果自负。


[注意]看雪招聘,专注安全领域的专业人才平台!

最后于 2025-3-15 18:18 被HandsomeBro编辑 ,原因:
收藏
免费 68
支持
分享
赞赏记录
参与人
雪币
留言
时间
thanh5763
非常支持你的观点!
2025-3-14 22:15
ptr1234565
感谢你的积极参与,期待更多精彩内容!
2025-3-14 13:04
qqizai
感谢你的积极参与,期待更多精彩内容!
2025-3-14 09:25
小傲骨
为你点赞!
2025-3-14 07:08
despacido~~
非常支持你的观点!
2025-3-13 22:01
ouokih
这个讨论对我很有帮助,谢谢!
2025-3-13 21:35
mb_zfqvurgb
这个讨论对我很有帮助,谢谢!
2025-3-13 20:39
mb_fcagklmv
为你点赞!
2025-3-13 17:56
hswizy
为你点赞!
2025-3-13 17:50
养只猫不好么
非常支持你的观点!
2025-3-13 16:27
sorryla
谢谢你的细致分析,受益匪浅!
2025-3-13 12:41
Forgo7ten
+1
你的帖子非常有用,感谢分享!
2025-3-12 14:22
Ive_406746
感谢你的积极参与,期待更多精彩内容!
2025-3-12 10:26
mb_qvxjmcan
你的分享对大家帮助很大,非常感谢!
2025-3-12 05:25
快乐的小跳蛙
为你点赞!
2025-3-11 23:11
mb_iriptvui
这个讨论对我很有帮助,谢谢!
2025-3-11 21:58
爱吃菠菜
你的分享对大家帮助很大,非常感谢!
2025-3-11 21:39
mb_cbitsgsv
谢谢你的细致分析,受益匪浅!
2025-3-11 17:34
mb_ijzlnybv
非常支持你的观点!
2025-3-11 15:52
@=llfly
期待更多优质内容的分享,论坛有你更精彩!
2025-3-11 14:41
兆兆的罩罩
你的帖子非常有用,感谢分享!
2025-3-11 14:36
lrzhao
你的分享对大家帮助很大,非常感谢!
2025-3-11 13:53
mb_wvlmehse
谢谢你的细致分析,受益匪浅!
2025-3-11 11:38
mb_fgcxqivc
非常支持你的观点!
2025-3-11 11:14
mb_fywmigrm
这个讨论对我很有帮助,谢谢!
2025-3-11 10:58
Lychow
谢谢你的细致分析,受益匪浅!
2025-3-11 10:49
gladly
为你点赞!
2025-3-11 10:24
MsScotch
请注意发帖规范,保持良好的讨论环境!
2025-3-11 08:54
mb_uthesfhv
你的分享对大家帮助很大,非常感谢!
2025-3-11 08:21
梧桐生
期待更多优质内容的分享,论坛有你更精彩!
2025-3-11 02:11
she.
这个讨论对我很有帮助,谢谢!
2025-3-11 01:59
sinker_
为你点赞!
2025-3-11 00:57
mb_spepqmin
谢谢你的细致分析,受益匪浅!
2025-3-10 22:44
mb_xpmuwjjc
期待更多优质内容的分享,论坛有你更精彩!
2025-3-10 21:34
mb_sexbafmg
期待更多优质内容的分享,论坛有你更精彩!
2025-3-10 20:10
wx_十二_866
非常支持你的观点!
2025-3-10 19:56
sun-shine
你的分享对大家帮助很大,非常感谢!
2025-3-10 18:54
小菜鸭
你的分享对大家帮助很大,非常感谢!
2025-3-10 18:03
得码西亚
你的分享对大家帮助很大,非常感谢!
2025-3-10 17:42
mb_aoooaosd
谢谢你的细致分析,受益匪浅!
2025-3-10 17:11
ChenSem
为你点赞!
2025-3-10 16:21
coder777
非常支持你的观点!
2025-3-10 14:40
D-t
期待更多优质内容的分享,论坛有你更精彩!
2025-3-10 14:04
Python成长路
感谢你的积极参与,期待更多精彩内容!
2025-3-10 13:59
岁月。
为你点赞!
2025-3-10 12:21
思睿
谢谢你的细致分析,受益匪浅!
2025-3-10 11:57
令狐双
你的帖子非常有用,感谢分享!
2025-3-10 11:36
不吃早饭
感谢你分享这么好的资源!
2025-3-10 11:12
juice4fun
感谢你分享这么好的资源!
2025-3-10 10:58
zhengcai
感谢你的贡献,论坛因你而更加精彩!
2025-3-10 10:48
CCC_
期待更多优质内容的分享,论坛有你更精彩!
2025-3-10 10:35
TreeHole
谢谢你的细致分析,受益匪浅!
2025-3-10 10:28
wx_byte
为你点赞!
2025-3-10 10:27
frankyxu
谢谢你的细致分析,受益匪浅!
2025-3-10 10:19
mb_bkkdeflr
谢谢你的细致分析,受益匪浅!
2025-3-10 10:17
Kr1s
期待更多优质内容的分享,论坛有你更精彩!
2025-3-10 10:03
fishod
感谢你的贡献,论坛因你而更加精彩!
2025-3-10 09:51
ChuXinﻬ.
非常支持你的观点!
2025-3-10 09:48
New对象处
你的分享对大家帮助很大,非常感谢!
2025-3-10 09:34
杨如画
非常支持你的观点!
2025-3-10 09:24
leiusurely
为你点赞!
2025-3-10 07:43
mb_bppcorlj
这个讨论对我很有帮助,谢谢!
2025-3-10 01:51
mb_ghpdxkem
感谢你分享这么好的资源!
2025-3-9 22:05
顽劣
感谢你分享这么好的资源!
2025-3-9 21:39
mb_asiwnxyv
这个讨论对我很有帮助,谢谢!
2025-3-9 21:01
百事可乐就好
期待更多优质内容的分享,论坛有你更精彩!
2025-3-9 20:00
mb_rjdrqvpa
感谢你的积极参与,期待更多精彩内容!
2025-3-9 19:42
醉染
为你点赞!
2025-3-9 19:07
最新回复 (49)
雪    币: 1868
活跃值: (2740)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
.
2025-3-9 18:53
0
雪    币: 78
活跃值: (1206)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
太好了
2025-3-9 20:16
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
6
2025-3-9 21:34
0
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
2025-3-9 21:52
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
kk
2025-3-9 21:58
0
雪    币: 58
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
包都抓不到 废了
2025-3-10 01:21
0
雪    币: 4232
活跃值: (4044)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
6666
2025-3-10 08:01
0
雪    币: 24
活跃值: (1345)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
666
2025-3-10 08:51
0
雪    币: 20
活跃值: (1669)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
666
2025-3-10 09:18
0
雪    币: 226
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
学习一下
2025-3-10 09:30
0
雪    币: 1
活跃值: (450)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
6
2025-3-10 09:41
0
雪    币: 14
活跃值: (409)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
666
2025-3-10 09:43
0
雪    币: 206
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
14
666
2025-3-10 10:22
0
雪    币: 3
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
6666
2025-3-10 10:44
0
雪    币: 220
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
66666
2025-3-10 10:55
0
雪    币: 90
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
6666666666666
2025-3-10 11:17
0
雪    币: 188
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18
6666666
2025-3-10 11:54
0
雪    币: 1662
活跃值: (1279)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
19
学习一下
2025-3-10 16:18
0
雪    币: 335
活跃值: (3274)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
111
2025-3-10 16:38
0
雪    币: 1839
活跃值: (2005)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
太好了
2025-3-10 16:56
0
雪    币: 7394
活跃值: (22445)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
22
看看
2025-3-10 17:06
0
雪    币: 230
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
23
6666
2025-3-10 17:34
0
雪    币: 375
活跃值: (2506)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
24
666
2025-3-10 17:34
0
雪    币: 253
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
25
牛啊牛啊
2025-3-10 22:08
1
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册