android逆向快手,[原创] 快手签名-Android安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com...
整理了下,发现还有个和达达类似套路的,一起看看吧。抓包发送短信验证码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&
整理了下,发现还有个和达达类似套路的,一起看看吧。
抓包
发送短信验证码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为签名字段。
逆向
确定调用链
找到实现
进入native
首先确定进入一个解密字符串的函数,有兴趣的可以看看,直接粘处来解密,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
被卓桐编辑
,原因:
更多推荐
所有评论(0)