好友
阅读权限30
听众
最后登录1970-1-1
|
h_one
发表于 2013-12-17 23:17
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。
【文章标题】: 【吾爱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:[0x4053B0] ; |hInst = NULL
004024AC |. FF15 9C414000 call dword ptr ds:[<&USER32.LoadStringW>] ; \LoadStringW
004024B2 |. 8B5D 08 mov ebx,[arg.1]
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:[0x4053C0] ; /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:[0x405378],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后面。保存在[0x4053D0]
004026A5 |. 8D46 FF lea eax,dword ptr ds:[esi-0x1]
004026A8 |. 8985 ECFEFFFF mov [local.69],eax
004026AE |. 8BF0 mov esi,eax
004026B0 |> 0FBE040A /movsx eax,byte ptr ds:[edx+ecx]
004026B4 |. 03F8 |add edi,eax
004026B6 |. 0FBE440A 01 |movsx eax,byte ptr ds:[edx+ecx+0x1]
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,[local.70]
004026CA |> 3BCE cmp ecx,esi
004026CC |. 7D 0A jge X2013CM1.004026D8
004026CE |. 0FBE040A movsx eax,byte ptr ds:[edx+ecx]
004026D2 |. 8985 F0FEFFFF mov [local.68],eax
004026D8 |> 8B8D F0FEFFFF mov ecx,[local.68]
004026DE |. 6A 0A push 0xA
004026E0 |. 68 04010000 push 0x104
004026E5 |. 8D85 F8FEFFFF lea eax,[local.66]
004026EB |. 50 push eax
004026EC |. 81C1 DD070000 add ecx,0x7DD
004026F2 |. 8D043B lea eax,dword ptr ds:[ebx+edi]
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,[local.66]
00402707 |. 50 push eax
00402708 |. 68 04010000 push 0x104
0040270D |. FF35 D0534000 push dword ptr ds:[0x4053D0]
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[0].Luid );//修改进程权限
tkp.PrivilegeCount=1;
tkp.Privileges[0].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 [local.409],eax
004020B1 |. 83F8 FF cmp eax,-0x1
004020B4 |. 0F84 37020000 je 2013CM1.004022F1
004020BA |. 8D8D C8FDFFFF lea ecx,[local.142]
004020C0 |. 51 push ecx
004020C1 |. 50 push eax
004020C2 |. C785 C8FDFFFF>mov [local.142],0x22C
004020CC |. C785 A0F9FFFF>mov [local.408],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:[ebx]
004020F0 |> 8B85 D0FDFFFF /mov eax,[local.140]
004020F6 |. 8985 8CF9FFFF |mov [local.413],eax
004020FC |. 3905 AC534000 |cmp dword ptr ds:[0x4053AC],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,[local.408]
00402122 |. 51 |push ecx
00402123 |. 50 |push eax
00402124 |. 8985 98F9FFFF |mov [local.410],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,[local.410]
0040213E |. 8BFF |mov edi,edi
00402140 |> 8D85 C0F9FFFF |/lea eax,[local.400]
00402146 |. 50 ||push eax
00402147 |. FF35 C0534000 ||push dword ptr ds:[0x4053C0] ; 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,[local.403] ; ModuelAddr
0040215C |. 8985 94F9FFFF ||mov [local.411],eax ////将kernel32,user32模块地址分别保存在全局变量中,注意地址后面会用到
00402162 |. 46 ||inc esi
00402163 |> 8D85 C0F9FFFF ||lea eax,[local.400]
00402169 |. 50 ||push eax
0040216A |. FF35 C4534000 ||push dword ptr ds:[0x4053C4] ; 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,[local.403]
0040217F |. 8985 90F9FFFF ||mov [local.412],eax
00402185 |. 46 ||inc esi
00402186 |> 8D85 A0F9FFFF ||lea eax,[local.408]
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:[0x4053DC],eax ; 存找到的进程pid,,,待会儿远程线程注入
call 2013CM1.00401B70
调用GetVolumeInformationW函数获取收卷序列号的变量,然后将输入用户名到的字符串求和(sum)
然后调用itoa分别对sum,和收卷序列号的变量 进行处理最后将得到的字符连接拷贝到 dword ptr ds:[0x4053CC]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,[local.586] ; |
00402792 |. 50 push eax ; |pFileSystemNameBuffer
00402793 |. 8D85 CCF6FFFF lea eax,[local.589] ; |
00402799 |. 50 push eax ; |pFileSystemFlags
0040279A |. 8D85 D0F6FFFF lea eax,[local.588] ; |
004027A0 |. 50 push eax ; |pMaxFilenameLength
004027A1 |. 8D85 D4F6FFFF lea eax,[local.587] ; |
004027A7 |. 50 push eax ; |pVolumeSerialNumber
004027A8 |. 68 04010000 push 0x104 ; |MaxVolumeNameSize = 104 (260.)
004027AD |. 8D85 E0F8FFFF lea eax,[local.456] ; |
004027B3 |. 50 push eax ; |VolumeNameBuffer
004027B4 |. 6A 00 push 0x0 ; |RootPathName = NULL
004027B6 |. C785 D0F6FFFF>mov [local.588],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:[0x4053D0]
004027D2 |> 0FBE040A /movsx eax,byte ptr ds:[edx+ecx] ; 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,[local.196]
004027F0 |. 50 push eax
004027F1 |. FFB5 D4F6FFFF push [local.587] ; 指向收卷序列号的变量
004027F7 |. FFD6 call esi ; <&MSVCR110._itoa_s>
004027F9 |. 6A 10 push 0x10 ; 16进制
004027FB |. 68 04010000 push 0x104
00402800 |. 8D85 F8FEFFFF lea eax,[local.66]
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] ; 将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:[edi]
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:[edi],byte ptr ds:[esi] 比较是否输入正确,,,,
00C4003E 74 02 je X00C40042 ,改成jmp
00C40040 61 popad
00C40041 C3 retn
for(int i = 0; i < len; i++)
{
key = FinalUser^templen;
templen--;
}
那么直接可以在母本程序中对两处进行jmp修改. |
免费评分
-
查看全部评分
|