在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

最佳答案

在x64中,返回值在RAX中,这是EAX的64位版本。但是,由于在写入32位子寄存器时会清除高32位,因此“xor eax,eax”等效于“xor rax,rax”,无需更改。

但是,由于x64上的调用约定不同,因此相同的返回指令在此处不起作用:
在x86 winapi函数中,使用stdcall约定,在该约定中,被调用者从堆栈中弹出参数(因此,“retn 4”指令将SetUnhandledExceptionFilter中的一个参数从堆栈中弹出(您可能要在代码中修复该注释)) 。
在x64中,被调用者不会清除堆栈,因此需要使用常规的“retn”指令:

const BYTE PatchBytes[3] = { 0x33, 0xC0, 0xC3 }; // XOR EAX,EAX; RET;

关于winapi - 如何在运行时修补Windows API,以使其在x64中返回0?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3010626/

10-11 15:39