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

2019-05-23 约 2185 字 预计阅读 11 分钟

声明:本文 【国赛-bbvvmm-SM4逆向分析,虚拟机指令分析】 由作者 playm**** 于 2019-05-23 08:57:00 首发 先知社区 曾经 浏览数 109 次

感谢 playm**** 的辛苦付出!

国赛-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{|}

总结

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

关键词:[‘安全技术’, ‘CTF’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now