首页
社区
课程
招聘
[原创] 2019看雪CTF 第二题 变形金钢 WriteUp
发表于: 2019-3-25 15:53 12010

[原创] 2019看雪CTF 第二题 变形金钢 WriteUp

2019-3-25 15:53
12010
IDA中分析liboo000oo.so,可以看出
.datadiv_decode5009363700628197108在程序开始时对数据解码:

.init_array:00003E78 ; ELF Initialization Function Table
.init_array:00003E78 ; ===========================================================================
.init_array:00003E78
.init_array:00003E78 ; Segment type: Pure data
.init_array:00003E78                 AREA .init_array, DATA
.init_array:00003E78                 ; ORG 0x3E78
.init_array:00003E78                 DCD .datadiv_decode5009363700628197108+1 ; 对数据解码
.init_array:00003E78 ; .init_array   ends
.init_array:00003E78

// 对数据解码
char *datadiv_decode5009363700628197108()
{
  int v0; // r0
  int v1; // r0
  int v2; // r0
  char *result; // r0

  v0 = 0;
  do
  {
    a650f909c721736[v0] ^= 0xA5u;               // 解码串 "650f909c-7217-3647-9331-c82df8b98e98",0
    ++v0;
  }
  while ( v0 != 0x25 );
  v1 = 0;
  do
    aAbcdefghijklmn[v1++] ^= 0xA5u;             // 解码 Base64 编码表:
                                                //  "!:#",0x24,"%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\';",0
  while ( v1 != 0x42 );
  v2 = 0;
  do
    aAndroidSupport[v2++] ^= 0x84u;             // 解码串 "android/support/v7/app/AppCompiatActivity",0
  while ( v2 != 0x2A );
  result = &byte_40D0;
  byte_40CA ^= 0xFCu;
  byte_40CB ^= 0xFCu;
  byte_40CC ^= 0xFCu;
  byte_40D0 ^= 0x62u;
  byte_40D1 ^= 0x62u;
  byte_40D2 ^= 0x62u;
  byte_40D3 ^= 0x62u;
  byte_40D4 ^= 0x62u;
  byte_40D5 ^= 0x62u;
  word_40D6 = __PAIR__(HIBYTE(word_40D6), (word_40D6 ^ 0x62)) ^ 0x6200;
  byte_40D8 ^= 0x62u;
  byte_40D9 ^= 0x62u;
  byte_40DA ^= 0x62u;
  byte_40DB ^= 0x62u;
  byte_40DC ^= 0x62u;
  byte_40DD ^= 0x62u;
  byte_40DE ^= 0x62u;
  byte_40DF ^= 0x62u;
  byte_40E0 ^= 0x62u;
  byte_40E1 ^= 0x62u;
  byte_40E2 ^= 0x62u;
  byte_40E3 ^= 0x62u;
  byte_40E4 ^= 0x62u;
  byte_40E5 ^= 0x62u;
  return result;
}

再来看
signed int __fastcall JNI_OnLoad(_JavaVM *a1)
{
  signed int result; // r0
  _JNIEnv *v2; // r5
  int v3; // r6
  _JNIEnv *env; // [sp+0h] [bp-18h]
  int v5; // [sp+4h] [bp-14h]

  env = 0;
  if ( !(a1->functions->GetEnv)() )
    goto LABEL_4;
LABEL_2:
  result = -1;
  while ( _stack_chk_guard != v5 )
  {
LABEL_4:
    v2 = env;
    v3 = (env->functions->FindClass)(env, off_4010);// "android/support/v7/app/AppCompiatActivity"
    dword_4110 = (v2->functions->NewGlobalRef)(v2, v3);
    if ( !v3 || (v2->functions->RegisterNatives)(v2, v3, &JNINativeMethodEq, 1) <= -1 )// 注册 boolean NativeMethod 函数 eq(String)
      goto LABEL_2;
    result = 65542;
  }
  return result;
}

其中:.data:00004014 JNINativeMethodEq JNINativeMethod <aEq, aLjavaLangStrin, eq+1>

可以看到,在函数JNI_OnLoad中注册了一个NativeMethod boolean eq(String),这个就是验证核心

// 注册码核心验证代码
int __fastcall eq(_JNIEnv *a1)
{
  size_t v1; // r10
  unsigned __int8 *v2; // r6
  _BYTE *v3; // r8
  _BYTE *v4; // r11
  int v5; // r0
  size_t v6; // r2
  char *v7; // r1
  int v8; // r3
  int v9; // r1
  unsigned int v10; // r2
  int v11; // r3
  int v12; // r0
  int v13; // r4
  unsigned __int8 v14; // r0
  _BYTE *v15; // r3
  _BYTE *v16; // r5
  char *v17; // r4
  int v18; // r5
  int v19; // r1
  int v20; // r0
  signed int v21; // r1
  int v22; // r2
  size_t v23; // r0
  unsigned int lenSN; // r8
  unsigned int v25; // r5
  _BYTE *buf; // r0
  int v27; // r3
  int v28; // r10
  unsigned int v29; // r2
  int v30; // r12
  bool v31; // zf
  _BYTE *v32; // r1
  bool v33; // zf
  int v34; // r3
  int v35; // r1
  unsigned __int8 v36; // r11
  unsigned int v37; // lr
  char v38; // r1
  char *v39; // r2
  int v40; // t1
  unsigned int v42; // [sp+4h] [bp-234h]
  unsigned int v43; // [sp+8h] [bp-230h]
  unsigned int v44; // [sp+10h] [bp-228h]
  char *SN; // [sp+14h] [bp-224h]
  char v46[256]; // [sp+18h] [bp-220h]
  char v47[256]; // [sp+118h] [bp-120h]
  int v48; // [sp+218h] [bp-20h]

  SN = (a1->functions->GetStringUTFChars)();    // 取SN
  v1 = strlen(a650f909c721736);                 // 用 "650f909c-7217-3647-9331-c82df8b98e98" 初始加密表
                                                // 算法没看太出来,不过不要紧,最后XOR的序列是不变的,只要得到那个序列就可以算出SN
  v2 = malloc(v1);
  v3 = malloc(v1);
  v4 = malloc(v1);
  _aeabi_memclr(v2, v1);
  _aeabi_memclr(v3, v1);
  _aeabi_memclr(v4, v1);
  if ( v1 )
  {
    v5 = 0;
    v6 = v1;
    v7 = a650f909c721736;
    do
    {
      v8 = *v7++;
      if ( v8 != '-' )
        v3[v5++] = v8;
      --v6;
    }
    while ( v6 );
    if ( v5 >= 1 )
    {
      v9 = v5 - 1;
      v10 = -8;
      v11 = 0;
      v12 = 0;
      do
      {
        if ( (v11 | (v10 >> 2)) > 3 )
        {
          v13 = v12;
        }
        else
        {
          v13 = v12 + 1;
          v2[v12] = '-';
        }
        v14 = v3[v9--];
        v11 += 0x40000000;
        v2[v13] = v14;
        ++v10;
        v12 = v13 + 1;
      }

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

收藏
免费 2
支持
分享
最新回复 (5)
雪    币: 1534
活跃值: (495)
能力值: ( LV4,RANK:52 )
在线值:
发帖
回帖
粉丝
2
求教师傅”!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\';“这个字符串变成标准的base64是怎么变得
为什么后面直接加上\
2019-4-1 21:00
0
雪    币: 13076
活跃值: (4077)
能力值: ( LV15,RANK:1673 )
在线值:
发帖
回帖
粉丝
3
两个字符表一一对应还不好求吗?
由字符查表得位置:pos=strchr(p1,c1)-p1,再在另一个表由位置得字符:c2=p2[pos]
2019-4-2 09:17
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
师傅您好,请教一下,v46这个加密序列不是在加密的时候一直在改变吗,为什么可以直接从内存中取出来解密呢?
2021-6-14 14:05
0
雪    币: 13076
活跃值: (4077)
能力值: ( LV15,RANK:1673 )
在线值:
发帖
回帖
粉丝
5
st0ne31 师傅您好,请教一下,v46这个加密序列不是在加密的时候一直在改变吗,为什么可以直接从内存中取出来解密呢?
是在变,但是是一个常数序列{0x9b, 0x6b....},也就是说第一次为0x9b, 第二次为0x6b,....
2021-6-15 09:20
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
AloneWolf 是在变,但是是一个常数序列{0x9b, 0x6b....},也就是说第一次为0x9b, 第二次为0x6b,....
明白了,感谢师傅解答
2021-6-15 12:34
0
游客
登录 | 注册 方可回帖
返回
//