JoyChou 发表于 2013-12-18 23:25

【吾爱2013CM大赛解答】 -- Crack Me--RedAgl 反调试+爆破详细分析

先简单描述一下快速爆破的做法。
搜索字符串,来到00404230=2013CM-j.00404230 (UNICODE "SeDebugPrivilege")这个位置,ctrl+F9执行到返回
00401458|.E8 730F0000   call 2013CM-j.004023D0                                       ;提升权限
0040145D|.8B0D D0534000 mov ecx,dword ptr ds:
00401463|.8D51 01       lea edx,dword ptr ds:
00401466|>8A01          /mov al,byte ptr ds:
00401468|.41            |inc ecx
00401469|.84C0          |test al,al
0040146B|.^ 75 F9         \jnz X2013CM-j.00401466
0040146D|.2BCA          sub ecx,edx
0040146F|.83F9 04       cmp ecx,0x4
00401472|.7C 0A         jl X2013CM-j.0040147E
00401474|.E8 C70B0000   call 2013CM-j.00402040                                       ;得到XX进程ID
00401479|.E8 F2060000   call 2013CM-j.00401B70                                       ;好东西



得到iexplorer.exectfmon.exeexplorer.exe   STService.exe   spoolsv.exe这几个进程PID以及当前遍历他们模块得到kernel32和user32的dllbase,方便注入。
00402113|.50            |push eax                                                      ; /ProcessID
00402114|.6A 08         |push 0x8                                                      ; |Flags = TH32CS_SNAPMODULE
00402116|.FF15 2C404000 |call dword ptr ds:[<&KERNEL32.CreateToolhelp32Snapshot>]      ; \CreateToolhelp32Snapshot
0040211C|.8D8D A0F9FFFF |lea ecx,
00402122|.51            |push ecx
00402123|.50            |push eax
00402124|.8985 98F9FFFF |mov ,eax
0040212A|.FF15 34404000 |call dword ptr ds:[<&KERNEL32.Module32FirstW>]                ;kernel32.Module32FirstW


0040230A|.50            push eax
0040230B|.FFB5 90F9FFFF push                                              ;ProcessName
00402311|.FFB5 94F9FFFF push                                              ;user32 dllbase
00402317|.FFB5 8CF9FFFF push                                              ;kernel32 dllbase
0040231D|.E8 BE050000   call 2013CM-j.004028E0


开始注入
00401D32|> \8B35 7C404000 mov esi,dword ptr ds:[<&KERNEL32.OpenProcess>]               ;kernel32.OpenProcess
00401D38|.50            push eax                                                       ; /ProcessId = 638
00401D39|.6A 00         push 0x0                                                       ; |Inheritable = FALSE
00401D3B|.68 FFFF1F00   push 0x1FFFFF                                                ; |Access = TERMINATE|CREATE_THREAD|VM_OPERATION|VM_READ|VM_WRITE|DUP_HANDLE|CREATE_PROCESS|SET_QUOTA|SET_INFORMATION|QUERY_INFORMATION|SYNCHRONIZE|STANDARD_RIGHTS_REQUIRED|F804
00401D40|.FFD6          call esi                                                       ; \OpenProcess


写入注入进程关键数据
00401F44|.6A 00         push 0x0                                                       ; /pBytesWritten = NULL
00401F46|.68 00080000   push 0x800                                                   ; |BytesToWrite = 800 (2048.)
00401F4B|.68 50234000   push 2013CM-j.00402350                                       ; |Buffer = 2013CM-j.00402350
00401F50|.56            push esi                                                       ; |Address
00401F51|.53            push ebx                                                       ; |hProcess
00401F52|.FF15 18404000 call dword ptr ds:[<&KERNEL32.WriteProcessMemory>]             ; \WriteProcessMemory


来到00402350,写入的数据,修改两处即可爆破。
00402350   .60            pushad
00402351   .8B0B          mov ecx,dword ptr ds:
00402353   .8B53 04       mov edx,dword ptr ds:
00402356   .3BCA          cmp ecx,edx
00402358      74 02         je X2013CM-j.0040235C                                          ; 改为jmp
0040235A   .61            popad
0040235B   .C3            retn
0040235C   >8BC3          mov eax,ebx
0040235E   .51            push ecx
0040235F   .BF 1C000000   mov edi,0x1C
00402364   .BE 20010000   mov esi,0x120
00402369   .03F8          add edi,eax
0040236B   .03F0          add esi,eax
0040236D   .57            push edi
0040236E   .56            push esi
0040236F   >83F9 0F       cmp ecx,0xF
00402372   .72 05         jb X2013CM-j.00402379
00402374   .83E9 0F       sub ecx,0xF
00402377   .^ EB F6         jmp X2013CM-j.0040236F
00402379   >33C0          xor eax,eax
0040237B   .8BF7          mov esi,edi
0040237D   .FC            cld
0040237E   >AC            lods byte ptr ds:
0040237F   .3C 2D         cmp al,0x2D
00402381   .74 02         je X2013CM-j.00402385
00402383   .33C1          xor eax,ecx
00402385   >AA            stos byte ptr es:
00402386   .^ E2 F6         loopd X2013CM-j.0040237E
00402388   .5E            pop esi
00402389   .5F            pop edi
0040238A   .59            pop ecx
0040238B   .FC            cld
0040238C   .F3:A6         repe cmps byte ptr es:,byte ptr ds:
0040238E      74 02         je X2013CM-j.00402392                                          ; 改为jmp
00402390   .61            popad
00402391   .C3            retn
00402392   >8B8B 34020000 mov ecx,dword ptr ds:
00402398   .8BD3          mov edx,ebx
0040239A   .83C2 10       add edx,0x10
0040239D   .8B43 0C       mov eax,dword ptr ds:
004023A0   .52            push edx
004023A1   .50            push eax
004023A2   .FFD1          call ecx
004023A4   .8BCB          mov ecx,ebx
004023A6   .81C1 24020000 add ecx,0x224
004023AC   .8BD3          mov edx,ebx
004023AE   .81C2 2A020000 add edx,0x22A
004023B4   .BF 00000000   mov edi,0x0
004023B9   .6A 00         push 0x0
004023BB   .51            push ecx
004023BC   .52            push edx
004023BD   .57            push edi
004023BE   .FFD0          call eax
004023C0   .61            popad
004023C1   .C3            retn




再重头看看可以学习的地方
IDA看窗口回调
.text:00401138               mov   , 30h
.text:0040113F               mov   , 3
.text:00401146               mov   , offset sub_4011C0
.text:0040114D               mov   , 0
.text:00401154               mov   , 0
.text:0040115B               mov   , ebx
可以看到窗口回调函数是0x004011C0

WM_TIMER利用EnumWindows反调试
0040132A|> \6A 00         push 0x0                                 ; /lParam = 0; Case 113 (WM_TIMER) of switch 004011DC
0040132C|.68 60244000   push 2013CM.00402460                     ; |Callback = 2013CM.00402460
00401331|.FF15 78414000 call dword ptr ds:[<&USER32.EnumWindows>>; \EnumWindows
00401337|.85C0          test eax,eax
00401339      0F85 9F030000 jnz 2013CM.004016DE                      ;改为jmp
0040133F|>6A 00         push 0x0
00401341|>6A 00         push 0x0                                 ; |wParam = 0
00401343|.6A 10         push 0x10                              ; |Message = WM_CLOSE
00401345|.57            push edi                                 ; |hWnd
00401346|.FF15 A0414000 call dword ptr ds:[<&USER32.SendMessageW>; \SendMessageW
0040134C|.33C0          xor eax,eax
0040134E|.5F            pop edi
0040134F|.5E            pop esi
00401350|.8B4C24 44   mov ecx,dword ptr ss:
00401354|.33CC          xor ecx,esp
00401356|.E8 BB150000   call 2013CM.00402916
0040135B|.8BE5          mov esp,ebp
0040135D|.5D            pop ebp
0040135E|.C2 1000       retn 0x10


EnumWIndows回调函数,检测调试器

004024C0|.68 04010000   push 0x104                               ; /Count = 104 (260.)
004024C5|.57            push edi                                 ; |Buffer
004024C6|.53            push ebx                                 ; |hWnd
004024C7|.FF15 50414000 call dword ptr ds:[<&USER32.GetWindowTex>; \GetWindowTextW
004024CD|.8B1D 2C414000 mov ebx,dword ptr ds:[<&SHLWAPI.StrStrIW>;shlwapi.StrStrIW
004024D3|.56            push esi                                 ; /Pattern
004024D4|.57            push edi                                 ; |String
004024D5|.FFD3          call ebx                                 ; \StrStrIW
004024D7|.85C0          test eax,eax
004024D9      74 09         je X2013CM.004024E4                      ;如果窗口文本含有ollydbg,那么返回值不等于0
004024DB      5F            pop edi
004024DC      5E            pop esi
004024DD      33C0          xor eax,eax                              ;返回值赋值为0,EnumWindows也就返回0
004024DF      5B            pop ebx
004024E0|.5D            pop ebp
004024E1|.C2 0800       retn 0x8
004024E4|>68 04010000   push 0x104                               ; /n = 104 (260.)
004024E9|.6A 00         push 0x0                                 ; |c = 00
004024EB|.56            push esi                                 ; |s
004024EC|.E8 970C0000   call <jmp.&MSVCR110.memset>            ; \memset
004024F1|.83C4 0C       add esp,0xC
004024F4|.68 04010000   push 0x104                               ; /Count = 104 (260.)
004024F9|.56            push esi                                 ; |Buffer
004024FA|.68 67200000   push 0x2067                              ; |RsrcID = STRING "2013CM.exe"
004024FF|.FF35 B0534000 push dword ptr ds:             ; |hInst = 00400000
00402505|.FF15 9C414000 call dword ptr ds:[<&USER32.LoadStringW>>; \LoadStringW
0040250B|.56            push esi
0040250C|.57            push edi
0040250D|.FFD3          call ebx
0040250F|.85C0          test eax,eax
00402511|.^ 75 C8         jnz X2013CM.004024DB
00402513|>5F            pop edi
00402514|.5E            pop esi
00402515|.B8 01000000   mov eax,0x1

检测调试器代码简单还原:
#include "stdafx.h"
#include <string.h>
#include <windows.h>
#include <shlwapi.h>// StrStrI头文件
BOOL CALLBACK EnumWindowsProc(
    HWND hwnd,      // handle to parent window
    LPARAM lParam) // application-defined value
{
    char szOD[] = "ollydbg";
    char szExeName[] = "2013CM";
    char szTemp = {0};
    if (IsWindowVisible(hwnd))
    {
      GetWindowText(hwnd, szTemp, MAX_PATH);
                // 且不区分大小写,在szTemp里面查找szOD,以及szExeName,查找到就返回找到字符串的地址
                // 否则返回0
      if ( StrStrI(szTemp, szOD) || StrStrI(szTemp, szExeName) )
      {
            printf("发现调试器\n");
            return FALSE;
      }
    }
    return TRUE;
}
int main(int argc, char *argv[])
{      
      // 遍历窗口,成功返回非0,失败返回0,如果回调函数返回0,EnumWindows也返回0
    if (EnumWindows(EnumWindowsProc, NULL))
    {
      printf("没有发现调试器\n");
    }
    return 0;
}

在WM_CREATE 0x1消息中,创建互斥体,保证只有一个程序运行。
00401240|.FF35 C0534000 push dword ptr ds:             ; /MutexName = "CreateMe @2013 Game"
00401246|.6A 00         push 0x0                                 ; |InitialOwner = FALSE
00401248|.6A 00         push 0x0                                 ; |pSecurity = NULL
0040124A|.FF15 88404000 call dword ptr ds:[<&KERNEL32.CreateMute>; \CreateMutexW
00401250|.FF15 80404000 call dword ptr ds:[<&KERNEL32.GetLastErr>; [GetLastError
00401256|.3D B7000000   cmp eax,0xB7
0040125B|.0F84 DE000000 je 2013CM-j.0040133F

简单利用IsDebuggerPresent和CheckRemoteDebuggerPresent反调试
00402520/$55            push ebp
00402521|.8BEC          mov ebp,esp
00402523|.83EC 08       sub esp,0x8
00402526|.A1 00504000   mov eax,dword ptr ds:
0040252B|.33C5          xor eax,ebp
0040252D|.8945 FC       mov ,eax
00402530|.C745 F8 00000>mov ,0x0
00402537|.FF15 84404000 call dword ptr ds:[<&KERNEL32.IsDebuggerPresent>]               ; [IsDebuggerPresent
0040253D|.85C0          test eax,eax
0040253F|.75 38         jnz X2013CM-j.00402579
00402541|.FF15 48404000 call dword ptr ds:[<&KERNEL32.GetCurrentProcessId>]             ; [GetCurrentProcessId
00402547|.50            push eax                                                      ; /ProcessId
00402548|.6A 00         push 0x0                                                      ; |Inheritable = FALSE
0040254A|.68 FFFF1F00   push 0x1FFFFF                                                   ; |Access = TERMINATE|CREATE_THREAD|VM_OPERATION|VM_READ|VM_WRITE|DUP_HANDLE|CREATE_PROCESS|SET_QUOTA|SET_INFORMATION|QUERY_INFORMATION|SYNCHRONIZE|STANDARD_RIGHTS_REQUIRED|F804
0040254F|.FF15 7C404000 call dword ptr ds:[<&KERNEL32.OpenProcess>]                     ; \OpenProcess
00402555|.8D4D F8       lea ecx,
00402558|.51            push ecx
00402559|.50            push eax
0040255A|.FF15 4C404000 call dword ptr ds:[<&KERNEL32.CheckRemoteDebuggerPresent>]      ;kernel32.CheckRemoteDebuggerPresent

最后附上成功图

JoyChou 发表于 2013-12-18 23:26

坐完沙发赶紧扯。

Ylca 发表于 2013-12-18 23:54

页: [1]
查看完整版本: 【吾爱2013CM大赛解答】 -- Crack Me--RedAgl 反调试+爆破详细分析