整理了下,发现还有个和达达类似套路的,一起看看吧。
发送短信验证码
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<String> list = new ArrayList<>(); HashMap<String, String> 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"}
应该是风控的部分,懒得再看了。
[公告]看雪.纽盾 KCTF 2019晋级赛Q3攻击方规则,9月10日开赛,华为P30 Pro、iPad、kindle等你来拿!
最后于 6小时前 被卓桐编辑 ,原因: