简答:bu $exentry; g
长答案:
一个进程在ntdll 中找到的操作系统代码中开始其用户模式执行,该代码执行各种初始化并最终调用存储在 PE 标头中的入口点。
WinDbg 在所谓的初始断点(或 WinDbg 用语中的 ibp)处中断。 OllyDbg 在此断点后继续运行,并在 PE 入口点设置断点。这很好,除非它搞砸了你。例如,针对 olly 的一个众所周知的反调试技巧是使用自定义 TLS 回调创建二进制文件,这是一个相当深奥的功能。这些回调在 PE 入口点之前被调用,因此 olly 无法检测到。
您确实要做的是在PE入口点上设置一个断点。
困难的方法是像 blabb 那样做 - 使用!dh 转储模块头并在其中记录的地址上设置断点。即使是困难的方法也可以更容易一些,因为在运行!dh 之前不需要lm。在 WinDbg 中,模块名称在其基地址处解释。例如:
0:000> !dh -f notepad
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (i386)
5 number of sections
55BEBE90 time date stamp Sun Aug 02 18:06:24 2015
...
OPTIONAL HEADER VALUES
10B magic #
12.10 linker version
15400 size of code
1F000 size of initialized data
0 size of uninitialized data
159F0 address of entry point
1000 base of code
然后这只是一个问题:
0:000> bu notepad+159F0
0:000> bl
0 e 002259f0 0001 (0001) 0:**** notepad!WinMainCRTStartup
但简单的方法是使用 WinDbg 的内置 pseudo-registers 之一(“自动伪寄存器”是他们的术语,与用户定义的伪寄存器),即上述$exentry。
0:000> ? notepad + 159F0 == $exentry
Evaluate expression: 1 = 00000001
0:000> ? $exentry
Evaluate expression: 2251248 = 002259f0
您可以看到002259f0与我们手动计算的地址相同。
为了完整起见,我注意到$iment(address) 运算符提供了任何模块的入口点,而不仅仅是主模块(EXE):
0:000> ? $iment(winspool)
Evaluate expression: 1889096272 = 70995250
0:000> ln $iment(winspool)
Browse module
Set bu breakpoint
(70995250) WINSPOOL!_DllMainCRTStartup | (7099526b) WINSPOOL!__CppXcptFilter
Exact matches:
WINSPOOL!_DllMainCRTStartup (<no parameter info>)