h_one 发表于 2013-12-17 23:17

【吾爱2013CM大赛解答】--crack me-RedAgl详细分析

【文章标题】: 【吾爱2013CM大赛解答】--crack me-RedAgl
【文章作者】:zxcfvasd
【作者主页】: 无
【操作平台】: win xp
【工具】 OD,IDA
【博客地址】http://honeblog.duapp.com/

详细分析:
call 401110,里面主要对窗口类填充,最关心的就是WinProc,窗口消息处理函数了,成功找到并下断。然后根据消息ID下断点,对于这种程序的关心寻找
WM_INIT(初始化),WM_TIMER,WM_COMMAND或按钮消息。这就就很快能分析道程序关键点了。

WM_TIMER 中反调试:

BOOL bRet = EnumWindows(lpEnumFunc/*00402460*/, lParam/*NULL*/);这个函数会列出屏幕上所有的顶级窗口,并以窗口句柄作为的LpEnumFunc参数,这个函数会一直工作到列出所有窗口,
0040132A|> \6A 00         push 0x0                                              ; /lParam = 0; Case 113 (WM_TIMER) of switch 004011DC
0040132C|.68 60244000   push 2013CM1.00402460                                 ; |Callback = 2013CM1.00402460
00401331|.FF15 78414000 call dword ptr ds:[<&USER32.EnumWindows>]             ; \EnumWindows
00401337|.85C0          test eax,eax
00401339|.E9 A0030000   jmp 2013CM1.004016DE
0040133E|   90            nop      
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
LpEnumFunc函数   查看进程列表是否运行ollydbg

0040249B|.68 04010000   push 0x104                                          ; /Count = 104 (260.)
004024A0|.56            push esi                                              ; |Buffer
004024A1|.68 66200000   push 0x2066                                           ; |RsrcID = STRING "ollydbg"
004024A6|.FF35 B0534000 push dword ptr ds:                        ; |hInst = NULL
004024AC|.FF15 9C414000 call dword ptr ds:[<&USER32.LoadStringW>]             ; \LoadStringW
004024B2|.8B5D 08       mov ebx,
004024B5|.53            push ebx                                              ; /hWnd
004024B6|.FF15 54414000 call dword ptr ds:[<&USER32.IsWindowVisible>]         ; \IsWindowVisible
004024BC|.85C0          test eax,eax
004024BE|.74 53         je X2013CM1.00402513
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.GetWindowTextW>]          ; \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
可以直接将je,改成jmp就可以了(上面红色字体),,,,也可以在初始化消息中xxooSetTimer等等


WM_CREATE(初始化中)
首先创建一个互斥对象,保证系统中只有一个程序实例运行
00401240|.FF35 C0534000 push dword ptr ds:                        ; /MutexName = NULL
00401246|.6A 00         push 0x0                                              ; |InitialOwner = FALSE
00401248|.6A 00         push 0x0                                              ; |pSecurity = NULL
0040124A|.FF15 88404000 call dword ptr ds:[<&KERNEL32.CreateMutexW>]          ; \CreateMutexW
00401250|.FF15 80404000 call dword ptr ds:[<&KERNEL32.GetLastError>]          ; [GetLastError
00401256|.3D B7000000   cmp eax,0xB7
0040125B|.0F84 DE000000 je 2013CM1.0040133F
call 00401700函数中,这个call是创建静态文本框,和编辑框函数。注意最后几行位置00401A8A|.A3 78534000   mov dword ptr ds:,eax ,全局变量【0x405378】是保存的用户名编辑框句柄,接下来调用SetWindowLongW(NULL, GWL_WNDPROC, EditProc/*401AA0*/);这是给用户名编辑框设置窗口消息回调函数,所以跟上继续分析,

00401ABA|.3D 02010000   cmp eax,0x102    MSG
接下来会调用GetWindowText获取到输入用户名
00401B38|.E8 E30A0000   call 2013CM1.00402620 进入
可以了解输入用户名位数大于4
int len = strlen(user);
int sum = 0, temp;
char *userstr1;
for(int i; i < len; i++)
{
    sum += user;

}
temp = sum+0x7DD;
temp =temp*0x34;
itoa(temp, usestr1);
这里就是将输入的用户名计算的过程,最后将得到的userstr1,strcat到user后面。保存在
004026A5|.8D46 FF       lea eax,dword ptr ds:
004026A8|.8985 ECFEFFFF mov ,eax
004026AE|.8BF0          mov esi,eax
004026B0|>0FBE040A      /movsx eax,byte ptr ds:
004026B4|.03F8          |add edi,eax
004026B6|.0FBE440A 01   |movsx eax,byte ptr ds:
004026BB|.83C1 02       |add ecx,0x2
004026BE|.03D8          |add ebx,eax
004026C0|.3BCE          |cmp ecx,esi
004026C2|.^ 7C EC         \jl X2013CM1.004026B0
004026C4|.8BB5 E8FEFFFF mov esi,
004026CA|>3BCE          cmp ecx,esi
004026CC|.7D 0A         jge X2013CM1.004026D8
004026CE|.0FBE040A      movsx eax,byte ptr ds:
004026D2|.8985 F0FEFFFF mov ,eax
004026D8|>8B8D F0FEFFFF mov ecx,
004026DE|.6A 0A         push 0xA
004026E0|.68 04010000   push 0x104
004026E5|.8D85 F8FEFFFF lea eax,
004026EB|.50            push eax
004026EC|.81C1 DD070000 add ecx,0x7DD
004026F2|.8D043B      lea eax,dword ptr ds:
004026F5|.03C1          add eax,ecx                                           ;usersum + 0x7DD
004026F7|.6BC0 34       imul eax,eax,0x34
004026FA|.50            push eax
004026FB|.FF15 04414000 call dword ptr ds:[<&MSVCR110._itoa_s>]               ;MSVCR110._itoa_s
00402701|.8D85 F8FEFFFF lea eax,
00402707|.50            push eax
00402708|.68 04010000   push 0x104
0040270D|.FF35 D0534000 push dword ptr ds:
00402713|.FF15 08414000 call dword ptr ds:[<&MSVCR110.strcat_s>]            ;MSVCR110.strcat_s


WM_LBUTTONUP消息


接下来隐藏窗口,然后调用本进程权限,以备后面远程线程注入准备
BOOL EnablePriv()
{
HANDLE hToken;
if ( OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken) )
{
       TOKEN_PRIVILEGES tkp;

       LookupPrivilegeValue( NULL,SE_DEBUG_NAME,&tkp.Privileges.Luid );//修改进程权限
       tkp.PrivilegeCount=1;
       tkp.Privileges.Attributes=SE_PRIVILEGE_ENABLED;
       AdjustTokenPrivileges( hToken,FALSE,&tkp,sizeof tkp,NULL,NULL );//通知系统修改进程权限

       return( (GetLastError()==ERROR_SUCCESS) );
}
       return TRUE;
}

接下来进入两个关键call
00401474|.E8 C70B0000   call 2013CM1.00402040
00401479|.E8 F2060000   call 2013CM1.00401B70
0040147E|>6A 05         push 0x5
00401480|.57            push edi
call 2013CM1.00402040:

调用CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0)函数拍进程成快照,查找PID大于1000的进程,然后调用CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0)拍进程模块,得到kerner32,user32模块地址,然后调用LoadStringW解密字符(),然后比较当前进程是否为解密出进程名其中一个,若是则找到远程注入线程,然后保存该进程PID,在call 2013CM1.00401B70中进行远程注入
004020A2|.56            push esi                                              ; /ProcessID => 0
004020A3|.6A 02         push 0x2                                              ; |Flags = TH32CS_SNAPPROCESS
004020A5|.FF15 2C404000 call dword ptr ds:[<&KERNEL32.CreateToolhelp32Snapsho>; \CreateToolhelp32Snapshot
004020AB|.8985 9CF9FFFF mov ,eax
004020B1|.83F8 FF       cmp eax,-0x1
004020B4|.0F84 37020000 je 2013CM1.004022F1
004020BA|.8D8D C8FDFFFF lea ecx,
004020C0|.51            push ecx
004020C1|.50            push eax
004020C2|.C785 C8FDFFFF>mov ,0x22C
004020CC|.C785 A0F9FFFF>mov ,0x428
004020D6|.FF15 30404000 call dword ptr ds:[<&KERNEL32.Process32FirstW>]       ;kernel32.Process32FirstW
004020DC|.85C0          test eax,eax
004020DE|.0F84 0D020000 je 2013CM1.004022F1
004020E4|.8B1D 00414000 mov ebx,dword ptr ds:[<&MSVCR110._wcsicmp>]         ;MSVCR110._wcsicmp
004020EA|.8D9B 00000000 lea ebx,dword ptr ds:
004020F0|>8B85 D0FDFFFF /mov eax,
004020F6|.8985 8CF9FFFF |mov ,eax
004020FC|.3905 AC534000 |cmp dword ptr ds:,eax                      ;判断是否是当前进程
00402102|.0F84 C2010000 |je 2013CM1.004022CA
00402108|.3D E8030000   |cmp eax,0x3E8                                        ;保存pid大于1000 ,,,kernel,user32
0040210D|.0F8E B7010000 |jle 2013CM1.004022CA
00402113|.50            |push eax                                             ; /ProcessID
00402114|.6A 08         |push 0x8                                             ; |Flags = TH32CS_SNAPMODULE
00402116|.FF15 2C404000 |call dword ptr ds:[<&KERNEL32.CreateToolhelp32Snapsh>; \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
00402130|.85C0          |test eax,eax         
00402132|.0F84 86010000 |je 2013CM1.004022BE
00402138|.8BBD 98F9FFFF |mov edi,
0040213E|.8BFF          |mov edi,edi
00402140|>8D85 C0F9FFFF |/lea eax,
00402146|.50            ||push eax
00402147|.FF35 C0534000 ||push dword ptr ds:                        ;kernel32
0040214D|.FFD3          ||call ebx
0040214F|.83C4 08       ||add esp,0x8
00402152|.85C0          ||test eax,eax
00402154|.75 0D         ||jnz X2013CM1.00402163
00402156|.8B85 B4F9FFFF ||mov eax,                                 ;ModuelAddr
0040215C|.8985 94F9FFFF ||mov ,eax                      ////将kernel32,user32模块地址分别保存在全局变量中,注意地址后面会用到
00402162|.46            ||inc esi
00402163|>8D85 C0F9FFFF ||lea eax,
00402169|.50            ||push eax
0040216A|.FF35 C4534000 ||push dword ptr ds:                        ;user32
00402170|.FFD3          ||call ebx
00402172|.83C4 08       ||add esp,0x8
00402175|.85C0          ||test eax,eax
00402177|.75 0D         ||jnz X2013CM1.00402186
00402179|.8B85 B4F9FFFF ||mov eax,
0040217F|.8985 90F9FFFF ||mov ,eax
00402185|.46            ||inc esi
00402186|>8D85 A0F9FFFF ||lea eax,
0040218C|.50            ||push eax
0040218D|.57            ||push edi   
0040218E|.FF15 38404000 ||call dword ptr ds:[<&KERNEL32.Module32NextW>]       ;kernel32.Module32NextW
00402194|.85C0          ||test eax,eax
00402196|.^ 75 A8         |\jnz X2013CM1.00402140


004028E9|.A3 DC534000   mov dword ptr ds:,eax                     ;存找到的进程pid,,,待会儿远程线程注入


call 2013CM1.00401B70
调用GetVolumeInformationW函数获取收卷序列号的变量,然后将输入用户名到的字符串求和(sum)
然后调用itoa分别对sum,和收卷序列号的变量 进行处理最后将得到的字符连接拷贝到 dword ptr ds:FinalUser

00402782|> \83F9 04       cmp ecx,0x4
00402785|.^ 7C E9         jl X2013CM1.00402770
00402787|.68 04010000   push 0x104                                          ; /pFileSystemNameSize = 00000104
0040278C|.8D85 D8F6FFFF lea eax,                                 ; |
00402792|.50            push eax                                              ; |pFileSystemNameBuffer
00402793|.8D85 CCF6FFFF lea eax,                                 ; |
00402799|.50            push eax                                              ; |pFileSystemFlags
0040279A|.8D85 D0F6FFFF lea eax,                                 ; |
004027A0|.50            push eax                                              ; |pMaxFilenameLength
004027A1|.8D85 D4F6FFFF lea eax,                                 ; |
004027A7|.50            push eax                                              ; |pVolumeSerialNumber
004027A8|.68 04010000   push 0x104                                          ; |MaxVolumeNameSize = 104 (260.)
004027AD|.8D85 E0F8FFFF lea eax,                                 ; |
004027B3|.50            push eax                                              ; |VolumeNameBuffer
004027B4|.6A 00         push 0x0                                              ; |RootPathName = NULL
004027B6|.C785 D0F6FFFF>mov ,0xFF                                  ; |
004027C0|.FF15 58404000 call dword ptr ds:[<&KERNEL32.GetVolumeInformationW>] ; \GetVolumeInformationW
004027C6|.33C9          xor ecx,ecx
004027C8|.85F6          test esi,esi
004027CA|.7E 11         jle X2013CM1.004027DD
004027CC|.8B15 D0534000 mov edx,dword ptr ds:
004027D2|>0FBE040A      /movsx eax,byte ptr ds:                      ;edi += usertemp
004027D6|.41            |inc ecx
004027D7|.03F8          |add edi,eax
004027D9|.3BCE          |cmp ecx,esi
004027DB|.^ 7C F5         \jl X2013CM1.004027D2
004027DD|>8B35 04414000 mov esi,dword ptr ds:[<&MSVCR110._itoa_s>]            ;MSVCR110._itoa_s
004027E3|.6A 0A         push 0xA                                              ;10进制
004027E5|.68 04010000   push 0x104
004027EA|.8D85 F0FCFFFF lea eax,
004027F0|.50            push eax
004027F1|.FFB5 D4F6FFFF push                                     ;指向收卷序列号的变量
004027F7|.FFD6          call esi                                              ;<&MSVCR110._itoa_s>
004027F9|.6A 10         push 0x10                                             ;16进制
004027FB|.68 04010000   push 0x104
00402800|.8D85 F8FEFFFF lea eax,
00402806|.50            push eax
00402807|.57            push edi                                              ;sum
00402808|.FFD6          call esi
得到FinalUser字符串




终于到最后一个call了,,,
鼠标一拉发现CreateRemoteThread,哈哈作者真有想法,接下来就是为远程函数准备参数(lpParamer)了
参数中第一个双字是FinalUser长度,第二个是输入假吗长度


00401FB2|> \6A 00         push 0x0                                              ; /lpThreadId = NULL
00401FB4|.6A 00         push 0x0                                              ; |dwCreationFlags = 0
00401FB6|.57            push edi                                              ; |lpParameter
00401FB7|.56            push esi                                              ; |lpStartAddress
00401FB8|.6A 00         push 0x0                                              ; |dwStackSize = 0
00401FBA|.6A 00         push 0x0                                              ; |lpThreadAttributes
00401FBC|.53            push ebx                                              ; |hProcess
00401FBD|.FF15 24404000 call dword ptr ds:[<&KERNEL32.CreateRemoteThread>]    ; \CreateRemoteThread

接下来就是对注入进程进行分析了,,,看看传过去的数据是怎么验证的了。提前挂起被注入进程。对lpStartAddress地址下断

然后运行CreateRemoteThread函数
首先判断传入的FinalUser,与假吗长度是否相等,,,然后对FinalUser变换得到真正序列号
00C40029    33C0            xor eax,eax
00C4002B    8BF7            mov esi,edi
00C4002D    FC            cld                                                   ; ecx 作为循环次数,也作为解密秘钥
00C4002E    AC            lods byte ptr ds:                                  ; 将esi指向的值传给eax
00C4002F    3C 2D         cmp al,0x2D
00C40031    74 02         je X00C40035                                          ; -
00C40033    33C1            xor eax,ecx                                             ; ecx = C
00C40035    AA            stos byte ptr es:
00C40036^ E2 F6         loopd X00C4002E
00C40038    5E            pop esi
00C40039    5F            pop edi
00C4003A    59            pop ecx
00C4003B    FC            cld
00C4003C    F3:A6         repe cmps byte ptr es:,byte ptr ds:      比较是否输入正确,,,,
00C4003E    74 02         je X00C40042   ,改成jmp
00C40040    61            popad
00C40041    C3            retn


for(int i = 0; i < len; i++)
{
      key = FinalUser^templen;
      templen--;
}


那么直接可以在母本程序中对两处进行jmp修改.

Hmily 发表于 2013-12-17 23:25

代码最好用代码框,不然discuz的代码会有反斜杠的问题。

JoyChou 发表于 2013-12-18 10:04

帅气的排版。

h_one 发表于 2013-12-18 11:07

Hmily 发表于 2013-12-17 23:25 static/image/common/back.gif
代码最好用代码框,不然discuz的代码会有反斜杠的问题。

昨天晚上太急了,,,,下次注意的{:1_903:}

h_one 发表于 2013-12-18 11:09

JoyChou 发表于 2013-12-18 10:04 static/image/common/back.gif
帅气的排版。

嘲讽,,,走的太急没管
页: [1]
查看完整版本: 【吾爱2013CM大赛解答】--crack me-RedAgl详细分析