lizhirui 发表于 2018-10-8 17:00

对吾爱破解2016年安全挑战赛第一题的相关分析

本帖最后由 lizhirui 于 2018-10-9 08:09 编辑

注意,此分析中包含部分关于Windows对话框消息处理机制的分析首先我们用Peid查壳,发现是Visual C++ 8写成的程序,然后我们用OD加载,看到了软件界面,随便输入一组信息,提示failed!
接下来,用WinDbg加载程序,对DispatchMessageW函数下断,可以发现其堆栈如下:

ChildEBP RetAddr
0018fe6c 763dcdfd USER32!DispatchMessageW
0018feac 763dcf5c USER32!DialogBox2+0x175
0018fed8 763dce8a USER32!InternalDialogBox+0xe5
0018fef8 763fcb58 USER32!DialogBoxIndirectParamAorW+0x37
0018ff24 0040123f USER32!DialogBoxParamA+0x4c
WARNING: Stack unwind information not available. Following frames may be wrong.
0018ff88 769033aa 52challenge+0x123f
0018ff94 771c9f72 kernel32!BaseThreadInitThunk+0xe
0018ffd4 771c9f45 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

其中52challenge+0x123f就是调用DialogBoxParamA的代码,其中根据ReactOS 0.4.9的源代码如下:

INT_PTR
WINAPI
DialogBoxParamA(
HINSTANCE hInstance,
LPCSTR lpTemplateName,
HWND hWndParent,
DLGPROC lpDialogFunc,
LPARAM dwInitParam)
{
    HWND hwnd;
    HRSRC hrsrc;
    LPCDLGTEMPLATE ptr;
//// ReactOS rev 33532
    if (!(hrsrc = FindResourceA( hInstance, lpTemplateName, (LPCSTR)RT_DIALOG )) ||
      !(ptr = LoadResource(hInstance, hrsrc)))
    {
      SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
      return -1;
    }
    if (hWndParent != NULL && !IsWindow(hWndParent))
    {
      SetLastError(ERROR_INVALID_WINDOW_HANDLE);
      return 0;
    }
    hwnd = DIALOG_CreateIndirect(hInstance, ptr, hWndParent, lpDialogFunc, dwInitParam, FALSE, &hWndParent );
    if (hwnd) return DIALOG_DoDialogBox(hwnd, hWndParent);
    return -1;
}


可见其中有一个lpDialogFunc函数指针,其是用于处理Dialog的事件的。
我们进入DIALOG_CreateIndirect看看:

static HWND DIALOG_CreateIndirect( HINSTANCE hInst, LPCVOID dlgTemplate,
                                 HWND owner, DLGPROC dlgProc, LPARAM param,
                                 BOOL unicode, HWND *modal_owner )
{
    HWND hwnd;
    RECT rect;
    POINT pos;
    SIZE size;
    DLG_TEMPLATE template;
    DIALOGINFO * dlgInfo = NULL;
    DWORD units = GetDialogBaseUnits();
    HWND disabled_owner = NULL;
    HMENU hMenu = 0;
    HFONT hUserFont = 0;
    UINT flags = 0;
    UINT xBaseUnit = LOWORD(units);
    UINT yBaseUnit = HIWORD(units);


      /* Parse dialog template */


    if (!dlgTemplate) return 0;
    dlgTemplate = DIALOG_ParseTemplate32( dlgTemplate, &template );


      /* Load menu */


    if (template.menuName) hMenu = LoadMenuW( hInst, template.menuName );


      /* Create custom font if needed */


    if (template.style & DS_SETFONT)
    {
      HDC dc = GetDC(0);


      if (template.pointSize == 0x7fff)
      {
            /* We get the message font from the non-client metrics */
            NONCLIENTMETRICSW ncMetrics;


            ncMetrics.cbSize = sizeof(NONCLIENTMETRICSW);
            if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
                                    sizeof(NONCLIENTMETRICSW), &ncMetrics, 0))
            {
                hUserFont = CreateFontIndirectW( &ncMetrics.lfMessageFont );
            }
      }
      else
      {
            /* We convert the size to pixels and then make it -ve.This works
             * for both +ve and -ve template.pointSize */
            int pixels = MulDiv(template.pointSize, GetDeviceCaps(dc , LOGPIXELSY), 72);
            hUserFont = CreateFontW( -pixels, 0, 0, 0, template.weight,
                                              template.italic, FALSE, FALSE, DEFAULT_CHARSET, 0, 0,
                                              PROOF_QUALITY, FF_DONTCARE,
                                              template.faceName );
      }


      if (hUserFont)
      {
            SIZE charSize;
            HFONT hOldFont = SelectObject( dc, hUserFont );
            charSize.cx = GdiGetCharDimensions( dc, NULL, &charSize.cy );
            if (charSize.cx)
            {
                xBaseUnit = charSize.cx;
                yBaseUnit = charSize.cy;
            }
            SelectObject( dc, hOldFont );
      }
      ReleaseDC(0, dc);
      TRACE("units = %d,%d\n", xBaseUnit, yBaseUnit );
    }


    /* Create dialog main window */


    SetRect(&rect, 0, 0, MulDiv(template.cx, xBaseUnit, 4), MulDiv(template.cy, yBaseUnit, 8));
    if (template.style & DS_CONTROL)
      template.style &= ~(WS_CAPTION|WS_SYSMENU);
    template.style |= DS_3DLOOK;
    if (template.style & DS_MODALFRAME)
      template.exStyle |= WS_EX_DLGMODALFRAME;
    if ((template.style & DS_CONTROL) || !(template.style & WS_CHILD))
      template.exStyle |= WS_EX_CONTROLPARENT;
    AdjustWindowRectEx( &rect, template.style, (hMenu != 0), template.exStyle );
    pos.x = rect.left;
    pos.y = rect.top;
    size.cx = rect.right - rect.left;
    size.cy = rect.bottom - rect.top;


    if (template.x == CW_USEDEFAULT16)
    {
      pos.x = pos.y = CW_USEDEFAULT;
    }
    else
    {
      HMONITOR monitor = 0;
      MONITORINFO mon_info;


      mon_info.cbSize = sizeof(mon_info);
      if (template.style & DS_CENTER)
      {
            monitor = MonitorFromWindow( owner ? owner : GetActiveWindow(), MONITOR_DEFAULTTOPRIMARY );
            GetMonitorInfoW( monitor, &mon_info );
            pos.x = (mon_info.rcWork.left + mon_info.rcWork.right - size.cx) / 2;
            pos.y = (mon_info.rcWork.top + mon_info.rcWork.bottom - size.cy) / 2;
      }
      else if (template.style & DS_CENTERMOUSE)
      {
            GetCursorPos( &pos );
            monitor = MonitorFromPoint( pos, MONITOR_DEFAULTTOPRIMARY );
            GetMonitorInfoW( monitor, &mon_info );
      }
      else
      {
            pos.x += MulDiv(template.x, xBaseUnit, 4);
            pos.y += MulDiv(template.y, yBaseUnit, 8);
            //
            // REACTOS : Need an owner to be passed!!!
            //
            if (!(template.style & (WS_CHILD|DS_ABSALIGN)) && owner ) ClientToScreen( owner, &pos );
      }
      if ( !(template.style & WS_CHILD) )
      {
            INT dX, dY;


            /* try to fit it into the desktop */


            if (!monitor)
            {
                SetRect( &rect, pos.x, pos.y, pos.x + size.cx, pos.y + size.cy );
                monitor = MonitorFromRect( &rect, MONITOR_DEFAULTTOPRIMARY );
                GetMonitorInfoW( monitor, &mon_info );
            }
            if ((dX = pos.x + size.cx + GetSystemMetrics(SM_CXDLGFRAME) - mon_info.rcWork.right) > 0)
                pos.x -= dX;
            if ((dY = pos.y + size.cy + GetSystemMetrics(SM_CYDLGFRAME) - mon_info.rcWork.bottom) > 0)
                pos.y -= dY;
            if( pos.x < mon_info.rcWork.left ) pos.x = mon_info.rcWork.left;
            if( pos.y < mon_info.rcWork.top ) pos.y = mon_info.rcWork.top;
      }
    }


    if (modal_owner && owner)
    {
      HWND parent = NULL;
      /*
         * Owner needs to be top level window. We need to duplicate the logic from server,
         * because we need to disable it before creating dialog window. Note that we do that
         * even if dialog has WS_CHILD, but only for modal dialogs, which matched what
         * Windows does.
         */
      while ((GetWindowLongW( owner, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) == WS_CHILD)
      {
            parent = GetParent( owner );
            if (!parent || parent == GetDesktopWindow()) break;
            owner = parent;
      }
      ////// Wine'ie babies need to fix your code!!!! CORE-11633
      if (!parent) parent = GetAncestor( owner, GA_ROOT );


      if (parent)
      {
         owner = parent;


         if (IsWindowEnabled( owner ))
         {
               disabled_owner = owner;
               EnableWindow( disabled_owner, FALSE );
         }
      }
      *modal_owner = owner;
    }


    if (unicode)
    {
      hwnd = CreateWindowExW(template.exStyle, template.className, template.caption,
                               template.style & ~WS_VISIBLE, pos.x, pos.y, size.cx, size.cy,
                               owner, hMenu, hInst, NULL );
    }
    else
    {
      LPCSTR class = (LPCSTR)template.className;
      LPCSTR caption = (LPCSTR)template.caption;
      LPSTR class_tmp = NULL;
      LPSTR caption_tmp = NULL;


      if (!IS_INTRESOURCE(class))
      {
            DWORD len = WideCharToMultiByte( CP_ACP, 0, template.className, -1, NULL, 0, NULL, NULL );
            class_tmp = HeapAlloc( GetProcessHeap(), 0, len );
            WideCharToMultiByte( CP_ACP, 0, template.className, -1, class_tmp, len, NULL, NULL );
            class = class_tmp;
      }
      if (!IS_INTRESOURCE(caption))
      {
            DWORD len = WideCharToMultiByte( CP_ACP, 0, template.caption, -1, NULL, 0, NULL, NULL );
            caption_tmp = HeapAlloc( GetProcessHeap(), 0, len );
            WideCharToMultiByte( CP_ACP, 0, template.caption, -1, caption_tmp, len, NULL, NULL );
            caption = caption_tmp;
      }
      hwnd = CreateWindowExA(template.exStyle, class, caption,
                               template.style & ~WS_VISIBLE, pos.x, pos.y, size.cx, size.cy,
                               owner, hMenu, hInst, NULL );
      HeapFree( GetProcessHeap(), 0, class_tmp );
      HeapFree( GetProcessHeap(), 0, caption_tmp );
    }


    if (!hwnd)
    {
      if (hUserFont) DeleteObject( hUserFont );
      if (hMenu) DestroyMenu( hMenu );
      if (disabled_owner) EnableWindow( disabled_owner, TRUE );
      return 0;
    }


    /* moved this from the top of the method to here as DIALOGINFO structure
    will be valid only after WM_CREATE message has been handled in DefDlgProc
    All the members of the structure get filled here using temp variables */
    dlgInfo = DIALOG_get_info( hwnd, TRUE );
    // ReactOS
    if (dlgInfo == NULL)
    {
      if (hUserFont) DeleteObject( hUserFont );
      if (hMenu) DestroyMenu( hMenu );
      if (disabled_owner) EnableWindow( disabled_owner, TRUE );
      return 0;
    }
    //
    dlgInfo->hwndFocus   = 0;
    dlgInfo->hUserFont   = hUserFont;
    dlgInfo->hMenu       = hMenu;
    dlgInfo->xBaseUnit   = xBaseUnit;
    dlgInfo->yBaseUnit   = yBaseUnit;
    dlgInfo->flags       = flags;


    if (template.helpId) SetWindowContextHelpId( hwnd, template.helpId );


    if (unicode) SetWindowLongPtrW( hwnd, DWLP_DLGPROC, (ULONG_PTR)dlgProc );
    else SetWindowLongPtrA( hwnd, DWLP_DLGPROC, (ULONG_PTR)dlgProc );


    if (dlgProc && dlgInfo->hUserFont)
      SendMessageW( hwnd, WM_SETFONT, (WPARAM)dlgInfo->hUserFont, 0 );


    /* Create controls */


    if (DIALOG_CreateControls32( hwnd, dlgTemplate, &template, hInst, unicode ))
    {
      /* Send initialisation messages and set focus */


      if (dlgProc)
      {
            HWND focus = GetNextDlgTabItem( hwnd, 0, FALSE );
            if (!focus) focus = GetNextDlgGroupItem( hwnd, 0, FALSE );
            if (SendMessageW( hwnd, WM_INITDIALOG, (WPARAM)focus, param ) && IsWindow( hwnd ) &&
                ((~template.style & DS_CONTROL) || (template.style & WS_VISIBLE)))
            {
                /* By returning TRUE, app has requested a default focus assignment.
               * WM_INITDIALOG may have changed the tab order, so find the first
               * tabstop control again. */
                focus = GetNextDlgTabItem( hwnd, 0, FALSE );
                if (!focus) focus = GetNextDlgGroupItem( hwnd, 0, FALSE );
                if (focus)
                {
                  if (SendMessageW( focus, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
                        SendMessageW( focus, EM_SETSEL, 0, MAXLONG );
                  SetFocus( focus );
                }
            }
//// ReactOS see 43396, Fixes setting focus on Open and Close dialogs to the FileName edit control in OpenOffice.
//// This now breaks test_SaveRestoreFocus.
            //DEFDLG_SaveFocus( hwnd );
////
      }
//// ReactOS Rev 30613 & 30644
      if (!(GetWindowLongPtrW( hwnd, GWL_STYLE ) & WS_CHILD))
            SendMessageW( hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, 0), 0);
////
      if (template.style & WS_VISIBLE && !(GetWindowLongPtrW( hwnd, GWL_STYLE ) & WS_VISIBLE))
      {
         ShowWindow( hwnd, SW_SHOWNORMAL );   /* SW_SHOW doesn't always work */
         UpdateWindow( hwnd );
         IntNotifyWinEvent(EVENT_SYSTEM_DIALOGSTART, hwnd, OBJID_WINDOW, CHILDID_SELF, 0);
      }
      return hwnd;
    }
    if (disabled_owner) EnableWindow( disabled_owner, TRUE );
    IntNotifyWinEvent(EVENT_SYSTEM_DIALOGEND, hwnd, OBJID_WINDOW, CHILDID_SELF, 0);
    if( IsWindow(hwnd) )
    {
      DestroyWindow( hwnd );
      //// ReactOS
      if (owner)
      {ERR("DIALOG_CreateIndirect 1\n");
         if ( NtUserGetThreadState(THREADSTATE_FOREGROUNDTHREAD) && // Rule #1.
             !NtUserQueryWindow(owner, QUERY_WINDOW_FOREGROUND) )
         { ERR("DIALOG_CreateIndirect SFW\n");
            SetForegroundWindow(owner);
         }
      }
      ////
    }
    return 0;
}

从中可以看到其调用了SetWindowLong API将DlgProc写入了DWLP_DLGPROC(在真正的windows中叫做DWL_DLGPROC )
随后其会调用DIALOG_DoDialogBox启动消息循环(在windows中比这要复杂):

INT DIALOG_DoDialogBox( HWND hwnd, HWND owner )
{
    DIALOGINFO * dlgInfo;
    MSG msg;
    INT retval;
    BOOL bFirstEmpty;
    PWND pWnd;


    pWnd = ValidateHwnd(hwnd);
    if (!pWnd) return -1;


    if (!(dlgInfo = GETDLGINFO(hwnd))) return -1;


    bFirstEmpty = TRUE;
    if (!(dlgInfo->flags & DF_END)) /* was EndDialog called in WM_INITDIALOG ? */
    {
      for (;;)
      {
            if (!PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ))
            {
                if (bFirstEmpty)
                {
                  /* ShowWindow the first time the queue goes empty */
                  ShowWindow( hwnd, SW_SHOWNORMAL );
                  bFirstEmpty = FALSE;
                }
                if (!(GetWindowLongPtrW( hwnd, GWL_STYLE ) & DS_NOIDLEMSG))
               {
                  /* No message present -> send ENTERIDLE and wait */
                  SendMessageW( owner, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)hwnd );
                }
                GetMessageW( &msg, 0, 0, 0 );
            }


            if (msg.message == WM_QUIT)
            {
                PostQuitMessage( msg.wParam );
                if (!IsWindow( hwnd )) return 0;
                break;
            }


            /*
             * If the user is pressing Ctrl+C, send a WM_COPY message.
             * Guido Pola, CORE-4829, Is there another way to check if the Dialog is a MessageBox?
             */
            if (msg.message == WM_KEYDOWN &&
                pWnd->state & WNDS_MSGBOX && // Yes!
                GetForegroundWindow() == hwnd)
            {
                if (msg.wParam == L'C' && GetKeyState(VK_CONTROL) < 0)
                  SendMessageW(hwnd, WM_COPY, 0, 0);
            }


            if (!IsWindow( hwnd )) return 0;
            if (!(dlgInfo->flags & DF_END) && !IsDialogMessageW( hwnd, &msg))
            {
                TranslateMessage( &msg );
                DispatchMessageW( &msg );
            }
            if (!IsWindow( hwnd )) return 0;
            if (dlgInfo->flags & DF_END) break;


            if (bFirstEmpty && msg.message == WM_TIMER)
            {
                ShowWindow( hwnd, SW_SHOWNORMAL );
                bFirstEmpty = FALSE;
            }
      }
    }
    retval = dlgInfo->idResult;
    DestroyWindow( hwnd );
    return retval;
}

总之,我们回到程序的DialogFunc中,
汇编如下:

.text:00401180 ; BOOL __stdcall DialogFunc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)
.text:00401180 DialogFunc      proc near               ; DATA XREF: sub_401220+Ao
.text:00401180
.text:00401180 hWnd            = dword ptr8
.text:00401180 msg             = dword ptr0Ch
.text:00401180 wparam          = dword ptr10h
.text:00401180
.text:00401180               push    ebp
.text:00401181               mov   ebp, esp
.text:00401183               mov   eax,
.text:00401186               sub   eax, 10h
.text:00401189               jz      short loc_401207
.text:0040118B               sub   eax, 100h
.text:00401190               jz      short loc_4011D0
.text:00401192               dec   eax
.text:00401193               jnz   short loc_401212
.text:00401195               mov   eax,
.text:00401198               movzx   eax, ax
.text:0040119B               sub   eax, 3E9h
.text:004011A0               jz      short loc_4011C2
.text:004011A2               sub   eax, 7
.text:004011A5               jnz   short loc_401212
.text:004011A7               push    1               ; nShowCmd
.text:004011A9               push    eax             ; lpDirectory
.text:004011AA               push    eax             ; lpParameters
.text:004011AB               push    offset File   ; "http://www.52pojie.cn"
.text:004011B0               push    offset Operation ; "open"
.text:004011B5               push    eax             ; hwnd
.text:004011B6               call    ds:ShellExecuteA
.text:004011BC               xor   eax, eax
.text:004011BE               pop   ebp
.text:004011BF               retn    10h
.text:004011C2 ; ---------------------------------------------------------------------------
.text:004011C2
.text:004011C2 loc_4011C2:                           ; CODE XREF: DialogFunc+20j
.text:004011C2               mov   ecx,
.text:004011C5               call    sub_401030
.text:004011CA               xor   eax, eax
.text:004011CC               pop   ebp
.text:004011CD               retn    10h
.text:004011D0 ; ---------------------------------------------------------------------------
.text:004011D0
.text:004011D0 loc_4011D0:                           ; CODE XREF: DialogFunc+10j
.text:004011D0               push    offset unk_4174B8 ; lParam
.text:004011D5               push    0               ; wParam
.text:004011D7               push    0Ch             ; Msg
.text:004011D9               push          ; hWnd
.text:004011DC               call    ds:SendMessageA
.text:004011E2               push    67h             ; lpIconName
.text:004011E4               push    hInstance       ; hInstance
.text:004011EA               call    ds:LoadIconA
.text:004011F0               push    eax             ; lParam
.text:004011F1               push    1               ; wParam
.text:004011F3               push    80h             ; Msg
.text:004011F8               push          ; hWnd
.text:004011FB               call    ds:SendMessageA
.text:00401201               xor   eax, eax
.text:00401203               pop   ebp
.text:00401204               retn    10h
.text:00401207 ; ---------------------------------------------------------------------------
.text:00401207
.text:00401207 loc_401207:                           ; CODE XREF: DialogFunc+9j
.text:00401207               push    0               ; nResult
.text:00401209               push          ; hDlg
.text:0040120C               call    ds:EndDialog
.text:00401212
.text:00401212 loc_401212:                           ; CODE XREF: DialogFunc+13j
.text:00401212                                       ; DialogFunc+25j
.text:00401212               xor   eax, eax
.text:00401214               pop   ebp
.text:00401215               retn    10h
.text:00401215 DialogFunc      endp

使用IDA得到如下伪代码:

BOOL __stdcall DialogFunc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
HICON v5; // eax@8

if ( msg == 16 )
{
    EndDialog(hWnd, 0);
}
else
{
    if ( msg == 272 )
    {
      SendMessageA(hWnd, 0xCu, 0, (LPARAM)&unk_4174B8);
      v5 = LoadIconA(hInstance, (LPCSTR)0x67);
      SendMessageA(hWnd, 0x80u, 1u, (LPARAM)v5);
      return 0;
    }
    if ( msg == 273 )                           // WM_COMMAND
    {
      if ( (unsigned __int16)wparam == 1001 )   // Register Button
      {
      sub_401030(hWnd);
      return 0;
      }
      if ( (unsigned __int16)wparam == 1008 )
      {
      ShellExecuteA(0, "open", "http://www.52pojie.cn", 0, 0, 1);
      return 0;
      }
    }
}
return 0;
}

可见sub_401030就是注册按钮的处理函数,我们进入看看:


sub_401030 proc near
jmp   loc_44068A
sub_401030 endp

跳入代码如下:

.ximo:0044068A loc_44068A:                           ; CODE XREF: sub_401030j
.ximo:0044068A               pusha
.ximo:0044068B               test    dh, 0ABh
.ximo:0044068E               xadd    bh, bl
.ximo:00440691               xor   ebx, ecx
.ximo:00440693               mov   bl, ah
.ximo:00440695               btc   ebx, edx
.ximo:00440698               rep mov ebx, 3784153Ah
.ximo:0044069F               db      65h
.ximo:0044069F               xadd    esi, ebx
.ximo:004406A3               mov   bl, ah
.ximo:004406A5               inc   ebx
.ximo:004406A6               rep imul ebx, edx, 8FBCADB2h
.ximo:004406AD               shr   bl, 53h
.ximo:004406B0               btr   esi, ecx
.ximo:004406B3               mov   ebx, ecx
.ximo:004406B5               shrd    esi, ecx, cl
.ximo:004406B8               xor   ebx, 9764751Ah
.ximo:004406BE               db      36h
.ximo:004406BE               popa
.ximo:004406C0               push    ebp
.ximo:004406C1 loc_4406C1:                           ; CODE XREF: .ximo:004406F4j
.ximo:004406C1               jge   loc_442D44
.ximo:004406C7               jl      loc_442D44

代码疑似被加密,使用windbg跟踪到004406C7处发现跳入了另一段程序:

.ximo:00442D44 loc_442D44:                           ; CODE XREF: .ximo:loc_4406C1j
.ximo:00442D44                                       ; .ximo:004406C7j
.ximo:00442D44               push    ebx
.ximo:00442D45               push    ebp
.ximo:00442D46               push    esi
.ximo:00442D47               neg   bl
.ximo:00442D49               btc   ebx, edx
.ximo:00442D4C               db      64h
.ximo:00442D4C               movzx   ebx, cx
.ximo:00442D50               xchg    ebx, ebp
.ximo:00442D52               shld    ebx, edx, cl
.ximo:00442D55               shld    ebx, edx, cl
.ximo:00442D58               imul    ebx, edx, 4DD2FB98h
.ximo:00442D5E               imul    esi, ecx
.ximo:00442D61               lea   ebx, ds:0D5FA4380h
.ximo:00442D67               xchg    bl, bh
.ximo:00442D69               not   ebx
.ximo:00442D6B               btc   ebx, edx
.ximo:00442D6E               bswap   ebx
.ximo:00442D70               bsf   ebx, edx
.ximo:00442D73               lea   ebx, ds:9D62CBA8h
.ximo:00442D79               rep pop esi
.ximo:00442D7B               pop   ebp
.ximo:00442D7C               pop   ebx
.ximo:00442D7D               push    offset loc_436935
.ximo:00442D82               retn

最后两行明显构成了一个跳转,跳往00436935处:

.ximo:00436935 loc_436935:                           ; CODE XREF: .ximo:00442D82j
.ximo:00436935                                       ; DATA XREF: .ximo:00442D7Do
.ximo:00436935               push    eax
.ximo:00436936               push    edx
.ximo:00436937               push    esi
.ximo:00436938               imul    edx, ebp, 258A1390h
.ximo:0043693E               shr   dh, cl
.ximo:00436940               rep dec dh
.ximo:00436943               mov   dh, 94h
.ximo:00436946               imul    esi, ecx
.ximo:00436949               movsx   esi, ah
.ximo:0043694C               mov   dh, ah
.ximo:0043694E               mov   dh, 0D4h
.ximo:00436951               mov   dh, ah
.ximo:00436953               bsr   esi, ecx
.ximo:00436956               lea   esi, ds:691E3784h
.ximo:0043695C               lea   eax, ds:7B18392Eh
.ximo:00436962               mov   dl, al
.ximo:00436964               bsr   eax, ebx
.ximo:00436967               test    dl, bl
.ximo:00436969               sub   al, 54h
.ximo:0043696B               shrd    esi, ecx, 0E4h
.ximo:0043696F               pop   esi
.ximo:00436970               pop   edx
.ximo:00436971               pop   eax
.ximo:00436972               jle   loc_43A9DA
.ximo:00436978               jg      loc_43A9DA

显然进一步跳转到0043A9DA处:

.ximo:0043A9DA loc_43A9DA:                           ; CODE XREF: .ximo:00436972j
.ximo:0043A9DA                                       ; .ximo:00436978j
.ximo:0043A9DA               push    eax
.ximo:0043A9DB               push    edx
.ximo:0043A9DC               push    esi
.ximo:0043A9DD               btr   esi, ecx
.ximo:0043A9E0               lea   esi, ds:0E99EB704h
.ximo:0043A9E6               cmp   al, dh
.ximo:0043A9E8               xchg    dh, al
.ximo:0043A9EA               jmp   short loc_43A9ED
.ximo:0043A9EA ; ---------------------------------------------------------------------------
.ximo:0043A9EC               db 0B4h
.ximo:0043A9ED ; ---------------------------------------------------------------------------
.ximo:0043A9ED
.ximo:0043A9ED loc_43A9ED:                           ; CODE XREF: .ximo:0043A9EAj
.ximo:0043A9ED               movsx   esi, ah
.ximo:0043A9F0               mov   dh, 0D4h
.ximo:0043A9F3               imul    esi, ecx, 0C9FE9764h
.ximo:0043A9F9               shrd    eax, ebx, 0Eh
.ximo:0043A9FD               imul    eax, ebx, 2B88691Eh
.ximo:0043AA03               ror   dl, 18h
.ximo:0043AA06               jmp   short loc_43AA09
.ximo:0043AA06 ; ---------------------------------------------------------------------------
.ximo:0043AA08               db 0A8h
.ximo:0043AA09 ; ---------------------------------------------------------------------------
.ximo:0043AA09
.ximo:0043AA09 loc_43AA09:                           ; CODE XREF: .ximo:0043AA06j
.ximo:0043AA09               or      dl, al
.ximo:0043AA0B               db      26h
.ximo:0043AA0B               sub   dh, ah
.ximo:0043AA0E               sub   dh, ah
.ximo:0043AA10               db      65h
.ximo:0043AA10               movsx   esi, ah
.ximo:0043AA14               pop   esi
.ximo:0043AA15               pop   edx
.ximo:0043AA16               pop   eax
.ximo:0043AA17               jz      loc_442149
.ximo:0043AA1D               jnz   loc_442149

又是二连跳,最后的jz和jnz构成了jmp条件,跳往00442149处:

.ximo:00442149               add   ebp, ebx
.ximo:0044214B               shld    ebp, edi, 0A8h
.ximo:0044214F               shld    ebp, edi, cl
.ximo:00442152               xadd    ebp, ebp
.ximo:00442155               not   ebp
.ximo:00442157               imul    ebp, edi
.ximo:0044215A               xadd    ebp, ebp
.ximo:0044215D               shld    ebp, edi, 0B8h
.ximo:00442161               db      64h
.ximo:00442161               lea   ebp, fs:5D228B68h
.ximo:00442168               bts   ebp, edi
.ximo:0044216B               repne bsf ebp, edi
.ximo:0044216F               mov   ebp, ebx
.ximo:00442171               jmp   short loc_442174
.ximo:00442171 ; ---------------------------------------------------------------------------
.ximo:00442173               db 0E8h
.ximo:00442174 ; ---------------------------------------------------------------------------
.ximo:00442174
.ximo:00442174 loc_442174:                           ; CODE XREF: .ximo:00442171j
.ximo:00442174               bts   ebp, 40h
.ximo:00442178               add   ebp, ebx
.ximo:0044217A               mov   ebp, esp
.ximo:0044217C               push    offset loc_440B83
.ximo:00442181               retn
.ximo:00442181 ; ---------------------------------------------------------------------------

跳往00440B83处:

.ximo:00440B83 loc_440B83:                           ; CODE XREF: .ximo:00442181j
.ximo:00440B83                                       ; DATA XREF: .ximo:0044217Co
.ximo:00440B83               and   esp, 0FFFFFFF8h
.ximo:00440B86               pusha
.ximo:00440B87               mov   ebx, 6C1DE24Bh
.ximo:00440B8D               test    eax, 56CFFCEDh
.ximo:00440B93               and   ecx, 1091661Fh
.ximo:00440B99               imul    ebx, edx
.ximo:00440B9C               bswap   ebx
.ximo:00440B9E               btc   ebx, edx
.ximo:00440BA1               imul    ebx, edx, 14E54AD3h
.ximo:00440BA7               mov   esi, ebp
.ximo:00440BA9               bswap   edi
.ximo:00440BAB               mov   esi, ebp
.ximo:00440BAD               bswap   edi
.ximo:00440BAF               db      3Eh
.ximo:00440BAF               popa
.ximo:00440BB1               jnz   loc_43C645
.ximo:00440BB7               jz      loc_43C645

跳到0043C645:

.ximo:0043C645 ; ---------------------------------------------------------------------------
.ximo:0043C645
.ximo:0043C645 loc_43C645:                           ; CODE XREF: .ximo:00440BB1j
.ximo:0043C645                                       ; .ximo:00440BB7j
.ximo:0043C645               pusha
.ximo:0043C646               xchg    dh, al
.ximo:0043C648               shr   dh, 24h
.ximo:0043C64B               mov   dh, ah
.ximo:0043C64D               shrd    esi, ecx, 44h
.ximo:0043C651               dec   esi
.ximo:0043C652               lea   esi, ds:0C9FE9764h
.ximo:0043C658               xchg    al, bl
.ximo:0043C65A               dec   dh
.ximo:0043C65C               btr   esi, 14h
.ximo:0043C660               mov   dh, 0A4h
.ximo:0043C663               rep shrd esi, ecx, 0C4h
.ximo:0043C668               mov   dh, 54h
.ximo:0043C66A               dec   dh
.ximo:0043C66C               neg   dh
.ximo:0043C66E               sub   al, 4
.ximo:0043C670               sub   dh, ah
.ximo:0043C672               popa
.ximo:0043C673               push    offset loc_4398D3
.ximo:0043C678               retn
.ximo:0043C678 ; ---------------------------------------------------------------------------

。。。相似的代码模式。。怀疑是VMP加密
参考文章:https://blog.csdn.net/whatday/article/details/23448007
经过OD直接F8不松手,发现在00441F3C处有一句:

.ximo:00441F3C               call    esi

此处esi为GetDlgItemTextA
我们在IDA中利用CodeDoctor开始逐行提取(此处人工用时2小时):


004406C0 push ebp
0044217A mov ebp,esp
;(以下很多地方省略地址和一些非关键的代码,可能有一些错的或者遗漏的)
         sub esp,164h
         mov eax,es:__security_cookie
         xor eax,esp
00443BD6 mov ,eax
00438C05 push esi
         push edi
         mov eax,__security_cookie
         xor eax,esp
         push eax
         lea eax,
         mov large fs:0,eax
         lea eax,
         mov ,0
         call _memset;此处分配Key字符串存储空间
         add esp,0ch
         mov esi,GetDlgItemTextA;此处加载GetDlgItemTextA API地址
0043A989 call esi;此处调用GetDLgItemTextA获取Key文本框文本
00443FAD call _memset;此处分配Serial字符串存储空间
00441F3C call esi;此处调用GetDlgItemTextA获取Serial文本框文本
00440882 call 00401260h;VC编译器API
004390BF call 00401540h;VC编译器API
00442792 push 00440048h;未知代码
0043D613 call eax;关键call,其指向一个动态申请的内存空间,内存权限为:Execute和Read
;函数原型为:int func(const char *Key,const char *Serial);

注意到那个关键call,怀疑是加密函数,我们将该处内存使用Scylla进行Dump:

将导出后的文件送入IDA分析,由于刚才的函数地址是03731450,DUMP基址是03731000,所以此处的偏移为450,
我们看到相关代码(只截取一部分):

seg000:00000450               push    ebp
seg000:00000451               mov   ebp, esp
seg000:00000453               sub   esp, 0ECh
seg000:00000459               mov   eax, ds:3742000h
seg000:0000045E               xor   eax, ebp
seg000:00000460               mov   , eax
seg000:00000463               push    ebx
seg000:00000464               mov   ebx,
seg000:00000467               mov   , ebx
seg000:0000046D               push    edi
seg000:0000046E               mov   edi,
seg000:00000471               test    ebx, ebx
seg000:00000473               jz      loc_977
seg000:00000479               mov   ecx, ebx
seg000:0000047B               lea   edx,
seg000:0000047E               mov   edi, edi
seg000:00000480
seg000:00000480 loc_480:                              ; CODE XREF: sub_450+35j
seg000:00000480               mov   al,
seg000:00000482               inc   ecx
seg000:00000483               test    al, al
seg000:00000485               jnz   short loc_480
seg000:00000487               sub   ecx, edx
seg000:00000489               jz      loc_977
seg000:0000048F               test    edi, edi
seg000:00000491               jz      loc_977
seg000:00000497               push    esi
seg000:00000498               mov   esi, edi
seg000:0000049A               lea   ecx,
seg000:0000049D               lea   ecx,
seg000:000004A0
seg000:000004A0 loc_4A0:                              ; CODE XREF: sub_450+55j
seg000:000004A0               mov   al,
seg000:000004A2               inc   esi
seg000:000004A3               test    al, al
seg000:000004A5               jnz   short loc_4A0
seg000:000004A7               sub   esi, ecx
seg000:000004A9               lea   eax,
seg000:000004AC               cmp   eax, 31h ; '1'
seg000:000004AF               ja      loc_962
seg000:000004B5               push    12h
seg000:000004B7               push    edi
seg000:000004B8               lea   eax,
seg000:000004BB               mov   , 0
seg000:000004BF               xorps   xmm0, xmm0
seg000:000004C2               mov   , 0
seg000:000004C8               push    12h
seg000:000004CA               push    eax
seg000:000004CB               movdqu, xmm0
seg000:000004D0               call    sub_C5C
seg000:000004D5               push    32h ; '2'
seg000:000004D7               lea   eax,
seg000:000004DA               mov   , 0
seg000:000004DE               push    0
seg000:000004E0               push    eax
seg000:000004E1               call    sub_2260
seg000:000004E6               lea   eax,
seg000:000004E9               push    eax
seg000:000004EA               lea   eax,
seg000:000004ED               push    eax
seg000:000004EE               lea   eax,
seg000:000004F1               push    32h ; '2'
seg000:000004F3               push    eax
seg000:000004F4               call    sub_C5C
seg000:000004F9               add   esp, 2Ch
seg000:000004FC               mov   ecx, ebx
seg000:000004FE               call    sub_200
seg000:00000503               and   eax, 1
seg000:00000506               mov   , 3
seg000:00000510               lea   ecx,
seg000:00000516               mov   , eax
seg000:0000051C               mov   , 3
seg000:00000526               call    sub_0
seg000:0000052B               xor   al, al
seg000:0000052D               mov   , al

我们在此创建函数,并且按F5进行C反编译分析:

char __stdcall sub_450(int a1, const char *a2)
{
int v2; // ecx@2
char v3; // al@3
unsigned int v4; // esi@6
char v5; // al@7
unsigned __int8 v6; // bh@8
int v7; // eax@8
int v8; // edi@9
signed int v9; // ecx@9
int v10; // esi@9
char v11; // dl@9
int v12; // ecx@15
char v13; // bl@15
int v14; // edx@15
float v15; // xmm1_4@21
int v16; // ecx@23
int v17; // eax@27
unsigned __int8 v18; // bh@27
signed int v19; // esi@28
unsigned __int8 v20; // bl@28
int v21; // edi@31
int v22; // ecx@33
int v23; // edi@35
int v24; // ebx@35
signed int v25; // esi@40
signed int v26; // ecx@41
__int128 v27; // xmm1@44
__int128 v29; // xmm0@45
unsigned int v32; // kr00_4@49
unsigned __int8 v33; // bl@49
int v34; // eax@50
int v35; // ecx@51
char v36; // dl@54
char result; // al@57
int v38; // @35
int v39; // @35
int v40; // @35
int v41; // @35
int v42; // @35
int v43; // @35
int v44; // @27
int v45; // @27
int v46; // @27
int v47; // @1
int v48; // @7
int v49; // @27
int v50; // @27
int v51; // @27
int v52; // @35
int v53; // @35
int v54; // @35
int v55; // @7
int v56; // @7
int v57; // @25
int v58; // @8
char v59; // @7
__int128 v60; // @27
__int128 v61; // @27
int v62; // @27
__int128 v63; // @27
__int128 v64; // @27
int v65; // @27
char v66; // @7
char v67; // @7
char v68; // @7
__int128 v69; // @7
__int16 v70; // @7

v47 = a1;
if ( !a1 )
    goto LABEL_62;
v2 = a1;
do
    v3 = *(_BYTE *)v2++;
while ( v3 );
if ( v2 != a1 + 1 && a2 )
{
    v4 = strlen(a2);
    if ( v4 - 19 <= 0x31 )
    {
      v68 = 0;
      v70 = 0;
      _mm_storeu_si128((__m128i *)&v69, 0i64);
      sub_C5C(&v68, 18, a2, 18);
      v66 = 0;
      sub_2260(&v67, 0, 50);
      sub_C5C(&v66, 50, a2 + 18, v4 - 18);
      v55 = 3;
      v48 = sub_200(a1) & 1;
      v56 = 3;
      sub_0(&v55);
      v5 = 0;
      v59 = 0;
LABEL_8:
      v6 = 0;
      v58 = (unsigned __int8)v5;
      v7 = 3 * (unsigned __int8)v5;
      while ( 1 )
      {
      v8 = v6;
      v9 = -1;
      v10 = v6 + v7;
      v11 = *(&v68 + 2 * v10);
      if ( (unsigned __int8)(*(&v68 + 2 * v10) - 48) > 9u )
      {
          if ( (unsigned __int8)(v11 - 65) > 5u )
          {
            if ( (unsigned __int8)(v11 - 97) <= 5u )
            v9 = v11 - 87;
          }
          else
          {
            v9 = v11 - 55;
          }
      }
      else
      {
          v9 = v11 - 48;
      }
      v12 = v9 % 2;
      v13 = *((_BYTE *)&v69 + 2 * v10);
      v14 = -1;
      if ( (unsigned __int8)(*((_BYTE *)&v69 + 2 * v10) - 48) > 9u )
      {
          if ( (unsigned __int8)(v13 - 65) > 5u )
          {
            if ( (unsigned __int8)(v13 - 97) <= 5u )
            v14 = v13 - 87;
          }
          else
          {
            v14 = v13 - 55;
          }
      }
      else
      {
          v14 = v13 - 48;
      }
      v15 = (float)v14;
      if ( v12 != v48 )
          v15 = 0.0 - v15;
      v16 = v58;
      if ( v58 >= v55 || v6 >= v56 )
          break;
      ++v6;
      *(float *)(v57 + 4 * (v8 + v58 * v56)) = v15;
      v7 = 3 * v16;
      if ( v6 >= 3u )
      {
          v5 = v59 + 1;
          v59 = v5;
          if ( (unsigned __int8)v5 < 3u )
            goto LABEL_8;
          v49 = 3;
          v50 = 3;
          v44 = 3;
          v45 = 3;
          v51 = sub_9D2(36);
          v17 = sub_9D2(36);
          v60 = v3740590;
          v18 = 0;
          v46 = v17;
          v61 = v37405A0;
          v62 = 1065353216;
          v63 = v3740580;
          v65 = 1065353216;
          v64 = v3740580;
LABEL_28:
          v19 = v18;
          v20 = 0;
          v58 = v18;
          while ( v19 < 3 )
          {
            if ( (signed int)v20 >= 3 )
            break;
            v21 = v20 + 3 * v19;
            *(_DWORD *)(v51 + 4 * v21) = *((_DWORD *)&v60 + v21);
            v19 = v58;
            if ( v58 >= 3 || (signed int)v20 >= 3 )
            break;
            v22 = v58 + v20++ + 2 * v58;
            *(_DWORD *)(v46 + 4 * v22) = *((_DWORD *)&v63 + v21);
            if ( v20 >= 3u )
            {
            ++v18;
            if ( v18 < 3u )
                goto LABEL_28;
            v52 = 3;
            v53 = 3;
            v38 = 3;
            v39 = 3;
            v41 = 3;
            v42 = 3;
            v54 = sub_9D2(36);
            v23 = sub_9D2(36);
            v40 = v23;
            v24 = sub_9D2(36);
            v43 = v24;
            if ( sub_100(&v55, &v52) != -1
                && sub_30(&v44, &v38) != -1
                && sub_100(&v49, &v52) != -1
                && v55 == 3
                && sub_30(&v55, &v41) != -1 )
            {
                v25 = 0;
LABEL_41:
                v26 = 0;
                while ( v25 < 9 )
                {
                  if ( v26 >= 3 )
                  break;
                  v27 = *(_DWORD *)(v23 + 4 * (v26 + v25));
                  __asm { lahf }
                  if ( !__SETP__(_AH & 0x44, 0) )
                  break;
                  v29 = *(_DWORD *)(v24 + 4 * (v26 + v25));
                  __asm { lahf }
                  if ( !__SETP__(_AH & 0x44, 0) )
                  break;
                  __asm { lahf }
                  if ( __SETP__(_AH & 0x44, 0) )
                  break;
                  ++v26;
                  if ( v26 >= 3 )
                  {
                  v25 += 3;
                  if ( v25 < 9 )
                      goto LABEL_41;
                  v32 = strlen(&v66);
                  sub_310(v47);
                  v33 = 0;
                  if ( v32 )
                  {
                      v34 = 0;
                      do
                      {
                        v35 = *(&v66 + v34);
                        if ( (unsigned int)(v35 - 48) <= 8 )
                        sub_3C0(v35 - 48);
                        ++v33;
                        v34 = v33;
                      }
                      while ( v33 < v32 );
                  }
                  v36 = 1;
                  do
                  {
                      if ( *(_BYTE *)((unsigned __int8)v36 + 0x3743F10) < *(_BYTE *)((unsigned __int8)v36 + 0x3743F0F) )
                        break;
                      ++v36;
                  }
                  while ( (unsigned __int8)v36 < 8u );
                  return v36 == 8;
                  }
                }
            }
            goto LABEL_58;
            }
          }
          break;
      }
      }
    }
LABEL_58:
    result = 0;
}
else
{
LABEL_62:
    result = 0;
}
return result;
}


我们注意到其中有两处result = 0,初步怀疑返回0也就是错误,返回1就是正确。
因此我们回到00430613处,并将代码修改为下面这样:

0043D613    FFD0            call eax
0043D615    B8 01000000   mov eax,0x1
0043D61A    E9 6D2F0000   jmp CrackMe.0044058C
0043D61F    90            nop

然后运行,结果如下图所示:

证明我们的猜想是对的,具体的注册算法,留待以后再分析。
本文所使用的、生成的所有文件,包括dump文件,IDA库文件,以及本文笔记PDF版本,均在附件中:

lizhirui 发表于 2018-10-9 08:11

KevinHacker 发表于 2018-10-8 17:19
666~但是哪一步是关键吖?

开头是关于对话框事件处理机制的分析
接下来是根据事件处理机制找到按钮按下事件入口点
接下来结合CodeDoctor人工解X86指令膨胀和混淆
接下来找到关键CALL,然后走爆破流程

lizhirui 发表于 2018-10-9 08:10

感觉不到风 发表于 2018-10-8 17:21
这是什么语言啊????

已修复,发现代码里面带了文本格式导致显示的乱七八糟,刚清除了文本格式重新提交了

KevinHacker 发表于 2018-10-8 17:19

{:301_1008:}666~但是哪一步是关键吖?

感觉不到风 发表于 2018-10-8 17:21

这是什么语言啊????

babyxinloveyou 发表于 2018-10-8 17:40

坐等看大神评论。

戰龍在野 发表于 2018-10-8 17:41

太高深了看不明白啊呵呵

haoyaer 发表于 2018-10-8 19:01


坐等看大神评论

三点一线 发表于 2018-10-8 20:34

本人纯小白一个,只能看看热闹了

muzb 发表于 2018-10-9 14:15

页: [1] 2
查看完整版本: 对吾爱破解2016年安全挑战赛第一题的相关分析