调试程序调试到系统库函数的代码时,总会发现系统函数都是从一条MOV EDI, EDI指令开始的,紧接着这条指令下面才是标准的建立函数局部栈的代码。对系统DLL比如ntdll.dll进行反汇编,可以发现它的每个导出函数都是如此,并且每个导出函数开始处的MOV EDI, EDI上面紧接着5条NOP指令。比如在WinDbg中查看TextOutA周围的代码:
0:000> u TextOutA-0x0a L 10
GDI32!NtGdiTransparentBlt+0xa:
77efc43f ff12 call dword ptr [edx]
77efc441 c22c00 ret 2Ch
77efc444 90 nop
77efc445 90 nop
77efc446 90 nop
77efc447 90 nop
77efc448 90 nop
GDI32!TextOutA:
77efc449 8bff mov edi,edi
77efc44b 55 push ebp
77efc44c 8bec mov ebp,esp
很明显,两个字节的MOV EDI,EDI指令什么事情也不做,那么,就有两个问题:第一,为什么不直接从函数体开始而要从这条什么都不做的指令开始呢?第二,即使需要在函数一开始空出两个字节,为什么不直接使用两条NOP指令,而要使用这条M
0:000> u TextOutA-0x0a L 10
GDI32!NtGdiTransparentBlt+0xa:
77efc43f ff12 call dword ptr [edx]
77efc441 c22c00 ret 2Ch
77efc444 90 nop
77efc445 90 nop
77efc446 90 nop
77efc447 90 nop
77efc448 90 nop
GDI32!TextOutA:
77efc449 8bff mov edi,edi
77efc44b 55 push ebp
77efc44c 8bec mov ebp,esp
很明显,两个字节的MOV EDI,EDI指令什么事情也不做,那么,就有两个问题:第一,为什么不直接从函数体开始而要从这条什么都不做的指令开始呢?第二,即使需要在函数一开始空出两个字节,为什么不直接使用两条NOP指令,而要使用这条M