欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创] 快手签名

[原创] 快手签名

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

抓包

发送短信验证码

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"}

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

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功