首页
社区
课程
招聘
[原创]某站平台的签名算法分享
发表于: 2024-1-16 17:30 10787

[原创]某站平台的签名算法分享

2024-1-16 17:30
10787

先charles抓包,api.xxxxxx.com域名的包

分析包 看到路径参数如下
图片描述
appkey=1d8b6e7d45233436&build=5531000&channel=dw056&mobi_app=android&mode=0&oid=326052200&plat=2&platform=android&ps=20&statistics=%7B%22appId%22%3A1%2C%22platform%22%3A3%2C%22version%22%3A%225.53.1%22%2C%22abtest%22%3A%22%22%7D&ts=1705305495&type=1&sign=2c9086d4acc853a017ec087699902634
可以看到一个sign,是个32字符,128位,直觉告诉我可能是个md5签名

然后用jadx打开xxx.apk包,全局搜索sign字符串,在众多函数方法中,找到一个SignedQuery函数,跟进去看,发现又个loadLibrary(xxx),那么直接告诉我是在一个so里

用apktool把xxx.apk decode出来,拿到libxxx.so

用ida打开该libxxx.so,直接看JNI_OnLoad函数,找到这一行

if ( (*v5)->RegisterNatives(v5, v4, (const JNINativeMethod *)&register_native_struct, 5) < 0

register_native_struct跟进去
图片描述

每个函数进去看下,有惊喜,确实是个md5算法,找到 md5_impl,跟进去看看算法参数

分析代码,发现关键在 check_app_key_get_type和global_key,一个是app key获取type,还有一个存着类似于secret key的 global key

整体看下来,结论就是 md5加密,按参数字典序排序,然后拼接SecretKey,再md5得到sign,取其中一个type来验证下:

图片描述
和app请求生成的sign一样,secret key打码,如果想要,可以按步骤自己去试试,实测成功,关键地方都写清楚了
图片描述

最后,写个python脚本试试,确实都能访问,这里脚本就不放了,求赞求加精,求账号升级,感谢

int __fastcall md5_impl(JNIEnv *a1, jobject (*a2)(JNIEnv *, jclass, jmethodID, ...))
{
JNIEnv *v2; // r11
jobject (*v3)(JNIEnv *, jclass, jmethodID, ...); // r6
const char *v4; // r2
const char *v5; // r1
int result; // r0
int v7; // r0
JNIEnv v8; // r1
int v9; // r0
int v10; // r4
int v11; // r0
int v12; // r10
signed int v13; // r9
int v14; // r5
int v15; // r8
time_t v16; // r0
int v17; // r6
int v18; // r5
const char *input_str; // r8
_DWORD *v20; // r10
int v21; // r4
_DWORD *v22; // r0
int v23; // r1
int v24; // r2
int v25; // r0
unsigned int input_len; // r5
signed int v27; // r4
char *v28; // r5
int v29; // r4
const char *v30; // [sp+8h] [bp-C0h]
int v31; // [sp+8h] [bp-C0h]
int v32; // [sp+Ch] [bp-BCh]
char v33; // [sp+10h] [bp-B8h]
int s; // [sp+38h] [bp-90h]
int v35; // [sp+3Ch] [bp-8Ch]
int v36; // [sp+40h] [bp-88h]
int v37; // [sp+44h] [bp-84h]
char v38[24]; // [sp+90h] [bp-38h]
int v39; // [sp+A8h] [bp-20h]
 
v2 = a1;
v3 = a2;
if ( !sub_2D20((int)a1) )
goto LABEL_5;
v4 = "com.xxxxxxxx.nativelibrary.SignedQuery";
v5 = "java/lang/ClassNotFoundException";
LABEL_3:
sub_401C((int)v2, (int)v5, (int)v4);
result = 0;
while ( _stack_chk_guard != v39 )
{
LABEL_5:
if ( !v3 )
{
  v5 = "java/lang/NullPointerException";
  v4 = "Null params!";
  goto LABEL_3;
}
v7 = is_empty(v2, (int)v3);
v8 = *v2;
if ( v7 )
{
  v3 = v8->NewObject;
  result = ((int (__fastcall *)(JNIEnv *, int, int, _DWORD, _DWORD))v3)(
             v2,
             cls_signed_query,
             signed_query_init,
             0,
             0);
}
else
{
  v9 = ((int (__fastcall *)(JNIEnv *, const char *))v8->NewStringUTF)(v2, "appkey");
  v10 = v9;
  v11 = sub_60CC(v2, (int)v3, v9);          // // 校验appkey
  v12 = v11;
  if ( v11 )
  {
    v30 = (const char *)((int (__fastcall *)(JNIEnv *, int, _DWORD))(*v2)->GetStringUTFChars)(v2, v11, 0);
    v13 = check_app_key_get_type(v30);
  }
  else
  {
    v13 = -1;
    v30 = 0;
  }
  v14 = ((int (__fastcall *)(JNIEnv *, const char *))(*v2)->NewStringUTF)(v2, "ts");
  v15 = sub_60CC(v2, (int)v3, v14);
  if ( !v15 )
  {
    v36 = 0;
    v37 = 0;
    s = 0;
    v35 = 0;
    v16 = time(0);
    sprintf((char *)&s, "%ld", v16);
    ((void (__fastcall *)(JNIEnv *, int *))(*v2)->NewStringUTF)(v2, &s);
    sub_6188((int)v2);
  }
  sub_41D0(v2, v14);
  sub_41D0(v2, v15);
  v17 = ((int (__fastcall *)(JNIEnv *, int, int, jobject (*)(JNIEnv *, jclass, jmethodID, ...)))(*v2)->CallStaticObjectMethod)(
          v2,
          cls_signed_query,
          method_signed_query_r,
          v3);
  v18 = 0;
  if ( sub_3F70((int)v2) )
    v17 = 0;
  v32 = v17;
  input_str = (const char *)((int (__fastcall *)(JNIEnv *, int, _DWORD))(*v2)->GetStringUTFChars)(v2, v17, 0);
  if ( v13 != -1 )
  {
    ((void (__fastcall *)(JNIEnv *, int, const char *))(*v2)->ReleaseStringUTFChars)(v2, v12, v30);
    v20 = malloc(0x10u);
    if ( v20 )
    {
      v31 = v10;
      v21 = global_key[v13];
      v22 = &global_key[v13];
      v23 = v22[5];
      v24 = v22[10];
      v25 = v22[15];
      *v20 = v21;
      v20[1] = v23;
      v20[2] = v24;
      v20[3] = v25;
      _aeabi_memclr8(&v33, 33);
      input_len = strlen(input_str);
      _aeabi_memclr8(v38, 24);
      _aeabi_memclr8(&s, 88);
      md5_init(&s);
      md5_update((int)&s, (int)input_str, input_len);
      sprintf(v38, "%08x", v21);
      md5_update((int)&s, (int)v38, 8u);
      v27 = 1;
      do
      {
        sprintf(v38, "%08x", v20[v27]);
        md5_update((int)&s, (int)v38, 8u);
        ++v27;
      }
      while ( v27 != 4 );
      md5_final((int)v38, (int)&s);
      v28 = &v33;
      v29 = 0;
      do
      {
        sprintf(v28, "%02x", (unsigned __int8)v38[v29++]);
        v28 += 2;
      }
      while ( v29 != 16 );
      free(v20);
      v10 = v31;
      v18 = ((int (__fastcall *)(JNIEnv *, char *))(*v2)->NewStringUTF)(v2, &v33);
    }
    else
    {
      v18 = 0;
    }
  }
  sub_41D0(v2, v10);
  v3 = (*v2)->NewObject;
  result = ((int (__fastcall *)(JNIEnv *, int, int, int, int))v3)(v2, cls_signed_query, signed_query_init, v32, v18);
}
}
return result;} 
int __fastcall md5_impl(JNIEnv *a1, jobject (*a2)(JNIEnv *, jclass, jmethodID, ...))
{
JNIEnv *v2; // r11
jobject (*v3)(JNIEnv *, jclass, jmethodID, ...); // r6
const char *v4; // r2
const char *v5; // r1
int result; // r0
int v7; // r0
JNIEnv v8; // r1
int v9; // r0
int v10; // r4
int v11; // r0
int v12; // r10
signed int v13; // r9
int v14; // r5
int v15; // r8
time_t v16; // r0
int v17; // r6
int v18; // r5
const char *input_str; // r8
_DWORD *v20; // r10
int v21; // r4
_DWORD *v22; // r0
int v23; // r1
int v24; // r2
int v25; // r0
unsigned int input_len; // r5
signed int v27; // r4
char *v28; // r5
int v29; // r4
const char *v30; // [sp+8h] [bp-C0h]
int v31; // [sp+8h] [bp-C0h]
int v32; // [sp+Ch] [bp-BCh]
char v33; // [sp+10h] [bp-B8h]
int s; // [sp+38h] [bp-90h]
int v35; // [sp+3Ch] [bp-8Ch]
int v36; // [sp+40h] [bp-88h]
int v37; // [sp+44h] [bp-84h]
char v38[24]; // [sp+90h] [bp-38h]
int v39; // [sp+A8h] [bp-20h]
 
v2 = a1;
v3 = a2;
if ( !sub_2D20((int)a1) )
goto LABEL_5;
v4 = "com.xxxxxxxx.nativelibrary.SignedQuery";
v5 = "java/lang/ClassNotFoundException";
LABEL_3:
sub_401C((int)v2, (int)v5, (int)v4);
result = 0;
while ( _stack_chk_guard != v39 )
{
LABEL_5:
if ( !v3 )
{
  v5 = "java/lang/NullPointerException";
  v4 = "Null params!";
  goto LABEL_3;
}
v7 = is_empty(v2, (int)v3);
v8 = *v2;
if ( v7 )
{
  v3 = v8->NewObject;
  result = ((int (__fastcall *)(JNIEnv *, int, int, _DWORD, _DWORD))v3)(
             v2,
             cls_signed_query,
             signed_query_init,
             0,
             0);
}
else
{
  v9 = ((int (__fastcall *)(JNIEnv *, const char *))v8->NewStringUTF)(v2, "appkey");
  v10 = v9;
  v11 = sub_60CC(v2, (int)v3, v9);          // // 校验appkey
  v12 = v11;
  if ( v11 )
  {
    v30 = (const char *)((int (__fastcall *)(JNIEnv *, int, _DWORD))(*v2)->GetStringUTFChars)(v2, v11, 0);
    v13 = check_app_key_get_type(v30);
  }
  else
  {
    v13 = -1;

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2024-1-16 17:33 被mb_qjzbupqg编辑 ,原因: 标题重复
收藏
免费 5
支持
分享
最新回复 (1)
雪    币: 3535
活跃值: (31011)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2024-1-18 10:14
1
游客
登录 | 注册 方可回帖
返回
//