国赛-bbvvmm-SM4逆向分析,虚拟机指令分析
playmak3r CTF 11391浏览 · 2019-05-23 00:57

国赛-bbvvmm-SM4逆向分析,虚拟机指令分析

SM4

拿到程序是一个ELF,64位程序程序大意是让你输入用户名和密码,放入IDA中看主函数

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  __int64 v3; // rax
  char *s1; // ST28_8
  char v5; // ST1B_1
  unsigned __int8 i; // [rsp+19h] [rbp-1A7h]
  int v8; // [rsp+1Ch] [rbp-1A4h]
  void *virtual_1; // [rsp+20h] [rbp-1A0h]
  char v10; // [rsp+30h] [rbp-190h]
  __int64 username; // [rsp+140h] [rbp-80h]
  char v12; // [rsp+148h] [rbp-78h]
  __int64 v13; // [rsp+150h] [rbp-70h]
  __int64 v14; // [rsp+158h] [rbp-68h]
  __int64 v15; // [rsp+160h] [rbp-60h]
  __int64 v16; // [rsp+168h] [rbp-58h]
  char v17; // [rsp+170h] [rbp-50h]
  char v18; // [rsp+171h] [rbp-4Fh]
  char v19; // [rsp+172h] [rbp-4Eh]
  char v20; // [rsp+173h] [rbp-4Dh]
  char v21; // [rsp+174h] [rbp-4Ch]
  char v22; // [rsp+175h] [rbp-4Bh]
  char v23; // [rsp+176h] [rbp-4Ah]
  char v24; // [rsp+177h] [rbp-49h]
  char v25; // [rsp+178h] [rbp-48h]
  char v26; // [rsp+179h] [rbp-47h]
  char v27; // [rsp+17Ah] [rbp-46h]
  char v28; // [rsp+17Bh] [rbp-45h]
  char v29; // [rsp+17Ch] [rbp-44h]
  char v30; // [rsp+17Dh] [rbp-43h]
  char v31; // [rsp+17Eh] [rbp-42h]
  char v32; // [rsp+17Fh] [rbp-41h]
  __int64 v33; // [rsp+180h] [rbp-40h]
  __int64 v34; // [rsp+188h] [rbp-38h]
  char s[8]; // [rsp+190h] [rbp-30h]
  __int64 v36; // [rsp+198h] [rbp-28h]
  __int64 v37; // [rsp+1A0h] [rbp-20h]
  __int64 v38; // [rsp+1A8h] [rbp-18h]
  char v39; // [rsp+1B0h] [rbp-10h]
  unsigned __int64 v40; // [rsp+1B8h] [rbp-8h]

  v40 = __readfsqword(0x28u);
  virtual_1 = malloc(0x4D0uLL);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  puts("Powered by ????? !");
  sub_406656("Powered by ????? !", 0LL);
  puts("---------[LOGIN]---------");
  printf("Username:", a2);
  sub_405B25((__int64)virtual_1);
  username = 0LL;
  v12 = 0;
  __isoc99_scanf("%9s", &username);
  printf("\x1B[?25l", &username);
  printf("Password:");
  for ( i = 0; i <= 5u; ++i )
    read(0, (char *)ptr + 4 * (i + 36LL), 1uLL);// 读取输入的6个字节
  sub_406607((__int64)virtual_1);
  *(_QWORD *)s = 0LL;
  v36 = 0LL;
  v37 = 0LL;
  v38 = 0LL;
  v39 = 0;
  v13 = 0LL;
  v14 = 0LL;
  sub_4066C0((__int64)&username, (__int64)&v13, 8);
  v15 = 0LL;
  v16 = 0LL;
  v17 = -38;
  v18 = -104;
  v19 = -15;
  v20 = -38;
  v21 = 49;
  v22 = 42;
  v23 = -73;
  v24 = 83;
  v25 = -91;
  v26 = 112;
  v27 = 58;
  v28 = 11;
  v29 = -3;
  v30 = 41;
  v31 = 13;
  v32 = -42;
  v33 = 0LL;
  v34 = 0LL;
  sub_401738(&v10, (__int64)&v17);
  sub_4018C4((__int64)&v10, 1, 16, &v15, &v13, &v33);
  sub_4067BD((__int64)&v33, (__int64)s, 16);
  v3 = strlen(s);
  s1 = sub_400AA6(s, v3);
  v5 = strcmp(s1, "RVYtG85NQ9OPHU4uQ8AuFM+MHVVrFMJMR8FuF8WJQ8Y=");
  printf("\x1B[?25h", "RVYtG85NQ9OPHU4uQ8AuFM+MHVVrFMJMR8FuF8WJQ8Y=");
  v8 = *((_DWORD *)ptr + 0x19);
  sub_405AA8();
  if ( v5 || v8 )
  {
    puts("\n----------[EXIT]----------");
    system("exit");
  }
  else
  {
    puts("\n---------[WELCOME]---------");
    system("cat flag");
  }
  return 0LL;
}

首先是输入用户名,用户名的处理再于函数4066c0处,进入该函数分析

unsigned __int64 __fastcall sub_4066C0(__int64 username, __int64 a2, signed int a3)
{
  unsigned __int8 i; // [rsp+25h] [rbp-Bh]
  unsigned __int8 v5; // [rsp+26h] [rbp-Ah]
  char v6; // [rsp+27h] [rbp-9h]
  unsigned __int8 v7; // [rsp+27h] [rbp-9h]
  unsigned __int64 v8; // [rsp+28h] [rbp-8h]

  v8 = __readfsqword(0x28u);
  for ( i = 0; i < a3; ++i )
  {
    v6 = *(_BYTE *)(i + username) & 0xF;
    v5 = (*(_BYTE *)(i + username) >> 4) + 0x30;
    if ( v5 <= 0x39u )
      *(_BYTE *)(a2 + 2 * i) = v5;
    else
      *(_BYTE *)(2 * i + a2) = (*(_BYTE *)(i + username) >> 4) + 55;
    v7 = v6 + 0x30;
    if ( v7 <= 0x39u )
      *(_BYTE *)(a2 + 2 * i + 1LL) = v7;
    else
      *(_BYTE *)(2 * i + 1LL + a2) = v7 + 7;
  }
  return __readfsqword(0x28u) ^ v8;
}

该函数大致为将字符转换为ASCII码,并且存储到main函数的v13之中,继续往下分析main函数,有关v13的处理再main为4018c4函数,分析该函数

unsigned __int64 __fastcall sub_4018C4(__int64 a1, int a2, int a3, _QWORD *a4, _QWORD *a5, _QWORD *a6)
{
  __int64 v6; // rdx
  _QWORD *v8; // [rsp+8h] [rbp-58h]
  _QWORD *encode_username; // [rsp+10h] [rbp-50h]
  _QWORD *v10; // [rsp+18h] [rbp-48h]
  int v11; // [rsp+20h] [rbp-40h]
  signed int i; // [rsp+3Ch] [rbp-24h]
  signed int j; // [rsp+3Ch] [rbp-24h]
  __int64 v14; // [rsp+40h] [rbp-20h]
  __int64 v15; // [rsp+48h] [rbp-18h]
  unsigned __int64 v16; // [rsp+58h] [rbp-8h]

  v11 = a3;
  v10 = a4;
  encode_username = a5;
  v8 = a6;
  v16 = __readfsqword(0x28u);
  if ( a2 == 1 )                                // a2恒为1
  {
    while ( v11 > 0 )                           // v11的值为16
    {
      for ( i = 0; i <= 15; ++i )
        *((_BYTE *)v8 + i) = *((_BYTE *)encode_username + i) ^ *((_BYTE *)v10 + i);// 复制数组
      sub_401362(a1 + 8, (unsigned __int8 *)v8, v8);
      v6 = v8[1];                               // 两组复制
      *v10 = *v8;
      v10[1] = v6;
      encode_username += 2;
      v8 += 2;
      v11 -= 16;
    }
  }
  else
  {
    while ( v11 > 0 )
    {
      v14 = *encode_username;
      v15 = encode_username[1];
      sub_401362(a1 + 8, (unsigned __int8 *)encode_username, v8);
      for ( j = 0; j <= 15; ++j )
        *((_BYTE *)v8 + j) ^= *((_BYTE *)v10 + j);
      *v10 = v14;
      v10[1] = v15;
      encode_username += 2;
      v8 += 2;
      v11 -= 16;
    }
  }
  return __readfsqword(0x28u) ^ v16;

将用户名转换成为的ASCII码数组复制到该函数的V8,执行该函数的401362函数,进入401362函数分析

unsigned __int64 __fastcall sub_401362(__int64 a1, unsigned __int8 *a2, _BYTE *a3)
{
unsigned __int8 *encode_username; // ST10_8
  _BYTE *encode_username2; // [rsp+8h] [rbp-168h]
  unsigned __int64 v6; // [rsp+28h] [rbp-148h]
  unsigned __int64 s; // [rsp+30h] [rbp-140h]
  unsigned __int64 v8; // [rsp+38h] [rbp-138h]
  unsigned __int64 v9; // [rsp+40h] [rbp-130h]
  unsigned __int64 v10; // [rsp+48h] [rbp-128h]
  __int64 v11; // [rsp+130h] [rbp-40h]
  __int64 v12; // [rsp+138h] [rbp-38h]
  __int64 v13; // [rsp+140h] [rbp-30h]
  __int64 v14; // [rsp+148h] [rbp-28h]
  unsigned __int64 v15; // [rsp+158h] [rbp-18h]

  encode_username = a2;
  encode_username2 = a3;
  v15 = __readfsqword(0x28u);
  v6 = 0LL;
  memset(&s, 0, 0x120uLL);
  s = ((unsigned __int64)encode_username[2] << 8) | ((unsigned __int64)encode_username[1] << 16) | ((unsigned __int64)*encode_username << 24) | encode_username[3];
  v8 = ((unsigned __int64)encode_username[6] << 8) | ((unsigned __int64)encode_username[5] << 16) | ((unsigned __int64)encode_username[4] << 24) | encode_username[7];
  v9 = ((unsigned __int64)encode_username[10] << 8) | ((unsigned __int64)encode_username[9] << 16) | ((unsigned __int64)encode_username[8] << 24) | encode_username[11];
  v10 = ((unsigned __int64)encode_username[14] << 8) | ((unsigned __int64)encode_username[13] << 16) | ((unsigned __int64)encode_username[12] << 24) | encode_username[15];
  while ( v6 <= 0x1F )                          // 将数组分成了四组ASCII码
  {
    *(&s + v6 + 4) = sub_400EE2(*(&s + v6), *(&s + v6 + 1), *(&s + v6 + 2), *(&s + v6 + 3), *(_QWORD *)(8 * v6 + a1));
    ++v6;
  }
  *encode_username2 = BYTE3(v14);
  encode_username2[1] = BYTE2(v14);
  encode_username2[2] = BYTE1(v14);
  encode_username2[3] = v14;
  encode_username2[4] = BYTE3(v13);
  encode_username2[5] = BYTE2(v13);
  encode_username2[6] = BYTE1(v13);
  encode_username2[7] = v13;
  encode_username2[8] = BYTE3(v12);
  encode_username2[9] = BYTE2(v12);
  encode_username2[10] = BYTE1(v12);
  encode_username2[11] = v12;
  encode_username2[12] = BYTE3(v11);
  encode_username2[13] = BYTE2(v11);
  encode_username2[14] = BYTE1(v11);
  encode_username2[15] = v11;
  return __readfsqword(0x28u) ^ v15;

该函数先将用户名生成的ASCII码即16个字符分成4组,接着执行32次循环,执行40EE2函数,第一次执行时参数为4组ASCCII码和一个不清楚的数字,进入40EE2函数

unsigned __int64 __fastcall sub_400EE2(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5)
{
  return a1 ^ sub_400D87(a5 ^ a4 ^ a3 ^ a2);
}

该处函数将3组ASCII码和未知数字异或后执行400D87最后再与第一组ASCII码异或,再进入400D87函数

unsigned __int64 __fastcall sub_400D87(int a1)
{
  unsigned __int8 v1; // ST30_1
  unsigned __int8 v2; // ST31_1
  unsigned __int8 v3; // ST32_1
  unsigned __int8 v4; // al
  unsigned __int64 v5; // ST10_8

  v1 = sub_400D38(HIBYTE(a1));
  v2 = sub_400D38(BYTE2(a1));
  v3 = sub_400D38(BYTE1(a1));
  v4 = sub_400D38(a1);
  v5 = ((unsigned __int64)v3 << 8) | ((unsigned __int64)v2 << 16) | ((unsigned __int64)v1 << 24) | v4;
  return (((unsigned __int64)((v3 << 8) | (v2 << 16) | (v1 << 24) | (unsigned int)v4) << 18) | (v5 >> 14)) ^ v5 ^ (4LL * ((v3 << 8) | (v2 << 16) | (v1 << 24) | (unsigned int)v4) | (v5 >> 30)) ^ (((unsigned __int64)(unsigned int)v5 << 10) | (v5 >> 22)) ^ (((unsigned __int64)((v3 << 8) | (v2 << 16) | (v1 << 24) | (unsigned int)v4) << 24) | (v5 >> 8));
}

4个异或后的数字将其分成4组,在下图表中执行4次变换,重新生成4个字符

并将这四个字符合并成新的字符,最后一步过长。。就不分析了。。。但是从这一遍流程

走下来,我们大概就能看出来是某种特定的加密方式,尤其是这个字母表更让人确信不疑。

如果了解SM4加密就知道其位SM4加密了,而那串未知的数字就是经过处理的密钥。

SM4加密参考教程

密钥加密的函数在主函数401738也就是我们之前未分析的函数进入该函数看一下

unsigned __int64 __fastcall sub_401738(_DWORD *a1, __int64 a2)
{
  unsigned __int64 v2; // ST18_8

  v2 = __readfsqword(0x28u);
  *a1 = 1;
  sub_401063((__int64)(a1 + 2), (unsigned __int8 *)a2);
  return __readfsqword(0x28u) ^ v2;
}

再进入401063函数

unsigned __int64 __fastcall sub_401063(__int64 a1, unsigned __int8 *a2)
{
  unsigned __int64 v2; // ST28_8
  unsigned __int64 v3; // ST30_8
  unsigned __int64 v4; // ST38_8
  __int64 v5; // r12
  unsigned __int64 v7; // [rsp+18h] [rbp-168h]
  unsigned __int64 v8; // [rsp+40h] [rbp-140h]
  unsigned __int64 v9; // [rsp+48h] [rbp-138h]
  unsigned __int64 v10; // [rsp+50h] [rbp-130h]
  unsigned __int64 v11; // [rsp+58h] [rbp-128h]
  unsigned __int64 v12; // [rsp+168h] [rbp-18h]

  v12 = __readfsqword(0x28u);
  v7 = 0LL;
  v2 = ((unsigned __int64)a2[6] << 8) | ((unsigned __int64)a2[5] << 16) | ((unsigned __int64)a2[4] << 24) | a2[7];
  v3 = ((unsigned __int64)a2[10] << 8) | ((unsigned __int64)a2[9] << 16) | ((unsigned __int64)a2[8] << 24) | a2[11];
  v4 = ((unsigned __int64)a2[14] << 8) | ((unsigned __int64)a2[13] << 16) | ((unsigned __int64)a2[12] << 24) | a2[15];
  v8 = (((unsigned __int64)a2[2] << 8) | ((unsigned __int64)a2[1] << 16) | ((unsigned __int64)*a2 << 24) | a2[3]) ^ 0xA3B1BAC6;
  v9 = v2 ^ 0x56AA3350;
  v10 = v3 ^ 0x677D9197;
  v11 = v4 ^ 0xB27022DC;
  while ( v7 <= 0x1F )
  {
    v5 = *(&v8 + v7);
    *(&v8 + v7 + 4) = v5 ^ sub_400F3F(*(&v8 + v7 + 3) ^ *(&v8 + v7 + 2) ^ *(&v8 + v7 + 1) ^ qword_406D80[v7]);
    *(_QWORD *)(a1 + 8 * v7) = *(&v8 + v7 + 4);
    ++v7;
  }
  return __readfsqword(0x28u) ^ v12;

在这里我们看到了系统参数FK分别为

0xA3B1BAC6
0x56AA3350
0x677D9197
0xB27022DC
与其异或的就是密钥为主函数的v17将其整理一下
0xDA98F1DA
0X312AB753
0XA5703A0B
0XFD290DD6

密钥也便可以得知。

接着分析主函数的4067BD

unsigned __int64 __fastcall sub_4067BD(__int64 a1, __int64 a2, int a3)
{
  int v4; // [rsp+Ch] [rbp-34h]
  int i; // [rsp+2Ch] [rbp-14h]
  char s[2]; // [rsp+30h] [rbp-10h]
  unsigned __int64 v7; // [rsp+38h] [rbp-8h]

  v4 = a3;
  v7 = __readfsqword(0x28u);
  for ( i = 0; i < v4; ++i )
  {
    sprintf(s, "%02X", *(unsigned __int8 *)(i + a1));
    *(_WORD *)(a2 + 2 * i) = *(_WORD *)s;
  }
  return __readfsqword(0x28u) ^ v7;
}

变种base64

将加密之后的ASCII码转换为字符,之后进入400AA6函数

_BYTE *__fastcall sub_400AA6(char *a1, __int64 a2)
{
  _BYTE *result; // rax
  signed int v3; // edx
  char *v4; // rax
  __int64 v5; // rax
  __int64 v6; // rax
  __int64 v7; // rax
  __int64 v8; // rax
  signed int v9; // eax
  __int64 v10; // [rsp+0h] [rbp-50h]
  char *v11; // [rsp+8h] [rbp-48h]
  signed int v12; // [rsp+18h] [rbp-38h]
  signed int i; // [rsp+18h] [rbp-38h]
  signed int j; // [rsp+1Ch] [rbp-34h]
  int k; // [rsp+1Ch] [rbp-34h]
  void *ptr; // [rsp+20h] [rbp-30h]
  __int64 v17; // [rsp+28h] [rbp-28h]
  unsigned __int8 v18; // [rsp+30h] [rbp-20h]
  unsigned __int8 v19; // [rsp+31h] [rbp-1Fh]
  unsigned __int8 v20; // [rsp+32h] [rbp-1Eh]
  char v21; // [rsp+40h] [rbp-10h]
  char v22; // [rsp+41h] [rbp-Fh]
  char v23; // [rsp+42h] [rbp-Eh]
  char v24; // [rsp+43h] [rbp-Dh]
  unsigned __int64 v25; // [rsp+48h] [rbp-8h]

  v11 = a1;
  v10 = a2;
  v25 = __readfsqword(0x28u);
  v12 = 0;
  v17 = 0LL;
  ptr = malloc(1uLL);
  if ( !ptr )
    return 0LL;
  while ( 1 )
  {
    v6 = v10--;
    if ( !v6 )
      break;
    v3 = v12++;
    v4 = v11++;
    *(&v18 + v3) = *v4;
    if ( v12 == 3 )
    {
      v21 = v18 >> 2;
      v22 = 16 * (v18 & 3) + (v19 >> 4);
      v23 = 4 * (v19 & 0xF) + (v20 >> 6);
      v24 = v20 & 0x3F;
      ptr = realloc(ptr, v17 + 4);
      for ( i = 0; i <= 3; ++i )
      {
        v5 = v17++;
        *((_BYTE *)ptr + v5) = byte_406C20[(unsigned __int8)*(&v21 + i)];
      }
      v12 = 0;
    }
  }
  if ( v12 > 0 )
  {
    for ( j = v12; j <= 2; ++j )
      *(&v18 + j) = 0;
    v21 = v18 >> 2;
    v22 = 16 * (v18 & 3) + (v19 >> 4);
    v23 = 4 * (v19 & 0xF) + (v20 >> 6);
    v24 = v20 & 0x3F;
    for ( k = 0; v12 + 1 > k; ++k )
    {
      ptr = realloc(ptr, v17 + 1);
      v7 = v17++;
      *((_BYTE *)ptr + v7) = byte_406C20[(unsigned __int8)*(&v21 + k)];
    }
    while ( 1 )
    {
      v9 = v12++;
      if ( v9 > 2 )
        break;
      ptr = realloc(ptr, v17 + 1);
      v8 = v17++;
      *((_BYTE *)ptr + v8) = 61;
    }
  }
  result = realloc(ptr, v17 + 1);
  result[v17] = 0;
  return result;
}

此处便为base64解密但是字母表却发生了变化.之后便是与RVYtG85NQ9OPHU4uQ8AuFM+MHVVrFMJMR8FuF8WJQ8Y=进行比较
写脚本解密

base64_table='IJLMNOPKABDEFGHCQRTUVWXSYZbcdefa45789+/6ghjklmnioprstuvqwxz0123y'
base_encode=str(raw_input(u"请输入解密字符"))
counter=base_encode.count("=")
length=len(base_encode)
encode=""
encode_re=""
if(counter==2):
    a=base64_table.find(base_encode[length-4:length-3])#取前六位
    a=a<<2
    b=base64_table.find(base_encode[length-3:length-2])#取2位
    b=b>>4
    encode_re=chr(a+b)
if(counter==1):
    a=base64_table.find(base_encode[length-4:length-3])#第一个字符前6位
    a=a<<2
    b=base64_table.find(base_encode[length-3:length-2])#第二个字符前2位
    b=b>>4
    encode_re1=chr(a+b)
    a=base64_table.find(base_encode[length-3:length-2])#第二个字符后4位
    a=(a&0xf)<<4
    b=base64_table.find(base_encode[length-2:length-1])#第三个字符前4位
    b=b>>2
    encode_re2=chr(a+b)
    encode_re=encode_re1+encode_re2
length=length-4
if(counter==0):
    length=length+4
for i in range(0,length,4):#以4个字符为一组
   a=base64_table.find(base_encode[i:i+1])#第一个字符6位
   a=a<<2
   b=base64_table.find(base_encode[i+1:i+2])#第二个字符前2位
   b=b>>4
   encode=encode+chr(a+b)
   a=base64_table.find(base_encode[i+1:i+2])#第二个字符后4位
   a=((a&0xf)<<4)
   b=base64_table.find(base_encode[i+2:i+3])#第三个字符前4位
   b=b>>2
   encode=encode+chr(a+b)
   a=base64_table.find(base_encode[i+2:i+3])#取第三个字符后2位
   a=(a&3)<<6
   b=base64_table.find(base_encode[i+3:i+4])#取第四个字符6位
   encode=encode+chr(a+b)
encode=encode+encode_re
print(encode)

解密出来之后为EF468DBAF985B2509C9E200CF3525AB6,再进行SM4解密参考教程,由于之前将ASCII码进行转换为字符串,所以解密时字符串就为其ASCII码
解密过程如下

得到0x36323631363437323635373233313332
由于前面将字符变为ASCII码在进行两次base16解密可得
用户名badrer12但是还缺少一个密码,由于最后的判断条件ptr+25的值要为0,且前面还有一些函数尚未分析 点开一看是虚拟机指令,由于函数较多只好将虚拟机指令拿出来慢慢分析

虚拟机分析

B019000000         push 0x19
B50A               pop  r11           r11=0x19    
B20B               push r12           r12=0
B409               pop ptr[r11]       ptr[0x19]=0
B01A000000         push 0x1a
B50A               pop  r11           r11=0x1a
040B09             mov ptr[r11],r12   ptr[0x1a]=0
B01A000000         push 0x1a         
B50A               pop r11
B20B               push r12  
B409               pop  ptr[r11]      ptr[0x1a]=0
90c2               jmp 0xc2
26:
011a0000000a       mov r11,0x1a        r11=0x1a
020900             mov r1,ptr[r11]    r1=ptr[0x1a]
10093000000001     r2=ptr[0x30] r2=&ptr[0x30]
b201               push r2            
b200               push r1             
c0                 mov [esp+4],r2+4*r1 
b500               pop r1            r1=&ptr[0x30]
b0f4ffffff         push fffffff4 
b50a               pop r11           r11=-12
b100               push r1[r11]      ptr[0x30-12]=ptr[0x24]  为第一个输入的字符
b501               pop r2            r2=input[0]
011a0000000a       mov r11,0x1a      r11=0x1a
b109               push ptr[r11]     
b500               pop  r1           r1=ptr[0x1a]
100078000000       r1=r1+78          r1=0x78+ptr[0x1a]
7000FF000000       r1=0xff&r1        
500018000000       r1=r1<<0x18       
b200               push r1   
b018000000         push 0x18        
c8                 (esp_1)=r1>>18    
b500               pop r1           
b201               push r2          
b200               push r1
c3                 esp-1^=esp-2     
b500               pop r1           r1=input[0]^0x78
500018000000       r1=r1<<0x18      
b200               push r1
b018000000         push 0x18
c8                 esp_1=r1>>0x18  
b500               pop r1     
7000ff000001       r2=r1&&0xff     r2=(input[0]^0x78)&0xff
01190000000a       r11=0x19     
020900             r1=ptr[r11]   
11010000           if(r2==0) r1=r2+4*r1 else r1=r2+r1
b019000000         push 0x19
b50a               pop  r11
b200               push r1
b409               pop  ptr[r11]   ptr[0x19]=r1
011a0000000a       r11=0x1a
b109               push ptr[r11]   prt[0x1a]
b500               pop  r1
10000100000000     r1=r1+1      
011a0000000a       r11=0x1a
040009             ptr[0x1a]=r1=1
b01a000000         push 0x1a
b50a               pop r11
020900             r1=ptr[r11]=ptr[0x1a]
86000600000000     r1=r1<0x6
8800026000000      r1!=0 jz 0x26  
91                 nop
ff                 exit
c2:
b01a000000         push 0x1a
b50a               pop r11
020900             mov r1,ptr[r11]  r1=0
86000600000000     r1=r1<0x6            
880026000000       r1!=0;jz 0x26    
91                 nop    
ff                 exit

由此可得知prt[0x1a]处计数循环,循环输入6次字符,且改变异或的值。ptr[0x19]为判断位。。判断异或后的值是否为0。而与其异或的就是xyz{|}

就可以得到密码
xyz{|}

总结

逆向题目中虚拟机经常是一个重要的考点,而最近密码法的出台使得密码,尤其是国密受到了重视。就在最近的中石油比赛中也碰到了国密。这题收获还是不小的。

0 条评论
某人
表情
可输入 255

没有评论

目录