对吾爱破解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版本,均在附件中:
KevinHacker 发表于 2018-10-8 17:19
666~但是哪一步是关键吖?
开头是关于对话框事件处理机制的分析
接下来是根据事件处理机制找到按钮按下事件入口点
接下来结合CodeDoctor人工解X86指令膨胀和混淆
接下来找到关键CALL,然后走爆破流程 感觉不到风 发表于 2018-10-8 17:21
这是什么语言啊????
已修复,发现代码里面带了文本格式导致显示的乱七八糟,刚清除了文本格式重新提交了 {:301_1008:}666~但是哪一步是关键吖? 这是什么语言啊???? 坐等看大神评论。 太高深了看不明白啊呵呵
坐等看大神评论 本人纯小白一个,只能看看热闹了
页:
[1]
2