本帖最后由 JoyChou 于 2013-12-19 14:21 编辑
一眼望去,发现是mfc写的,就不查壳了,先双击运行下,发现有按钮,就上MFC按钮入口事件工具。
可以看到按钮入口点为:0x004029A0
经测试,MFC任何版本都是可以的。VS2012我没测试过。具体原理,可以google下或者逆袭下它的源码。
最好能做到,不借助OD外的其他工具。
OD载入,Ctrl+G 来到0x004029A0,F2下断,F9运行,输入用户名JoyChou和密码123456,程序断下,先看看整体流程先。
[AppleScript] 纯文本查看 复制代码 00402BE2 > \33C0 xor eax,eax
00402BE4 > 56 push esi
00402BE5 . 50 push eax
00402BE6 . 68 EC685800 push lele.005868EC ; %s %s
00402BEB . 8D85 FCFBFFFF lea eax,dword ptr ss:[ebp-0x404]
00402BF1 . 68 00040000 push 0x400
00402BF6 . 50 push eax
00402BF7 . E8 02411200 call lele.00526CFE ; spirntf格式化
这就是格式化自己输入的username和pwd为"JoyChou 123456"
重点就在下面这个WriteFile这
[AppleScript] 纯文本查看 复制代码 00402CE7 . 6A 00 push 0x0 ; /pOverlapped = NULL
00402CE9 . 8D85 F8FBFFFF lea eax,dword ptr ss:[ebp-0x408] ; |
00402CEF . 50 push eax ; |pBytesWritten
00402CF0 . 2BCA sub ecx,edx ; |
00402CF2 . 51 push ecx ; |nBytesToWrite
00402CF3 . 8D85 FCFBFFFF lea eax,dword ptr ss:[ebp-0x404] ; |
00402CF9 . 50 push eax ; |Buffer
00402CFA . FF35 740C5B00 push dword ptr ds:[0x5B0C74] ; |hFile = 000000A0 (window)
00402D00 . FF15 10345500 call dword ptr ds:[<&KERNEL32.WriteFile>] ; \WriteFile
这有一个问题:WriteFile的句柄哪来的?
我用文件监视工具看没有发现有修改其他文件的动静。
问题先留到这,先把程序跟完,继续单步看,发现在下面就Exit。
这个时候就有点无奈了,啥都没看见,只是看见了无穷无尽的算法。
回到刚说那个文件句柄的问题,这时,想到一个小技巧,OD中,右键->查找->所有常量,输入句柄的地址0x5B0C74
双击到第一个进去,可以发现,原来是创建了一个匿名管道。顿时就有重生般的感觉。
[AppleScript] 纯文本查看 复制代码 004027B3 |. 6A 00 push 0x0 ; /BufSize = 0
004027B5 |. 8D45 F0 lea eax,[local.4] ; |
004027B8 |. 50 push eax ; |pSecurity
004027B9 |. 68 740C5B00 push lele.005B0C74 ; |pWriteHandle = lele.005B0C74
004027BE |. 68 780C5B00 push lele.005B0C78 ; |pReadHandle = lele.005B0C78
004027C3 |. C745 F0 0C000>mov [local.4],0xC ; |
004027CA |. C745 F4 00000>mov [local.3],0x0 ; |
004027D1 |. C745 F8 01000>mov [local.2],0x1 ; |
004027D8 |. FF15 40345500 call dword ptr ds:[<&KERNEL32.CreatePipe>] ; \CreatePipe
此时,我们可以发现,CreatePipe函数创建了一个管道的读入[005B0C78]和写入端句柄[005B0C74],
再继续右键常量搜索005B0C78去寻找读取数据的操作。
CreatePipe类似这样的代码:
[C++] 纯文本查看 复制代码 #include "stdafx.h"
#include <windows.h>
HANDLE hWrite = NULL;
HANDLE hRead = NULL;
void WritePipe()
{
char szContent[] = "Have a test";
DWORD dwWrite = 0;
WriteFile(hWrite, szContent, sizeof(szContent), &dwWrite, NULL);
}
void ReadPipe()
{
char szRead[MAX_PATH] = {0};
DWORD dwReaded = 0;
ReadFile(hRead, szRead, sizeof(szRead), &dwReaded, NULL);
puts(szRead); // 输出 Have a test
}
int main(int argc, char* argv[])
{
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle = TRUE; // 句柄继承
sa.lpSecurityDescriptor = NULL;
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
if (!CreatePipe(&hRead, &hWrite, &sa, 0))
{
MessageBox(NULL, "创建匿名管道失败", "结果", 0);
return -1;
}
WritePipe();
ReadPipe();
return 0;
}
在找到后的第一个双击进去下断,可以发现如下代码
[AppleScript] 纯文本查看 复制代码 00402602 . 6A 00 push 0x0 ; /pOverlapped = NULL
00402604 . 8D85 D8F3FFFF lea eax,dword ptr ss:[ebp-0xC28] ; |
0040260A . 50 push eax ; |pBytesRead
0040260B . 68 00040000 push 0x400 ; |BytesToRead = 400 (1024.)
00402610 . 8D85 DCF7FFFF lea eax,dword ptr ss:[ebp-0x824] ; |
00402616 . 50 push eax ; |Buffer
00402617 . FF35 780C5B00 push dword ptr ds:[0x5B0C78] ; |hFile = 0000009C (window)
0040261D . FF15 2C345500 call dword ptr ds:[<&KERNEL32.ReadFile>] ; \ReadFile
很明显了,后续的操作肯定都会在ReadFile里面进行,
在ReadFile下面,我们可以看到如下的关键比较
[AppleScript] 纯文本查看 复制代码 00402678 . 8D4D EC lea ecx,dword ptr ss:[ebp-0x14]
0040267B . 8D55 DC lea edx,dword ptr ss:[ebp-0x24]
0040267E . BE 0C000000 mov esi,0xC
00402683 > 8B01 mov eax,dword ptr ds:[ecx]
00402685 . 3B02 cmp eax,dword ptr ds:[edx]
00402687 75 41 jnz Xlele.004026CA ; 这是关键比较
00402689 . 83C1 04 add ecx,0x4
0040268C . 83C2 04 add edx,0x4
0040268F . 83EE 04 sub esi,0x4
00402692 .^ 73 EF jnb Xlele.00402683
00402694 . 8A85 DCFBFFFF mov al,byte ptr ss:[ebp-0x424] ; 输入的假码
0040269A . 8A9D DDFBFFFF mov bl,byte ptr ss:[ebp-0x423]
004026A0 . 8A8D DEFBFFFF mov cl,byte ptr ss:[ebp-0x422]
004026A6 . 8A95 DFFBFFFF mov dl,byte ptr ss:[ebp-0x421]
004026AC . 8AA5 E0FBFFFF mov ah,byte ptr ss:[ebp-0x420]
004026B2 . 8ABD E1FBFFFF mov bh,byte ptr ss:[ebp-0x41F]
004026B8 . 8AAD E2FBFFFF mov ch,byte ptr ss:[ebp-0x41E]
004026BE . 8AB5 E3FBFFFF mov dh,byte ptr ss:[ebp-0x41D] ; 证明应该有8位密码
004026C4 . 33F6 xor esi,esi
004026C6 . F7F6 div esi ; 除0异常,异常码是C00000094h,此处F7
004026C8 . EB 01 jmp Xlele.004026CB
004026CA > CC int3 ; 断点异常,异常码是80000003h,F7
我们就先按照程序的流程这样先走,
00402687这句跳了,跳到004026CA 处,这时F7,步入,如下
[AppleScript] 纯文本查看 复制代码 004024F0 . FF7424 04 push dword ptr ss:[esp+0x4]
004024F4 . FF7424 04 push dword ptr ss:[esp+0x4]
004024F8 . E8 03FFFFFF call lele.00402400 ; F7
004024FD . C2 0800 retn 0x8
这就发生了断点异常,关于SEH,不太了解的可以看看《加密与解密》补补
004024F8 F7步入后,如下代码:
[AppleScript] 纯文本查看 复制代码 00402400 /$ 55 push ebp
00402401 |. 8BEC mov ebp,esp
00402403 |. 53 push ebx
00402404 |. 8B5D 08 mov ebx,[arg.1]
00402407 |. 57 push edi
00402408 |. 8B03 mov eax,dword ptr ds:[ebx] ; [ebx]异常码
0040240A |. 8B7D 0C mov edi,[arg.2]
0040240D |. 3D 940000C0 cmp eax,0xC0000094 ; 判断是否是除0错误
00402412 |. 75 48 jnz Xlele.0040245C
00402414 |. B8 6C640000 mov eax,0x646C
00402419 |. 66:3987 B0000>cmp word ptr ds:[edi+0xB0],ax ; 判断异常前的eax是否等于0x646c
00402420 |. 75 2B jnz Xlele.0040244D
00402422 |. B8 69750000 mov eax,0x7569
00402427 |. 66:3987 A4000>cmp word ptr ds:[edi+0xA4],ax ; 判断异常前的ebx是否等于0x7569
0040242E |. 75 1D jnz Xlele.0040244D
00402430 |. B8 6E780000 mov eax,0x786E
00402435 |. 66:3987 AC000>cmp word ptr ds:[edi+0xAC],ax ; 判断异常前的ecx是否等于0x786E
0040243C |. 75 0F jnz Xlele.0040244D
0040243E |. 66:83BF A8000>cmp word ptr ds:[edi+0xA8],0x67 ; 判断异常前的edx是否等于0x67
00402446 |. 75 05 jnz Xlele.0040244D
00402448 |. E8 63FFFFFF call lele.004023B0 ; 正确提示
0040244D |> CC int3
0040244E |. 57 push edi
0040244F |. 53 push ebx
00402450 |. FF15 6C0C5B00 call dword ptr ds:[0x5B0C6C]
00402456 |. 5F pop edi
00402457 |. 5B pop ebx
00402458 |. 5D pop ebp
00402459 |. C2 0800 retn 0x8
0040245C |> 3D 050000C0 cmp eax,0xC0000005 ; 判断是否是内存冲突
00402461 |. 75 19 jnz Xlele.0040247C
00402463 |. 68 E8030000 push 0x3E8 ; /Timeout = 1000. ms
00402468 |. FF15 3C345500 call dword ptr ds:[<&KERNEL32.Sleep>] ; \Sleep
0040246E |. 57 push edi
0040246F |. 53 push ebx
00402470 |. FF15 6C0C5B00 call dword ptr ds:[0x5B0C6C]
00402476 |. 5F pop edi
00402477 |. 5B pop ebx
00402478 |. 5D pop ebp
00402479 |. C2 0800 retn 0x8
0040247C |> 56 push esi
0040247D |. C745 0C 00000>mov [arg.2],0x0
00402484 |. C745 08 00000>mov [arg.1],0x0
0040248B |. 8965 0C mov [arg.2],esp
0040248E |. 8BC5 mov eax,ebp
00402490 |> 8B00 /mov eax,dword ptr ds:[eax]
00402492 |. 8038 00 |cmp byte ptr ds:[eax],0x0
00402495 |.^ 75 F9 \jnz Xlele.00402490
00402497 |. 8945 08 mov [arg.1],eax
0040249A |. 8B4D 0C mov ecx,[arg.2]
0040249D |. 8B45 08 mov eax,[arg.1]
004024A0 |. 2BC1 sub eax,ecx
004024A2 |. 50 push eax
004024A3 |. 6A 00 push 0x0
004024A5 |. 51 push ecx
004024A6 |. E8 B5531200 call lele.00527860
004024AB |. 83C4 0C add esp,0xC
004024AE |. 68 CC685800 push lele.005868CC ; /ntdll
004024B3 |. FF15 38345500 call dword ptr ds:[<&KERNEL32.GetModuleHandleW>>; \GetModuleHandleW
004024B9 |. 68 D8685800 push lele.005868D8 ; /ZwTerminateProcess
004024BE |. 50 push eax ; |hModule
004024BF |. FF15 34345500 call dword ptr ds:[<&KERNEL32.GetProcAddress>] ; \GetProcAddress
004024C5 |. 6A 00 push 0x0
004024C7 |. 8BF0 mov esi,eax
004024C9 |. FF15 30345500 call dword ptr ds:[<&KERNEL32.GetCurrentProcess>; [GetCurrentProcess
004024CF |. 50 push eax
004024D0 |. FFD6 call esi ; 进程退出
004024D2 |. 5E pop esi
004024D3 |. 57 push edi
004024D4 |. 53 push ebx
004024D5 |. FF15 6C0C5B00 call dword ptr ds:[0x5B0C6C]
004024DB |. 5F pop edi
004024DC |. 5B pop ebx
004024DD |. 5D pop ebp
004024DE \. C2 0800 retn 0x8
分析上面的代码:
如果00402687这句跳了,就会产生0x80000003的断点异常,一路执行就会推出程序。
所以得出结论,00402687这句不能跳。nop后,就会产生C0000094h的除零错误,
[AppleScript] 纯文本查看 复制代码 00402414 |. B8 6C640000 mov eax,0x646C
00402419 |. 66:3987 B0000>cmp word ptr ds:[edi+0xB0],ax ; 判断异常前的eax是否等于0x646c
00402420 |. 75 2B jnz Xlele.0040244D
00402422 |. B8 69750000 mov eax,0x7569
00402427 |. 66:3987 A4000>cmp word ptr ds:[edi+0xA4],ax ; 判断异常前的ebx是否等于0x7569
0040242E |. 75 1D jnz Xlele.0040244D
00402430 |. B8 6E780000 mov eax,0x786E
00402435 |. 66:3987 AC000>cmp word ptr ds:[edi+0xAC],ax ; 判断异常前的ecx是否等于0x786E
0040243C |. 75 0F jnz Xlele.0040244D
0040243E |. 66:83BF A8000>cmp word ptr ds:[edi+0xA8],0x67 ; 判断异常前的edx是否等于0x67
00402446 |. 75 05 jnz Xlele.0040244D
00402448 |. E8 63FFFFFF call lele.004023B0 ; 正确提示
把上面的几个jnz Nop后 就可以完成爆破了。不得不说,这程序写得蛮有意思的。
如果有大牛要分析算法的,就分析之前寄存器的几个值就行了,菜鸟就不分析了。
MFC按钮入口定位器:
|