ciscn-bbvvmm-虚拟指令分析,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码,并且存储到V13之中。
而有关v13的处理函数在函数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函数

 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;

该函数首先将数组8个字符生成的ASCII码即16个字符分成4组,接着执行32次循环执行函数40EE2函数,第一次执行时参数为4组ASCII码和一个不知道是啥的数字,进入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最后再与a1异或,在进入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个8位的字符
在这里插入图片描述
最后一步返回是一串比较复杂的加密,其实这便是SM4加密最后一步应该便是L变换,而上面那一串看不懂的数字便是轮密钥,那个字母表便是SM4的S盒,确定了加密明文盒加密方式之后便是寻找密钥了,然而密钥处理是第一步,便是主函数的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
与其异或的分别为
0xDA98F1DA
0X312AB753
0XA5703A0B
0XFD290DD6
由此便可以知道此处为密钥,继续向下分析

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;
}

此处将加密之后的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,且前面还有一些函数尚未分析 点开一看为虚拟机指令

nsigned __int64 __fastcall sub_405B25(__int64 a1)
{
  unsigned __int64 v1; // ST18_8

  v1 = __readfsqword(0x28u);
  *(_DWORD *)a1 = 0;
  *(_DWORD *)(a1 + 4) = 0;
  *(_DWORD *)(a1 + 8) = 0;
  *(_DWORD *)(a1 + 12) = 0;
  *(_DWORD *)(a1 + 16) = 0;
  *(_DWORD *)(a1 + 20) = 0;
  *(_DWORD *)(a1 + 24) = 0;
  *(_DWORD *)(a1 + 28) = 0;
  *(_DWORD *)(a1 + 32) = 0;
  *(_DWORD *)(a1 + 36) = 0;
  *(_DWORD *)(a1 + 40) = 0;
  *(_DWORD *)(a1 + 44) = 0;
  *(_DWORD *)(a1 + 48) = (unsigned __int64)&unk_6090E0;
  *(_QWORD *)(a1 + 56) = &unk_6090E0;
  qword_609240 = malloc(0x1000uLL);
  ptr = malloc(0x1000uLL);
  qword_609260 = malloc(0x1000uLL);
  qword_609248 = malloc(0x1000uLL);
  qword_609268 = malloc(0x1000uLL);
  qword_609250 = malloc(0x1000uLL);
  memset(qword_609240, 0, 0x1000uLL);
  memset(ptr, 0, 0x1000uLL);
  memset(qword_609260, 0, 0x1000uLL);
  memset(qword_609248, 0, 0x1000uLL);
  memset(qword_609268, 0, 0x1000uLL);
  memset(qword_609250, 0, 0x1000uLL);
  *(_DWORD *)(a1 + 16) = (_DWORD)qword_609260;
  *(_DWORD *)(a1 + 20) = (_DWORD)qword_609248;
  *(_DWORD *)(a1 + 24) = (_DWORD)qword_609268;
  *(_DWORD *)(a1 + 28) = (_DWORD)qword_609250;
  *(_DWORD *)(a1 + 36) = (_DWORD)ptr;
  *(_DWORD *)(a1 + 64) = 1;
  *(_QWORD *)(a1 + 72) = sub_401AA3;
  *(_DWORD *)(a1 + 80) = 2;
  *(_QWORD *)(a1 + 88) = sub_401B32;
  *(_DWORD *)(a1 + 96) = 3;
  *(_QWORD *)(a1 + 104) = sub_401C23;
  *(_DWORD *)(a1 + 112) = 4;
  *(_QWORD *)(a1 + 120) = sub_401CCF;
  *(_DWORD *)(a1 + 128) = 5;
  *(_QWORD *)(a1 + 136) = sub_401DC0;
  *(_DWORD *)(a1 + 144) = 16;
  *(_QWORD *)(a1 + 152) = sub_401E94;
  *(_DWORD *)(a1 + 160) = 17;
  *(_QWORD *)(a1 + 168) = sub_401F89;
  *(_DWORD *)(a1 + 176) = 18;
  *(_QWORD *)(a1 + 184) = sub_40209B;
  *(_DWORD *)(a1 + 192) = 19;
  *(_QWORD *)(a1 + 200) = sub_4021C1;
  *(_DWORD *)(a1 + 208) = 20;
  *(_QWORD *)(a1 + 216) = sub_4022CA;
  *(_DWORD *)(a1 + 224) = 38;
  *(_QWORD *)(a1 + 232) = sub_4023F0;
  *(_DWORD *)(a1 + 240) = 39;
  *(_QWORD *)(a1 + 248) = sub_4024B4;
  *(_DWORD *)(a1 + 256) = 40;
  *(_QWORD *)(a1 + 264) = sub_402595;
  *(_DWORD *)(a1 + 272) = 41;
  *(_QWORD *)(a1 + 280) = sub_4026BB;
  *(_DWORD *)(a1 + 288) = 42;
  *(_QWORD *)(a1 + 296) = sub_4027C4;
  *(_DWORD *)(a1 + 304) = 48;
  *(_QWORD *)(a1 + 312) = sub_4028EA;
  *(_DWORD *)(a1 + 320) = 49;
  *(_QWORD *)(a1 + 328) = sub_4029AF;
  *(_DWORD *)(a1 + 336) = 50;
  *(_QWORD *)(a1 + 344) = sub_402A91;
  *(_DWORD *)(a1 + 352) = 51;
  *(_QWORD *)(a1 + 360) = sub_402BB8;
  *(_DWORD *)(a1 + 368) = 52;
  *(_QWORD *)(a1 + 376) = sub_402CC2;
  *(_DWORD *)(a1 + 384) = 70;
  *(_QWORD *)(a1 + 392) = sub_402DE9;
  *(_DWORD *)(a1 + 400) = 71;
  *(_QWORD *)(a1 + 408) = sub_402EAF;
  *(_DWORD *)(a1 + 416) = 72;
  *(_QWORD *)(a1 + 424) = sub_402F92;
  *(_DWORD *)(a1 + 432) = 73;
  *(_QWORD *)(a1 + 440) = sub_4030BA;
  *(_DWORD *)(a1 + 448) = 74;
  *(_QWORD *)(a1 + 456) = sub_4031C5;
  *(_DWORD *)(a1 + 464) = 80;
  *(_QWORD *)(a1 + 472) = sub_4032ED;
  *(_DWORD *)(a1 + 480) = 81;
  *(_QWORD *)(a1 + 488) = sub_4033B3;
  *(_DWORD *)(a1 + 496) = 82;
  *(_QWORD *)(a1 + 504) = sub_403496;
  *(_DWORD *)(a1 + 512) = 83;
  *(_QWORD *)(a1 + 520) = sub_4035BE;
  *(_DWORD *)(a1 + 528) = 84;
  *(_QWORD *)(a1 + 536) = sub_4036C9;
  *(_DWORD *)(a1 + 544) = 102;
  *(_QWORD *)(a1 + 552) = sub_4037F1;
  *(_DWORD *)(a1 + 560) = 103;
  *(_QWORD *)(a1 + 568) = sub_4038B5;
  *(_DWORD *)(a1 + 576) = 104;
  *(_QWORD *)(a1 + 584) = sub_403996;
  *(_DWORD *)(a1 + 592) = 105;
  *(_QWORD *)(a1 + 600) = sub_403ABC;
  *(_DWORD *)(a1 + 608) = 106;
  *(_QWORD *)(a1 + 616) = sub_403BC5;
  *(_DWORD *)(a1 + 624) = 112;
  *(_QWORD *)(a1 + 632) = sub_403CEB;
  *(_DWORD *)(a1 + 640) = 113;
  *(_QWORD *)(a1 + 648) = sub_403DAF;
  *(_DWORD *)(a1 + 656) = 114;
  *(_QWORD *)(a1 + 664) = sub_403E90;
  *(_DWORD *)(a1 + 672) = 115;
  *(_QWORD *)(a1 + 680) = sub_403FB6;
  *(_DWORD *)(a1 + 688) = 116;
  *(_QWORD *)(a1 + 696) = sub_4040BF;
  *(_DWORD *)(a1 + 704) = 128;
  *(_QWORD *)(a1 + 712) = sub_4041E5;
  *(_DWORD *)(a1 + 720) = 129;
  *(_QWORD *)(a1 + 728) = sub_4042A9;
  *(_DWORD *)(a1 + 736) = 130;
  *(_QWORD *)(a1 + 744) = sub_40438A;
  *(_DWORD *)(a1 + 752) = 131;
  *(_QWORD *)(a1 + 760) = sub_4044B0;
  *(_DWORD *)(a1 + 768) = 0x84;
  *(_QWORD *)(a1 + 776) = sub_4045B9;
  *(_DWORD *)(a1 + 784) = 0x86;
  *(_QWORD *)(a1 + 792) = sub_404BED;
  *(_DWORD *)(a1 + 800) = 0x87;
  *(_QWORD *)(a1 + 808) = sub_404CC3;
  *(_DWORD *)(a1 + 816) = 0x88;
  *(_QWORD *)(a1 + 824) = sub_404DB6;
  *(_DWORD *)(a1 + 832) = 0x89;
  *(_QWORD *)(a1 + 840) = sub_404E61;
  *(_DWORD *)(a1 + 848) = 0x8A;
  *(_QWORD *)(a1 + 856) = sub_404F3F;
  *(_DWORD *)(a1 + 864) = 0x8B;
  *(_QWORD *)(a1 + 872) = sub_404FEA;
  *(_DWORD *)(a1 + 880) = 0x90;
  *(_QWORD *)(a1 + 888) = sub_4050C8;
  *(_DWORD *)(a1 + 896) = 145;
  *(_QWORD *)(a1 + 904) = sub_405126;
  *(_DWORD *)(a1 + 912) = 160;
  *(_QWORD *)(a1 + 920) = sub_4046DF;
  *(_DWORD *)(a1 + 928) = 0xA1;
  *(_QWORD *)(a1 + 936) = sub_4047A7;
  *(_DWORD *)(a1 + 944) = 0xA2;
  *(_QWORD *)(a1 + 952) = sub_40488C;
  *(_DWORD *)(a1 + 960) = 163;
  *(_QWORD *)(a1 + 968) = sub_4049B6;
  *(_DWORD *)(a1 + 976) = 164;
  *(_QWORD *)(a1 + 984) = sub_404AC3;
  *(_DWORD *)(a1 + 992) = 0xB0;
  *(_QWORD *)(a1 + 1000) = sub_40516C;
  *(_DWORD *)(a1 + 1008) = 0xB1;
  *(_QWORD *)(a1 + 1016) = sub_4051E3;
  *(_DWORD *)(a1 + 1024) = 0xB2;
  *(_QWORD *)(a1 + 1032) = sub_4052BC;
  *(_DWORD *)(a1 + 1040) = 0xB3;
  *(_QWORD *)(a1 + 1048) = sub_405350;
  *(_DWORD *)(a1 + 1056) = 0xB4;
  *(_QWORD *)(a1 + 1064) = sub_4053C7;
  *(_DWORD *)(a1 + 1072) = 0xB5;
  *(_QWORD *)(a1 + 1080) = sub_4054A0;
  *(_DWORD *)(a1 + 1088) = 192;
  *(_QWORD *)(a1 + 1096) = sub_405534;
  *(_DWORD *)(a1 + 1104) = 193;
  *(_QWORD *)(a1 + 1112) = sub_4055D6;
  *(_DWORD *)(a1 + 1120) = 194;
  *(_QWORD *)(a1 + 1128) = sub_405649;
  *(_DWORD *)(a1 + 1136) = 195;
  *(_QWORD *)(a1 + 1144) = sub_4056BC;
  *(_DWORD *)(a1 + 1152) = 196;
  *(_QWORD *)(a1 + 1160) = sub_40572F;
  *(_DWORD *)(a1 + 1168) = 197;
  *(_QWORD *)(a1 + 1176) = sub_4057A2;
  *(_DWORD *)(a1 + 1184) = 198;
  *(_QWORD *)(a1 + 1192) = sub_405817;
  *(_DWORD *)(a1 + 1200) = 199;
  *(_QWORD *)(a1 + 1208) = sub_40588B;
  *(_DWORD *)(a1 + 1216) = 200;
  *(_QWORD *)(a1 + 1224) = sub_405904;
  return __readfsqword(0x28u) ^ v1;
}
unsigned __int64 __fastcall sub_406607(__int64 virtual_1)
{
  unsigned __int64 v2; // [rsp+18h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  while ( **(_BYTE **)(virtual_1 + 56) != -1 )  // 第一个字符为B0
    sub_40656D(virtual_1);
  return __readfsqword(0x28u) ^ v2;
}
unsigned __int64 __fastcall sub_40656D(__int64 virtual_1)
{
  unsigned __int8 i; // [rsp+17h] [rbp-9h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  for ( i = 0; i <= 0x48u; ++i )
  {
    if ( **(unsigned __int8 **)(virtual_1 + 56) == *(_DWORD *)(16 * (i + 4LL) + virtual_1) )// 第一个字符为B0执行40516c函数
    {
      (*(void (__fastcall **)(__int64))(16 * (i + 4LL) + virtual_1 + 8))(virtual_1);
      return __readfsqword(0x28u) ^ v3;
    }
  }
  return __readfsqword(0x28u) ^ v3;

和上次DDCTF的虚拟指令分析很像。字节码在6090E0处,起初分析了一会儿后来觉得挺复杂的干脆就动态调试看汇编,下硬件断点调试过也找到了异或的数据。但是其实虚拟机指令也可以分析

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值