如何在运行时修补 Windows API,使其在 x64 中返回 0?
在 x86 中,我使用 GetProcAddress() 获取函数地址并编写一个简单的 XOR EAX,EAX; RET 4; 在里面。简单有效。如何在 x64 中执行相同操作?
bool DisableSetUnhandledExceptionFilter()
{
const BYTE PatchBytes[5] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 }; // XOR EAX,EAX; RET 4;
// Obtain the address of SetUnhandledExceptionFilter
HMODULE hLib = GetModuleHandle( _T("kernel32.dll") );
if( hLib == NULL )
return false;
BYTE* pTarget = (BYTE*)GetProcAddress( hLib, "SetUnhandledExceptionFilter" );
if( pTarget == 0 )
return false;
// Patch SetUnhandledExceptionFilter
if( !WriteMemory( pTarget, PatchBytes, sizeof(PatchBytes) ) )
return false;
// Ensures out of cache
FlushInstructionCache(GetCurrentProcess(), pTarget, sizeof(PatchBytes));
// Success
return true;
}
static bool WriteMemory( BYTE* pTarget, const BYTE* pSource, DWORD Size )
{
// Check parameters
if( pTarget == 0 )
return false;
if( pSource == 0 )
return false;
if( Size == 0 )
return false;
if( IsBadReadPtr( pSource, Size ) )
return false;
// Modify protection attributes of the target memory page
DWORD OldProtect = 0;
if( !VirtualProtect( pTarget, Size, PAGE_EXECUTE_READWRITE, &OldProtect ) )
return false;
// Write memory
memcpy( pTarget, pSource, Size );
// Restore memory protection attributes of the target memory page
DWORD Temp = 0;
if( !VirtualProtect( pTarget, Size, OldProtect, &Temp ) )
return false;
// Success
return true;
}
此示例改编自此处的代码: http://www.debuginfo.com/articles /debugfilters.html#overwrite 。
In x86, I get the function address using GetProcAddress()
and write a simple XOR EAX,EAX; RET 4;
in it. Simple and effective. How do I do the same in x64?
bool DisableSetUnhandledExceptionFilter()
{
const BYTE PatchBytes[5] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 }; // XOR EAX,EAX; RET 4;
// Obtain the address of SetUnhandledExceptionFilter
HMODULE hLib = GetModuleHandle( _T("kernel32.dll") );
if( hLib == NULL )
return false;
BYTE* pTarget = (BYTE*)GetProcAddress( hLib, "SetUnhandledExceptionFilter" );
if( pTarget == 0 )
return false;
// Patch SetUnhandledExceptionFilter
if( !WriteMemory( pTarget, PatchBytes, sizeof(PatchBytes) ) )
return false;
// Ensures out of cache
FlushInstructionCache(GetCurrentProcess(), pTarget, sizeof(PatchBytes));
// Success
return true;
}
static bool WriteMemory( BYTE* pTarget, const BYTE* pSource, DWORD Size )
{
// Check parameters
if( pTarget == 0 )
return false;
if( pSource == 0 )
return false;
if( Size == 0 )
return false;
if( IsBadReadPtr( pSource, Size ) )
return false;
// Modify protection attributes of the target memory page
DWORD OldProtect = 0;
if( !VirtualProtect( pTarget, Size, PAGE_EXECUTE_READWRITE, &OldProtect ) )
return false;
// Write memory
memcpy( pTarget, pSource, Size );
// Restore memory protection attributes of the target memory page
DWORD Temp = 0;
if( !VirtualProtect( pTarget, Size, OldProtect, &Temp ) )
return false;
// Success
return true;
}
This example is adapted from code found here: http://www.debuginfo.com/articles/debugfilters.html#overwrite .
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在 x64 中,返回值位于 RAX 中,这是 EAX 的 64 位版本。但由于写入 32 位子寄存器时高 32 位被清除,因此“xor eax, eax”相当于“xor rax, rax”,不需要更改。
但是,由于 x64 上的调用约定不同,因此相同的返回指令在 x64 上不起作用:
在 x86 winapi 函数中,使用 stdcall 约定,其中被调用者从堆栈中弹出参数(因此出现了“retn 4”指令,它将 SetUnhandledExceptionFilter 中的一个参数从堆栈中弹出(您可能希望在代码中修复该注释)) 。
在 x64 中,堆栈不会被被调用者清理,因此需要使用普通的“retn”指令:
In x64 the return value is in RAX, which is the 64bit version of EAX. But because the upper 32 bits are cleared when a 32 bit sub-register is written, "xor eax, eax" is equivalent to "xor rax, rax" and doesn't need to be changed.
However, because the calling convention is different on x64, the same return instruction won't work there:
In x86 winapi functions use the stdcall convention, where the callee pops the arguments from the stack (hence the "retn 4" instruction, which pops that one argument from SetUnhandledExceptionFilter off the stack (you may want to fix that comment in your code)).
In x64 the stack is not cleaned by the callee, so a normal "retn" instruction needs to be used:
使用 Microsoft Detours 或 EasyHook,两者都支持这种类型的修补,其中之一至少可以在 x64 上运行。
Use a library like Microsoft Detours or EasyHook, both of which support exactly this kind of patching, and one of which at least works in x64.