2012-01-23 9 views
17

में पैच रूटीन कॉल मैं कुछ संशोधनों के साथ स्वयं को संभालने में सक्षम होने के लिए एक नियमित कॉल पैच करना चाहता हूं। मैं संसाधन लोडर लिख रहा हूं। मैं डेल्फी के लोडरसोर्स मॉड्यूल और इनिट इनहेरिट कॉम्पोनेंट दिनचर्या को मेरे साथ पैच करना चाहता हूं। मैंने MadExcept.pas इकाई में पैचएपीआई कॉल की जांच की है, लेकिन अगर मैं इसे अपने प्रोजेक्ट के लिए उपयोग कर सकता हूं तो इसे समझ नहीं सका। करने के लिए> कूद - -> LoadResourceModule -डेल्फी

मैं क्रम कॉल पर की तरह

मेरी exe कुछ चाहते हैं> MyCustomResourceModule ...

इस पर कोई संकेत बहुत मददगार होगा।

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; 

आप RedirectProcedure फोन करके अपने हुक/पैच/चक्कर लगा देंगी::

RedirectProcedure(@LoadResourceModule, @MyLoadResourceModule); 

यह 32 बिट कोड के लिए काम करेंगे

+3

यह 'कहा जाता है इस सवाल जाँच detour' [एक बाह्य घोषित समारोह के कार्यान्वयन (चक्कर) बदलने के लिए] (http://stackoverflow.com/questions/6905287/ कैसे-टू-चेंज-द-कार्यान्वयन-एक-बाहरी रूप से घोषित-फ़ंक्शन) – RRUZ

+0

मैं बस उसी के बारे में सोच रहा था - इसलिए इस तकनीक का उपयोग करने से घटक स्ट्रीमिंग में कोड जोड़ने की अनुमति होगी (डीएफएम से आवेदन करने के लिए) तंत्र? तो, उदाहरण के लिए, मेरे पास प्रयुक्त घटक वर्गों को लॉग करने के लिए एक केंद्रीय स्थान हो सकता है, या कुछ गुणवत्ता आश्वासन ('बीडीई कक्षाओं का उपयोग न करें! या घटक एक्स का पुराना संस्करण!')? – mjn

+2

@mjn अन्य एक्सटेंशन पॉइंट हैं जो इसे अधिक आसानी से करने की अनुमति देते हैं। उदाहरण के लिए 'TReader.OnFindComponentClass'। पैचिंग कोड हमेशा एक अंतिम उपाय होना चाहिए जब कुछ और काम नहीं मिल सकता है। –

उत्तर

16

मैं निम्नलिखित कोड का उपयोग करें। यह 64 बिट कोड के लिए भी काम करेगा बशर्ते पुराने और नए फ़ंक्शन दोनों एक ही निष्पादन योग्य मॉड्यूल में रहते हों। अन्यथा कूद दूरी 32 बिट पूर्णांक की सीमा से अधिक हो सकती है।

मुझे बहुत दिलचस्पी होगी यदि कोई व्यक्ति वैकल्पिक विकल्प प्रदान कर सकता है जो कि 64 बिट एड्रेस स्पेस के लिए काम करता है चाहे दो पते कितने दूर थे।

+6

या तो * अनपैच * रीडायरेक्शन या यह सुनिश्चित करना अच्छा होगा कि एप्लिकेशन बंद होने पर कोई कोड ब्रेक नहीं होगा - रीडायरेक्ट कॉल किया जा सकता है (उदाहरण के लिए आरटीएल या रीडायरेक्शन यूनिट से पहले लोड की गई दूसरी इकाई), और कूदें कुछ अनियमित कोड के लिए। –

+0

@ अर्नुड यह सच हो सकता है। इस के मेरे सभी उपयोग में मैं किसी भी कॉल किए जाने से पहले रीडायरेक्ट करता हूं, या यह कोई साइड इफेक्ट्स वाला दिनचर्या नहीं है और इसलिए अवांछित कोई फर्क नहीं पड़ता –

+0

@ डेविड हेफरन बस एक विचार के लिए, अगर मैं डिफ़ॉल्ट प्राप्त करना चाहता हूं तो मैं पुरानी प्रक्रिया को कैसे कॉल कर सकता हूं मूल्य और फिर उस मूल्य पर काम करते हैं। चूंकि उपरोक्त कोड में, हम नई प्रक्रिया में कूदने के लिए पुराने दिनचर्या के पते को ओवरराइट करते हैं। MyLoadResourceModule जैसे कुछ आंतरिक रूप से LoadResourceModule का उपयोग करते हैं और कुछ अतिरिक्त करते हैं .... –

7

इसके लिए पहले से ही Delphi detours library है।

डेल्फी मार्ग-परिवर्तन लाइब्रेरी में एक पुस्तकालय आप हुक करने डेल्फी और खिड़कियों एपीआई कार्यों यह डालने के लिए एक आसान तरीका और निकालने हुक प्रदान करता है अनुमति देता है।

विशेषताएं:

  • समर्थन x86 और x64 आर्किटेक्चर।
  • ट्रैम्पोलिन फ़ंक्शन के माध्यम से मूल फ़ंक्शन को कॉल करने की अनुमति दें।
  • मल्टी हुक के लिए समर्थन।
  • COM/इंटरफेस/win32api समर्थन।
  • समर्थन COM vtable पैचिंग।
  • पूरी तरह से थ्रेड-सुरक्षित कोड हुकिंग और अनहूकिंग।
  • समर्थन हुकिंग ऑब्जेक्ट विधि।
  • समर्थित डेल्फी 7/2005-2010/एक्सई-एक्सई 7।
  • लाजर/एफपीसी का समर्थन करें।
  • 64 बिट पता समर्थित है।
  • लाइब्रेरी किसी बाहरी पुस्तकालय का उपयोग नहीं करती है।
  • लाइब्रेरी किसी भी समय हुक डालने और निकालने में सक्षम हो सकती है।
  • लाइब्रेरी में InstDecode लाइब्रेरी है, जो आपको एएसएम निर्देशों को डीकोड करने की अनुमति देती है (x86 x64)।
3

मैं 64-बिट समर्थन और एक बीपीएल में तरीकों को अप्रत्यक्ष कूद के लिए डेविड हेफेरनान के कोड को संशोधित किया। से कुछ मदद के साथ: 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;