2017-07-11 8 views
0

私は、WinAPIフック関数でデータをバイパス/実行するためにフラムとトランポリンの概念を学びました(別の実行可能ファイルで、DLL注入)。これまでのところ、私はアセンブリとCの混合物を使ってトランポリンとフックを作る方法を知っていますが、私は何かが欠けているように、Cを使うだけではできないようです。誰かが私が間違ってやっていることやそれをどうやって解決するか教えてもらえればと思っています。WinAPIフックのためのフックとトランポリンの機能の作り方

は今の私のコード:

#include <Windows.h> 

unsigned char* address = 0; 

__declspec(naked) int __stdcall MessageBoxAHookTrampoline(HWND Window, char* Message, char* Title, int Type) { 
    __asm 
    { 
     push ebp 
     mov ebp, esp 
     mov eax, address 
     add eax, 5 
     jmp eax 
    } 
} 

int __stdcall MessageBoxAHook(HWND Window, char* Message, char* Title, int Type) { 
    wchar_t* WMessage = L"Hooked!"; 
    wchar_t* WTitle = L"Success!"; 
    MessageBoxW(0, WMessage, WTitle, 0); 
    return MessageBoxAHookTrampoline(Window, Message, Title, Type); 
} 

unsigned long __stdcall Thread(void* Context) { 
    address = (unsigned char*)GetProcAddress(LoadLibraryA("user32"), "MessageBoxA"); 
    ULONG OP = 0; 
    if (VirtualProtect(address, 1, PAGE_EXECUTE_READWRITE, &OP)) { 
     memset(address, 0x90, 5); 
     *address = 0xE9; 
     *(unsigned long*)(address + 1) = (unsigned long)MessageBoxAHook - (unsigned long)address - 5; 
    } 
    else { 
     MessageBoxA(0, "Failed to change protection", "RIP", 0); 
    } 
    return 1; 
} 

// Entry point. 
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) { 
    if (fdwReason == DLL_PROCESS_ATTACH) { 
     CreateThread(0, 0, Thread, 0, 0, 0); 
    } 
    else if (fdwReason == DLL_PROCESS_DETACH) { 

    } 
    return true; 
} 

そこで質問です:どのように私は、関数がフックをインストールし、私は簡単にそれを使用することができるようにトランポリンを返しますInstallHookを言う作るでしょうか? 関数のプロトタイプはおそらく:void* InstallHook(void* originalFunc, void* targetFunc, int jumpsize)なので、私はオンラインで読むことを理解しましたが、何がjumpsizeに使用されるのか分かりません。

これまでのところ、最初の5バイトを保存して復元する必要があり、元のフック機能のアドレスにジャンプする必要があることがわかりました。だから私はメモリを割り当てるためにmallocを使う必要があります。memcpyはバイトをコピーします。0xE9はジャンプ命令などの値ですが、純粋なCを使って実装する方法は分かりません。I figure it would be something similar to the code in this question.私はWinAPI関数のための純粋なCを使用してトランポリンを返すフック関数を書いていますか?

+1

フックとトランポリンが単独で純粋なCで書かれたことができない、いくつかの低レベルのアセンブリが必要とされ、コールスタックを直接操作する必要があるため。あなたはそれを避けることはできません。あなたのためのこの種のものを処理する利用可能なライブラリをフックしてたくさんあります。なぜそれらの1つを使用しないのですか? –

+0

@RemyLebeau私はあなたがmemcpyとmemsetを使ってそれを行うことができるという印象を受けましたか?私が話したプログラマーの少なくとも一人がそれを暗示していました。 – Annabelle

+1

確かに、実行時にメモリのブロックを割り付け、生のアセンブリ命令をそのブロックにmemcpyすると、しかし、それはフックとトランスフリンが実行時にアセンブリ命令を使用しているという事実を変えず、純粋なC言語で書かれていません。 –

答えて

1

私が質問を正しく理解していれば、アセンブリーでトランポリン機能を「ハードコーディング」しないようにしたいと思います。おそらく、コードを複製せずに複数のトランポリンを同時に使用できます。 VirtualAllocを使用してこれを達成することができます(返されたメモリは実行できないため、mallocは機能しません)。

これはコンパイラにアクセスしないでメモリから書きましたので、マイナーなバグがあるかもしれませんが、一般的な考え方はここにあります。ちょうどその考え

void *CreateTrampoline(void *originalFunc) 
{ 
    /* Allocate the trampoline function */ 
    uint8_t *trampoline = VirtualAlloc(
     NULL, 
     5 + 5, /* 5 for the prologue, 5 for the JMP */ 
     MEM_COMMIT | MEM_RESERVE, 
     PAGE_EXECUTE_READWRITE); /* Make trampoline executable */ 

    /* Copy the original function's prologue */ 
    memcpy(trampoline, originalFunc, 5); 

    /* JMP rel/32 opcode */ 
    trampoline[5] = 0xE9; 

    /* JMP rel/32 operand */ 
    uint32_t jmpDest = (uint32_t)originalFunc + 5; /* Skip original prologue */ 
    uint32_t jmpSrc = (uint32_t)trampoline + 10; /* Starting after the JMP */ 
    uint32_t delta = jmpDest - jmpSrc; 
    memcpy(trampoline + 6, &delta, 4); 

    return trampoline; 
} 

あなたInstallHook機能:通常、あなたはまた、あなたがそれを修正完了したらr-x代わりのrwxにページのアクセス権を変更するVirtualProtectを使用しますが、私は簡単のためにそのを残してきましたCreateTrampolineを呼び出してトランポリンを作成し、元の機能の最初の5バイトをJMP rel/32にパッチしてください。

これはWinAPI関数でのみ有効です。マイクロソフトではホットパッチを有効にするために5バイトのプロローグが必要であるためです(ここで行っていることです)。通常の関数ではこの要件はありません。通常は、3バイトだけので始まります(コンパイラが最適化を決定した場合でもそうでないこともあります)。

編集:ここでは数学がどのように動作するかです:

      _______________delta______________ 
         |         | 
trampoline    |     originalFunc | 
    |     |      |   | 
    v     |      v   v 
    [prologue][jmp delta]       [prologue][rest of func] 
    |________||_________|       |________| 
     5 + 5         5 
+0

これをテストします。ありがとうございました。 – Annabelle

+0

'uint32_t jmpDest =(uint32_t)originalFunc + 5;という行を説明してください。/*元のプロローグをスキップする*/ uint32_t jmpSrc =(uint32_t)trampoline + 10;/* JMPの後で始める*/'トランポリンから+10をどうやって得たのかよくわからないのですか? – Annabelle

+0

@Annabelle JMP命令の置き換えは、命令が実行された後の[EIP' *]に相対的です([こちらを参照](https://c9x.me/x86/html/file_module_x86_id_147.html)を参照)。 '+ 10 'は、トランポリン関数の開始からJMP命令の終わりまでのバイト単位の距離です。 (または単にトランポリンの総サイズ、「5 + 5」と考えることができます) –

関連する問題