整理了下,发现还有个和达达类似套路的,一起看看吧。

抓包

发送短信验证码POST /rest/n/user/requestMobileCode?app=0&lon=146.3516&did_gt=1562212339132&c=MYAPP%2C1&sys=ANDROID_8.1&isp=&mod=LGE%28AOSP%20on%20TTOG%29&did=ANDROID_a515efd201ca2590&hotfix_ver=&ver=6.5&net=WIFI&country_code=CN&iuid=&appver=6.5.5.9591&max_memory=192&oc=MYAPP%2C1&ftt=&kpn=KUAISHOU&ud=0&language=zh-cn&kpf=ANDROID_PHONE&lat=30.005368 HTTP/1.1

Connection: close

Accept-Language: zh-cn

User-Agent: kwai-android

X-REQUESTID: 141829000

Content-Type: application/x-www-form-urlencoded

Content-Length: 117

Host: apissl.gifshow.com

Accept-Encoding: gzip, deflate

mobileCountryCode=%2B86&mobile=13655338668&type=1&os=android&client_key=3c2cd3f3&sig=c8a22b77755169b9ecfc63b30e428d32

老规矩,确定sig为签名字段。

逆向

确定调用链

d3a5b2d252d97fefde0df0e29dd72651.png

找到实现

fddb52f936f114a2a4ada8871bb2a2f4.png

进入native

ca4931007634a523eec0a88f0ead9e34.png   

c7db990d99ada8af517a44c7fc554eba.png

首先确定进入一个解密字符串的函数,有兴趣的可以看看,直接粘处来解密,char *__fastcall deStr(int a1, size_t a2)

{

int v2; // r4

size_t i_32; // r8

_DWORD *v4; // r1

char *v5; // r5

int v6; // r1

int v7; // r0

int v8; // r3

int v9; // r4

unsigned int v10; // r6

unsigned int v11; // lr

int v12; // r11

char *v13; // r9

unsigned int v14; // r0

int v15; // r5

unsigned int v16; // r2

unsigned int v17; // r0

unsigned int v18; // r1

unsigned int v19; // ST1C_4

__int64 v20; // kr10_8

unsigned int v21; // r1

unsigned int v22; // r1

unsigned int v23; // r0

unsigned int v24; // r11

unsigned int v25; // r0

unsigned int v26; // r8

unsigned int v27; // r2

unsigned int v28; // r0

unsigned int v29; // r2

int v30; // r6

int v31; // r5

unsigned int v32; // r2

unsigned int *v33; // r0

size_t v35; // [sp+4h] [bp-44h]

char *v36; // [sp+8h] [bp-40h]

int v37; // [sp+Ch] [bp-3Ch]

int v38; // [sp+10h] [bp-38h]

int v39; // [sp+14h] [bp-34h]

_DWORD *ptr; // [sp+18h] [bp-30h]

signed int v41; // [sp+28h] [bp-20h]

v2 = a1;

i_32 = a2;

v4 = malloc(32u);

*v4 = 0xFFF3A2E6;

v4[1] = 0xA66E1F1C;

v4[2] = 0x21772905;

v4[3] = 0xC0D58234;

*((_WORD *)v4 + 8) = 0x706;

*(_DWORD *)((char *)v4 + 18) = 0x24ED1653;

*(_DWORD *)((char *)v4 + 22) = 0xCB39377A;

*(_DWORD *)((char *)v4 + 26) = 0xA90383A3;

*((_WORD *)v4 + 15) = 0xF68Bu;

if ( i_32 << 28 )

{

free(v4);

v5 = 0;

}

else

{

ptr = v4;

v5 = (char *)malloc(i_32);

if ( i_32 >> 4 )

{

v6 = 0;

v35 = i_32 >> 4;

v36 = v5;

v37 = v2;

do

{

v7 = v2 + 16 * v6;

v39 = v6;

v8 = 0;

v38 = 16 * v6;

v9 = *(_DWORD *)(v2 + 16 * v6);

v10 = *(_QWORD *)(v7 + 4) >> 32;

v11 = *(_QWORD *)(v7 + 4);

v12 = *(_DWORD *)(v7 + 12);

v41 = 8;

do

{

v13 = (char *)&unk_7B226754 + v8;

v8 -= 28;

v14 = ptr[*((_DWORD *)v13 + 54)] + v12;

v15 = byte_7B226652[(unsigned __int16)v14 >> 8];

v16 = ((((byte_7B226652[(v14 >> 16) & 0xFF] << 16) | (v15 << 8) | ((unsigned int)byte_7B226652[v14 >> 24] << 24)) >> 11) | ((byte_7B226652[(unsigned __int8)v14] | (v15 << 8)) << 21)) ^ v10;

v17 = ptr[*((_DWORD *)v13 + 55)] + v9;

v18 = (32

* (byte_7B226652[(unsigned __int8)v17] | (byte_7B226652[(unsigned __int16)v17 >> 8] << 8) | (byte_7B226652[(v17 >> 16) & 0xFF] << 16) | (byte_7B226652[v17 >> 24] << 24)) | ((unsigned int)byte_7B226652[v17 >> 24] >> 3)) ^ v11;

v19 = v18;

v20 = *(_QWORD *)(v13 + 204);

v21 = v18 + v16 + ptr[HIDWORD(v20)];

v22 = ((((byte_7B226652[(v21 >> 16) & 0xFF] << 16) | (byte_7B226652[(unsigned __int16)v21 >> 8] << 8) | ((unsigned int)byte_7B226652[v21 >> 24] << 24)) >> 11) | ((byte_7B226652[(unsigned __int8)v21] | (byte_7B226652[(unsigned __int16)v21 >> 8] << 8)) << 21)) ^ v41;

v23 = ptr[(_DWORD)v20] + v16 - v22;

v24 = v12

+ ((((byte_7B226652[v23 >> 24] << 24) | ((unsigned int)byte_7B226652[(v23 >> 16) & 0xFF] << 16)) >> 19) | ((byte_7B226652[(unsigned __int8)v23] | (byte_7B226652[(unsigned __int16)v23 >> 8] << 8) | (byte_7B226652[(v23 >> 16) & 0xFF] << 16)) << 13));

v25 = ptr[(unsigned int)*(_QWORD *)(v13 + 196)] + v24;

v26 = (32

* (byte_7B226652[(unsigned __int8)v25] | (byte_7B226652[(unsigned __int16)v25 >> 8] << 8) | (byte_7B226652[(v25 >> 16) & 0xFF] << 16) | (byte_7B226652[v25 >> 24] << 24)) | ((unsigned int)byte_7B226652[v25 >> 24] >> 3)) ^ (v16 - v22);

v27 = ptr[*((_DWORD *)v13 + 53)] + v19;

v28 = v9

- ((((byte_7B226652[v27 >> 24] << 24) | ((unsigned int)byte_7B226652[(v27 >> 16) & 0xFF] << 16)) >> 19) | ((byte_7B226652[(unsigned __int8)v27] | (byte_7B226652[(unsigned __int16)v27 >> 8] << 8) | (byte_7B226652[(v27 >> 16) & 0xFF] << 16)) << 13));

v29 = ptr[*(_QWORD *)(v13 + 196) >> 32] + v28;

v30 = byte_7B226652[(unsigned __int16)v29 >> 8];

v31 = byte_7B226652[(unsigned __int8)v29] | (v30 << 8);

--v41;

v11 = v28;

v32 = (byte_7B226652[(v29 >> 16) & 0xFF] << 16) | (v30 << 8) | (byte_7B226652[v29 >> 24] << 24);

v10 = v24;

v9 = v26;

v12 = ((v32 >> 11) | (v31 << 21)) ^ (v22 + v19);

}

while ( v8 != -224 );

v5 = v36;

*(_DWORD *)&v36[v38] = v10;

v33 = (unsigned int *)&v36[v38 + 4];

*v33 = v26;

v33[1] = v12;

v33[2] = v11;

v2 = v37;

v6 = v39 + 1;

}

while ( v39 + 1 != v35 );

}

free(ptr);

}

return v5;

}

接下来进入一个签名校验的函数,其实都可以跳过,因为我们可以看到上面的函数都没有参与最后返回值的生成。int __fastcall checkSign(JNIEnv *a1, jobject a2, char *a3)

{

JNIEnv *env; // r11

jfieldID obj_ctx; // r9

JNIEnv v5; // r10

char *v6; // r4

char *v7; // r6

jclass jcls_ctx; // r5

jstring v9; // r8

const char *v10; // r0

const char *v11; // r6

int v12; // r4

int v13; // r5

char *v14; // r4

char *v15; // r0

char *v16; // r6

int v17; // r5

int v18; // r6

bool v19; // zf

__int64 v21; // r4

void *v22; // r6

__int64 v23; // r4

jstring v24; // r0

void *v25; // r8

char *v26; // r5

jclass v27; // r6

jobject v28; // r6

jobject v29; // r5

char *v30; // r8

char *v31; // r0

char *v32; // r8

unsigned int v33; // r0

char *v34; // r4

int v35; // r6

char *v36; // r4

const char *v37; // r0

const char *v38; // r4

JNIEnv v39; // [sp+10h] [bp-E8h]

const char *s2; // [sp+14h] [bp-E4h]

_jfieldID *v41; // [sp+18h] [bp-E0h]

void *v42; // [sp+20h] [bp-D8h]

void *v43; // [sp+28h] [bp-D0h]

int v44; // [sp+30h] [bp-C8h]

jstring v45; // [sp+38h] [bp-C0h]

char v46; // [sp+47h] [bp-B1h]

_QWORD v47[11]; // [sp+48h] [bp-B0h]

unsigned __int8 v48; // [sp+A0h] [bp-58h]

unsigned __int8 v49; // [sp+A1h] [bp-57h]

unsigned __int8 v50; // [sp+A2h] [bp-56h]

unsigned __int8 v51; // [sp+A3h] [bp-55h]

unsigned __int8 v52; // [sp+A4h] [bp-54h]

unsigned __int8 v53; // [sp+A5h] [bp-53h]

unsigned __int8 v54; // [sp+A6h] [bp-52h]

unsigned __int8 v55; // [sp+A7h] [bp-51h]

unsigned __int8 v56; // [sp+A8h] [bp-50h]

unsigned __int8 v57; // [sp+A9h] [bp-4Fh]

unsigned __int8 v58; // [sp+AAh] [bp-4Eh]

unsigned __int8 v59; // [sp+ABh] [bp-4Dh]

unsigned __int8 v60; // [sp+ACh] [bp-4Ch]

unsigned __int8 v61; // [sp+ADh] [bp-4Bh]

unsigned __int8 v62; // [sp+AEh] [bp-4Ah]

unsigned __int8 v63; // [sp+AFh] [bp-49h]

char s1; // [sp+B0h] [bp-48h]

__int16 v65; // [sp+B2h] [bp-46h]

int v66; // [sp+B4h] [bp-44h]

int v67; // [sp+B8h] [bp-40h]

int v68; // [sp+BCh] [bp-3Ch]

int v69; // [sp+C0h] [bp-38h]

int v70; // [sp+C4h] [bp-34h]

int v71; // [sp+C8h] [bp-30h]

int v72; // [sp+CCh] [bp-2Ch]

int v73; // [sp+D8h] [bp-20h]

env = a1;

obj_ctx = (jfieldID)a2;

s2 = a3;

v5 = *a1;

v6 = deStr((int)&unk_7B226944, 0x10u); // getName

v7 = deStr((int)&c_mtd_sign_ret_str, 0x20u); // ()Ljava/lang/String;

jcls_ctx = (*env)->GetObjectClass(env, (jobject)obj_ctx);

sub_7B223814(&v45, env, &v46, (unsigned int)jcls_ctx, __PAIR__((unsigned int)v7, (unsigned int)v6));// 获取application的类名

v9 = v45;

v5->DeleteLocalRef(env, jcls_ctx);

free(v6);

free(v7);

if ( v9 && !v46 )

{

v39 = v5;

v5 = (JNIEnv)deStr((int)&unk_7B226884, 0x20u);// com.yxcorp.gifshow.App

if ( v5 && (v10 = (*env)->GetStringUTFChars(env, v9, 0), (v11 = v10) != 0) )

{

v12 = strcasecmp(v10, (const char *)v5);

(*env)->ReleaseStringUTFChars(env, v9, v11);

if ( v12 )

v12 = -1;

}

else

{

v12 = -1;

}

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

if ( v5 )

free((void *)v5);

if ( v12 )

{

v13 = -2;

goto LABEL_28;

}

v14 = deStr((int)&c_getPackageName, 0x10u); // getPackageName

v15 = deStr((int)&c_mtd_sign_ret_str, 0x20u);// ()Ljava/lang/String;

v16 = v15;

sub_7B223814((jstring *)&v44, env, &v46, (unsigned int)obj_ctx, __PAIR__((unsigned int)v15, (unsigned int)v14));// 获取包名

v17 = v44;

free(v14);

free(v16);

if ( v46 )

goto LABEL_27;

if ( !((unsigned int)s2 | v17) )

{

v18 = 0;

v5 = v39;

if ( !v17 )

goto LABEL_26;

LABEL_25:

(*env)->DeleteLocalRef(env, (jobject)v17);

goto LABEL_26;

}

v5 = v39;

v19 = s2 == 0;

v18 = -1;

if ( s2 )

v19 = v17 == 0;

if ( v19 )

{

if ( !v17 )

goto LABEL_26;

goto LABEL_25;

}

v37 = (*env)->GetStringUTFChars(env, (jstring)v17, 0);// 肯定是com.smile.gifmaker

v38 = v37;

if ( v37 )

{

v18 = strcasecmp(v37, s2);

(*env)->ReleaseStringUTFChars(env, (jstring)v17, v38);

if ( v18 )

v18 = -1;

if ( v17 )

goto LABEL_25;

}

else

{

v18 = -1;

if ( v17 )

goto LABEL_25;

}

LABEL_26:

if ( !v18 )

goto LABEL_30;

LABEL_27:

v13 = -3;

goto LABEL_28;

}

if ( v9 )

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

v13 = -1;

LABEL_28:

while ( MEMORY[0x40103384] != v73 )

{

LABEL_30:

LODWORD(v21) = deStr((int)&c_getPackageManager, 0x20u);// getPackageManager

HIDWORD(v21) = deStr((int)&c_mtd_sign_ret_PM, 0x30u);// ()Landroid/content/pm/PackageManager;

sub_7B223814(&v43, env, &v46, (unsigned int)obj_ctx, v21);// 得到pm

v22 = v43;

free((void *)v21);

free((void *)HIDWORD(v21));

if ( !v22 || v46 )

{

if ( v22 )

v5->DeleteLocalRef(env, v22);

v13 = -4;

}

else

{

LODWORD(v23) = deStr((int)&c_getPackageInfo, 0x10u);// getPackageInfo

HIDWORD(v23) = deStr((int)&c_mtd_sign_ret_PkInfo, 0x40u);// (Ljava/lang/String;I)Landroid/content/pm/PackageInfo;

v24 = v5->NewStringUTF(env, s2);

sub_7B223814(&v42, env, &v46, (unsigned int)v22, v23, v24, 64);// 得到pkackageinfo

v25 = v42; // 后面懒得看了,猜测肯定是获取签名md5,判断是不是debug或者release版本,就是校验签名

v5->DeleteLocalRef(env, v22);

free((void *)v23);

free((void *)HIDWORD(v23));

if ( !v25 || v46 )

{

if ( v25 )

v5->DeleteLocalRef(env, v25);

v13 = -5;

}

else

{

v5 = (JNIEnv)deStr((int)&unk_7B226B04, 0x10u);

v26 = deStr((int)&unk_7B226B44, 0x20u);

v27 = v39->GetObjectClass(env, v25);

obj_ctx = v39->GetFieldID(env, v27, (const char *)v5, v26);

free((void *)v5);

free(v26);

v39->DeleteLocalRef(env, v27);

v28 = v39->GetObjectField(env, v25, obj_ctx);

v39->DeleteLocalRef(env, v25);

if ( v28 )

{

v29 = v39->GetObjectArrayElement(env, v28, 0);

if ( v29 )

{

v30 = deStr((int)&unk_7B226B84, 0x10u);

v31 = deStr((int)&unk_7B226BC4, 0x10u);

v5 = (JNIEnv)v31;

sub_7B223814((jstring *)&v41, env, &v46, (unsigned int)v29, __PAIR__((unsigned int)v31, (unsigned int)v30));

obj_ctx = v41;

free(v30);

free((void *)v5);

v39->DeleteLocalRef(env, v28);

if ( !obj_ctx || v46 )

{

if ( obj_ctx )

v39->DeleteLocalRef(env, (jobject)obj_ctx);

v13 = -8;

}

else

{

v13 = 0;

v5 = (JNIEnv)&s1;

v32 = v39->GetByteArrayElements(env, (jbyteArray)obj_ctx, 0);

_aeabi_memclr8(&s1, 33);

md5_init(v47);

v33 = v39->GetArrayLength(env, (jarray)obj_ctx);

md5_update(v47, v32, v33);

md5_final(v47);

sprintf(&s1, "%02x", v48);

sprintf((char *)&v65, "%02x", v49);

sprintf((char *)&v66, "%02x", v50);

sprintf((char *)((unsigned int)&s1 | 6), "%02x", v51);

sprintf((char *)&v67, "%02x", v52);

sprintf((char *)&v67 + 2, "%02x", v53);

sprintf((char *)&v68, "%02x", v54);

sprintf((char *)&v68 + 2, "%02x", v55);

sprintf((char *)&v69, "%02x", v56);

sprintf((char *)&v69 + 2, "%02x", v57);

sprintf((char *)&v70, "%02x", v58);

sprintf((char *)&v70 + 2, "%02x", v59);

sprintf((char *)&v71, "%02x", v60);

sprintf((char *)&v71 + 2, "%02x", v61);

sprintf((char *)&v72, "%02x", v62);

sprintf((char *)&v72 + 2, "%02x", v63);

v34 = deStr((int)&unk_7B2268C4, 0x30u);

v35 = strcasecmp(&s1, v34);

free(v34);

if ( v35 )

{

v36 = deStr((int)&unk_7B226904, 0x30u);

v13 = strcasecmp(&s1, v36);

free(v36);

if ( v13 )

v13 = -9;

}

v39->ReleaseByteArrayElements(env, (jbyteArray)obj_ctx, v32, 0);

v39->DeleteLocalRef(env, (jobject)obj_ctx);

}

}

else

{

v39->DeleteLocalRef(env, v28);

v13 = -7;

}

}

else

{

v13 = -6;

}

}

}

}

return v13;

}

看了一下,大概就可以猜出是干什么的,应该就是获取签名md5后判断是不是被重打包。int sub_7B223814(jstring *a1, JNIEnv *a2, _BYTE *a3, unsigned int a4, __int64 a5, ...)

{

jobject (__cdecl *v5)(JNIEnv *, jobject, jmethodID, va_list); // r6

int v6; // r11

jstring *v7; // r9

JNIEnv *env; // r5

_BYTE *v9; // r10

unsigned int v10; // r8

unsigned int v11; // r4

_jmethodID *v12; // r2

int v13; // t1

unsigned int v14; // r0

int (__fastcall *v15)(JNIEnv *, unsigned int); // r6

jobject (__cdecl *v16)(JNIEnv *, jobject, jmethodID, va_list); // r1

unsigned __int16 v17; // r0

int v18; // r0

int result; // r0

jclass v20; // [sp+0h] [bp-28h]

int v21; // [sp+8h] [bp-20h]

va_list va; // [sp+38h] [bp+10h]

va_start(va, a5);

v7 = a1;

env = a2;

v9 = a3;

v10 = a4;

if ( !(*env)->EnsureLocalCapacity(env, 2) )

{

v5 = (jobject (__cdecl *)(JNIEnv *, jobject, jmethodID, va_list))HIDWORD(a5);

LOBYTE(v6) = a5;

v20 = (*env)->GetObjectClass(env, (jobject)v10);

v12 = (*env)->GetMethodID(env, v20, (const char *)a5, (const char *)HIDWORD(a5));

if ( v12 )

{

do

{

v13 = *(unsigned __int8 *)v5;

v5 = (jobject (__cdecl *)(JNIEnv *, jobject, jmethodID, va_list))((char *)v5 + 1);

}

while ( v13 != ')' );

switch ( *(unsigned __int8 *)v5 )

{

case 'B':

v5 = (jobject (__cdecl *)(JNIEnv *, jobject, jmethodID, va_list))(*env)->CallByteMethodV;

goto LABEL_26;

case 'C':

v5 = (jobject (__cdecl *)(JNIEnv *, jobject, jmethodID, va_list))(*env)->CallCharMethodV;

v14 = ((int (__fastcall *)(JNIEnv *, unsigned int))v5)(env, v10);

LOBYTE(v6) = v14;

v11 = v14 >> 8;

goto LABEL_20;

case 'D':

v15 = (int (__fastcall *)(JNIEnv *, unsigned int))(*env)->CallDoubleMethodV;

goto LABEL_16;

case 'F':

v5 = (jobject (__cdecl *)(JNIEnv *, jobject, jmethodID, va_list))(*env)->CallFloatMethodV;

goto LABEL_14;

case 'I':

v5 = (jobject (__cdecl *)(JNIEnv *, jobject, jmethodID, va_list))(*env)->CallIntMethodV;

goto LABEL_14;

case 'J':

v15 = (int (__fastcall *)(JNIEnv *, unsigned int))(*env)->CallLongMethodV;

LABEL_16:

v6 = v15(env, v10);

v5 = v16;

v10 = v6 & 0xFFFF0000;

v11 = (unsigned __int16)v6 >> 8;

goto LABEL_21;

case 'L':

case '[':

v5 = (*env)->CallObjectMethodV;

LABEL_14:

v6 = (int)v5(env, (jobject)v10, v12, va);

v10 = v6 & 0xFFFF0000;

v11 = (unsigned __int16)v6 >> 8;

goto LABEL_21;

case 'S':

v5 = (jobject (__cdecl *)(JNIEnv *, jobject, jmethodID, va_list))(*env)->CallShortMethodV;

v17 = ((int (__fastcall *)(JNIEnv *, unsigned int))v5)(env, v10);

LOBYTE(v6) = v17;

v11 = v17 >> 8;

goto LABEL_20;

case 'V':

v5 = (jobject (__cdecl *)(JNIEnv *, jobject, jmethodID, va_list))(*env)->CallVoidMethodV;

((void (__fastcall *)(JNIEnv *, unsigned int))v5)(env, v10);

break;

case 'Z':

goto LABEL_25;

default:

(*env)->FatalError(env, "illegaldescriptor");

break;

}

}

v11 = 0;

goto LABEL_20;

}

v11 = 0;

v10 = 0;

if ( v9 )

goto LABEL_22;

while ( 1 )

{

*v7 = (jstring)((unsigned __int8)v6 | (v11 << 8) | v10);

v7[1] = v5;

result = MEMORY[0x40103384] - v21;

if ( MEMORY[0x40103384] == v21 )

break;

LABEL_25:

v5 = (jobject (__cdecl *)(JNIEnv *, jobject, jmethodID, va_list))(*env)->CallBooleanMethodV;

LABEL_26:

LOBYTE(v6) = ((int (__fastcall *)(JNIEnv *, unsigned int))v5)(env, v10);

v11 = 0;

LABEL_20:

v10 = 0;

LABEL_21:

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

if ( v9 )

{

LABEL_22:

v18 = (*env)->ExceptionCheck(env);

*v9 = v18;

if ( v18 )

(*env)->ExceptionClear(env);

}

}

return result;

}

分析出是md5算法,那么在源字符串后面拼接,确定是加盐。。。

梳理逻辑

get请求,取?后面的参数,以key进行排序,组合

post请求,额,这个post请求也有get的参数,所以把?后面的参数和post的参数一起排序,组合

代码实现package com.zhuo.tong.kuaishou;

import javax.net.ssl.HttpsURLConnection;

import java.io.*;

import java.net.URL;

import java.net.URLDecoder;

import java.nio.charset.Charset;

import java.security.MessageDigest;

import java.util.*;

public class Main {

public static String md5(String dataStr) {

try {

MessageDigest m = MessageDigest.getInstance("MD5");

m.update(dataStr.getBytes("UTF8"));

byte s[] = m.digest();

String result = "";

for (int i = 0; i < s.length; i++) {

result += Integer.toHexString((0x000000FF & s[i]) | 0xFFFFFF00).substring(6);

}

return result;

} catch (Exception e) {

e.printStackTrace();

}

return "";

}

private static class Holder{

List list = new ArrayList<>();

HashMap map = new HashMap<>();

public String getData() {

Collections.sort(list);

StringBuilder sb = new StringBuilder();

for (String s : list) {

String value = map.get(s);

sb.append(s).append("=").append(value);

}

return sb.toString();

}

}

private static Holder getHolder(Holder holder, String data) {

data = URLDecoder.decode(data, Charset.defaultCharset());

System.out.println(data);

String[] split = data.split("&");

for (String s : split) {

if (s.startsWith("sig=")) {

continue;

}

String[] split1 = s.split("=");//应该是取第一个=,懒得完善了

//额,某个包触发了这个bug,还是要修复

int index = s.indexOf("=");

String first = s.substring(0, index);

String secend = s.substring(index + 1, s.length());

split1 = new String[]{first, secend};

holder.list.add(split1[0]);

holder.map.put(split1[0], split1.length==2?split1[1]:"");

}

return holder;

}

public static void main(String[] args) {

String data = "app=0&lon=146.351638&did_gt=1562212339132&c=MYAPP,1&sys=ANDROID_8.1&isp=&mod=LGE(AOSP on TTOG)&did=ANDROID_a515efd201ca2590&hotfix_ver=&ver=6.5&net=WIFI&country_code=CN&iuid=&appver=6.5.5.9591&max_memory=192&oc=MYAPP,1&ftt=&kpn=KUAISHOU&ud=0&language=zh-cn&kpf=ANDROID_PHONE&lat=30.005315";

//去除一些参数,

// data = "app=0";//返回{"result":3,"error_msg":"客户端版本太旧,请升级到最新版本。","host-name":"bjfk-rs8594.yz02"}

Holder holder = new Holder();

getHolder(holder, data);

String postData = "op=test&os=android&sig=6a1f5f5c7ba6feeeff52b383815a0435&client_key=3c2cd3f3";

getHolder(holder, postData);

data = holder.getData();

String salt = "382700b563f4";

data += salt;

String sig = md5(data);

System.out.println(sig);

}

}

之后改包,签名,可以了。

有些api,对ANDROID有限制,例如判断用户是否注册的接口,就返回{"result":705,"error_url":"https://app.m.kuaishou.com/verify/captcha.html?key=oJ6ByMKELaoQWPXqHxD0weaclfXUn313nri0x8REq7OaNjhHczNypR1DsIwzGHYp&type=4&uri=%2Frest%2Fn%2Fuser%2Fmobile%2Fchecker&provider=tencent","error_msg":"","host-name":"bjm7-rs1856.jxq"}

应该是风控的部分,懒得再看了。

最后于 2019-9-7 01:41

被卓桐编辑

,原因:

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐