2012-01-23 10 views
17

Chcę załączyć rutynowe wywołanie, aby samemu sobie z nim poradzić, z pewnymi modyfikacjami. Piszę moduł ładujący zasoby. Chcę połączyć procedury LoadResourceModule i InitInheritedComponent Delphi z tymi z mojej. Sprawdziłem połączenie PatchAPI w jednostce MadExcept.pas, ale nie mogłem go rozgryźć, jeśli mogę użyć tego dla mojego projektu.Rutynowe wywołanie poprawki w delphi

chcę coś takiego

mojego exe na połączeniach wykonywania -> LoadResourceModule -> skokiem -> MyCustomResourceModule ...

Wszelkie wskazówki na ten temat byłoby bardzo pomocne.

+3

To się nazywa 'detour' sprawdzić to pytanie [Jak zmienić realizacji (objazdu) zewnętrznie zadeklarowanej funkcji] (http://stackoverflow.com/questions/6905287/ jak-zmienić-implementację-objazdu-z-zewnętrznie-zadeklarowanej-funkcji) – RRUZ

+0

Po prostu myślałem o tym samym dzisiaj - więc użycie tej techniki pozwoliłoby np. na dodanie kodu w strumieniu komponentu (z DFM do zastosowania) mechanizmu? Tak więc, na przykład, mogę mieć centralne miejsce do rejestrowania używanych klas komponentów lub do zapewnienia jakości ("nie stosuj klas BDE!" Lub starej wersji komponentu X!)? – mjn

+2

@mjn Istnieją inne punkty rozszerzenia, które umożliwiają łatwiejsze wykonanie. Na przykład 'TReader.OnFindComponentClass'. Kod paskowy powinien być zawsze ostatecznością, kiedy nic innego nie może wykonać zadania. –

Odpowiedz

16

używam następujący kod:

procedure PatchCode(Address: Pointer; const NewCode; Size: Integer); 
var 
    OldProtect: DWORD; 
begin 
    if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then 
    begin 
    Move(NewCode, Address^, Size); 
    FlushInstructionCache(GetCurrentProcess, Address, Size); 
    VirtualProtect(Address, Size, OldProtect, @OldProtect); 
    end; 
end; 

type 
    PInstruction = ^TInstruction; 
    TInstruction = packed record 
    Opcode: Byte; 
    Offset: Integer; 
    end; 

procedure RedirectProcedure(OldAddress, NewAddress: Pointer); 
var 
    NewCode: TInstruction; 
begin 
    NewCode.Opcode := $E9;//jump relative 
    NewCode.Offset := NativeInt(NewAddress)-NativeInt(OldAddress)-SizeOf(NewCode); 
    PatchCode(OldAddress, NewCode, SizeOf(NewCode)); 
end; 

by wdrożyć swój hak/patch/objazd przez wywołanie RedirectProcedure:

RedirectProcedure(@LoadResourceModule, @MyLoadResourceModule); 

to będzie pracować dla 32 bitowego kodu. Będzie również działać pod kodem 64-bitowym, pod warunkiem, że zarówno stare, jak i nowe funkcje znajdują się w tym samym module wykonywalnym. W przeciwnym razie odległość skoku może przekraczać zakres 32-bitowej liczby całkowitej.

Byłbym bardzo zainteresowany, gdyby ktoś mógł zapewnić alternatywę, która działałaby na 64-bitową przestrzeń adresową, niezależnie od tego, jak daleko od siebie znajdowały się te dwa adresy.

+6

Dobrym pomysłem może być albo * przeniesienie * przekierowania albo upewnienie się, że przy zamykaniu aplikacji nie nastąpi przerwa w kodzie - przekierowane połączenie może zostać wykonane (np. Przez RTL lub inną jednostkę załadowaną przed jednostką przekierowania) i przeskoczyć do niezainicjowanego kodu. –

+0

@Arnaud To może być prawda. W całym moim korzystaniu z tego przekierowuję przed wywołaniem jakichkolwiek wywołań lub jest to rutyna bez efektów ubocznych, a więc niepodzielenie nie ma znaczenia –

+0

@DavidHeffernan Tylko na samą myśl, jak mogę wywołać starą procedurę, jeśli chcę uzyskać domyślne wartości, a następnie pracować nad tą wartością. Ponieważ w powyższym kodzie, nadpisujemy adres starej procedury, aby przejść do nowej procedury. Coś takiego jak MyLoadResourceModule wewnętrznie używa LoadResourceModule i zrobić coś ekstra .... –

7

Do tego jest już Delphi detours library.

Delphi Detours Biblioteka jest biblioteka pozwala na podłączenie funkcje Delphi i Windows API .To pozwala w łatwy sposób wstawić i usuń haczyk.

Cechy:

  • Pomoc x86 i x64 architektury.
  • Umożliwia wywoływanie oryginalnej funkcji za pomocą funkcji Trampolina.
  • Obsługa Multi Hook.
  • Obsługa COM/Interfaces/win32api.
  • Obsługa poprawek COM vtable.
  • Całkowicie wątkowy i bezpieczny sposób zaczepiania i odczepiania kodu.
  • Sposób podpinania obiektu Metoda obiektu.
  • Obsługiwany Delphi 7/2005-2010/XE-XE7.
  • Obsługa Lazarus/FPC.
  • Adres 64-bitowy jest obsługiwany.
  • Biblioteka nie korzysta z żadnej biblioteki zewnętrznej.
  • Biblioteka może w dowolnym momencie wstawić i usunąć hak.
  • Biblioteka zawiera bibliotekę InstDecode, która umożliwia dekodowanie instrukcji asm (x86 & x64).
3

I zmodyfikowany kod Davida Heffernan dla 64-bitowego i pośredniego Skocz do metod w BPL. Z pomocą: http://chee-yang.blogspot.com.tr/2008/11/hack-into-delphi-class.html

type 
    PAbsoluteIndirectJmp = ^TAbsoluteIndirectJmp; 
    TAbsoluteIndirectJmp = packed record 
    OpCode: Word; // $FF25(Jmp, FF /4) 
    Addr: DWORD; // 32-bit address 
        // in 32-bit mode: it is a direct jmp address to target method 
        // in 64-bit mode: it is a relative pointer to a 64-bit address used to jmp to target method 
    end; 

    PInstruction = ^TInstruction; 
    TInstruction = packed record 
    Opcode: Byte; 
    Offset: Integer; 
    end; 


function GetActualAddr(Proc: Pointer): Pointer; 
begin 
    Result := Proc; 
    if Result <> nil then 
    if PAbsoluteIndirectJmp(Result)^.OpCode = $25FF then // we need to understand if it is proc entry or a jmp following an address 
{$ifdef CPUX64} 
     Result := PPointer(NativeInt(Result) + PAbsoluteIndirectJmp(Result)^.Addr + SizeOf(TAbsoluteIndirectJmp))^; 
     // in 64-bit mode target address is a 64-bit address (jmp qword ptr [32-bit relative address] FF 25 XX XX XX XX) 
     // The address is in a loaction pointed by (Addr + Current EIP = XX XX XX XX + EIP) 
     // We also need to add (instruction + operand) size (SizeOf(TAbsoluteIndirectJmp)) to calculate relative address 
     // XX XX XX XX + Current EIP + SizeOf(TAbsoluteIndirectJmp) 
{$else} 
     Result := PPointer(PAbsoluteIndirectJmp(Result)^.Addr)^; 
     // in 32-bit it is a direct address to method 
{$endif} 
end; 

procedure PatchCode(Address: Pointer; const NewCode; Size: Integer); 
var 
    OldProtect: DWORD; 
begin 
    if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then //FM: remove the write protect on Code Segment 
    begin 
    Move(NewCode, Address^, Size); 
    FlushInstructionCache(GetCurrentProcess, Address, Size); 
    VirtualProtect(Address, Size, OldProtect, @OldProtect); // restore write protection 
    end; 
end; 

procedure RedirectProcedure(OldAddress, NewAddress: Pointer); 
var 
    NewCode: TInstruction; 
begin 
    OldAddress := GetActualAddr(OldAddress); 

    NewCode.Opcode := $E9;//jump relative 
    NewCode.Offset := NativeInt(NewAddress) - NativeInt(OldAddress) - SizeOf(NewCode); 

    PatchCode(OldAddress, NewCode, SizeOf(NewCode)); 
end; 
Powiązane problemy