Windows_HOOKまとめ_完備を待つ.

11454 ワード

DLL作成:
DLL使用:
メッセージフック注入DLL:
フックの取り付け:
HHOOK WINAPI SetWindowsHookEx(
	 	\\1,    
		 __in int idHook, 	
		 \\2,    ,          ,         ;
		__in HOOKPROC lpfn, 	
		 \\3,    dll,  dll             ;    
		__in HINSTANCE hMod, 	
		 \\4,  ID,0      ,0     GUI    
		__in DWORD dwThreadId);  	
//      ,          .      ,    NULL.
//         ,   GetLastError

フックのタイプ:
最初のパラメータはフックのタイプで、フックのタイプは全部で14種類あり、いつフックを呼び出すかを示します.
一般的なフックのタイプは次のとおりです.
(1)キーボードフックとローレベルキーボードフックは,各種キーボードメッセージを監視できる.(2)マウスフックとローレベルマウスフックは,様々なマウスメッセージを監視できる.(3)シェルフックは各種シェルイベントメッセージを監視することができる.たとえば、アプリケーションの起動と停止を行います.(4)ログフックは、システムメッセージキューから取り出された様々なイベントメッセージを記録することができる.(5)ウィンドウ・プロシージャ・フックは、システム・メッセージ・キューからターゲット・ウィンドウに送信されるすべてのメッセージを監視する.
例:
#include "stdafx.h"
#include 
 
int _tmain(int argc, _TCHAR* argv[])
{
	/*
	* Load library in which we'll be hooking our functions.
	*/
	HMODULE dll = LoadLibrary(L"test_dll.dll");
	if(dll == NULL) {
		DWORD err = GetLastError();
		printf("The DLL could not be found.
"); getchar(); return -1; } //__asm int 3; /* * Get the address of the function inside the DLL. */ HOOKPROC addr = (HOOKPROC)GetProcAddress(dll, "meconnect"); if(addr == NULL) { printf("The function was not found.
"); getchar(); return -1; } /* * Hook the function. */ HHOOK handle = SetWindowsHookEx(WH_KEYBOARD, addr, dll, 0); if(handle == NULL) { printf("The KEYBOARD could not be hooked.
"); } /* * Unhook the function. */ printf("Program successfully hooked,
Press enter to unhook the function and stop the program.
"); getchar(); UnhookWindowsHookEx(handle); return 0; }

フックの取り外し:
BOOL WINAPI UnhookWindowsHookEx(
  _In_ HHOOK hhk
);

HOOKプロセス(原理):

いくつかの説明:
1、マウスメッセージなどの同じイベントにスレッドフックとシステムフックがインストールされている場合、システムは自動的にスレッドフックを呼び出し、システムフックを呼び出します.2、同じイベントメッセージに対して複数のフック処理プロセスをインストールすることができ、これらのフック処理プロセスはフックチェーンを形成する.現在のフック処理が終了したら、フック情報を次のフック関数に渡す必要があります.3、特にシステムフックはメッセージ処理時間を消費し、システム性能を低下させる.必要に応じてフックを取り付け、使用後すぐにアンインストールします.4、32ビットDLLは64ビットプロセスに注入できず、64ビットDLLは32ビットプロセスに注入できない.5、CallNextHookEx関数を呼び出して次のフックにリンクするプロセスはオプションですが、強くお勧めします.それ以外の場合、フックがインストールされている他のアプリケーションではフック通知が受信されないため、エラーが発生する可能性があります.CallNextHookExを呼び出すべきです.6、すべてのグローバルフック関数はライブラリにある必要があります.7、ターゲットプロセスBは先に実行しなければならない.フックを取り付けるには、ターゲットプロセスが実行した後にしなければならない.そうしないと、フックは失効する.グローバルフックをインストールすると、現在のシステムのすべてのスレッドにフックが関連付けられます.後で作成されるスレッドはもちろん列にありません.8、AがLoadLibraryでval.dllをロードする場合、両方が同じバージョン、すなわち同じDebug版またはRelease版でなければ、ターゲットファイルが見つからないエラーが発生します.
リモートスレッド注入DLL:
実際には、注入が必要なプロセスを正確に指定したり、GUI以外のプログラムに注入したりする最も広範な注入方法が使用されています.DLL注入とは、実行中の他のプロセスに特定のDLLファイルを強制的に挿入し、特定のコードを実行させることを意味します.DLL注入基本手順:プログラムを実行して他のプロセスにLoadLibrary()APIを呼び出し、ユーザーが指定したDLLファイルを呼び出し、LoadLibrary()が完了した後にDLLファイルのDllMain()関数を呼び出す.DLLがプロセスにロードされると自動的にDllMain()関数が実行され、ユーザは実行したいコードをDllMain()関数に入れることができ、そのDLLがロードされるたびに追加されたコードが実行される.このプロセスによりプログラムバグを修復し,悪意のあるDLLなどを記述することができる.
  • CreateRemoteThread、原型は以下の通り:
  • WINBASEAPI
    _Ret_maybenull_
    HANDLE
    WINAPI
    CreateRemoteThread(
        //           .
        _In_ HANDLE hProcess,
        
        //     SECURITY_ATTRIBUTES      ,             .
        _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
        
        //      ,      ,      0,          .
        _In_ SIZE_T dwStackSize,
        
        //           ,             .
        _In_ LPTHREAD_START_ROUTINE lpStartAddress,
        
        //         .
        _In_opt_ LPVOID lpParameter,
        
               .
        _In_ DWORD dwCreationFlags,
        
        //       ID   ,      ,    NULL.
        _Out_opt_ LPDWORD lpThreadId
        );
    
    	//      ,       
    	//    ,  NULL
    

    最初のパラメータは、新しく作成したスレッドがどのプロセスに所有されるかを指定します.他のパラメータはCreateThreadと同じです.
  • VirtualAllocEx、原型は以下の通り:
  • WINBASEAPI
    _Ret_maybenull_ _Post_writable_byte_size_(dwSize)
    LPVOID
    WINAPI
    VirtualAllocEx(
        //           。
        _In_ HANDLE hProcess,
        
        //         ;   NULL    。
        _In_opt_ LPVOID lpAddress, 
        
        //        ,    ;
        //                     
        _In_ SIZE_T dwSize,
        
        //         ,       
        _In_ DWORD flAllocationType,
        
        //           ,       
        _In_ DWORD flProtect
        );
    

    関数の実行に成功すると、割り当てられたメモリのヘッダアドレスが返されます.成功しない場合はNULLです.リモート注入DLLパス:
    hTargeProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID); // dwProcessID           ID
    if (!hTargeProcess) {
        return;
    }
    
    SIZE_T dllPathSize = strlen(pszDllPath); // pszDllPath   DLL   
    pVM4DllPath = VirtualAllocEx(hTargeProcess, NULL, dllPathSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (!pVM4DllPath) {
        return;
    }
    
    if (!WriteProcessMemory(hTargeProcess, pVM4DllPath, pszDllPath, dllPathSize, NULL)) {
        return;
    }
    
  • WriteProcessMemory、原型は以下の通り:
  • WaitForSingleObject、原型は以下の通り:
  • リモートスレッド注入手順:
    1、VirtualAllocEx関数でリモートプロセス申請スペース.2、DLLのパスをWriteProcessMemory関数で申請したメモリにコピーします.3.GetProcessAddress関数でLoadLibraryW(LoadLibraryA)関数(Kernel 32.dll)の実際のアドレスを得る.4、CreateRenoteThread関数でリモートスレッドにスレッドを作成し、新しいスレッドにLoadLibrary関数を呼び出し、パラメータに最初のステップで割り当てられたメモリアドレスを入力させる.このときDLLはリモートプロセスアドレス空間に注入され、DLL関数DLMainはトリガイベントを受け取り、実行する必要があるコードを実行し、DLMainが戻るとリモートスレッドはLoadLibraryW(LoadLibraryA)呼び出しからBaseThreadStart関数に戻る.BaseThreadStartは、ExitThreadを呼び出し、リモートスレッドを終了させます.5、申請のスペースを整理する必要があり、リモートスレッドはまだ目標プロセスのアドレススペースにある.6、VirtualFreeExで申請のメモリを解放する.7.GetProcessAddressを用いて、Kernel 32.dllにおけるFreeLibrary関数の実際のアドレスを得る.
    注入解除:
    注入をキャンセルすることはDLLをターゲットプロセスからアンインストールすることです.DLLをアンインストールするために使用されるAPIはFreeLibraryであることを知っていますが、この関数を直接呼び出すことはできません.直接呼び出すと、ターゲットプロセスではなく、私たちのプロセスでDLLをアンインストールするので、アンインストールの目的に達しないことは明らかです.DLLをロードするときと同様に、FreeLibraryのアドレスを4番目のパラメータとしてCreateRemoteThread関数に渡す必要がありますが、GetProcAddressによってFreeLibraryの正確なアドレスを得る必要があります.
    PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "FreeLibrary");
    if(pfnThreadRtn) {
        hThread = CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, me.modBaseAddr, 0, NULL);
    }
    

    いくつかの説明:
    1、コード注入の時、必要な変数は自分でメモリコピーの方式で伝えたほうがいいです.例えば、私は直接スレッド関数に変数char[512]=「00000」を開きました.この関数のアドレスを指定のプロセスにコピーしたとき、「00000」が占めた内容はコピーされませんでした.これにより、呼び出し時にメモリがエラーになります.2、コード注入制限は非常に多く、注入されたスレッド関数の中には内容が非常にこだわり、大きさに制限があり、記憶方式に制限があり、API関数を勝手に呼び出すことはできません.例えば、直接中にSleep(1000)が来ました.この関数はシステムだと思います.そこで呼び出すことができますが、メモリエラーではありません.3、注入するプログラムは注入プログラムと注入DLLと同位であることを保証してください.32ビットプログラムを使用して64ビット(または64ビット注入32ビット)を注入しないでください.管理者権限で実行することをお勧めします.