可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Unit FastCodePatch.pas works in Win32 platform. Delphi XE2 supports Win64 platform, any ideas how to make FastCodePatch works in Win64 platform?
unit FastcodePatch; interface function FastcodeGetAddress(AStub: Pointer): Pointer; procedure FastcodeAddressPatch(const ASource, ADestination: Pointer); implementation uses Windows; type PJump = ^TJump; TJump = packed record OpCode: Byte; Distance: Pointer; end; function FastcodeGetAddress(AStub: Pointer): Pointer; begin if PBYTE(AStub)^ = $E8 then begin Inc(Integer(AStub)); Result := Pointer(Integer(AStub) + SizeOf(Pointer) + PInteger(AStub)^); end else Result := nil; end; procedure FastcodeAddressPatch(const ASource, ADestination: Pointer); const Size = SizeOf(TJump); var NewJump: PJump; OldProtect: Cardinal; begin if VirtualProtect(ASource, Size, PAGE_EXECUTE_READWRITE, OldProtect) then begin NewJump := PJump(ASource); NewJump.OpCode := $E9; NewJump.Distance := Pointer(Integer(ADestination) - Integer(ASource) - 5); FlushInstructionCache(GetCurrentProcess, ASource, SizeOf(TJump)); VirtualProtect(ASource, Size, OldProtect, @OldProtect); end; end; end.
The solution provided by Ville Krumlinde doesn't work on 64 bits package. It works on Standalone .exe application only.
回答1:
For the FastcodeAddressPatch-function, this version works both in 32-bit and 64-bit when I try. The key is changing "pointer" to "integer" because the Intel relative jump-instruction ($E9) still use an 32-bit offset in 64-bit mode.
type PJump = ^TJump; TJump = packed record OpCode: Byte; Distance: integer; end; procedure FastcodeAddressPatch(const ASource, ADestination: Pointer); const Size = SizeOf(TJump); var NewJump: PJump; OldProtect: Cardinal; begin if VirtualProtect(ASource, Size, PAGE_EXECUTE_READWRITE, OldProtect) then begin NewJump := PJump(ASource); NewJump.OpCode := $E9; NewJump.Distance := NativeInt(ADestination) - NativeInt(ASource) - Size; FlushInstructionCache(GetCurrentProcess, ASource, SizeOf(TJump)); VirtualProtect(ASource, Size, OldProtect, @OldProtect); end; end; procedure Test; begin MessageBox(0,'Original','',0); end; procedure NewTest; begin MessageBox(0,'Patched','',0); end; procedure TForm5.FormCreate(Sender: TObject); begin FastcodeAddressPatch(@Test,@NewTest); Test; end;
I'm not sure what the other function does but I'm guessing it should be like this:
function FastcodeGetAddress(AStub: Pointer): Pointer; begin if PBYTE(AStub)^ = $E8 then begin Inc(NativeInt(AStub)); Result := Pointer(NativeInt(AStub) + SizeOf(integer) + PInteger(AStub)^); end else Result := nil; end;
回答2:
The following code works for both Win32 - Standalone and Package, Win64 - Standalone and Package:
type TNativeUInt = {$if CompilerVersion < 23}Cardinal{$else}NativeUInt{$ifend}; PJump = ^TJump; TJump = packed record OpCode: Byte; Distance: integer; end; function GetActualAddr(Proc: Pointer): Pointer; type PAbsoluteIndirectJmp = ^TAbsoluteIndirectJmp; TAbsoluteIndirectJmp = packed record OpCode: Word; //$FF25(Jmp, FF /4) Addr: Cardinal; end; var J: PAbsoluteIndirectJmp; begin J := PAbsoluteIndirectJmp(Proc); if (J.OpCode = $25FF) then {$ifdef Win32}Result := PPointer(J.Addr)^{$endif} {$ifdef Win64}Result := PPointer(TNativeUInt(Proc) + J.Addr + 6{Instruction Size})^{$endif} else Result := Proc; end; procedure FastcodeAddressPatch(const ASource, ADestination: Pointer); const Size = SizeOf(TJump); var NewJump: PJump; OldProtect: Cardinal; P: Pointer; begin P := GetActualAddr(ASource); if VirtualProtect(P, Size, PAGE_EXECUTE_READWRITE, OldProtect) then begin NewJump := PJump(P); NewJump.OpCode := $E9; NewJump.Distance := TNativeUInt(ADestination) - TNativeUInt(P) - Size; FlushInstructionCache(GetCurrentProcess, P, SizeOf(TJump)); VirtualProtect(P, Size, OldProtect, @OldProtect); end; end;