52pj2025春节红包解题-安卓中级

打印 上一主题 下一主题

主题 863|帖子 863|积分 2589


先找到判断方法,显然是一个native


ida加载so,导出表中没有这个函数,所以是动态注册的,找到jni_onload

找到函数地址

修改3个参数的范例,便于分析

总得来看,最终要执行的不是a就是ao了
  1. bool __fastcall sub_BE440(JNIEnv *env, jobject object, jstring inputKey)
  2. {
  3.   int v5; // r4
  4.   const char *key; // r0
  5.   const char *v7; // r9
  6.   int v8; // r4
  7.   int v9; // r6
  8.   int v10; // r1
  9.   unsigned int v11; // r6
  10.   char *v12; // r4
  11.   _BOOL4 v13; // r8
  12.   int v14; // r0
  13.   void (__fastcall *v15)(_BYTE *, const char *, int, void *); // r8
  14.   void *v16; // r5
  15.   int v17; // r4
  16.   const std::nothrow_t *v18; // r1
  17.   unsigned __int64 v20; // [sp+0h] [bp-58h]
  18.   _BYTE v21[16]; // [sp+18h] [bp-40h] BYREF
  19.   _QWORD v22[2]; // [sp+28h] [bp-30h] BYREF
  20.   v5 = 0;
  21.   key = (*env)->GetStringUTFChars(env, inputKey, 0);
  22.   if ( key )
  23.   {
  24.     v7 = key;
  25.     HIDWORD(v20) = inputKey;
  26.     v8 = A();
  27.     v9 = CNJAK();
  28.     if ( !byte_134E49 )
  29.     {
  30.       afdm::decrypt_buffer((afdm *)byte_134D7E, &byte_4, 0xA8FC3415, v20);
  31.       byte_134E49 = 1;
  32.     }
  33.     v10 = -1;
  34.     if ( v8 )
  35.       v10 = 1;
  36.     v11 = v9 + v10;
  37.     v12 = getenv(byte_134D7E);                  // 反调?
  38.     v13 = v12 == 0 || v11 < 3;
  39.     v14 = jgbjkb();                             // 反调?
  40.     if ( v11 <= 2 && v12 )
  41.     {
  42.       v13 = 1;
  43.       dword_134D90 = -559038669;
  44.     }
  45.     v22[0] = *(_QWORD *)&off_12FCE8;            // 下面的v15是为了获得一个函数,不是a就是ao
  46.     v22[1] = *(_QWORD *)&off_12FCF0;
  47.     v15 = (void (__fastcall *)(_BYTE *, const char *, int, void *))nullsub_9(*(_DWORD *)((unsigned int)v22 | (4 * ((v14 | v13) ^ (unsigned int)sub_BE6CC & 1 ^ (((unsigned int)ao ^ (unsigned int)a) >> 24) & 1))));
  48.     dword_134D90 = -559038669;
  49.     memset(v21, 0, sizeof(v21));
  50.     v16 = (void *)operator new[](0x13u);
  51.     v15(v21, v7, 19, v16);                      // v15是一个函数,这边v7就是输入的key
  52.     v17 = memcmp(v16, &unk_3A0FC, 0x13u);       // 比较结果
  53.     operator delete[](v16, v18);
  54.     (*env)->ReleaseStringUTFChars(env, (jstring)HIDWORD(v20), v7);
  55.     return v17 == 0;
  56.   }
  57.   return v5;
  58. }
复制代码
a和ao的差异很小,但总归是要执行此中的一个的,所以反调可以直接忽略掉,两个函数都看一下


改一下参数的范例,发现这两个函数唯一的差别就是ao没有去动态修改sub_BED58天生的值,因此解密函数应该是a
  1. int __fastcall a(_BYTE *a1, char *key, int a3, void *a4)
  2. {
  3.   __int64 v5; // d17
  4.   int i; // r6
  5.   int v9; // r5
  6.   char v10; // r0
  7.   _QWORD v12[2]; // [sp+0h] [bp-30h] BYREF
  8.   int v13; // [sp+14h] [bp-1Ch]
  9.   v5 = *((_QWORD *)a1 + 1);
  10.   v12[0] = *(_QWORD *)a1;
  11.   v12[1] = v5;
  12.   if ( a3 )                                     // a3=19
  13.   {
  14.     for ( i = 0; i != a3; ++i )
  15.     {
  16.       v9 = i & 0xF;
  17.       if ( (i & 0xF) == 0 )
  18.         sub_BED58((unsigned __int8 *)v12);      // 初始化v12的值,需要注意v12的长度是16,但一共有19次循环,第17次时这个函数又会被调用一次
  19.       v10 = key[i] ^ *((_BYTE *)v12 + v9);      // 异或
  20.       *((_BYTE *)a4 + i) = v10;
  21.       *((_BYTE *)v12 + v9) = v10;
  22.     }
  23.   }
  24.   return v13;
  25. }
复制代码
  1. int __fastcall ao(_BYTE *a1, char *key, int a3, void *a4)
  2. {
  3.   __int64 v5; // d17
  4.   int i; // r4
  5.   _QWORD v10[2]; // [sp+0h] [bp-30h] BYREF
  6.   int v11; // [sp+14h] [bp-1Ch]
  7.   v5 = *((_QWORD *)a1 + 1);
  8.   v10[0] = *(_QWORD *)a1;
  9.   v10[1] = v5;
  10.   if ( a3 )
  11.   {
  12.     for ( i = 0; i != a3; ++i )
  13.     {
  14.       if ( (i & 0xF) == 0 )
  15.         sub_BED58((unsigned __int8 *)v10);
  16.       *((_BYTE *)a4 + i) = key[i] ^ *((_BYTE *)v10 + (i & 0xF));
  17.     }
  18.   }
  19.   return v11;
  20. }
复制代码
最后比较结果,比较的值是0x48,0x27,0x8f,0xaf,0x9b,0xf8,0xec,0x72,0x98,0x07,0x72,0x0c,0x6b,0xe2,0x3a,0xb6,0x42,0x59,0xf7

最后根据手机的现实情况选择对应架构的so举行hook或者调试,分析时用的是armeabi-v7a,我的手机是arm64,应该用arm64-v8a(重打包apk,把其他架构的删掉也可以)
  1. Java.perform(function(){
  2.   var soAddr = Process.getModuleByName("libwuaipojie2025_game.so");
  3.   var func_addr = soAddr.base.add(0xE9954);
  4.   Interceptor.attach(func_addr, {
  5.     onEnter: function(args){
  6.       console.log("hook到函数");
  7.     },
  8.     onLeave: function(retval){
  9.       console.log(retval.readByteArray(16));
  10.     }
  11.   });
  12. });
复制代码

得到该函数两次执行的结果,第二次是要依据第一次的输入来做的,所以要先解一下前16位
0x2e,0x4b,0xee,0xc8,0xe0,0x95,0x88,0x47,0xb0,0x72,0x1b,0x68,0x40,0xd0,0x0a,0x84
  1. target = [0x48,0x27,0x8f,0xaf,0x9b,0xf8,0xec,0x72,0x98,0x07,0x72,0x0c,0x6b,0xe2,0x3a,0xb6,0x42,0x59,0xf7]
  2. result = [0x2e,0x4b,0xee,0xc8,0xe0,0x95,0x88,0x47,0xb0,0x72,0x1b,0x68,0x40,0xd0,0x0a,0x84]
  3. for i in range(0,len(result)):
  4.     print(chr(target[i]^result[i]),end='')
  5. #flag{md5(uid+202
复制代码
再次输入密钥时输入flag{md5(uid+202(发现反调试时需要getenv返回非0,hook了一下,至于另一个函数,大概是由于我用frida的原因?它没有检测到),得到后3位0x77,0x70,0x8a
  1. Java.perform(function(){
  2.   var soAddr = Process.getModuleByName("libwuaipojie2025_game.so");
  3.   var jgbjkb_addr = Module.findExportByName("libwuaipojie2025_game.so","_Z6jgbjkbv");
  4.   Interceptor.attach(jgbjkb_addr, {
  5.     onEnter: function(args){
  6.       console.log("hook到jgbjkb");
  7.     },
  8.     onLeave: function(retval){
  9.       console.log("jgbjkb返回值为"+retval);
  10.     }
  11.   });   
  12.   var getenv_addr = Module.findExportByName("libc.so","getenv");
  13.   Interceptor.attach(getenv_addr, {
  14.     onEnter: function(args){
  15.       console.log("hook到getenv");
  16.     },
  17.     onLeave: function(retval){
  18.       console.log("修改getenv返回值为1");
  19.       retval.replace(1);
  20.     }
  21.   });   
  22.   var func_addr = soAddr.base.add(0xE9954);
  23.   Interceptor.attach(func_addr, {
  24.     onEnter: function(args){
  25.       console.log("hook到函数");
  26.     },
  27.     onLeave: function(retval){
  28.       console.log(retval.readByteArray(16));
  29.     }
  30.   });
  31. });
复制代码
  1. target = [0x48,0x27,0x8f,0xaf,0x9b,0xf8,0xec,0x72,0x98,0x07,0x72,0x0c,0x6b,0xe2,0x3a,0xb6,0x42,0x59,0xf7]
  2. result = [0x2e,0x4b,0xee,0xc8,0xe0,0x95,0x88,0x47,0xb0,0x72,0x1b,0x68,0x40,0xd0,0x0a,0x84,0x77,0x70,0x8a]
  3. for i in range(0,len(result)):
  4.     print(chr(target[i]^result[i]),end='')
  5. #flag{md5(uid+2025)}
复制代码
得到flagflag{md5(uid+2025)}


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

兜兜零元

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表