AndroidNative网络协议中请求加密、签名生成与响应解密机制逆向分析

admin 2026-07-22 06:06:08 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文逆向分析了Android应用BOSS直聘的Native网络协议加密机制。通过抓包发现请求参数sp和sig,利用FridaHook定位到加密函数,最终在so库中识别出LZ4压缩和RC4加密算法。分析揭示了请求体先经LZ4压缩再RC4加密生成sp,以及基于特定字符串拼接后签名生成sig的完整流程。该分析为理解应用层协议安全提供了实战参考。 综合评分: 88 文章分类: 逆向分析,实战经验,WEB安全,漏洞分析,安全工具


cover_image

Android Native 网络协议中请求加密、签名生成与响应解密机制逆向分析

lingyi223 lingyi223

看雪学苑

2026年7月20日 18:05 上海

在小说阅读器读本章

去阅读

sp

#

抓个包请求体,主要有sqh好像是对查询参数的封装,sig是一个hash签名:

params = {
'sp': 'zwp_NCTRJTSwi3Deh8DkHOCGvU04AYbyceqJ44s9CxuyL65jv20XaVYg1XpFLNVaF7LolNJtanuLr-ARNM136qI3RFO3xe8JyDZtt-TQVeh_TOtTgNw-LeFjEs8hx0tJoj7v9ncKmYZWKNui4my5Fc9Loyx67W-9L8MQyX1JatkuDl9Ec4gZFqDhg7Z1SBl0Q5EvXAZ_LJ35wN_c_ViiMlj3uGWAABuj9TFoIfCmIcIOaRu9i17K6XcsIJIEghrjY_AQsFedXLouh-p8zBzplaSLQy8yuaoULyZDqtdxw86gRZuOCUabqvRweZ50Ts-rnpqw0cJQkcepJGJbYAT2oPuMb9UvAxskJpjN8Vn5m9p8AC3Qf315z1Ph4lPo_uqiWXyB28eW9nIwZIgxKBLh2xOq54lTA5Ct31iIUOxoOj04438qYjIFex15STw8UT7JBX015qL0qMzCgA2hHNktJyB3aWKLQB9WA49WA4-3NPUFYeG9MG5ctKnjGm3rM_ExFlhOvCR8kzQpG-dlpneNXI7mrKm_h7YAuJvgGMvuYJykEqRFtRjqmY9PNSNjTWlVJ5rKy11ia6ww9XkqQ9O99CJD6yMDB1NvUMx1qKwI4Z6pOsWID9QSFgU2jyItA8casHba5AW_fneHDzDFA-4eMVDzE--jy9U3o0uhDlgpcEUGWdoQY3NpppAOpyt1Ba4Gp8eLiw6lMzGY2l-49oq2Q8tsJLJ14fQ0CoY-I6Bl2U4Y4pQiH0q-xzSVNWY7OkePHrfvEPLh0WU~',
'sig': 'V3.0da0bd61bc37b38f86b7cef6f5c641015',
'app_id': '1003',
}

hook一下hashMap定位

Java.perform(function (){
var hashMap = Java.use("java.util.HashMap");
    hashMap.put.implementation = function (a, b) {
if (a != null) {
var keyStr = a.toString();
if (keyStr === "sp" || keyStr === "sig") {
console.log(`检测到目标key: ${keyStr},value: ${b}`);
console.log("调用栈信息:");
var stackTrace = Java.use("java.lang.Thread").currentThread().getStackTrace();
for&nbsp;(var&nbsp;i =&nbsp;0; i < stackTrace.length; i++) {
console.log(` &nbsp;${stackTrace[i].toString()}`);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }
return&nbsp;this.put(a, b);
&nbsp; &nbsp; }
});
[M2011K2C::com.hpbr.bosszhipin ]-> 检测到目标key: sp,value: zwp_NCTRJTSwi3Deh8DkHOCGvU04AYbyceqJ44s9CxuyL65jv20XaVYg1XpFLNVaF7LolNJtanuLr-ARNM136qI3RFO3xe8JyDZtt-TQVeh_TOtTgNw-LeFjEs8hx0tJoj7v9ncKmYZWy5FcBDry1-4muxL8MQyX1JatkuDl9Ec4gZFqDhg7Z1SBl0Q5EvXAZ_LJ35wN_c_ViiMlj3uGWAABuj9TFoIfCmIcIOaRu9i17K6XcsIJIEghrjY_AQsFedXLouh-p8zBzplaSLQy8yuaoULyZDqtdxw86gRZuOCUabqvRweZ50Ts-rnpqw0cJQkcepJGJbYAT2oPuMb9UvAxskJpjN8Vn5m9p8AC3Qf315z1Ph4lPo_uqiWXyB28eW9nIwZIgxKBLh2xOq54lTA5Ct31iIUOxoOj04438qYjIFex15STw8UT7JBX015qL0qMzCgA2hHNktJyB3aWKLQB9WA49WA4-3NPUFYeG9MG5ctKnjGm3rM_ExFlhOvCR8kzQpG-dlpneNXI7mrKm_h7YAuJvgGMvuYJykEqRFtRjqmY9PNSNjTWlVJ5rKy11ia6ww9XkqQ9O99CJD6yMDB1NvUMx1qKwI4Z6pOsWID9QSFgU2jyItA8casHba5AW_fneHDzDFA-4eMVDzE--jy9U3o0uhDlgpcEUGWdoQY3NpppAOpyt1Ba4Gp8eLiw6lMzGY2l-49oq2Q8tsJLJ14fQ0CoY-I6Bl2U4Y4pQrFku-xzSVNWY7OkePHrfvEPLh0WU~
调用栈信息:
&nbsp; dalvik.system.VMStack.getThreadStackTrace(Native Method)
&nbsp; java.lang.Thread.getStackTrace(Thread.java:2842)
&nbsp; java.util.HashMap.put(Unknown Source)
&nbsp; jf0.b.w(SourceFile:30)
&nbsp; net.bosszhipin.base.m.f(SourceFile:67)
&nbsp; net.bosszhipin.base.m.c(SourceFile:127)
&nbsp; net.bosszhipin.base.k$a.a(SourceFile:21)
&nbsp; com.twl.http.client.AbsBatchApiRequest.getBatchParamsV3(SourceFile:100)

然后就看到这两行,都在:

String&nbsp;strD2 = com.twl.signer.a.d(strD, secretKey);
bVar.w("sp", strD2);
if&nbsp;(strD.length() >&nbsp;0x1388) {
strD = strD.substring(0x0,&nbsp;0x1388);
}
bVar.w("sig", com.twl.signer.a.i(com.hpbr.bosszhipin.config.m.f(str) + strD, secretKey));
public&nbsp;static&nbsp;String&nbsp;d(String&nbsp;str,&nbsp;String&nbsp;str2) {
String&nbsp;strEncodeRequest =&nbsp;YZWG.encodeRequest(str, str2);
b(strEncodeRequest,&nbsp;"");
return&nbsp;strEncodeRequest;
&nbsp; &nbsp; }

然后hook一下d函数就能知道参数什么的了,好像是一个类似与url编码的先不管了。

a.d is called: str=client_info=%7B%22version%22%3A%2216%22%2C%22os%22%3A%22Android%22%2C%22start_time%22%3A%221783348924685%22%2C%22resume_time%22%3A%221783348924685%22%2C%22channel%22%3A%220%22%2C%22model%22%3A%22Xiaomi%7C%7CM2011K2C%22%2C%22dzt%22%3A0%2C%22loc_per%22%3A0%2C%22uniqid%22%3A%22b93ddbdc-ccbe-4340-be6b-d070f2b1fd3a%22%2C%22oaid%22%3A%22NA%22%2C%22oaid_honor%22%3A%22NA%22%2C%22did%22%3A%22DUOJFPDWDfdBIkVuTvtq-PI5ItdBFw0gaNa9RFVPSkZQRFdEZmRCSWtWdVR2dHEtUEk1SXRkQkZ3MGdhTmE5c2h1%22%2C%22tinker_id%22%3A%22Prod-arm64-v8a-release-14.110.1411010_0629-10-29-16%22%2C%22is_bg_req%22%3A0%2C%22network%22%3A%22wifi%22%2C%22operator%22%3A%22CHN-CT%22%2C%22abi%22%3A1%2C%22version_flag%22%3A%221411010%22%7D&curidentity=0&req_time=1783349112261&uniqid=b93ddbdc-ccbe-4340-be6b-d070f2b1fd3a&v=14.110, str2=null

一直跟下去会调用一个native函数

private&nbsp;static&nbsp;native&nbsp;String&nbsp;nativeEncodeRequest(byte[] bArr, String str);

然后找一下动态注册的地址,可以用unidbg,和hook注册函数

RegisterNative(com/twl/signer/YZWG,&nbsp;nativeEncodeRequest([BLjava/lang/String;)Ljava/lang/String;, RX@0x4001f6ac[libyzwg.so]0x1f6ac)

直接上ida,找到对应函数交叉引用一下,很容易发现一个函数的入参就是它,然后用frida hook一下进一步验证。

找到函数根据LZ4_compress_limitedOutput重命名一下,然后搜一下,知道这里一个压缩的方法,下面的赋值操作应该是自定义文件头,out应该是输出缓冲区。

__int64 __fastcall&nbsp;LZ4(__int64 inputs, _DWORD *out, unsigned&nbsp;int&nbsp;len,&nbsp;int&nbsp;size)
{
&nbsp; __int64 result;&nbsp;// x0
int&nbsp;v7;&nbsp;// [xsp+8h] [xbp-28h]

&nbsp; v7 = LZ4_compress_limitedOutput(inputs);
if&nbsp;( v7 >&nbsp;0&nbsp;)
&nbsp; {
&nbsp; &nbsp; *out&nbsp;=&nbsp;'kcolBPZB';
out[2] =&nbsp;0;
out[3] = v7;
out[4] = len;
out[5] = len ^ v7;
&nbsp; &nbsp; LODWORD(result) = v7 +&nbsp;24;
&nbsp; }
else
&nbsp; {
&nbsp; &nbsp; LODWORD(result) = v7;
&nbsp; }
return&nbsp;result;
}

然后在对out进行交叉引用,很明显就能看到一下函数的入参,然后第一个参数和上面一个函数有关可以看一下。

RC4_Box(key, s_2, size);
rc4(key, out, out, n32);

特征也算是特别明显了,大概率是一个rc4的s_box初始化,s很可能就是密钥。

__int64 __fastcall&nbsp;RC4_Box(__int64 result,&nbsp;char&nbsp;*s,&nbsp;int&nbsp;a3){
char&nbsp;v3;&nbsp;// w1
&nbsp; __int64 v4;&nbsp;// x26
int&nbsp;i;&nbsp;// w11
char&nbsp;v6;&nbsp;// w1
int&nbsp;n256_1;&nbsp;// w14
unsigned&nbsp;__int8 v8;&nbsp;// w8
int&nbsp;j;&nbsp;// w26
unsigned&nbsp;__int8 v11;&nbsp;// [xsp+Ch] [xbp-74h]
int&nbsp;n256;&nbsp;// [xsp+18h] [xbp-68h]
unsigned&nbsp;__int8 v13;&nbsp;// [xsp+1Ch] [xbp-64h]

for&nbsp;( i =&nbsp;0; ; ++i )
&nbsp; {
while&nbsp;( y <&nbsp;10&nbsp;&& y >&nbsp;9&nbsp;)
&nbsp; &nbsp; &nbsp; ;
if&nbsp;( i >=&nbsp;256&nbsp;)
break;
&nbsp; &nbsp; *(result + i) = i;
&nbsp; }
&nbsp; n256_1 =&nbsp;0;
&nbsp; v8 =&nbsp;0;
&nbsp; *(result +&nbsp;256) =&nbsp;0;
for&nbsp;( j =&nbsp;-401696071; ; j =&nbsp;-401696071&nbsp;)
&nbsp; {
while&nbsp;( j ==&nbsp;-401696071&nbsp;)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; n256 = n256_1;
&nbsp; &nbsp; &nbsp; v13 = v8;
&nbsp; &nbsp; &nbsp; j =&nbsp;-85974536;
&nbsp; &nbsp; }
if&nbsp;( n256 >=&nbsp;256&nbsp;)
break;
while&nbsp;(&nbsp;1&nbsp;)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; v6 = *(result + n256);
&nbsp; &nbsp; &nbsp; v11 = s[n256 % a3] + v6 + v13;
&nbsp; &nbsp; &nbsp; *(result + n256) = *(result + v11);
&nbsp; &nbsp; &nbsp; *(result + v11) = v6;
if&nbsp;( y >=&nbsp;10&nbsp;|| y <=&nbsp;9&nbsp;)
break;
&nbsp; &nbsp; &nbsp; v3 = *(result + n256);
&nbsp; &nbsp; &nbsp; v4 = (v13 + s[n256 % a3] + v3);
&nbsp; &nbsp; &nbsp; *(result + n256) = *(result + v4);
&nbsp; &nbsp; &nbsp; *(result + v4) = v3;
&nbsp; &nbsp; }
&nbsp; &nbsp; v8 = v11;
&nbsp; &nbsp; n256_1 = n256 +&nbsp;1;
&nbsp; }
return&nbsp;result;
}

剩下这个就是rc4的加密函数了

__int64 __fastcall&nbsp;rc4(__int64 s_box, __int64 inputs, __int64 a3,&nbsp;int&nbsp;len){
int&nbsp;i;&nbsp;// w12
char&nbsp;v5;&nbsp;// w13
unsigned&nbsp;__int8 v6;&nbsp;// w12
unsigned&nbsp;__int8 v7;&nbsp;// w13
char&nbsp;v8;&nbsp;// w15
int&nbsp;i_1;&nbsp;// [xsp+Ch] [xbp-4h]

for&nbsp;( i =&nbsp;0; ; i = i_1 +&nbsp;1&nbsp;)
&nbsp; {
&nbsp; &nbsp; i_1 = i;
if&nbsp;( i >= len )
break;
&nbsp; &nbsp; v5 = *(s_box +&nbsp;257);
&nbsp; &nbsp; v6 = *(s_box +&nbsp;256) +&nbsp;1;
&nbsp; &nbsp; *(s_box +&nbsp;256) = v6;
&nbsp; &nbsp; v7 = v5 + *(s_box + v6);
&nbsp; &nbsp; *(s_box +&nbsp;257) = v7;
&nbsp; &nbsp; v8 = *(s_box + v6);
&nbsp; &nbsp; *(s_box + v6) = *(s_box + v7);
&nbsp; &nbsp; *(s_box + v7) = v8;
&nbsp; &nbsp; *(a3 + i_1) = *(s_box + (*(s_box + *(s_box +&nbsp;257)) + *(s_box + *(s_box +&nbsp;256)))) ^ *(inputs + i_1);
&nbsp; }
return&nbsp;s_box;
}

直接dump s_box

S_box&nbsp;= [0xbd,&nbsp;0x32,&nbsp;0x03,&nbsp;0xc7,&nbsp;0x6c,&nbsp;0x0e,&nbsp;0x77,&nbsp;0xcc,&nbsp;0xcb,&nbsp;0x40,&nbsp;0x97,&nbsp;0xab,&nbsp;0x17,&nbsp;0xcd,&nbsp;0x6b,&nbsp;0x7f,&nbsp;0x25,&nbsp;0xee,
0x6f,&nbsp;0x1a,&nbsp;0x44,&nbsp;0x18,&nbsp;0x89,&nbsp;0x11,&nbsp;0xbc,&nbsp;0xc0,&nbsp;0x26,&nbsp;0xfd,&nbsp;0xac,&nbsp;0x3a,&nbsp;0x7e,&nbsp;0x28,&nbsp;0x5f,&nbsp;0xa3,&nbsp;0xf5,&nbsp;0x47,
0xda,&nbsp;0x2e,&nbsp;0xfb,&nbsp;0xd4,&nbsp;0x2c,&nbsp;0xaa,&nbsp;0xdd,&nbsp;0x88,&nbsp;0x73,&nbsp;0xd0,&nbsp;0x06,&nbsp;0x46,&nbsp;0x24,&nbsp;0xd1,&nbsp;0xa5,&nbsp;0x3b,&nbsp;0xd3,&nbsp;0xc1,
0xa4,&nbsp;0x30,&nbsp;0xd2,&nbsp;0x29,&nbsp;0xaf,&nbsp;0x87,&nbsp;0x79,&nbsp;0x01,&nbsp;0x7a,&nbsp;0x22,&nbsp;0xad,&nbsp;0x9d,&nbsp;0x4c,&nbsp;0x27,&nbsp;0xdb,&nbsp;0x5b,&nbsp;0xf1,&nbsp;0x43,
0xea,&nbsp;0x3d,&nbsp;0x5e,&nbsp;0xfe,&nbsp;0xef,&nbsp;0xc8,&nbsp;0x7c,&nbsp;0x34,&nbsp;0x5a,&nbsp;0xde,&nbsp;0x75,&nbsp;0x60,&nbsp;0xae,&nbsp;0x23,&nbsp;0x82,&nbsp;0x0a,&nbsp;0x9f,&nbsp;0x48,
0x1c,&nbsp;0xe2,&nbsp;0x6e,&nbsp;0x61,&nbsp;0x16,&nbsp;0x1e,&nbsp;0x8e,&nbsp;0xd5,&nbsp;0xcf,&nbsp;0xfc,&nbsp;0xc6,&nbsp;0xc3,&nbsp;0x94,&nbsp;0x5d,&nbsp;0x71,&nbsp;0x4e,&nbsp;0x91,&nbsp;0x38,
0x5c,&nbsp;0x39,&nbsp;0x4d,&nbsp;0x58,&nbsp;0xe6,&nbsp;0x8a,&nbsp;0xca,&nbsp;0x9b,&nbsp;0x78,&nbsp;0x65,&nbsp;0x4b,&nbsp;0xe0,&nbsp;0xb9,&nbsp;0x8b,&nbsp;0xf8,&nbsp;0xff,&nbsp;0xb1,&nbsp;0x0c,
0x4f,&nbsp;0x41,&nbsp;0x80,&nbsp;0x15,&nbsp;0x8c,&nbsp;0x21,&nbsp;0x55,&nbsp;0x56,&nbsp;0x57,&nbsp;0xa8,&nbsp;0x96,&nbsp;0x90,&nbsp;0xba,&nbsp;0xb8,&nbsp;0x69,&nbsp;0x1f,&nbsp;0xc2,&nbsp;0x98,
0xb0,&nbsp;0x09,&nbsp;0xa9,&nbsp;0x3f,&nbsp;0x31,&nbsp;0x74,&nbsp;0x37,&nbsp;0xf6,&nbsp;0xbf,&nbsp;0xc9,&nbsp;0x49,&nbsp;0xa0,&nbsp;0x54,&nbsp;0x13,&nbsp;0x8f,&nbsp;0xbb,&nbsp;0x0d,&nbsp;0x14,
0x05,&nbsp;0xb5,&nbsp;0xbe,&nbsp;0x86,&nbsp;0x1d,&nbsp;0xa7,&nbsp;0x36,&nbsp;0x99,&nbsp;0xe4,&nbsp;0x72,&nbsp;0x0b,&nbsp;0xc4,&nbsp;0x20,&nbsp;0x10,&nbsp;0x12,&nbsp;0xf2,&nbsp;0xd9,&nbsp;0x42,
0x2a,&nbsp;0x64,&nbsp;0xd6,&nbsp;0x93,&nbsp;0xf4,&nbsp;0x63,&nbsp;0xe1,&nbsp;0x0f,&nbsp;0x51,&nbsp;0xed,&nbsp;0x7b,&nbsp;0x6a,&nbsp;0x7d,&nbsp;0x6d,&nbsp;0xe5,&nbsp;0x19,&nbsp;0x50,&nbsp;0x53,
0xb7,&nbsp;0xe9,&nbsp;0xf3,&nbsp;0xb6,&nbsp;0xd7,&nbsp;0x59,&nbsp;0xb4,&nbsp;0xf7,&nbsp;0xb2,&nbsp;0x08,&nbsp;0xd8,&nbsp;0x3e,&nbsp;0x33,&nbsp;0xb3,&nbsp;0x2b,&nbsp;0x62,&nbsp;0x04,&nbsp;0x8d,
0x70,&nbsp;0x95,&nbsp;0xa1,&nbsp;0x9e,&nbsp;0xe8,&nbsp;0x76,&nbsp;0xe7,&nbsp;0xce,&nbsp;0x84,&nbsp;0xa2,&nbsp;0x2f,&nbsp;0x9c,&nbsp;0xfa,&nbsp;0x3c,&nbsp;0x67,&nbsp;0x02,&nbsp;0xa6,&nbsp;0x83,
0xf9,&nbsp;0xdc,&nbsp;0x9a,&nbsp;0x2d,&nbsp;0x45,&nbsp;0x81,&nbsp;0xf0,&nbsp;0x85,&nbsp;0x4a,&nbsp;0xe3,&nbsp;0x00,&nbsp;0x68,&nbsp;0xec,&nbsp;0xdf,&nbsp;0x07,&nbsp;0x35,&nbsp;0x92,&nbsp;0x66,
0x1b,&nbsp;0xc5,&nbsp;0x52,&nbsp;0xeb,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x6e,&nbsp;0x77,&nbsp;0x48,&nbsp;0xb3,&nbsp;0xb5,&nbsp;0xd9,
0x54,&nbsp;0x90,&nbsp;0x60,&nbsp;0xeb,&nbsp;0x4a,&nbsp;0xde,&nbsp;0x78,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x40,&nbsp;0xab,&nbsp;0x4a,&nbsp;0x4a,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,
0x68,&nbsp;0x3f,&nbsp;0x0a,&nbsp;0x03,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00,&nbsp;0x02,&nbsp;0x00,&nbsp;0x00,&nbsp;0x00]
def&nbsp;rc4(inputs):
&nbsp; &nbsp; s_box = S_box.copy()
&nbsp; &nbsp; outputs = [0] * len(inputs)
for&nbsp;i in&nbsp;range(len(inputs)):
&nbsp; &nbsp; &nbsp; &nbsp; v5 = s_box[257]
&nbsp; &nbsp; &nbsp; &nbsp; v6 = (s_box[256] +&nbsp;1) &&nbsp;0xFF
&nbsp; &nbsp; &nbsp; &nbsp; s_box[256] =&nbsp;v6
v7&nbsp;=&nbsp;(v5 + s_box[v6]) &&nbsp;0xFF
&nbsp; &nbsp; &nbsp; &nbsp; s_box[257] =&nbsp;v7
v8&nbsp;=&nbsp;s_box[v6]
&nbsp; &nbsp; &nbsp; &nbsp; s_box[v6] = s_box[v7]
&nbsp; &nbsp; &nbsp; &nbsp; s_box[v7] =&nbsp;v8
part1&nbsp;=&nbsp;s_box[s_box[257]]
&nbsp; &nbsp; &nbsp; &nbsp; part2 = s_box[s_box[256]]
&nbsp; &nbsp; &nbsp; &nbsp; idx = (part1 + part2) &&nbsp;0xFF
&nbsp; &nbsp; &nbsp; &nbsp; keystream_byte = s_box[idx]
&nbsp; &nbsp; &nbsp; &nbsp; outputs[i] = (keystream_byte ^ inputs[i]) &&nbsp;0xFF

return&nbsp;outputs

然后经过base64就是我们的结果了

RC4_Box(key, s_2, size);
rc4(key,&nbsp;out,&nbsp;out, n32);
size_1 = sub_2EA10(n32);
ptr_2 = malloc(size_1);
base64(ptr_2,&nbsp;out, n32);

然后和标准base64对比一下,发现只替换了码表

BASE64_CHARS&nbsp;=&nbsp;"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"

lz4

def&nbsp;LZ4(inputs):
&nbsp; &nbsp; data = inputs.encode('utf-8')
&nbsp; &nbsp; original_len =&nbsp;len(data)
&nbsp; &nbsp; compressed = lz4.frame.compress(data).rstrip(b'\x00')
&nbsp; &nbsp; compressed_len =&nbsp;len(compressed) -&nbsp;19
print(hex(compressed_len))
&nbsp; &nbsp; header =&nbsp;bytearray(24)
&nbsp; &nbsp; header[0:8] = b'BZPBlock'
&nbsp; &nbsp; struct.pack_into('<I', header,&nbsp;12, compressed_len)
&nbsp; &nbsp; struct.pack_into('<I', header,&nbsp;16, original_len)
&nbsp; &nbsp; struct.pack_into('<I', header,&nbsp;20, original_len ^ compressed_len)
&nbsp; &nbsp; header.extend(compressed[19:])
&nbsp; &nbsp; return compressed

整理一下流程

参数封装->lz4压缩->rc4加密->魔改base64编码

#

sig

根据开始给出的地方直接定位,然后尝试hook

private&nbsp;static&nbsp;native&nbsp;byte[]&nbsp;nativeSignature(byte[] bArr, String str);

直接hook上一层的,可以直接看到String字符串

static&nbsp;String&nbsp;signature(String&nbsp;str,&nbsp;String&nbsp;str2) {
if&nbsp;(!loadSo()) {
return&nbsp;"";
&nbsp; &nbsp; &nbsp; &nbsp; }
try&nbsp;{
return&nbsp;bytes2String(nativeSignature(str.getBytes("UTF-8"), str2));
&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(UnsupportedEncodingException&nbsp;e11) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e11.printStackTrace();
return&nbsp;"";
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

可以看到和sq就是前后加了一点东西,1194187086好像是固定的是对一个字符串crc32的结果,跟一下看看。

a.i is called: str=/api/batch/requestsclient_info=%7B%22version%22%3A%2216%22%2C%22os%22%3A%22Android%22%2C%22start_time%22%3A%221783411220252%22%2C%22resume_time%22%3A%221783411220252%22%2C%22channel%22%3A%220%22%2C%22model%22%3A%22Xiaomi%7C%7CM2011K2C%22%2C%22dzt%22%3A0%2C%22loc_per%22%3A0%2C%22uniqid%22%3A%22b93ddbdc-ccbe-4340-be6b-d070f2b1fd3a%22%2C%22oaid%22%3A%22NA%22%2C%22oaid_honor%22%3A%22NA%22%2C%22did%22%3A%22DUOJFPDWDfdBIkVuTvtq-PI5ItdBFw0gaNa9RFVPSkZQRFdEZmRCSWtWdVR2dHEtUEk1SXRkQkZ3MGdhTmE5c2h1%22%2C%22tinker_id%22%3A%22Prod-arm64-v8a-release-14.110.1411010_0629-10-29-16%22%2C%22is_bg_req%22%3A0%2C%22network%22%3A%22wifi%22%2C%22operator%22%3A%22CHN-CT%22%2C%22abi%22%3A1%2C%22version_flag%22%3A%221411010%22%7D&curidentity=0&req_time=1783411794093&uniqid=b93ddbdc-ccbe-4340-be6b-d070f2b1fd3a&v=14.110&nbsp;1194187086, str2=null
a.i result=V3.0f1121a03da21087afeb5633e5898a6d8

这里拼接了一下strD

byte[] bArrE = com.twl.signer.a.e(yf0.n.h(batchBodyBeanD), secretKey);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bVar.y(bArrE);
StringstrA&nbsp;=&nbsp;com.twl.signer.a.a(bArrE);
longjElapsedRealtime&nbsp;=&nbsp;SystemClock.elapsedRealtime();
StringstrD2&nbsp;=&nbsp;com.twl.signer.a.d(strD, secretKey);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g(jElapsedRealtime, str, strD.length());
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bVar.w("sp", strD2);
if&nbsp;(strD.length() >&nbsp;0x1388) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; strD = strD.substring(0x0,&nbsp;0x1388);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bVar.w("sig", com.twl.signer.a.i(com.hpbr.bosszhipin.config.m.f(str) + strD + strA, secretKey));

直接看strA的结果跟下去就会知道是是一个crc32的运算,而且是标准的

[M2011K2C::com.hpbr.bosszhipin&nbsp;]-> a.a&nbsp;is&nbsp;called: bArr=-49,10,127,52,36,-47,3
a.a result=1194187086
private&nbsp;static&nbsp;native String&nbsp;nativeCalculateCRC32(byte[] bArr);

尝试了一下没定位到直接上unidbg补环境,还挺少的

@Override
public&nbsp;DvmObject<?>&nbsp;getStaticObjectField(BaseVM vm, DvmClass dvmClass,&nbsp;String&nbsp;signature) {
switch&nbsp;(signature) {
case&nbsp;"com/twl/signer/YZWG->gContext:Landroid/content/Context;":{
return&nbsp;vm.resolveClass("android/content/Context").newObject(null);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }
return&nbsp;super.getStaticObjectField(vm,dvmClass,signature);
&nbsp; &nbsp; }
@Override
public&nbsp;DvmObject<?>&nbsp;callObjectMethod(BaseVM vm, DvmObject<?> dvmObject,&nbsp;String&nbsp;signature, VarArg varArg) {
switch&nbsp;(signature) {
case&nbsp;"android/content/pm/PackageManager->getPackagesForUid(I)[Ljava/lang/String;":{
return&nbsp;new&nbsp;ArrayObject(new&nbsp;StringObject(vm, vm.getPackageName()));
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }
return&nbsp;super.callObjectMethod(vm,dvmObject,signature,varArg);
&nbsp; &nbsp; }
@Override
public&nbsp;int&nbsp;callIntMethod(BaseVM vm, DvmObject<?> dvmObject,&nbsp;String&nbsp;signature, VarArg varArg) {
if&nbsp;(signature.equals("java/lang/String->hashCode()I")){
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int i = dvmObject.getValue().toString().hashCode();
return&nbsp;i;
&nbsp; &nbsp; &nbsp; &nbsp; }
return&nbsp;super.callIntMethod(vm, dvmObject, signature, varArg);
&nbsp; &nbsp; }

写一个函数调用一下顺便写一个trace

&nbsp; &nbsp; public String getSign() throws UnsupportedEncodingException {
&nbsp; &nbsp; &nbsp; &nbsp; DvmClass CheckSignUtil = vm.resolveClass("com/twl/signer/YZWG");
&nbsp; &nbsp; &nbsp; &nbsp; String method =&nbsp;"nativeSignature([BLjava/lang/String;)[B";
&nbsp; &nbsp; &nbsp; &nbsp; String str =&nbsp;"/api/batch/requestsclient_info=%7B%22version%22%3A%2216%22%2C%22os%22%3A%22Android%22%2C%22start_time%22%3A%221783429715302%22%2C%22resume_time%22%3A%221783429715302%22%2C%22channel%22%3A%220%22%2C%22model%22%3A%22Xiaomi%7C%7CM2011K2C%22%2C%22dzt%22%3A0%2C%22loc_per%22%3A0%2C%22uniqid%22%3A%22b93ddbdc-ccbe-4340-be6b-d070f2b1fd3a%22%2C%22oaid%22%3A%22NA%22%2C%22oaid_honor%22%3A%22NA%22%2C%22did%22%3A%22DUOJFPDWDfdBIkVuTvtq-PI5ItdBFw0gaNa9RFVPSkZQRFdEZmRCSWtWdVR2dHEtUEk1SXRkQkZ3MGdhTmE5c2h1%22%2C%22tinker_id%22%3A%22Prod-arm64-v8a-release-14.110.1411010_0629-10-29-16%22%2C%22is_bg_req%22%3A0%2C%22network%22%3A%22wifi%22%2C%22operator%22%3A%22CHN-CT%22%2C%22abi%22%3A1%2C%22version_flag%22%3A%221411010%22%7D&curidentity=0&req_time=1783435136897&uniqid=b93ddbdc-ccbe-4340-be6b-d070f2b1fd3a&v=14.1101194187086";
&nbsp; &nbsp; &nbsp; &nbsp; byte[] bytes = str.getBytes();
&nbsp; &nbsp; &nbsp; &nbsp; DvmObject<?> resultObj = CheckSignUtil.callStaticJniMethodObject(emulator, method, new ByteArray(vm, bytes), null);
if&nbsp;(resultObj instanceof ByteArray){
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByteArray bytesResult= (ByteArray)resultObj;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte[] value = bytesResult.getValue();
return&nbsp;new String(value,"UTF-8");
&nbsp; &nbsp; &nbsp; &nbsp; }
return&nbsp;"";
&nbsp; &nbsp; }
void&nbsp;traceCode(){
StringtraceFile&nbsp;="D:\\unidbg-0.9.8\\unidbg-0.9.8\\unidbg-android\\src\\test\\java\\boss\\getSign.log";
PrintStreamtraceStream&nbsp;=null;
try&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; traceStream =&nbsp;new&nbsp;PrintStream(new&nbsp;FileOutputStream(traceFile),&nbsp;true);
&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(FileNotFoundException e) {
throw&nbsp;new&nbsp;RuntimeException(e);
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; emulator.traceCode(module.base,&nbsp;module.base+module.size).setRedirect(traceStream);
&nbsp; &nbsp; }
V3.0c54cce74b6d5d969b1abd0e9d825eedf

然后搜索最后1字节,定位到这里,然后根据这个地址搜,进一步验证

[13:04:27 689][libyzwg.so 0x01c9a8][63696a38]0x4001c9a8:&nbsp;"ldrb w3, [x11, x10]"&nbsp;x11=0xbffff570 x10=0xf => w3=0xdf

然后可以看到这个函数,hook一下入参

char&nbsp;*__fastcall&nbsp;sub_1C6E0(_BYTE *ptr,&nbsp;int&nbsp;n){
int&nbsp;n16;&nbsp;// w21
int&nbsp;v3;&nbsp;// w8
char&nbsp;*v7;&nbsp;// [xsp+30h] [xbp-F0h]
&nbsp; _BYTE v8[16];&nbsp;// [xsp+50h] [xbp-D0h] BYREF
&nbsp; _BYTE v9[88];&nbsp;// [xsp+60h] [xbp-C0h] BYREF
&nbsp; __int64 v10;&nbsp;// [xsp+B8h] [xbp-68h]

&nbsp; v10 = *(_ReadStatusReg(TPIDR_EL0) +&nbsp;40);
&nbsp; v7 =&nbsp;malloc(0x21u);
sub_2EE84(v9);
while&nbsp;( n >&nbsp;0&nbsp;)
&nbsp; {
if&nbsp;( n >&nbsp;512&nbsp;)
&nbsp; &nbsp; {
sub_2EE98(v9, ptr,&nbsp;512);
if&nbsp;( v3 ==&nbsp;-381856710&nbsp;)
goto&nbsp;LABEL_4;
&nbsp; &nbsp; }
else
&nbsp; &nbsp; {
sub_2EE98(v9, ptr, n);
&nbsp; &nbsp; }
&nbsp; &nbsp; n -=&nbsp;512;
&nbsp; &nbsp; ptr +=&nbsp;512;
&nbsp; }
md5(v8, v9); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// ;关键函数
&nbsp; n16 =&nbsp;0;
LABEL_4:
while&nbsp;( n16 <&nbsp;16&nbsp;)
&nbsp; {
snprintf(
&nbsp; &nbsp; &nbsp; &v7[2&nbsp;* n16],
0x20u,
&nbsp; &nbsp; &nbsp; aDqs9a, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// "dqs9A"
&nbsp; &nbsp; &nbsp; v8[n16]);
&nbsp; &nbsp; ++n16;
&nbsp; }
return&nbsp;v7;
}

前面和入参相容的,然后新增了不知道是hash还是啥,trace看一下

size: 900
0000: 2F 61 70 69 2F 62 61 74 63 68 2F 72 65 71 75 65 &nbsp; &nbsp;/api/batch/reque
0010: 73 74 73 63 6C 69 65 6E 74 5F 69 6E 66 6F 3D 25 &nbsp; &nbsp;stsclient_info=%
0020: 37 42 25 32 32 76 65 72 73 69 6F 6E 25 32 32 25 &nbsp; &nbsp;7B%22version%22%
0030: 33 41 25 32 32 31 36 25 32 32 25 32 43 25 32 32 &nbsp; &nbsp;3A%2216%22%2C%22
0040: 6F 73 25 32 32 25 33 41 25 32 32 41 6E 64 72 6F &nbsp; &nbsp;os%22%3A%22Andro
0050: 69 64 25 32 32 25 32 43 25 32 32 73 74 61 72 74 &nbsp; &nbsp;id%22%2C%22start
0060: 5F 74 69 6D 65 25 32 32 25 33 41 25 32 32 31 37 &nbsp; &nbsp;_time%22%3A%2217
0070: 38 33 34 32 39 37 31 35 33 30 32 25 32 32 25 32 &nbsp; &nbsp;83429715302%22%2
0080: 43 25 32 32 72 65 73 75 6D 65 5F 74 69 6D 65 25 &nbsp; &nbsp;C%22resume_time%
02F0: 6E 69 71 69 64 3D 62 39 33 64 64 62 64 63 2D 63 &nbsp; &nbsp;niqid=b93ddbdc-c
0300: 63 62 65 2D 34 33 34 30 2D 62 65 36 62 2D 64 30 &nbsp; &nbsp;cbe-4340-be6b-d0
0310: 37 30 66 32 62 31 66 64 33 61 26 76 3D 31 34 2E &nbsp; &nbsp;70f2b1fd3a&v=14.
0320: 31 31 30 31 31 39 34 31 38 37 30 38 36 61 33 30 &nbsp; &nbsp;1101194187086a30
0330: 38 66 33 36 32 38 62 33 66 33 39 66 37 64 33 35 &nbsp; &nbsp;8f3628b3f39f7d35
0340: 63 64 65 62 65 62 36 39 32 30 65 32 31 00 00 00 &nbsp; &nbsp;cdebeb6920e21...

hex to str 发现就是我们要的结果

[13:16:54&nbsp;578] Memory WRITE at&nbsp;0x40759335,&nbsp;data&nbsp;size =&nbsp;8,&nbsp;data&nbsp;value =&nbsp;0x3766393366336238, PC=RX@0x405ac184[libc.so]0x1c184, LR=RX@0x40024354[libyzwg.so]0x24354
[13:16:54&nbsp;578] Memory WRITE at&nbsp;0x4075933d,&nbsp;data&nbsp;size =&nbsp;8,&nbsp;data&nbsp;value =&nbsp;0x6562656463353364, PC=RX@0x405ac18c[libc.so]0x1c18c, LR=RX@0x40024354[libyzwg.so]0x24354
[13:16:54&nbsp;578] Memory WRITE at&nbsp;0x40759345,&nbsp;data&nbsp;size =&nbsp;8,&nbsp;data&nbsp;value =&nbsp;0x3132653032393662, PC=RX@0x405ac18c[libc.so]0x1c18c, LR=RX@0x40024354[libyzwg.so]0x24354
[13:16:54&nbsp;578] Memory WRITE at&nbsp;0x4075934d,&nbsp;data&nbsp;size =&nbsp;1,&nbsp;data&nbsp;value =&nbsp;0x00, PC=RX@0x40023ed8[libyzwg.so]0x23ed8, LR=RX@0x40024354[libyzwg.so]0x24354

是一个复制函数,下个断点看看

.text:0000000000024350 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.memcpy
mx1

>-----------------------------------------------------------------------------<
[13:21:11 776]x1=RW@0x40753030, md5=0a461c2d0db818ee663f9c7607f4dd08, hex=61333038663336323862336633396637643335636465626562363932306532310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
size: 112
0000: 61 33 30 38 66 33 36 32 38 62 33 66 33 39 66 37 &nbsp; &nbsp;a308f3628b3f39f7
0010: 64 33 35 63 64 65 62 65 62 36 39 32 30 65 32 31 &nbsp; &nbsp;d35cdebeb6920e21
0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &nbsp; &nbsp;................
0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &nbsp; &nbsp;................
0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &nbsp; &nbsp;................
0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &nbsp; &nbsp;................
0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 &nbsp; &nbsp;................
^-----------------------------------------------------------------------------^

接着对0x40753030进行追踪

[13:22:30&nbsp;314] Memory WRITE at&nbsp;0x40753030,&nbsp;data&nbsp;size =&nbsp;8,&nbsp;data&nbsp;value =&nbsp;0x3236336638303361, PC=RX@0x40029000[libyzwg.so]0x29000, LR=RX@0x40028ff0[libyzwg.so]0x28ff0
[13:22:30&nbsp;314] Memory WRITE at&nbsp;0x40753038,&nbsp;data&nbsp;size =&nbsp;8,&nbsp;data&nbsp;value =&nbsp;0x3766393366336238, PC=RX@0x40029000[libyzwg.so]0x29000, LR=RX@0x40028ff0[libyzwg.so]0x28ff0
[13:22:30&nbsp;315] Memory WRITE at&nbsp;0x40753040,&nbsp;data&nbsp;size =&nbsp;8,&nbsp;data&nbsp;value =&nbsp;0x6562656463353364, PC=RX@0x40029000[libyzwg.so]0x29000, LR=RX@0x40028ff0[libyzwg.so]0x28ff0

发现是在Jni_onload里面的,并且是对某个数据的rc4,我就没管了,因为这玩意只执行一次我觉得他是固定的,有兴趣可以看看。

RC4_Box(s_box, s, v4);
rc4(s_box, &inputs_, v13,&nbsp;32);
&nbsp; &nbsp; &nbsp; v14 =&nbsp;0;
&nbsp; &nbsp; &nbsp; s_1 =&nbsp;malloc(0x21u);
&nbsp; &nbsp; &nbsp; v6 = v13[1];
&nbsp; &nbsp; &nbsp; v7 = v13[0];

入参已经弄清楚了,这个追踪入参,然后看一下这个函数,进去瞎点点看看

.text:000000000001C958 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;md5
void&nbsp;__fastcall&nbsp;md5(__int64 ptr, __int64 a2){
unsignedint&nbsp;n0x38;&nbsp;// w8
int&nbsp;n120;&nbsp;// w9
unsignedint&nbsp;i;&nbsp;// w12
&nbsp; _BYTE ptra[8];&nbsp;// [xsp+10h] [xbp-50h] BYREF
&nbsp; __int64 v8;&nbsp;// [xsp+18h] [xbp-48h]

&nbsp; v8 = *(_ReadStatusReg(TPIDR_EL0) +&nbsp;40);
sub_33A8C(ptra, a2 +&nbsp;16,&nbsp;8u);
&nbsp; n0x38 = (*(a2 +&nbsp;16) >>&nbsp;3) &&nbsp;0xE000003F;
if&nbsp;( n0x38 >=&nbsp;0x38&nbsp;)
&nbsp; &nbsp; n120 =&nbsp;120;
else
&nbsp; &nbsp; n120 =&nbsp;56;
sub_2EE98(a2, ::ptr, n120 - n0x38);
sub_2EE98(a2, ptra,&nbsp;8u);
sub_33A8C(ptr, a2,&nbsp;0x10u);
for&nbsp;( i =&nbsp;0; i <&nbsp;0x58; ++i )
&nbsp; &nbsp; *(a2 + i) =&nbsp;0;
}

sub_2EE98

__int64 __fastcall&nbsp;sub_2EE98(_DWORD *n1575040482, _BYTE *ptr,&nbsp;unsignedint&nbsp;n512){
unsignedint&nbsp;v4;&nbsp;// w10
&nbsp; __int64 v5;&nbsp;// kr00_8
&nbsp; __int64 n1575040482_1;&nbsp;// x2
unsignedint&nbsp;i;&nbsp;// w8
&nbsp; __int64 v10;&nbsp;// [xsp+10h] [xbp-A0h]
unsignedint&nbsp;v11;&nbsp;// [xsp+18h] [xbp-98h]
unsignedint&nbsp;i_2;&nbsp;// [xsp+1Ch] [xbp-94h]
unsignedint&nbsp;v14;&nbsp;// [xsp+30h] [xbp-80h]
unsignedint&nbsp;v15;&nbsp;// [xsp+38h] [xbp-78h]
unsignedint&nbsp;i_1;&nbsp;// [xsp+4Ch] [xbp-64h]

&nbsp; v10 = (n1575040482 +&nbsp;6);
&nbsp; v4 = n1575040482[4];
&nbsp; v5 =&nbsp;8LL&nbsp;* n512;
&nbsp; v14 = (v4 >>&nbsp;3) &&nbsp;0xE000003F;
&nbsp; v15 =&nbsp;8&nbsp;* n512 + v4;
&nbsp; n1575040482[4] = v15;
if&nbsp;( v15 < v5 )
&nbsp; &nbsp; ++n1575040482[5];
&nbsp; n1575040482[5] +=&nbsp;HIDWORD(v5);
if&nbsp;(&nbsp;64&nbsp;- v14 > n512 )
&nbsp; {
&nbsp; &nbsp; v11 = (v4 >>&nbsp;3) &&nbsp;0xE000003F;
&nbsp; &nbsp; i_2 =&nbsp;0;
&nbsp; }
else
&nbsp; {
sub_2F3C0(n1575040482 + v14 +&nbsp;24, ptr,&nbsp;64&nbsp;- v14,&nbsp;0xC222DE52LL,&nbsp;0xD7B3D641LL,&nbsp;0x56D9A8A1);
hash(n1575040482, v10, n1575040482_1);
for&nbsp;( i =&nbsp;64&nbsp;- v14; ; i = i_1 +&nbsp;64&nbsp;)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; i_1 = i;
if&nbsp;( i +&nbsp;63&nbsp;>= n512 )
break;
hash(n1575040482, &ptr[i],&nbsp;3530282178LL);
&nbsp; &nbsp; }
&nbsp; &nbsp; v11 =&nbsp;0;
&nbsp; &nbsp; i_2 = i;
&nbsp; }
return&nbsp;sub_2F3C0(n1575040482 + v11 +&nbsp;24, &ptr[i_2], n512 - i_2,&nbsp;0xC222DE52LL,&nbsp;0xD7B3D641LL,&nbsp;0x56D9A8A1);
}

hash看到4轮密钥,很可能是一个md5啥的(其实,看见是hash算法后,我就拿着明文找个在线网站取测了),而且还是标准的。

&nbsp; v383 = a2;
&nbsp; n1575040482_1 = n1575040482_3;
&nbsp; StatusReg = _ReadStatusReg(TPIDR_EL0);
&nbsp; v392 = *(StatusReg +&nbsp;40);
&nbsp; v389 =&nbsp;1;
&nbsp; v390 = y_7 <&nbsp;10;
if&nbsp;( ((v389 | v390) &&nbsp;1) ==&nbsp;0&nbsp;)
goto&nbsp;LABEL_3;
while&nbsp;(&nbsp;1&nbsp;)
&nbsp; {
&nbsp; &nbsp; v185 = *n1575040482_1;
&nbsp; &nbsp; v186 = n1575040482_1[1];
&nbsp; &nbsp; v187 = n1575040482_1[2];
&nbsp; &nbsp; v188 = n1575040482_1[3];

signEnd&nbsp;= binascii.crc32(bytes(sign))
signBody&nbsp;=&nbsp;"/api/batch/requests"&nbsp;+ sqBody + str(signEnd) +&nbsp;"a308f3628b3f39f7d35cdebeb6920e21"
sign&nbsp;=&nbsp;"V3.0"&nbsp;+ hashlib.md5(signBody.encode()).hexdigest()

整个流程大概清楚了

响应解密

#

继续看这个java类非常的友好,nativeDecodeContent名字一看就是解密的。

&nbsp;private static native String&nbsp;nativeCalculateCRC32(byte[] bArr);

&nbsp; &nbsp; private static native byte[]nativeDecodeContent(String str, String str2);

&nbsp; &nbsp; private static native byte[]nativeDecodeContent(byte[] bArr, String str, int i11, int i12, int i13);

&nbsp; &nbsp; private static native byte[]nativeDecodePassword(String str);

&nbsp; &nbsp; private static native byte[]nativeDecodeRequestBody(byte[] bArr, String str);

&nbsp; &nbsp; private static native String&nbsp;nativeEncodeData(byte[] bArr, String str);

&nbsp; &nbsp; private static native String&nbsp;nativeEncodePassword(String str);

&nbsp; &nbsp; private static native String&nbsp;nativeEncodeRequest(byte[] bArr, String str);

&nbsp; &nbsp; private static native byte[]nativeEncodeRequestBody(byte[] bArr, String str);

&nbsp; &nbsp; private static native byte[]nativeSignature(byte[] bArr, String str);

然后根据入参定位一下,然后在根据这个函数的入参,继续trace

ptr&nbsp;= lz4(&v57, ptr_1, ptr_4, ptr_11, &v57);// ;这里已经解密了
emulator.attach().addBreakPoint(module.base +&nbsp;0x2765C);
emulator.attach().addBreakPoint(module.base +&nbsp;0x26354);
emulator.traceWrite(0x40447000,0x40447000 +&nbsp;0x10);
[13:42:54&nbsp;030] Memory WRITE at&nbsp;0x40447000,&nbsp;data&nbsp;size =&nbsp;1,&nbsp;data&nbsp;value =&nbsp;0x42, PC=RX@0x4003476c[libyzwg.so]0x3476c, LR=RX@0x40025c20[libyzwg.so]0x25c20
[13:42:54&nbsp;030] Memory WRITE at&nbsp;0x40447001,&nbsp;data&nbsp;size =&nbsp;1,&nbsp;data&nbsp;value =&nbsp;0x5a, PC=RX@0x4003476c[libyzwg.so]0x3476c, LR=RX@0x40025c20[libyzwg.so]0x25c20
[13:42:54&nbsp;030] Memory WRITE at&nbsp;0x40447002,&nbsp;data&nbsp;size =&nbsp;1,&nbsp;data&nbsp;value =&nbsp;0x50, PC=RX@0x4003476c[libyzwg.so]0x3476c, LR=RX@0x40025c20[libyzwg.so]0x25c20
[13:42:54&nbsp;030] Memory WRITE at&nbsp;0x40447003,&nbsp;data&nbsp;size =&nbsp;1,&nbsp;data&nbsp;value =&nbsp;0x42, PC=RX@0x4003476c[libyzwg.so]0x3476c, LR=RX@0x40025c20[libyzwg.so]0x25c20
[13:42:54&nbsp;030] Memory WRITE at&nbsp;0x40447004,&nbsp;data&nbsp;size =&nbsp;1,&nbsp;data&nbsp;value =&nbsp;0x6c, PC=RX@0x4003476c[libyzwg.so]0x3476c, LR=RX@0x40025c20[libyzwg.so]0x25c20
[13:42:54&nbsp;030] Memory WRITE at&nbsp;0x40447005,&nbsp;data&nbsp;size =&nbsp;1,&nbsp;data&nbsp;value =&nbsp;0x6f, PC=RX@0x4003476c[libyzwg.so]0x3476c, LR=RX@0x40025c20[libyzwg.so]0x25c20
[13:42:54&nbsp;030] Memory WRITE at&nbsp;0x40447006,&nbsp;data&nbsp;size =&nbsp;1,&nbsp;data&nbsp;value =&nbsp;0x63, PC=RX@0x4003476c[libyzwg.so]0x3476c, LR=RX@0x40025c20[libyzwg.so]0x25c20
[13:42:54&nbsp;030] Memory WRITE at&nbsp;0x40447007,&nbsp;data&nbsp;size =&nbsp;1,&nbsp;data&nbsp;value =&nbsp;0x6b, PC=RX@0x4003476c[libyzwg.so]0x3476c, LR=RX@0x40025c20[libyzwg.so]0x25c20

还是rc4

&nbsp; &nbsp; v10 =&nbsp;strlen(s);
RC4_Box(s_box, s, v10);
rc4(s_box, ptr, ptr, len);
if&nbsp;( y_107 >=&nbsp;10&nbsp;|| y_107 <=&nbsp;9&nbsp;)
def&nbsp;nativeDecodeContent(cont):
&nbsp; &nbsp; decrypted =&nbsp;rc4(cont)
&nbsp; &nbsp; length = struct.unpack_from('<I',&nbsp;bytes(decrypted)[16:20])[0]
&nbsp; &nbsp; lz = lz4.block.decompress(bytes(decrypted)[24:], length)
&nbsp; &nbsp; text = lz.decode('utf-8')
print(json.loads(text))

流程:rc4解密->lz4解压

参数基本都完成了,看看效果,非常nice

#

看雪ID:lingyi223

https://bbs.kanxue.com/user-home-1043807.htm

*本文为看雪论坛优秀文章,由 lingyi223 原创,转载请注明来自看雪社区

第十届安全开发者峰会【议题征集】-欢迎投稿

往期推荐

一道简单但不简约的堆题——CISCN2026初赛堆题robo分析

第二届软件系统安全赛决赛 StudentManagement 详解

APP整体加固原理

获取SYS加载方源头进程的方案-基于ETW技术

libmsaoaidsec.so 检测监测——绕过 Hook 脚本

球分享

球点赞

球在看

点击阅读原文查看更多


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:看雪学苑 lingyi223 lingyi223《Android Native 网络协议中请求加密、签名生成与响应解密机制逆向分析》

评论:0   参与:  0