一直知道自己对pe结构了解不足,做这个题就表现的很彻底,拼接exe的时间用了好几个小时,然后想把菜单加到资源里也没有成功
,可喜的是最后还是折腾出来了。下面是简要的分析过程:
从导入表入手,很明显存放在_rdata里面,在偏移0x061C的地方找到
00000618h: B4 76 00 00 00 00 00 00 00 00 00 00 AC 77 00 00 ; 磛..........瑆..
对应的是KERNEL32.DLL,因此这个文件的位置偏移应该是0x7000。
根据各个文件的大小,可以知道其顺序是:
Header:0x1000
_text :0x6000
_rdata:0x7000
_data :0x8000
将他们连接起来,然后随便copy一个exe的头进去,修改如下:
Number of Sections = 3
Size of Code Section = 0x6000
Entry Point RVA = 0x1000(临时)
Section Alignment = 0x1000
File Alignment = 0x1000
Import Table Address = 0x7618(关键)
Import Table Size = 0x50
保存以后用OD载入,查找函数GetVersion(多半是VC的程序,就猜它),得到入口点,修改
Entry Point RVA = 0x1527(修正)
exe拼接好了,然后开始diy。在创建窗口以后跳到自己的空间
00401282 . FF15 10714000 CALL NEAR DWORD PTR [<&USER32.CreateW>; \CreateWindowExA
00401288 .- E9 73770000 JMP 00408A00
先用高级语言写了个样子:
hMenu := CreateMenu;
hPopup := CreateMenu;
AppendMenu(hPopup, MF_POPUP, 555, '&About');
AppendMenu(hMenu, MF_POPUP, hPopup, '&Help');
SetMenu(Handle, hMenu);
然后在OD里面直接修改如下:
00408A00 60 PUSHAD
00408A01 8BF8 MOV EDI, EAX
00408A03 68 F5894000 PUSH 004089F5 ; ASCII "user32.dll"
00408A08 FF15 6C704000 CALL NEAR DWORD PTR [<&KERNEL32.LoadL>; kernel32.LoadLibraryA
00408A0E A3 BC894000 MOV DWORD PTR [4089BC], EAX
00408A13 68 EA894000 PUSH 004089EA ; ASCII "CreateMenu"
00408A18 FF35 BC894000 PUSH DWORD PTR [4089BC]
00408A1E FF15 A0704000 CALL NEAR DWORD PTR [<&KERNEL32.GetPr>; kernel32.GetProcAddress
00408A24 A3 B0894000 MOV DWORD PTR [4089B0], EAX
00408A29 68 DE894000 PUSH 004089DE ; ASCII "AppendMenuA"
00408A2E FF35 BC894000 PUSH DWORD PTR [4089BC]
00408A34 FF15 A0704000 CALL NEAR DWORD PTR [<&KERNEL32.GetPr>; kernel32.GetProcAddress
00408A3A A3 B4894000 MOV DWORD PTR [4089B4], EAX
00408A3F 68 D6894000 PUSH 004089D6 ; ASCII "SetMenu"
00408A44 FF35 BC894000 PUSH DWORD PTR [4089BC]
00408A4A FF15 A0704000 CALL NEAR DWORD PTR [<&KERNEL32.GetPr>; kernel32.GetProcAddress
00408A50 A3 B8894000 MOV DWORD PTR [4089B8], EAX
00408A55 FF15 B0894000 CALL NEAR DWORD PTR [4089B0]
00408A5B 8BD8 MOV EBX, EAX
00408A5D FF15 B0894000 CALL NEAR DWORD PTR [4089B0]
00408A63 8BF0 MOV ESI, EAX
00408A65 68 CF894000 PUSH 004089CF ; ASCII "&About"
00408A6A 68 55050000 PUSH 555 ; 菜单的ID
00408A6F 6A 10 PUSH 10
00408A71 56 PUSH ESI
00408A72 FF15 B4894000 CALL NEAR DWORD PTR [4089B4]
00408A78 68 C8894000 PUSH 004089C8 ; ASCII "&Help"
00408A7D 56 PUSH ESI
00408A7E 6A 10 PUSH 10
00408A80 53 PUSH EBX
00408A81 FF15 B4894000 CALL NEAR DWORD PTR [4089B4]
00408A87 53 PUSH EBX
00408A88 57 PUSH EDI
00408A89 FF15 B8894000 CALL NEAR DWORD PTR [4089B8]
00408A8F 61 POPAD
00408A90 FF75 14 PUSH DWORD PTR [EBP+14]
00408A93 8BF8 MOV EDI, EAX ; 恢复破坏的代码
00408A95 - E9 F387FFFF JMP 0040128D ; 跳回原来空间
处理菜单的事件在消息循环里修改:
004012DB . 8B45 0C MOV EAX, DWORD PTR [EBP+C]
004012DE . 48 DEC EAX
004012DF . 48 DEC EAX
004012E0 . 74 68 JE SHORT 0040134A
004012E2 .- E9 19780000 JMP 00408B00
跳到自己的空间里,判断一下是不是WM_COMMAND消息,
00408B00 2D 0F010000 SUB EAX, 10F
00408B05 74 11 JE SHORT 00408B18
00408B07 05 0C010000 ADD EAX, 10C
00408B0C - 0F84 2288FFFF JE 00401334
00408B12 - E9 D087FFFF JMP 004012E7
00408B17 90 NOP
然后判断一下是不是菜单555触发的,如果是就弹出对话框,
00408B18 817D 10 55050000 CMP DWORD PTR [EBP+10], 555
00408B1F 75 18 JNZ SHORT 00408B39
00408B21 90 NOP
00408B22 68 40200100 PUSH 12040
00408B27 68 C08A4000 PUSH 00408AC0 ; ASCII "pediy"
00408B2C 68 C68A4000 PUSH 00408AC6
00408B31 E8 8ECEFFFF CALL 004059C4
00408B36 83C4 0C ADD ESP, 0C
00408B39 - E9 1488FFFF JMP 00401352
注意的是exe本身就提供了MessageBoxA的调用,可以直接用函数4059C4,参数是:
消息内容: string;
窗口标题: string;
窗口ICON: Integer;
调用完后配平堆栈,返回消息循环处,收工。
这题比上题难多了,要不是有看雪精华、exescope、lordpe、winhex、ue、计算器、delphi、vc、msdn、baidu、google等的大力协助,几乎无法完成。