news 2026/4/23 11:07:13

新版喜马拉雅Ollvm混淆Signature参数解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
新版喜马拉雅Ollvm混淆Signature参数解析

案例为最新版某马拉雅,可在豌豆夹下载

抓包

发送验证码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

POST /mobile/sms/v3/send HTTP/2

host: passport.ximalaya.com

cookie: 1&_device=android&d13a02e8-8efe-3427-80d8-e9347afe3e63&9.4.21;channel=and-f5;impl=com.ximalaya.ting.android;osversion=29;fp=009527657x2222q22264v0500700000000000000000000000000000000000;device_model=Pixel+2+XL;XIM=;c-oper=%E6%9C%AA%E7%9F%A5;net-mode=WIFI;res=1440%2C2712;AID=YTBiNTZmNjE1NTc2ODcyYQ==;manufacturer=Google;XD=SwmCBcM0DUJdkboCzp7x4FOk8Sp6aAtdSin4EsgNbx7+LoTgvWvpnD0fJ9tPskX9e1UXnLxL3Bn06ANSvQ+LCerM3eC5cDACyylaE7O3AW2dCDBfUBXa7UlnA6pbyIEe;xm_grade=0;specialModeStatus=0;

cookie2: $version=1

accept: */*

user-agent: ting_9.4.21(Pixel+2+XL,Android29)

x-tk: TACaS_-ndE6AuiO_jQngNjpNHr-PmPYLLD6cS5y7RNafhjt4EGQcET4NNoJs_RgxpBcO8_6aq6Dos-dtDmhvp9dYDhJKt9jb20ueGltYWxheWEudGluZy5hbmRyb2lkITEuMy4yNyE5LjQuMjEuMyFiPXBhc3Nwb3J0JnM9bG9naW4mdT0w

http_dns_address: old,d_s=false;d_g=true;d_f=true;d_i=false;p=false;h=false

content-type: application/json; charset=utf-8

content-length: 1165

accept-encoding: gzip

{"fdsOtp":"{}",

"biz":"1",

"signature":"e4cf26b5e716127762507811a4c747cf8e127a6f",

"mobile":"",

"sendType":"1",

"nonce":"0-224742D9E414bf681cef6aa5dfb1440934eba4d3a13a82532c3cbca33a3d8a"}

我们主要分析signature参数,signature长度为40,大概率为SHA1

逆向分析

发送验证码参数signature

首先搜索请求体字段中的fdsOtp定位关键代码

总共有三个,分别对应不同的登录形式,我们只关注验证码登录即可

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

privatevoidb(String str2) {

HashMap map =newHashMap();

if(AnonymousClass11.this.f72593c !=null) {

if(AnonymousClass11.this.f72593c.containsKey("mobile")) {

map.put("mobile", (String) AnonymousClass11.this.f72593c.get("mobile"));

}

map.put("sendType", (String) AnonymousClass11.this.f72593c.get("sendType"));

}

map.put("nonce", str);

if(!TextUtils.isEmpty(str2)) {

map.put("fdsOtp", str2);

}

map.put(com.alipay.sdk.app.statistic.c.f5786b, AnonymousClass11.this.f72592b +"");

map.put("signature", LoginRequest.b(AnonymousClass11.this.f72594d, map));

LoginRequest.f72585b = System.currentTimeMillis();

LoginRequest.a(AnonymousClass11.this.f72594d, k.a().j(), map, AnonymousClass11.this.f72591a,newcom.ximalaya.ting.android.loginservice.b.a<BaseResponse>() {// from class: com.ximalaya.ting.android.loginservice.LoginRequest.11.1.2

@Override// com.ximalaya.ting.android.loginservice.b.a

/* renamed from: a, reason: merged with bridge method [inline-methods] */

publicBaseResponse b(String str3)throwsException {

return(BaseResponse)newGson().fromJson(str3, BaseResponse.class);

}

});

}

可以发现signature参数的生成与代码

1

map.put("signature", LoginRequest.b(AnonymousClass11.this.f72594d, map));

有关,追踪,最终定位到

最终定位到此处代码,发现需要分析so层实现内容(login_encrypt),为了更清楚的分析,我们需要先了解进入so层前传入的参数是什么形式,

打印传入的参数,内容为:

1

2

3

4

5

z = false

str = biz=1&fdsOtp={"captcha_id":"3723312ce42a04b5c0b40e605a882037","lot_number":"b48afede55594f09ba5c82b9593b7402","pass_token":"a6d1832f7fe4a37776e5b5d610b2c45f42dd2d00007f061f3c4e20613a67f22a","gen_time":"1764764163","captcha_output":"2Z76G2CapbcJxb3z0NRv6M3hvdvpPpJiZYrOHqnYCvDSbFN1VW0MwSEZ3bzVLqngdIUnBFLqkqeiuyHwBeNxxkik34W9dQ5VNZm9JK-HSYpcxrp0NAOilcOY2Hvd1fNbL1gaiSbmgIg2vkSkBKcNidZdAs6JYmiWSCWjxwaE_iQXvm1gZABlsGsilYp-owYg05gxV5FZ70aYkw5cjkllOPITxWc_B7js3HAoApNEamZuLa0mKyHoTKcpRf41IXVgauvjOHYhM2nXeiif08NADj8Ho4NaELWsS2qZD01zZNtT0AWOZuE_z85Kgy3XHDHKm6hNryiY_0XtMaVPUWHalIbmumT1UetSWnZmhOnaxiQfob3m4-9gSby6csz3TM_EgSoRlWbM_cA7aDcQ8uapUlDXi3caucce-a7rHF31LnJOdVcWw-0OS13zo-xh-cD0qkilsQ3wPKe94ESLrSFxR2W8Avfuin5zYpWW49U6cllffSicGk4B7fKO0mkVZMrHl9E5KxX0n4zG4-cED9B4kasrOrbirl8rWEQjFgVwUog="}&mobile=epMimImhTRIy8xX0F3mQa5ccuLd7UtpUEwpkLKp6KYE87t/GhiVYaGzhkFvctWeBhYP8xqpKEzwo

co/J+Zl6fOlaSRCa/3VGkQswp+W0eaZw9JXTSpFTj7yX6sB17qgQIecCwT4z1WpcK85lwyY6iSvE

8Ml8sVmq/VHvc6FI7fQ=

&nonce=0-3E044F385FFB3fa71dad20ad2190576fdf24e4d639e8b3a3b76fbbc3ba03ec&sendType=1&

发现so层代码将近2500行,存在Ollvm混淆

我们从头开始分析代码

修正函数头之后,先分析前几行代码

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

int*__fastcall sub_10F8(inta1,inta2)

{

inti;// r0

intv4;// r4

intv5;// r9

unsignedintv6;// r0

intv7;// r2

boolv8;// zf

intv9;// r2

int*v12;// [sp+4h] [bp-34h]

boolv13;// [sp+12h] [bp-26h]

boolv14;// [sp+13h] [bp-25h]

intv15;// [sp+14h] [bp-24h]

boolv16;// [sp+1Bh] [bp-1Dh]

v13 = (((x_149 * (x_149 - 1)) ^ 0xFFFFFFFE) & (x_149 * (x_149 - 1))) == 0;

v14 = y_150 < 10;

v12 = &y_150;

for( i = 642638909; ; i = 1890200666 )

{

LABEL_14:

while( i <= 642638908 )

{

i = 1448165231;

if( v16 )

i = -1518418466;

if( i <= -64863450 )

{

while( 1 )

{

LABEL_3:

while( i == -2015175878 )

{

v4 = (*(int(__fastcall **)(int,void*))(*(_DWORD *)a1 + 24))(a1, &unk_1B010);

(*(void(__fastcall **)(int,int,char*,char*))(*(_DWORD *)a1 + 132))(a1, v4, &byte_1B02F, &byte_1B040);

(*(void(__fastcall **)(int,int))(*(_DWORD *)a1 + 92))(a1, v4);

i = -957104787;

}

if( i != -957104787 )

break;

v5 = (*(int(__fastcall **)(int,void*))(*(_DWORD *)a1 + 24))(a1, &unk_1B010);

v15 = (*(int(__fastcall **)(int,int,char*,char*))(*(_DWORD *)a1 + 132))(

a1,

v5,

&byte_1B02F,

&byte_1B040);

v16 = v15 == 0;

(*(void(__fastcall **)(int,int))(*(_DWORD *)a1 + 92))(a1, v5);

v6 = (~(x_149 * (x_149 - 1)) | 0xFFFFFFFE) + 1;

v7 = -2015175878;

if( y_150 < 10 != (v6 == 0) )

v7 = -64863449;

v8 = v6 == 0;

i = v7;

if( v8 )

i = -64863449;

if( y_150 >= 10 )

i = v7;

if( i > -64863450 )

gotoLABEL_14;

}

i = 1890200666;

v12 = (int*)&unk_19B64;

}

}

if( i == 642638909 )

{

v9 = -2015175878;

if( (v13 ^ v14) << 31 )

v9 = -957104787;

i = v9;

if( v14 )

i = -957104787;

if( !v13 )

i = v9;

gotoLABEL_3;

}

if( i != 1448165231 )

break;

v12 = (int*)(*(int(__fastcall **)(int,int,int))(*(_DWORD *)a1 + 136))(a1, a2, v15);

}

returnv12;

}

可以看到存在一定程度的混淆,去除控制流垃圾

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// case i == -2015175878:

v4 = (*(int(__fastcall **)(int,void*))(*(_DWORD *)a1 + 24))(a1, &unk_1B010);

(*(void(__fastcall **)(int,int,char*,char*))(*(_DWORD *)a1 + 132))(a1, v4, &byte_1B02F, &byte_1B040);

(*(void(__fastcall **)(int,int))(*(_DWORD *)a1 + 92))(a1, v4);

i = -957104787;

// case i == -957104787:

v5 = (*(int(__fastcall **)(int,void*))(*(_DWORD *)a1 + 24))(a1, &unk_1B010);

v15 = (*(int(__fastcall **)(int,int,char*,char*))(*(_DWORD *)a1 + 132))(

a1,

v5,

&byte_1B02F,

&byte_1B040);

v16 = v15 == 0;

(*(void(__fastcall **)(int,int))(*(_DWORD *)a1 + 92))(a1, v5);

按照JNI模式解析,大概率为

1

2

3

4

jclass clazz = (*env)->FindClass(env,"xxx");// &unk_1B010

jmethodID mid = (*env)->GetMethodID(env, clazz,"name","sig");// &byte_1B02F, &byte_1B040

(*env)->DeleteLocalRef(env, clazz);

v16 = (mid == 0);

查看一下对应的内存地址,是否为类名

可以看到字符串被混淆了,根据交叉引用寻找

发现存在解密代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

# asc_1B010 原始密文字节

ida_chars = [

0xFC, 0xF3, 0xF9, 0xEF, 0xF2, 0xF4, 0xF9, 0xB2, 0xFE, 0xF2,

0xF3, 0xE9, 0xF8, 0xF3, 0xE9, 0xB2, 0xDE, 0xF2, 0xF3, 0xE9,

0xF8, 0xE5, 0xE9, 0xCA, 0xEF, 0xFC, 0xED, 0xED, 0xF8, 0xEF,

0x9D,

]

def decode(data):

out = []

forb in data:

# 按 C 里的写法: dst = ~( (b & 0x9D) | (~b & 0x62) );

# 再按 unsignedchar截断到 8 位

v = ~((b & 0x9D) | (~b & 0x62)) & 0xFF

out.append(v)

returnbytes(out)

plain = decode(ida_chars)

print("hex :", plain.hex())

try:

print("ascii:", plain.decode("ascii"))

except UnicodeDecodeError:

print("ascii decode failed")

#android/content/ContextWrapper

其他解密也是相同的,这样我们就知道了这个函数其实就是获取包名,脚本写为Idapython脚本更方便

发现都是进行比较,我们解密另一个参数即可,还是按照刚才的方法

1

2

3

4

5

6

7

8

byte_1B310-byte_1B32A 为

com.ximalaya.android.sleep

aJfdQDhehphfzYh 为

com.ximalayaos.pad[00]

byte_1BA00

com.ximalaya.huibenguan.android[00]

byte_1B330

com.ximalaya.android.sleep.dev\x00

可以看到所有的strcmp就是和硬编码的包名比较,所以我们需要找到对应的包名

最终是在一千一百多行发现

发现比较成功之后,会设置v13=1825021717,这个v13就是状态机,觉得下一步会执行什么代码,因此我们追踪if(v13==1825021717)的代码即可

这两个地址解密的数据为:

1

2

byte_1B510 解密后为;MOBIL-V1-PRODUCT-1

aD7dgkjj1K1g5Gk 解密后为:7D74899B338B4F348E2383970CC09991E8E8D8F2BC744EF0BEE94D76D718C0894

可以发现设置v13的状态为2590219376,继续跟进发现没有搜到,这时候可以切换为十六进制形式0x9A639C70发现找到了对应代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

elseif( v13 <= -1520500360 )

{

if( v13 == 0x9A639C70 )// = -1704747920

{

v261 = v228;// 保存 key 字符串

v262 = v230;// 保存标志位

v260 = v5;// 保存 "MOBIL-V1-PRODUCT-1" 之类

v239 = (char*)(*v231)->GetStringUTFChars(v231, str, 0);// jstring str -> char*

v13 = 923489355;

v14 = v15;

if( !v230 )

v13 = 816144671;// v230==0 时,状态改成 816144671

}

}

所以我们继续跟进新的状态

1

2

3

4

5

6

7

8

9

10

11

12

13

if( v13 == 816144671 )// 这里

{

v13 = 3581685779;

if( (~(x_153 * (x_153 - 1)) | 0xFFFFFFFE) == 0xFFFFFFFF )

v13 = 909332025;

v97 = 0;

if( y_154 < 10 )

v97 = 1;

else

v13 = 3581685779;

if( v97 != ((~(x_153 * (x_153 - 1)) | 0xFFFFFFFE) == -1) )

v13 = 909332025;

}

寻找有没有等于3581685779和909332025的

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

elseif( v13 == 909332025 )

{

v53 =strlen(v260);// 这个值为MOBIL-V1-PRODUCT-1

v54 = (char*)malloc(v53);

qmemcpy(v54, v260,strlen(v260) - 1);

v54[-(1 -strlen(v260))] = 0;// 复制的时候去除最后一位

v55 =strlen(v261);// 这个值为7D74899B338B4F348E2383970CC09991E8E8D8F2BC744EF0BEE94D76D718C0894

v56 = (char*)malloc(v55);

qmemcpy(v56, v261,strlen(v261) - 1);// 复制的时候去除最后一位

v56[strlen(v261) - 1] = 0;

v57 =strlen(c_str) - 123099768;

v58 =strlen(v54);

v59 =strlen(v56) + v58 + v57 + 123099769;// v59等于三段字符串总长度加\0

v60 =malloc(v59);

memset(v60, 0, v59);

strcat((char*)v60, c_str);// 拼接待签名原始数据

strcat((char*)v60, v54);// 拼接版本标识

strcat((char*)v60, v56);// 拼接key字符串

v240 = (int)(*v231)->NewStringUTF(v231, (constchar*)v60);

free(v54);

v61 = v56;

v12 = 1215952980;

free(v61);

free(v60);

v13 = -713281517;

if( (~(x_153 * (x_153 - 1)) | 0xFFFFFFFE) == 0xFFFFFFFF )

v13 = -1769657914;

v62 = 0;

if( y_154 < 10 )

v62 = 1;

else

v13 = -713281517;

v14 = v15;

if( v62 != ((~(x_153 * (x_153 - 1)) | 0xFFFFFFFE) == -1) )

v13 = -1769657914;

}

所以我们现在需要追踪v240

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

elseif( v13 > -1771541319 )

{

if( v13 != -1771541318 )

{

v45 = v240;

LABEL_360:

v13 = 493313113;

v223 = (char*)v45;

v14 = v15;

continue;

}

v208 = v231;

(*v231)->DeleteLocalRef(v231, (jobject)v254);

(*v208)->DeleteLocalRef(v208, (jobject)v242);

v257 = (int)(*v208)->CallObjectMethod(v208, (jobject)v246, (jmethodID)v245);

v209 = ((int(__fastcall *)(JNIEnv *))(*v208)->ExceptionCheck)(v208);

v13 = -1805937577;

v21 = v209 == 0;

v14 = v15;

if( !v21 )

v13 = 1741960892;

}

状态转移:v240 存进 v223,状态 v13 = 493313113

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

if( v13 == 493313113 )

{

v263 = v223;// ① 保存前面构造好的 jstring 指针

v189 = (~(x_153 * (x_153 - 1)) | 0xFFFFFFFE) + 1;

v190 = -1326811784;

if( y_154 < 10 != (v189 == 0) )

v190 = -925493942;

v21 = v189 == 0;

v13 = v190;

v14 = v15;

if( v21 )

v13 = -925493942;

if( y_154 >= 10 )

v13 = v190;

}

这两个新状态都可以找到,一个是加密后检查,一个是加密,我贴上加密的

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

elseif( v13 == -1326811784 )

{

v226 = v14;

v69 = v231;

v70 = (int)(*v231)->FindClass(v231, &byte_1BCA0);

v71 = (int)(*v69)->GetMethodID(v69, (jclass)v70, &byte_1BCB1, &byte_1B040);

v72 = (int)(*v69)->CallObjectMethod(v69, v263, (jmethodID)v71);

v73 = (int)(*v69)->GetMethodID(v69, (jclass)v70, &byte_1B29F, &byte_1B2B0);

CallObjectMethod = (*v231)->CallObjectMethod;

v75 = (int)(*v69)->NewStringUTF(v69, &byte_1BCBD);

CallObjectMethod(v231, (jobject)v72, (jmethodID)v73, v75);

v76 = (int)(*v69)->FindClass(v69, &byte_1BCD0);

v77 = (int)(*v69)->GetMethodID(v69, (jclass)v76, &byte_1B126, &byte_1B27E);

(*v69)->GetMethodID(v69, (jclass)v76, aJ, byte_1BCF0);

(*v69)->GetMethodID(v69, (jclass)v76, &byte_1BD1E, &byte_1B040);

(*v69)->NewObject(v69, (jclass)v76, (jmethodID)v77);

v12 = 1215952980;

(*v69)->GetMethodID(v69, (jclass)v76, aJ, &byte_1BD30);

v78 = (int)(*v69)->FindClass(v69, &byte_1BD50);

v79 = (int)(*v69)->GetStaticMethodID(v69, (jclass)v78, &byte_1B079, byte_1BD70);

v80 = (int)(*v69)->NewStringUTF(v69, &byte_1BDA2);

(*v69)->CallStaticObjectMethod(v69, (jclass)v78, (jmethodID)v79, v80);

(*v69)->ExceptionCheck(v69);

v13 = -925493942;

v14 = v226;

}

全部解密

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

elseif( v13 == -1326811784 )

{

v226 = v14;

v69 = v231;

v70 = (int)(*v231)->FindClass(v231, &byte_1BCA0);// java/lang/String

v71 = (int)(*v69)->GetMethodID(v69, (jclass)v70, &toUpperCase, &byte_1B040);// ()Ljava/lang/String;

v72 = (int)(*v69)->CallObjectMethod(v69, v263, (jmethodID)v71);

v73 = (int)(*v69)->GetMethodID(v69, (jclass)v70, &getBytes, &byte_1B2B0);// (Ljava/lang/String;)[B

CallObjectMethod = (*v231)->CallObjectMethod;

v75 = (int)(*v69)->NewStringUTF(v69, &byte_1BCBD);// utf-8

CallObjectMethod(v231, (jobject)v72, (jmethodID)v73, v75);

v76 = (int)(*v69)->FindClass(v69, &byte_1BCD0);// java/lang/StringBuilder

v77 = (int)(*v69)->GetMethodID(v69, (jclass)v76, &byte_1B126, &byte_1B27E);// 第三个参数为:<init>\x00([B)V\x00generatePublic\x00 第四个参数()V\x00write\x00toByteArrayÿ([B\x00close\x00getBytes\x00

(*v69)->GetMethodID(v69, (jclass)v76, append, byte_1BCF0);// (Ljava/lang/String;)Ljava/lang/StringBuilder;

(*v69)->GetMethodID(v69, (jclass)v76, &toString, &byte_1B040);// ()Ljava/lang/String;RSA

(*v69)->NewObject(v69, (jclass)v76, (jmethodID)v77);

v12 = 1215952980;

(*v69)->GetMethodID(v69, (jclass)v76, append, &byte_1BD30);// (I)Ljava/lang/StringBuilder;

v78 = (int)(*v69)->FindClass(v69, &byte_1BD50);// java/security/MessageDigest

v79 = (int)(*v69)->GetStaticMethodID(v69, (jclass)v78, &getInstance, byte_1BD70);// (Ljava/lang/String;)Ljava/security/MessageDigest;

v80 = (int)(*v69)->NewStringUTF(v69, &byte_1BDA2);// SHA-1updatedigest

(*v69)->CallStaticObjectMethod(v69, (jclass)v78, (jmethodID)v79, v80);

(*v69)->ExceptionCheck(v69);

v13 = -925493942;

v14 = v226;

}

可以看到进行了SHA1,现在我们需要搞清楚的就是

喂给 update 的 byte[] 是谁,digest 出来的 byte[] 是如何变成最终 sign

所以这时候重新考虑Hook

上面我们已经知道调用了java层的这么多方法,因此可以每个方法都试试,我这里选择的是hook toUpperCase

下面是输出

1

2

3

4

5

6

========== [toUpperCase] ==========

输入: biz=1&fdsOtp={"captcha_id":"3723312ce42a04b5c0b40e605a882037","lot_number":"43d0fb9d6ceb4d34b77f6998203fb7c3","pass_token":"cd28f0a8e166dd870f589c36bc43986fde88ceef418c92b6b3e8dfa1097ce027","gen_time":"1764831091","captcha_output":"2Z76G2CapbcJxb3z0NRv6M3hvdvpPpJiZYrOHqnYCvDSbFN1VW0MwSEZ3bzVLqngN4RJMRn1V6Uvj9gAHrgeznYrystLCzuDzpheGrXmtoInaTm_JIaayivXrDqJd1xrqxIqbMWmFj8RSFvxBFc2R1M8Ape_b6WdHTrf1BeQtjEN_sdWrJTbi48cbT6ayPbqPDU8vDchMd1tgXZDBKZhoFm3ANOcDQs_SP2GqsZANRo3sZR_X2sZQhGD2EgaJvrnlfLOTcZ8kDIPGOSQyoSEyNF6R1NuWtETfRTicTxTsj8b55gDWy72e16ItCupfEoQDye8zYIaHQ1UIg4TnXxFK1aTtqGFi551e-zcyIuQnTHqMAdNtIrac0khlYn8tfPFmpkkhJCa69hR-gcGFI_qvHCeFa4ab0xjeGbRNVosEfhxp3yBbv8tbPbZ-ObfR0LN3qYS8y1JPmB3EvamKHSmU7h76fVjRfZEyM-8UhIyzz5VJit0xT970VxEGgEqJ_ZE-7FBeXmrmFycDqjAN32aZYLKfE6y9WDHtwgu2D9vbbY="}&mobile=H+FK2BFDCnb7eyJ+5Y6MZ3Du/2lwuHI3wK9RnyE+g4VKStBxb/EyvBP4mudzGTeKKZFD1PZoJarJ

OoK9xq9LPSaQ+tialKCMq++5PmJLiiEkU6kqVdtqQVs0w9BKiakZKh+HH60bCpDVGTqFbhn4i/Sf

4W+bADoG3LzJGco9Vy4=

&nonce=0-4EE56BEBDE87cdb8b25529f4c7b2f9c8158d18e3ef90b13cff9725b5d652c4&sendType=1&MOBILE-V1-PRODUCT-7D74899B338B4F348E2383970CC09991E8E8D8F2BC744EF0BEE94D76D718C089

====================================

此时Signature参数的生成也很清晰了

1

2

输入 = 参数按字母排序拼接 +"MOBILE-V1-PRODUCT-"+"7D74899B338B4F348E2383970CC09991E8E8D8F2BC744EF0BEE94D76D718C089"

signature = SHA1(输入.toUpperCase().getBytes("UTF-8"))

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/21 14:36:34

5分钟搞定视频方向问题:ffmpeg-python零基础修复方案

5分钟搞定视频方向问题&#xff1a;ffmpeg-python零基础修复方案 【免费下载链接】ffmpeg-python Python bindings for FFmpeg - with complex filtering support 项目地址: https://gitcode.com/gh_mirrors/ff/ffmpeg-python 还在为手机拍摄的视频方向错误而烦恼吗&…

作者头像 李华
网站建设 2026/4/17 13:14:18

串口助手唐老鸭版:5个理由让你爱上这款串口调试神器

串口助手唐老鸭版&#xff1a;5个理由让你爱上这款串口调试神器 【免费下载链接】串口助手唐老鸭版使用说明 串口助手(唐老鸭版)是一款功能强大且易于使用的串口调试工具&#xff0c;专为开发者设计。其界面友好&#xff0c;操作简单&#xff0c;能够满足各种串口调试需求。无论…

作者头像 李华
网站建设 2026/4/23 12:49:41

38、Linux系统管理与网络服务全解析

Linux系统管理与网络服务全解析 1. 常用命令与基础操作 1.1 文件操作命令 在Linux系统中,有许多实用的文件操作命令。例如, tail 命令可用于查看文件的末尾内容,使用方法为 tail [选项] [文件名] ,常见选项有 -n 用于指定显示的行数。 tar 命令则用于文件的打包…

作者头像 李华
网站建设 2026/4/8 11:12:29

终极Python MCP调试指南:3步搞定服务器连接与测试

终极Python MCP调试指南&#xff1a;3步搞定服务器连接与测试 【免费下载链接】inspector Visual testing tool for MCP servers 项目地址: https://gitcode.com/gh_mirrors/inspector1/inspector 还在为Python MCP服务器的调试问题而烦恼吗&#xff1f;ModelContextPro…

作者头像 李华
网站建设 2026/4/23 12:59:14

如何快速搭建intl-tel-input开发环境:从零开始的完整指南

如何快速搭建intl-tel-input开发环境&#xff1a;从零开始的完整指南 【免费下载链接】intl-tel-input A JavaScript plugin for entering and validating international telephone numbers 项目地址: https://gitcode.com/gh_mirrors/in/intl-tel-input 国际电话号码输…

作者头像 李华