【CTF reverse】新160个CrackMe之084-slayer_crackme1

239 阅读2分钟

PETools查看概况

32位程序 Section: [.text], EP: 0x00000400,无壳。

被逆向exe可在资源下载1下载。

作者:hans774882968以及hans774882968

IDA静态分析

打开IDA,我们很快找到了唯一需要关注的函数。

INT_PTR __stdcall DialogFunc(HWND hWnd, UINT a2, WPARAM a3, LPARAM a4)
{
  HICON v4; // eax@2
  unsigned int v5; // et0@2
  int v6; // esi@2
  unsigned __int8 v7; // al@3
  __int16 v9; // ax@8
  HANDLE v10; // eax@13
  DWORD v11; // eax@14
  HGLOBAL v12; // eax@16
  HANDLE v13; // eax@25
  unsigned int v14; // et0@26
  int v15; // ecx@26
  unsigned int v16; // [sp-24h] [bp-24h]@2
  unsigned int v17; // [sp-24h] [bp-24h]@26

  if ( a2 != 272 )
  {
    if ( a2 == 16 )
      EndDialog(hWnd, 0);
    if ( a2 != 273 )
      return 0;
    v9 = a3;
    if ( (_WORD)a3 == 104 )
      v9 = EndDialog(hWnd, 0);
    if ( v9 == 105 )
      v9 = MessageBoxA(0, Text, Caption, 0x40u);
    if ( v9 != 106 )
    {
LABEL_24:
      if ( v9 == 103 )
      {
        OpenClipboard(0);
        v13 = GetClipboardData(1u);
        if ( !v13 )
          goto LABEL_35;
        dword_403233 = (int)v13;
        v14 = __readeflags();
        v17 = v14;
        dword_403342 = dword_40333E;
        v15 = dword_403346;
        do
          dword_403342 -= *((char *)v13 + v15-- - 1);
        while ( v15 );
        __writeeflags(v17);
        if ( 0 == dword_403342 )
        {
          SetDlgItemTextA(hWnd, 102, aStep1OkNowRegi);
          EnableWindow(dword_403356, 0);
          EnableWindow(::hWnd, 1);
        }
        else
        {
LABEL_35:
          SetDlgItemTextA(hWnd, 102, aRegistrationFa);
        }
        CloseClipboard();
      }
      return 0;
    }
    v10 = CreateFileA(FileName, 0x80000000, 1u, 0, 3u, 0x80u, 0);
    if ( v10 == (HANDLE)-1 )
      goto LABEL_22;
    hFile = v10;
    v11 = GetFileSize(v10, 0);
    if ( v11 < 8 )
    {
      CloseHandle(hFile);
LABEL_22:
      SetDlgItemTextA(hWnd, 102, aRegistrationFa);
      EnableWindow(::hWnd, 0);
      EnableWindow(dword_403356, 1);
      goto LABEL_23;
    }
    nNumberOfBytesToRead = v11;
    v12 = GlobalAlloc(0x40u, v11);
    if ( v12 )
    {
      lpBuffer = v12;
      if ( !ReadFile(hFile, v12, nNumberOfBytesToRead, &NumberOfBytesRead, 0) )
      {
        CloseHandle(hFile);
        GlobalFree(lpBuffer);
        goto LABEL_22;
      }
      CloseHandle(hFile);
      if ( dword_403342 + (*((_DWORD *)lpBuffer + 1) ^ *(_DWORD *)lpBuffer) != dword_40333E )
        goto LABEL_22;
      SetDlgItemTextA(hWnd, 102, aGoodWork_YouHa);
      EnableWindow(::hWnd, 0);
    }
    else
    {
      SetDlgItemTextA(hWnd, 102, aMemoryAllocati);
      CloseHandle(hFile);
    }
LABEL_23:
    v9 = (unsigned int)GlobalFree(lpBuffer);
    goto LABEL_24;
  }
  v4 = LoadIconA(hInstance, (LPCSTR)0x3E8);
  SendMessageA(hWnd, 0x80u, 1u, (LPARAM)v4);
  dword_403356 = GetDlgItem(hWnd, 103);
  ::hWnd = GetDlgItem(hWnd, 106);
  nSize = 255;
  GetComputerNameA(String, &nSize);
  dword_403346 = lstrlenA(String);
  v5 = __readeflags();
  v16 = v5;
  v6 = (int)String;
  dword_40333E = 0;
  do
  {
    v7 = *(_BYTE *)v6++;
    dword_40333E += v7;
  }
  while ( v7 );
  __writeeflags(v16);
  return 0;
}

另外,查看字符串

aStep1OkNowRegi db 'Step 1 ok -> now Register it!',0
aGoodWork_YouHa db 'Good work. You have done it!',0
aRegistrationFa db 'Registration failed!!!',0
aMemoryAllocati db 'Memory allocation error!',0
FileName        db 'reg.key',0

根据aStep1OkNowRegi。显然关键跳不止一处。

第一关

相关代码:

        OpenClipboard(0);
        v13 = GetClipboardData(1u);
        if ( !v13 )
          goto LABEL_35;
        dword_403233 = (int)v13;
        v14 = __readeflags();
        v17 = v14;
        dword_403342 = dword_40333E;
        v15 = dword_403346;
        do
          dword_403342 -= *((char *)v13 + v15-- - 1);
        while ( v15 );
        __writeeflags(v17);
        if ( 0 == dword_403342 )
        {
          SetDlgItemTextA(hWnd, 102, aStep1OkNowRegi);
          EnableWindow(dword_403356, 0);
          EnableWindow(::hWnd, 1);
        }
        else
        {
LABEL_35:
          SetDlgItemTextA(hWnd, 102, aRegistrationFa);
        }

这段代码要求你剪贴板字符串ASCII值之和等于dword_403342dword_403342初值来自于dword_40333E。那dword_40333E从哪来?狡猾啊!在DialogFunc最下面!

  GetComputerNameA(String, &nSize);
  dword_403346 = lstrlenA(String);
  v5 = __readeflags();
  v16 = v5;
  v6 = (int)String;
  dword_40333E = 0;
  do
  {
    v7 = *(_BYTE *)v6++;
    dword_40333E += v7;
  }
  while ( v7 );
  __writeeflags(v16);

逻辑很简单,取出ComputerName,把每个字符的ASCII值加起来。因此一个合法方案就是复制ComputerName。

第二关

    v10 = CreateFileA(FileName, 0x80000000, 1u, 0, 3u, 0x80u, 0);// reg.key
    if ( v10 == (HANDLE)-1 )
      goto LABEL_22;
    hFile = v10;
    v11 = GetFileSize(v10, 0);
    if ( v11 < 8 )
    {
      CloseHandle(hFile);
LABEL_22:
      SetDlgItemTextA(hWnd, 102, aRegistrationFa);
      EnableWindow(::hWnd, 0);
      EnableWindow(dword_403356, 1);
      goto LABEL_23;
    }
    nNumberOfBytesToRead = v11;
    v12 = GlobalAlloc(0x40u, v11);
    if ( v12 )
    {
      lpBuffer = v12;
      if ( !ReadFile(hFile, v12, nNumberOfBytesToRead, &NumberOfBytesRead, 0) )
      {
        CloseHandle(hFile);
        GlobalFree(lpBuffer);
        goto LABEL_22;
      }
      CloseHandle(hFile);
      if ( dword_403342 + (*((_DWORD *)lpBuffer + 1) ^ *(_DWORD *)lpBuffer) != dword_40333E )
        goto LABEL_22;
      SetDlgItemTextA(hWnd, 102, aGoodWork_YouHa);
      EnableWindow(::hWnd, 0);
    }
    else
    {
      SetDlgItemTextA(hWnd, 102, aMemoryAllocati);
      CloseHandle(hFile);
    }

因为不熟悉Windows api,在这个lpBuffer这里浪费了不少时间。根据 HGLOBAL v12; // eax@16lpBuffer = v12或者强转为DWORD,可知lpBuffer是4字节的。那么*lpBuffer + 1实际上是取输入文件reg.key的第4~7字节(0-indexed)。另外查了下,GlobalAlloc(0x40u, v11)用来分配一段堆上的内存,大小为文件size(v11)。

dword_403342在上面减为0之后没有改变,因此总是0。所以这里需要我们构造一个reg.key文件,它的第0~34~7个字节作为整数xy,满足x ^ y = dword_40333E。根据异或的性质可以秒掉。

如果想patch的话,就用IDA的patch功能把两个关键跳的汇编代码替换或者nop掉即可,难度比找到算法小。

注册机

下面的python3代码用到:

  1. bytearray可以直接写入文件
  2. bytearray的每个元素可以直接当int使
import os

computerName = os.environ['COMPUTERNAME']
ans = 0
for c in computerName:
    ans += ord(c)
print(computerName,hex(ans))# 0x3fd
u = bytearray("hans",encoding = "utf-8")
v = bytearray([u[i] ^ (ans >> (8*i) & 0xff) for i in range(4)])
print(v)
with open("reg.key","wb") as f:
    f.write(u)
    f.write(v)

资源下载

  1. exe文件可以在这个视频的简介给出的链接找到。