首页
社区
课程
招聘
[原创]2019看雪CTF 第四题:达芬奇密码
发表于: 2019-6-27 00:50 8256

[原创]2019看雪CTF 第四题:达芬奇密码

2019-6-27 00:50
8256
运行程序,随便输入一串字符,弹出提示框:

将程序拖入IDA,打开Strings窗口搜索 Wrong
emmmm,居然没有搜索到,这表示程序会在运行过程中,动态解密所需字符串。
动态调试,果然在程序内存中发现有Wrong字符串,计算出Wrong字符串偏移是0x1FDE
IDA打开程序,按住Ctrl+S,找出基址为0x400000,Wrong字符串在程序中偏移地址为0x400000+0x1FDE=0x401FDE
按G,输入0x401FDE,跳转到对应位置,按F5反编译成伪代码:
int __thiscall sub_401EA0(CWnd *this)
{
  CWnd *v1; // esi
  int v2; // eax
  WCHAR String; // [esp+Ch] [ebp-310h]
  char v5; // [esp+Eh] [ebp-30Eh]
  char v6; // [esp+20Ch] [ebp-110h]
  char v7; // [esp+20Dh] [ebp-10Fh]
  DWORD v8; // [esp+30Ch] [ebp-10h]
  CWnd *v9; // [esp+310h] [ebp-Ch]
  unsigned int v10; // [esp+314h] [ebp-8h]
  DWORD flOldProtect; // [esp+318h] [ebp-4h]

  v1 = this;
  v9 = this;
  String = 0;
  memset(&v5, 0, 0x1FEu);
  v6 = 0;
  memset(&v7, 0, 0xFFu);
  CWnd::GetDlgItemTextW(v1, 0x3E8, &String, 0x14);
  if ( wcslen(&String) == 0x10 )
  {
    v2 = 0;
    while ( !(*(&String + v2) & 0xFF00) )
    {
      *(&v6 + v2) = *((_BYTE *)&String + 2 * v2);
      if ( ++v2 >= 0x10 )
      {
        v8 = 0x40;
        flOldProtect = 0;
        VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect);
        if ( GetLastError() )
          return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
        qmemcpy(sub_4010E0, &byte_5647B8, 0x330u);
        VirtualProtect(sub_4010E0, 0xD17u, flOldProtect, &v8);
        if ( !GetLastError() )
        {
          v10 = 0;
          v10 = sub_4010E0();
          if ( v10 == 1 )
            return CWnd::MessageBoxW(v9, L"Congratulations! You are right!", 0, 0);
        }
        v1 = v9;
        return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
      }
    }
  }
  return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
}

int __thiscall sub_401EA0(CWnd *this)
{
  CWnd *v1; // esi
  int v2; // eax
  WCHAR String; // [esp+Ch] [ebp-310h]
  char v5; // [esp+Eh] [ebp-30Eh]
  char v6; // [esp+20Ch] [ebp-110h]
  char v7; // [esp+20Dh] [ebp-10Fh]
  DWORD v8; // [esp+30Ch] [ebp-10h]
  CWnd *v9; // [esp+310h] [ebp-Ch]
  unsigned int v10; // [esp+314h] [ebp-8h]
  DWORD flOldProtect; // [esp+318h] [ebp-4h]

  v1 = this;
  v9 = this;
  String = 0;
  memset(&v5, 0, 0x1FEu);
  v6 = 0;
  memset(&v7, 0, 0xFFu);
  CWnd::GetDlgItemTextW(v1, 0x3E8, &String, 0x14);
  if ( wcslen(&String) == 0x10 )
  {
    v2 = 0;
    while ( !(*(&String + v2) & 0xFF00) )
    {
      *(&v6 + v2) = *((_BYTE *)&String + 2 * v2);
      if ( ++v2 >= 0x10 )
      {
        v8 = 0x40;
        flOldProtect = 0;
        VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect);
        if ( GetLastError() )
          return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
        qmemcpy(sub_4010E0, &byte_5647B8, 0x330u);
        VirtualProtect(sub_4010E0, 0xD17u, flOldProtect, &v8);
        if ( !GetLastError() )
        {
          v10 = 0;
          v10 = sub_4010E0();
          if ( v10 == 1 )
            return CWnd::MessageBoxW(v9, L"Congratulations! You are right!", 0, 0);
        }
        v1 = v9;
        return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
      }
    }
  }
  return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
}

if ( wcslen(&String) == 0x10 ) //只能输入长度为16的字符

if ( wcslen(&String) == 0x10 ) //只能输入长度为16的字符

while ( !(*(&String + v2) & 0xFF00) ) // 字符范围是从0001到00FF,即ASCII码

while ( !(*(&String + v2) & 0xFF00) ) // 字符范围是从0001到00FF,即ASCII码

动态解密函数sub_4010E0
VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect);
if ( GetLastError() ) return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
qmemcpy(sub_4010E0, &byte_5647B8, 0x330u);
VirtualProtect(sub_4010E0, 0xD17u, flOldProtect, &v8);
VirtualProtect(sub_4010E0, 0xD17u, 0x40u, &flOldProtect);
if ( GetLastError() ) return CWnd::MessageBoxW(v1, L"Wrong!", 0, 0);
qmemcpy(sub_4010E0, &byte_5647B8, 0x330u);
VirtualProtect(sub_4010E0, 0xD17u, flOldProtect, &v8);

qmemcpy引起我的兴趣,其作用为将一段长度为0x330的字符复制到sub_4010E0里面。右击byte_5647B8,查找引用。发现sub_401D80()做了一些操作,它异或了0xAB

只要函数sub_4010E0返回值为1,我们就达到目的


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2019-6-27 15:28 被xmhwws编辑 ,原因:
收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//