AVALON 零散的一些题目 简单分析南宁杯 SMC.exe

简单分析南宁杯 SMC.exe

环境配置

系统 : Windows xp
程序 : SMC
要求 : 输入口令
使用工具 :IDA pro \ peid

开始分析

使用peid查看exe属性:
Microsoft Visual C++ 6.0
再用peid的密码学插件查看信息,点击拓展信息 -> 插件 -> krypto analyzer:

BASE64 table :: 0000805C :: 0040805C
    Referenced at 004010CC
    Referenced at 004010ED
    Referenced at 00401105
    Referenced at 0040110F

发现程序很有可能使用了base64编码,这里先用ida载入程序查看main函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  _BYTE *my_str; // esi@1
  int v4; // ST10_4@1
  int v5; // ST0C_4@1
  _BYTE *p_str; // eax@3
  signed int v7; // edi@3
  int result; // eax@8
  int v9; // [sp+0h] [bp-Ch]@0
  int index; // [sp+8h] [bp-4h]@3

  my_str = malloc(0x1Eu);
  print_4012E0((int)aWelcomeToGxnnc, v4);
  print_4012E0((int)aINeedYouToProv, v5);
  scanf(aS, my_str);
  if ( strlen(my_str) == 29 )
  {
    if ( my_str[28] == '}' )
    {
      index = 0;
      p_str = my_str;
      v7 = 8;
      do
      {
        if ( (*p_str ^ dword_40803C[(signed int)&p_str[3 - (_DWORD)my_str] % 8]) == p_str[aMww_cTw - my_str] )
          ++index;
        ++p_str;
        --v7;
      }
      while ( v7 );
      if ( index == 8 )
      {
        sub_401170((int)my_str);
        result = 0;
      }
      else
      {
        print_4012E0((int)aHereIsGxnnctf, v9);
        result = 0;
      }
    }
    else
    {
      print_4012E0((int)aUnlikeFlag____, v9);
      result = 0;
    }
  }
  else
  {
    print_4012E0((int)aUnlikeFlag_, v9);
    result = 0;
  }
  return result;
}

可以知道flag长度为29,其中最后一位为字符’}’,程序检测前面八个字节是否合规,这里查看aHereIsGxnnctf字符串可猜测前面八个字节为gxnnctf{

第一个检测

使用20个1去填充剩下的内容,然后使用ida动态调试代码,这里在第一个检测函数里面下断点:

int __cdecl sub_401170(char *my_str)
{
  signed int index_j; // eax@1
  int index; // esi@1
  int *v3; // ecx@1
  int result; // eax@6
  int v5; // [sp+8h] [bp-14h]@1
  int v6; // [sp+Ch] [bp-10h]@1
  int v7; // [sp+10h] [bp-Ch]@1
  int v8; // [sp+14h] [bp-8h]@1
  int v9; // [sp+18h] [bp-4h]@1

  index_j = 8;
  index = 0;
  v5 = 0x3D;
  v6 = 0xB;
  v7 = 0x5F;
  v8 = 8;
  v9 = 67;
  v3 = &v5;
  do
  {
    if ( (*v3 ^ my_str[index_j]) == 'n' )
      ++index;
    ++index_j;
    ++v3;
  }
  while ( index_j < 13 );
  if ( index == 5 )
    result = base64_401070((int)my_str);
  else
    result = print_4012E0((int)aWrongIDonotWan, v5);
  return result;
}

发现这里简单做了一个异或操作,写个脚本将固定字节与n异或:

➜  playground cat test.py
v5 = 0x3D
v6 = 0xB
v7 = 0x5F
v8 = 8
v9 = 67

mystr = ""
mystr += chr(0x3D^ord('n'))
mystr += chr(0xB^ord('n'))
mystr += chr(0x5F^ord('n'))
mystr += chr(8^ord('n'))
mystr += chr(67^ord('n'))

print mystr

得到第一段flag:

➜  playground python test.py 
Se1f-

第二个检测

继续动态调试,在第二个校验函数里下断点:

signed int __cdecl base64_401070(int my_str)
{
  char *v1; // eax@1
  int p_str_part2; // esi@1
  char v3; // cl@2
  signed int v4; // edx@2
  int v5; // eax@2
  signed int v6; // ecx@2
  signed int v7; // ebx@2
  int index; // ecx@3
  signed int index_j; // eax@3
  signed int result; // eax@8
  int v11; // [sp+0h] [bp-34h]@0
  int v12; // [sp+14h] [bp-20h]@1
  int v13; // [sp+18h] [bp-1Ch]@1
  int v14; // [sp+1Ch] [bp-18h]@1
  char v15; // [sp+20h] [bp-14h]@1
  char v16[16]; // [sp+24h] [bp-10h]@1

  v12 = dword_4080F8;
  v15 = byte_408104;
  v13 = dword_4080FC;
  v14 = dword_408100;
  v1 = v16;
  p_str_part2 = my_str + 14;
  do
  {
    v3 = *(_BYTE *)(p_str_part2 - 1);
    v4 = *(_BYTE *)(p_str_part2 - 1);
    v5 = (int)(v1 + 1);
    p_str_part2 += 3;
    *(_BYTE *)(v5 - 1) = base64_table_40805C[(v4 >> 2) & 0x3F];
    LOBYTE(v4) = *(_BYTE *)(p_str_part2 - 3);
    *(_BYTE *)(++v5 - 1) = base64_table_40805C[((signed int)*(_BYTE *)(p_str_part2 - 3) >> 4) & 0xF | 16 * (v3 & 3)];
    v6 = *(_BYTE *)(p_str_part2 - 2);
    v7 = v6;
    LOBYTE(v6) = base64_table_40805C[v6 & 0x3F];
    v1 = (char *)(v5 + 2);
    *(v1 - 2) = base64_table_40805C[4 * (v4 & 0xF) | (v7 >> 6) & 3];
    *(v1 - 1) = v6;
  }
  while ( -14 - my_str + p_str_part2 < 9 );
  index = 0;
  index_j = 0;
  do
  {
    if ( *((_BYTE *)&v12 + index_j) == v16[index_j] )
      ++index;
    ++index_j;
  }
  while ( index_j < 12 );
  if ( index == 12 )
    result = success_401000(my_str);
  else
    result = print_4012E0((int)aWrongIDonotWan, v11);
  return result;
}

发现取输入的字符串进行了一系列操作之后,将得出的字串和固定字符串对比,这里根据peid插件检测的结果,将相关数组改名为base64_table_40805C

经过动态调试,我们可以知道,do_while循环做的事base64加密操作,数据有如下对应关系:

TTBkaWZ5aW5n (decode) ->
M0difying

MTExMTExMTEx (decode) ->
111111111

所以第二段flag为M0difying

第三个检测

第三段就很简单了:

signed int __cdecl success_401000(char *my_str)
{
  signed int index; // eax@1
  int counter; // esi@1
  byte *p_key_data; // [sp+Ch] [bp-8h]@1
  __int16 v4; // [sp+10h] [bp-4h]@1
  char v5; // [sp+12h] [bp-2h]@1

  p_key_data = (byte *)dword_4080C4;
  v4 = word_4080C8;
  index = 22;
  counter = 0;
  v5 = byte_4080CA;
  do
  {
    if ( my_str[index] + 2 == LOBYTE((&p_key_data)[index - 22]) )
      ++counter;
    ++index;
  }
  while ( index < 28 );
  if ( counter == 6 )
    index = print_4012E0((int)aCongragulation, (int)p_key_data);
  return index;
}

直接将关键字节减去2就可以了,可编写如下python代码:

➜  playground cat test2.py 


print chr(0x66-2)
print chr(0x32-2)
print chr(0x65-2)
print chr(0x61-2)
print chr(0x23-2)
print chr(0x67-2)
➜  playground python test2.py
d
0
c
_
!
e

夺旗成功

输入按照各个步骤推理出的flag,提示成功:

Welcome to gxnnctf!I hope you could learn some knowledge.
I need you to provide something like flag:
gxnnctf{Se1f-M0difying_c0de!}
Congragulation!Your flag is right!

参考链接

  1. 南宁杯re之SMC.exe——OD动态调试查看栈内容 https://xz.aliyun.com/t/3841
  2. BASE64加密解密 https://base64.supfree.net/