Writeup of Imageprc(reverse) in reversing.kr

做这道题……收获是……了解了几个WINAPI吧

0x00 Program Logic

首先运行程序,发现出现一个空白画板,用光标作图,再点击'Check'Button,弹窗Wrong
把程序扔进IDA,观察代码逻辑。首先看WinMain函数
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
  int v4; // ST14_4@1
  int v5; // eax@1
  HWND v6; // eax@1
  int result; // eax@3
  struct tagMSG Msg; // [sp+4h] [bp-44h]@1
  WNDCLASSA WndClass; // [sp+20h] [bp-28h]@1

  dword_4084D8 = (int)hInstance;
  WndClass.cbClsExtra = 0;
  WndClass.cbWndExtra = 0;
  WndClass.hbrBackground = (HBRUSH)GetStockObject(0);
  WndClass.hCursor = LoadCursorA(0, (LPCSTR)0x7F00);
  WndClass.hInstance = hInstance;
  WndClass.hIcon = LoadIconA(0, (LPCSTR)0x7F00);
  WndClass.lpfnWndProc = (WNDPROC)sub_401130;
  WndClass.lpszClassName = lpWindowName;
  WndClass.lpszMenuName = 0;
  WndClass.style = 3;
  RegisterClassA(&WndClass);
  v4 = GetSystemMetrics(1) / 2 - 75;
  v5 = GetSystemMetrics(0);
  v6 = CreateWindowExA(0, lpWindowName, lpWindowName, 0xCA0000u, v5 / 2 - 100, v4, 200, 150, 0, 0, hInstance, 0);
  ShowWindow(v6, 5);
  if ( GetMessageA(&Msg, 0, 0, 0) )
  {
    do
    {
      TranslateMessage(&Msg);
      DispatchMessageA(&Msg);
    }
    while ( GetMessageA(&Msg, 0, 0, 0) );
    result = Msg.wParam;
  }
  else
  {
    result = Msg.wParam;
  }
  return result;
}

  • 用GetStockObject选取NULL_BRUSH画刷样式填充主窗口背景色,
  • 用LoadCursor选取IDC_ARROW(Standard arrow)作为光标样式,
  • 用LoadIcon选取IDI_APPLICATION(Default application icon)作为所加载的图标资源,
  • 随后lpfnWndProc来处理所接收到的键盘消息和鼠标消息(关键函数sub_401130),
  • lpszClassName描述窗口类名为lpWindowNmae,lpszMenuName设置菜单为NULL,style设置为3,
  • 注册窗口;
  • GetSystemMetrics(1)获取以像素为单位的计算机屏幕高度(SM_CYSCREEN),GetSystemMetrics(0)获取以像素为单位的计算机屏幕宽度(SM_CXSCREEN),其实也可以通过GetDeviceCaps获取计算机屏幕宽高,
  • 用CreateWindowEx创建窗口,dwExStyle是WS_EX_LTRREADING(默认样式),dwStyle是0xCA0000(然而我并没有在MSDN上查到该数值对应的风格?),高为150像素,宽为200像素,坐标……自己看吧
  • ShowWindow窗口展示;
  • 随后GetMessage,再通过TranslateMessage和DisPatchMessage将用户的键盘消息和鼠标消息转发到过程函数sub_401130,在该函数内完成judge。
接下来看看sub_401130的伪代码
LRESULT __stdcall sub_401130(HWND hWnd, UINT Msg, WPARAM wParam, unsigned int lParam)
{
  HDC v4; // eax@6
  LRESULT result; // eax@6
  HGDIOBJ v6; // eax@7
  HDC v7; // esi@8
  void *v8; // esi@10
  HRSRC v9; // eax@10
  HGLOBAL v10; // eax@10
  _BYTE *v11; // eax@10
  signed int v12; // edi@10
  _BYTE *v13; // ecx@10
  int v14; // eax@10
  char pv; // [sp+8h] [bp-80h]@10
  LONG v16; // [sp+Ch] [bp-7Ch]@10
  UINT cLines; // [sp+10h] [bp-78h]@10
  struct tagBITMAPINFO bmi; // [sp+20h] [bp-68h]@6

  if ( Msg <= 0x111 )
  {
    if ( Msg != 273 )
    {
      if ( Msg == 1 )
      {
        v7 = GetDC(hWnd);
        hbm = CreateCompatibleBitmap(v7, 200, 150);
        hdc = CreateCompatibleDC(v7);
        h = SelectObject(hdc, hbm);
        Rectangle(hdc, -5, -5, 205, 205);
        ReleaseDC(hWnd, v7);
        ::wParam = (WPARAM)CreateFontA(12, 0, 0, 0, 400, 0, 0, 0, 0x81u, 0, 0, 0, 0x12u, pszFaceName);
        dword_4084E0 = (int)CreateWindowExA(
                              0,
                              ClassName,
                              WindowName,
                              0x50000000u,
                              60,
                              85,
                              80,
                              28,
                              hWnd,
                              (HMENU)0x64,
                              hInstance,
                              0);
        SendMessageA((HWND)dword_4084E0, 0x30u, ::wParam, 0);
        return 0;
      }
      if ( Msg == 2 )
      {
        v6 = SelectObject(hdc, h);
        DeleteObject(v6);
        DeleteDC(hdc);
        PostQuitMessage(0);
        return 0;
      }
      if ( Msg == 15 )
      {
        v4 = BeginPaint(hWnd, (LPPAINTSTRUCT)bmi.bmiColors);
        BitBlt(v4, 0, 0, 200, 150, hdc, 0, 0, 0xCC0020u);
        EndPaint(hWnd, (const PAINTSTRUCT *)bmi.bmiColors);
        return 0;
      }
      return DefWindowProcA(hWnd, Msg, wParam, lParam);
    }
    if ( wParam == 100 )
    {
      GetObjectA(hbm, 24, &pv);
      memset(&bmi, 0, 0x28u);
      bmi.bmiHeader.biHeight = cLines;
      bmi.bmiHeader.biWidth = v16;
      bmi.bmiHeader.biSize = 40;
      bmi.bmiHeader.biPlanes = 1;
      bmi.bmiHeader.biBitCount = 24;
      bmi.bmiHeader.biCompression = 0;
      GetDIBits(hdc, (HBITMAP)hbm, 0, cLines, 0, &bmi, 0);
      v8 = (void *)sub_40150B(bmi.bmiHeader.biSizeImage);
      GetDIBits(hdc, (HBITMAP)hbm, 0, cLines, v8, &bmi, 0);
      v9 = FindResourceA(0, (LPCSTR)0x65, (LPCSTR)0x18);
      v10 = LoadResource(0, v9);
      v11 = LockResource(v10);
      v12 = 0;
      v13 = v8;
      v14 = v11 - (_BYTE *)v8;
      while ( *v13 == v13[v14] )
      {
        ++v12;
        ++v13;
        if ( v12 >= 90000 )
        {
          sub_401500(v8);
          return 0;
        }
      }
      MessageBoxA(hWnd, Text, Caption, 0x30u);
      sub_401500(v8);
      return 0;
    }
    return 0;
  }
  if ( Msg == 512 )
  {
    if ( dword_47D7F8 )
    {
      MoveToEx(hdc, x, y, 0);
      LineTo(hdc, (unsigned __int16)lParam, lParam >> 16);
      x = (unsigned __int16)lParam;
      y = lParam >> 16;
      InvalidateRect(hWnd, 0, 0);
    }
    return 0;
  }
  if ( Msg == 513 )
  {
    dword_47D7F8 = 1;
    y = lParam >> 16;
    x = (unsigned __int16)lParam;
    result = 0;
  }
  else
  {
    if ( Msg != 514 )
      return DefWindowProcA(hWnd, Msg, wParam, lParam);
    dword_47D7F8 = 0;
    result = 0;
  }
  return result;
}
  • GetDC指定hWnd为句柄,以后便可在GDI函数中用该句柄上下文环境中绘图,随后CreateCompatibleBitmap创建宽200高150的位图,CreateCompatibleDC创建上下文环境,然后那么一大通API就是用来让你在这个位图里绘图的OTZ(API太多了我已经不想解释了);
  • 一通API之后就开始Judge,首先是FindResource,然后是LoadResource,最后开始把Resource里的内容和画上去的内容逐像素点比较(拆成RGB是90000次Judge);
以上……就是程序逻辑……

0x01 Dump

开始动态调试……在LoadResource后把90000个数据用IDC给Dump下来,脚本及内存截图如下 Writeup of Imageprc(reverse) in reversing.kr_第1张图片
Run之后90000个bytes就被写到了文件里;


0x02 Restore bmp

不会PIL的哭了……
写了好久……还去查了官方文档……
from PIL import Image

width=200
height=150

f=open('imageprc.txt','rb')
data=f.read()
p=Image.frombytes('RGB',(width,height),data)
p=p.transpose(Image.FLIP_TOP_BOTTOM)
p.show()

那个FLIP_TOP_BOTTOM真是……后来在其他大师傅的脚本上才看到……加了上去……完善了一下

于是得到一张图……写着GOT(可是按道理不用TOP_BOTTOM应该能得到正确的GOT图啊?这里是一个疑问……也许和Resource加载的顺序有关?)

得到flag,即GOT

你可能感兴趣的:(Reverse_of_CTF)