1. 程式人生 > >Windows平臺Ring3下DLL注入(HOOK)方法整理彙總

Windows平臺Ring3下DLL注入(HOOK)方法整理彙總

1.dll劫持,粗略整理了下,可以劫持的dll有(持續更新):

lpk.dll、usp10.dll、msimg32.dll、midimap.dll、ksuser.dll、comres.dll、ddraw.dll

以lpk為例,在win7下由於lpk被加入KnownDLLs且該登錄檔值不可修改,使得lpk強制從系統目錄載入,

不過可以將lpk.dll加入ExcludeFromKnownDlls來解決,具體可以建立一個lpk.reg檔案:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager]
"ExcludeFromKnownDlls"=hex(7):6c,00,70,00,6b,00,2e,00,64,00,6c,00,6c,00,00,00,\
00,00

成功匯入後需要重新啟動電腦才能生效。

另外win7下的lpk在編寫方面需要注意:

WIN7有的程式呼叫LPK.DLL的LpkInitialize輸出函式在LPK的初始化前面.
要在LpkInitialize這個函式中加入一些處理,並且這部分程式碼不能加密.

因此為了相容各個系統,可以在DllMain和LpkInitialize裡均做判斷,如果沒有初始化就進行初始化。下面貼出完整程式碼:

複製程式碼
// lpk.cpp : Defines the entry point for the DLL application.
//

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 標頭檔案#include "stdafx.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 匯出函式#pragma
comment(linker, "/EXPORT:LpkInitialize=_AheadLib_LpkInitialize,@1") #pragma comment(linker, "/EXPORT:LpkTabbedTextOut=_AheadLib_LpkTabbedTextOut,@2") #pragma comment(linker, "/EXPORT:LpkDllInitialize=_AheadLib_LpkDllInitialize,@3") #pragma comment(linker, "/EXPORT:LpkDrawTextEx=_AheadLib_LpkDrawTextEx,@4") //
#pragma comment(linker, "/EXPORT:LpkEditControl=_AheadLib_LpkEditControl,@5")#pragma comment(linker, "/EXPORT:LpkExtTextOut=_AheadLib_LpkExtTextOut,@6") #pragma comment(linker, "/EXPORT:LpkGetCharacterPlacement=_AheadLib_LpkGetCharacterPlacement,@7") #pragma comment(linker, "/EXPORT:LpkGetTextExtentExPoint=_AheadLib_LpkGetTextExtentExPoint,@8") #pragma comment(linker, "/EXPORT:LpkPSMTextOut=_AheadLib_LpkPSMTextOut,@9") #pragma comment(linker, "/EXPORT:LpkUseGDIWidthCache=_AheadLib_LpkUseGDIWidthCache,@10") #pragma comment(linker, "/EXPORT:ftsWordBreak=_AheadLib_ftsWordBreak,@11") //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 巨集定義#define EXTERNC extern "C" #define NAKED __declspec(naked) #define EXPORT __declspec(dllexport) #define ALCPP EXPORT NAKED #define ALSTD EXTERNC EXPORT NAKED void __stdcall #define ALCFAST EXTERNC EXPORT NAKED void __fastcall #define ALCDECL EXTERNC NAKED void __cdecl //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //LpkEditControl匯出的是陣列,不是單一的函式(by Backer)EXTERNC void __cdecl AheadLib_LpkEditControl(void); EXTERNC __declspec(dllexport) void (*LpkEditControl[14])() = {AheadLib_LpkEditControl}; //////////////////////////////////////////////////////////////////////////////////////////////////新增全域性變數BOOL g_bInited = FALSE; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // AheadLib 名稱空間namespace AheadLib { HMODULE m_hModule = NULL; // 原始模組控制代碼 // 載入原始模組 BOOL WINAPI Load() { TCHAR tzPath[MAX_PATH]; TCHAR tzTemp[MAX_PATH * 2]; GetSystemDirectory(tzPath, MAX_PATH); lstrcat(tzPath, TEXT("\\lpk.dll")); OutputDebugString(tzPath); m_hModule=LoadLibrary(tzPath); if (m_hModule == NULL) { wsprintf(tzTemp, TEXT("無法載入 %s,程式無法正常執行。"), tzPath); MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP); }; return (m_hModule != NULL); } // 釋放原始模組 VOID WINAPI Free() { if (m_hModule) { FreeLibrary(m_hModule); } } // 獲取原始函式地址 FARPROC WINAPI GetAddress(PCSTR pszProcName) { FARPROC fpAddress; CHAR szProcName[16]; TCHAR tzTemp[MAX_PATH]; fpAddress = GetProcAddress(m_hModule, pszProcName); if (fpAddress == NULL) { if (HIWORD(pszProcName) == 0) { wsprintf(szProcName, "%d", pszProcName); pszProcName = szProcName; } wsprintf(tzTemp, TEXT("無法找到函式 %hs,程式無法正常執行。"), pszProcName); MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP); ExitProcess(-2); } return fpAddress; } } using namespace AheadLib; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////函式宣告void WINAPIV Init(LPVOID pParam); //////////////////////////////////////////////////////////////////////////////////////////////// void WINAPIV Init(LPVOID pParam) { //在這裡新增DLL載入程式碼 return; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 入口函式BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved) { if (dwReason == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(hModule); if ( g_bInited==FALSE ){ Load(); g_bInited = TRUE; } //LpkEditControl這個陣列有14個成員,必須將其複製過來 memcpy((LPVOID)(LpkEditControl+1), (LPVOID)((int*)GetAddress("LpkEditControl") + 1),52); _beginthread(Init,NULL,NULL); } else if (dwReason == DLL_PROCESS_DETACH) { Free(); } return TRUE; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 匯出函式ALCDECL AheadLib_LpkInitialize(void) { if ( g_bInited==FALSE ){ Load(); g_bInited = TRUE; } GetAddress("LpkInitialize"); __asm JMP EAX; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 匯出函式ALCDECL AheadLib_LpkTabbedTextOut(void) { GetAddress("LpkTabbedTextOut"); __asm JMP EAX; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 匯出函式ALCDECL AheadLib_LpkDllInitialize(void) { GetAddress("LpkDllInitialize"); __asm JMP EAX; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 匯出函式ALCDECL AheadLib_LpkDrawTextEx(void) { GetAddress("LpkDrawTextEx"); __asm JMP EAX; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 匯出函式ALCDECL AheadLib_LpkEditControl(void) { GetAddress("LpkEditControl"); __asm jmp DWORD ptr [EAX];//這裡的LpkEditControl是陣列,eax存的是函式指標} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 匯出函式ALCDECL AheadLib_LpkExtTextOut(void) { GetAddress("LpkExtTextOut"); __asm JMP EAX; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 匯出函式ALCDECL AheadLib_LpkGetCharacterPlacement(void) { GetAddress("LpkGetCharacterPlacement"); __asm JMP EAX; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 匯出函式ALCDECL AheadLib_LpkGetTextExtentExPoint(void) { GetAddress("LpkGetTextExtentExPoint"); __asm JMP EAX; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 匯出函式ALCDECL AheadLib_LpkPSMTextOut(void) { GetAddress("LpkPSMTextOut"); __asm JMP EAX; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 匯出函式ALCDECL AheadLib_LpkUseGDIWidthCache(void) { GetAddress("LpkUseGDIWidthCache"); __asm JMP EAX; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 匯出函式ALCDECL AheadLib_ftsWordBreak(void) { GetAddress("ftsWordBreak"); __asm JMP EAX; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
複製程式碼

2.通過CreateRemoteThread建立遠端執行緒。

XP以下使用程式碼:

複製程式碼
BOOL WINAPI RemoteLoadLibrary(LPCTSTR pszDllName, DWORD dwProcessId)
{
    // 開啟目標程序    HANDLE hProcess = ::OpenProcess(
        PROCESS_VM_WRITE|PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION, FALSE, dwProcessId);
    if(hProcess == NULL)
        return FALSE;


    // 在目標程序申請空間,存放字串pszDllName,作為遠端執行緒的引數    int cbSize = (::lstrlen(pszDllName) + 1);
    LPVOID lpRemoteDllName = ::VirtualAllocEx(hProcess, NULL, cbSize, MEM_COMMIT, PAGE_READWRITE);
    ::WriteProcessMemory(hProcess, lpRemoteDllName, pszDllName, cbSize, NULL);

    // 取得LoadLibraryA函式的地址,我們將以它作為遠端執行緒函式啟動    HMODULE hModule=::GetModuleHandle (_T("kernel32.dll"));
    LPTHREAD_START_ROUTINE pfnStartRoutine = 
        (LPTHREAD_START_ROUTINE)::GetProcAddress(hModule, "LoadLibraryA");


    // 啟動遠端執行緒    HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, lpRemoteDllName, 0, NULL);
    if(hRemoteThread == NULL)
    {
        ::CloseHandle(hProcess);
        return FALSE;


    }

    ::CloseHandle(hRemoteThread);
    ::CloseHandle(hProcess);

    return TRUE;
}
複製程式碼

我參考上面資料和程式碼,稍作整理使之編譯通過並能使用,目標程序開啟時最好使用PROCESS_ALL_ACCESS許可權。

vista的較為簡單些,只要修改一個記憶體裡的數值,這裡不再實現。

複製程式碼
typedef struct _CLIENT_ID {
    HANDLE UniqueProcess;
    HANDLE UniqueThread;
} CLIENT_ID,*PCLIENT_ID;

typedef struct _INITIAL_TEB
{
    PVOID PreviousStackBase;
    PVOID PreviousStackLimit;
    PVOID StackBase;
    PVOID StackLimit;
    PVOID AllocatedStackBase;
} INITIAL_TEB, *PINITIAL_TEB;


typedef NTSTATUS (NTAPI *TZwAllocateVirtualMemory)(
                                 __in     HANDLE ProcessHandle,
                                 __inout  PVOID *BaseAddress,
                                 __in     ULONG_PTR ZeroBits,
                                 __inout  PSIZE_T RegionSize,
                                 __in     ULONG AllocationType,
                                 __in     ULONG Protect
                                 );

static TZwAllocateVirtualMemory ZwAllocateVirtualMemory = (TZwAllocateVirtualMemory)GetProcAddress(GetModuleHandle("ntdll.dll"),"ZwAllocateVirtualMemory");

typedef NTSYSAPI NTSTATUS (NTAPI *TZwWriteVirtualMemory)    (    IN HANDLE     ProcessHandle,
                                                 IN PVOID     BaseAddress,
                                                 IN PVOID     Buffer,
                                                 IN SIZE_T     NumberOfBytesToWrite,
                                                 OUT PSIZE_T     NumberOfBytesWritten     
                                                 );
static TZwWriteVirtualMemory ZwWriteVirtualMemory = (TZwWriteVirtualMemory)GetProcAddress(GetModuleHandle("ntdll.dll"),"ZwWriteVirtualMemory");

typedef NTSYSAPI NTSTATUS (NTAPI *TZwProtectVirtualMemory)    (    IN HANDLE     ProcessHandle,
                                                 IN PVOID *     BaseAddress,
                                                 IN SIZE_T *     NumberOfBytesToProtect,
                                                 IN ULONG     NewAccessProtection,
                                                 OUT PULONG     OldAccessProtection     
                                                 );
static TZwProtectVirtualMemory ZwProtectVirtualMemory = (TZwProtectVirtualMemory)GetProcAddress(GetModuleHandle("ntdll.dll"),"ZwProtectVirtualMemory");

typedef NTSYSAPI NTSTATUS (NTAPI *TZwGetContextThread)    (    IN HANDLE     ThreadHandle,
                                             OUT PCONTEXT     Context     
                                             );
static TZwGetContextThread ZwGetContextThread = (TZwGetContextThread)GetProcAddress(GetModuleHandle("ntdll.dll"),"ZwGetContextThread");

typedef NTSYSAPI NTSTATUS (NTAPI *TZwCreateThread)    (    OUT PHANDLE     ThreadHandle,
                                         IN ACCESS_MASK     DesiredAccess,
                                         IN POBJECT_ATTRIBUTES ObjectAttributes     OPTIONAL,
                                         IN HANDLE     ProcessHandle,
                                         OUT PCLIENT_ID     ClientId,
                                         IN PCONTEXT     ThreadContext,
                                         IN PINITIAL_TEB     UserStack,
                                         IN BOOLEAN     CreateSuspended     
                                         );
static TZwCreateThread ZwCreateThread = (TZwCreateThread)GetProcAddress(GetModuleHandle("ntdll.dll"),"ZwCreateThread");

typedef NTSYSAPI NTSTATUS (NTAPI *TZwResumeThread)    (    IN HANDLE     ThreadHandle,
                                         OUT PULONG     SuspendCount     
                                         );
static TZwResumeThread ZwResumeThread = (TZwResumeThread)GetProcAddress(GetModuleHandle("ntdll.dll"),"ZwResumeThread");

HANDLE WINAPI myCreateRemoteThread(
                                    HANDLE hProcess,
                                    LPSECURITY_ATTRIBUTES lpThreadAttributes,
                                    SIZE_T dwStackSize,
                                    LPTHREAD_START_ROUTINE lpStartAddress,
                                    LPVOID lpParameter,
                                    DWORD dwCreationFlags,
                                    LPDWORD lpThreadId)
{
    //by 80695073(QQ) 
    //email [email protected]    CONTEXT    context = {CONTEXT_FULL}; 
    CLIENT_ID  cid={hProcess}; 
    DWORD    ret; 
    HANDLE    hThread = NULL;
    DWORD    StackReserve;
    DWORD    StackCommit = 0x1000;
    ULONG_PTR  Stack = 0;
    INITIAL_TEB InitialTeb={};
    ULONG    x; 
    const CHAR myBaseThreadInitThunk[] = 
    {
        //   00830000    8BFF            mov     edi, edi        '\x8B','\xFF',
        //   00830002    55              push    ebp        '\x55',
        //   00830003    8BEC            mov     ebp, esp        '\x8B','\xEC',
        //   00830005    51              push    ecx   //ntdll.RtlExitUserThread        '\x51',
        //   00830006    53              push    ebx   //引數        '\x53',
        //   00830007    FFD0            call    eax   //函式地址        '\xFF','\xD0',
        //   00830009    59              pop     ecx   //恢復結束函式地址        '\x59',
        //   0083000A    50              push    eax   //將剛才的結果壓棧        '\x50',
        //   0083000B    FFD1            call    ecx   //呼叫RtlExitUserThread 結束        '\xFF','\xD1',
        //  0083000D    90              nop        '\x90'
    };
    PVOID  pBaseThreadThunk = NULL; //不能釋放

    //0、分配非OS的載入函式    StackReserve = 0x1000;
    ret = ZwAllocateVirtualMemory(hProcess, 
        /*&stack.ExpandableStackBottom*/(PVOID*)&pBaseThreadThunk, 
        0, 
        &StackReserve,
        MEM_COMMIT, 
        PAGE_EXECUTE_READWRITE); 
    if (ret >= 0x80000000)
    {
        //失敗        TRACE("Error IN myCreateRemoteThread ZwAllocateVirtualMemory0 !\n");
        goto myCreateRemoteThreadRet;
        //end    }
    ret = ZwWriteVirtualMemory(hProcess,
        pBaseThreadThunk,
        (LPVOID)myBaseThreadInitThunk,
        sizeof(myBaseThreadInitThunk),&x);
    if (ret >= 0x80000000)
    {
        //失敗        TRACE("Error IN myCreateRemoteThread ZwAllocateVirtualMemory0 !\n");
        goto myCreateRemoteThreadRet;
        //end    }

    //1、準備堆疊    StackReserve = 0x10000;
    ret = ZwAllocateVirtualMemory(hProcess, 
        /*&stack.ExpandableStackBottom*/(PVOID*)&Stack, 
        0, 
        &StackReserve,
        MEM_RESERVE, 
        PAGE_READWRITE); 
    if (ret >= 0x80000000)
    {
        //失敗        TRACE("Error IN myCreateRemoteThread ZwAllocateVirtualMemory1!\n");
        goto myCreateRemoteThreadRet;
        //end    }
    TRACE("OK myCreateRemoteThread:ZwAllocateVirtualMemory 0x%08x\n",Stack);

    InitialTeb.AllocatedStackBase = (PVOID)Stack;
    InitialTeb.StackBase = (PVOID)(Stack + StackReserve);

    /* Update the Stack Position */
    Stack += StackReserve - StackCommit;

    Stack -= 0x1000;
    StackCommit += 0x1000;

    /* Allocate memory for the stack */
    ret = ZwAllocateVirtualMemory(hProcess,
        (PVOID*)&Stack,
        0,
        &StackCommit,
        MEM_COMMIT,
        PAGE_READWRITE);
    if (ret >= 0x80000000)
    {
        //失敗        TRACE("Error IN myCreateRemoteThread ZwAllocateVirtualMemory2!\n");
        goto myCreateRemoteThreadRet;
        //end    }
    TRACE("OK myCreateRemoteThread:ZwAllocateVirtualMemory 2 0x%08x\n",Stack);
    InitialTeb.StackLimit = (PVOID)Stack;


    StackReserve = 0x1000; 
    ret = ZwProtectVirtualMemory(hProcess, (PVOID*)&Stack, &StackReserve, PAGE_READWRITE | PAGE_GUARD, &x); 
    if (ret >= 0x80000000)
    {
        //失敗        TRACE("Error IN myCreateRemoteThread ZwProtectVirtualMemory!\n");
        goto myCreateRemoteThreadRet;
        //end    }
    /* Update the Stack Limit keeping in mind the Guard Page */
    InitialTeb.StackLimit = (PVOID)((ULONG_PTR)InitialTeb.StackLimit - 0x1000);
    //2、準備CONTEXT
    //  CONTEXT context = {CONTEXT_FULL};     ret = ZwGetContextThread(GetCurrentThread(),&context); 
    if (ret >= 0x80000000)
    {
        //失敗        TRACE("Error IN myCreateRemoteThread ZwGetContextThread!\n");
        goto myCreateRemoteThreadRet;
        //end    }
    context.Esp = (DWORD)InitialTeb.StackBase; 
    context.Eip = (DWORD)pBaseThreadThunk; //這裡填寫需要載入的地址,不過需要自己終結自己    context.Ebx = (DWORD)lpParameter;
    //other init
    //must    context.Eax = (DWORD)lpStartAddress;
    context.Ecx = (DWORD)GetProcAddress(GetModuleHandle("ntdll.dll"),"RtlExitUserThread");//0x778B0859;/*win7*///0x77AEEC01;/*vista*/ //ntdll.RtlExitUserThread    context.Edx = 0x00000000; //nouse

    ret = ZwCreateThread(&hThread, THREAD_ALL_ACCESS, 0, hProcess, &cid, &context, &InitialTeb, TRUE); 
    if (ret >= 0x80000000)
    {
        //失敗        TRACE("Error %d\n",GetLastError());
        goto myCreateRemoteThreadRet;
        //end    }
    if(lpThreadId)
    {
        *lpThreadId = (DWORD)cid.UniqueThread;
    }
    if (!(dwCreationFlags & CREATE_SUSPENDED))
    {
        ZwResumeThread(hThread, NULL);
    }
myCreateRemoteThreadRet:
    return hThread;
}
複製程式碼


 最後通用的使用方法是:

複製程式碼
// 啟動遠端執行緒    HANDLE hRemoteThread = NULL;
    OSVERSIONINFO svex = {sizeof(OSVERSIONINFO)};
    GetVersionEx(&svex);
    if( svex.dwMajorVersion<=5 ){
        hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, lpRemoteDllName, 0, NULL);
    }else{
        hRemoteThread = myCreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, lpRemoteDllName, 0, NULL);
    }
複製程式碼

3.通過SetWindowsHookEx安裝鉤子,如WH_CALLWNDPROC,WH_KEYBOARD,WH_MOUSE,WH_GETMESSAGE鉤子可以實現全域性注入。

SetWindowsHookEx(WH_MOUSE,(HOOKPROC)MouseProc,AfxGetInstanceHandle(),dwThreadId);

4.AppInit_DLLs方式:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs注入到所有載入了user32.dll的程序。

win7下會被對映到:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows,

並且需要設定LoadAppInit_DLLs為1時AppInit_DLLs才會被啟用,預設為0。

例如在xp下建立一個.reg檔案:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows]
"AppInit_DLLs"="c:\\message.dll"

手動匯入後是可以載入指定dll的,但是在win7下面就不行,通過該.reg檔案操作的登錄檔子鍵路徑並沒有被重定向到

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows,

但是通過寫程式碼的方式是成功的:

複製程式碼
void LoadLibByAppInit_DLLs(LPCTSTR pszDllName,BOOL bInstall)
{
    HKEY hKey = NULL;
    DWORD dwRet = 0;

    //win7下會被對映到:HKEY_LOCAL