您当前的位置: 首页 >  windows

鱼儿-1226

暂无认证

  • 4浏览

    0关注

    1100博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Windows Dll注入与API HOOK

鱼儿-1226 发布时间:2020-07-27 10:53:54 ,浏览量:4

DLL注入:

1.  使用注册表注入dll

 

HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Windows\AppInit_DLLs

 

AppInit_Dlls中设置待注入的dll绝对路径

LoadAppInit_Dlls值设为1

2.  使用Windows挂钩注入dll

需要使用SetWindowsHookEx函数,MSDN定义如下:

 
  1. HHOOK WINAPI SetWindowsHookEx(

  2. _In_ int idHook,

  3. _In_ HOOKPROC lpfn,

  4. _In_ HINSTANCE hMod,

  5. _In_ DWORD dwThreadId

  6. );

第一个参数为挂钩类型;

 

第二个参数为一个函数地址,即挂钩类型事件发生时,系统应该调用的函数;

第三个参数标识一个dll,这个dll中包含第二个参数表示的函数;

第四个参数表示要给哪个线程挂钩,0表示所有运行线程

以下给出一个示例:

 

 
  1. HOOKPROC hkprcSysMsg;

  2. static HINSTANCE hinstDLL;

  3. static HHOOK hhookSysMsg;

  4.  
  5. hinstDLL = LoadLibrary(TEXT("c:\\myapp\\sysmsg.dll"));

  6. hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc");

  7.  
  8. hhookSysMsg = SetWindowsHookEx(

  9. WH_SYSMSGFILTER,

  10. hkprcSysMsg,

  11. hinstDLL,

  12. 0);

可以使用UnhookWindowsHookEx取消挂钩:

 

 

 
  1. BOOL WINAPI UnhookWindowsHookEx(

  2. _In_ HHOOK hhk

  3. );

 

3.  使用远程线程注入dll

Dll注入的本质即让目标进程中的一个线程通过LoadLibrary()加载待注入dll文件。

通常情况下,无法控制目标进程线程,此时可以创建一个线程了实现上述目的,CreateRemoteThread便提供了此功能。

 

 
  1. HANDLE WINAPI CreateRemoteThread(

  2. _In_ HANDLE hProcess,

  3. _In_ LPSECURITY_ATTRIBUTES lpThreadAttributes,

  4. _In_ SIZE_T dwStackSize,

  5. _In_ LPTHREAD_START_ROUTINE lpStartAddress,

  6. _In_ LPVOID lpParameter,

  7. _In_ DWORD dwCreationFlags,

  8. _Out_ LPDWORD lpThreadId

  9. );

hProcess表示待注入的目标进程;

 

lpStartAddress表示线程函数,此处设置为LoadLibrary();

lpParameter表示传递给线程函数的参数,此时设置为待注入的dll文件绝对路径。 使用CreateRemoteThread具体注入过程如下:

(1) 使用VirtualAllocEx在远程进程中申请一块内存空间;

(2) 使用WriteProcessMemory将Dll路径名复制到(1)中申请的地址;

(3) 使用GetProcAddress获取LoadLibraryW或LoadLibraryA的实际地址;

(4) 使用CreateRemoteThread在远程进程中创建新的线程,新线程调用LoadLibrary,并在参数中传入(1)中申请的内存地址,此时dll文件已经注入到远程线程,DllMain将执行我们设计的代码。

此时远程线程中保留一块申请的内存空间,需要对其进行释放:

(5) 使用VirtualFreeEx释放(1)中申请的内存;

(6) 使用GetProcAddress获取FreeLibrary函数实际地址;

(7) 使用CreateRemoteThread创建新的线程,调用FreeLibrary,参数传入已注入Dll的HMODULE.

4.  使用木马dll注入dll

将进程需要加载的dll文件替换掉,实现dll劫持。

例如,进程需要使用lpk.dll,通过伪造lpk.dll文件,利用windows应用程序加载dll的顺序,让其优先加载伪造的lpk.dll文件。

5.  把dll作为调试器注入

(1) DebugActiveProcess(pid)附加进程;

(2) Debug循环函数:WaitForDebugEvent等待调试事件,针对不同类型进行处理;

(3) ReadProcessMemory, WriteProcessMemory操作目标进程,钩取指定API

6.  使用CreateProcess注入代码

该方法用于向子进程注入代码:

(1) 创建子进程并挂起;

(2) 获取主线程内存地址;

(3) 保存主线程起始地址指令;

(4) 插入指令,调用LoadLibrary加载dll

(5) 子进程恢复运行;

(6) 执行插入的指令;

(7) 恢复原指令,按照原来的逻辑继续执行。

 

API 拦截:

1.  通过覆盖代码拦截API

(1) 获取待拦截函数地址;

(2) 保存该函数初始几个字节指令;

(3) 使用JMP替换这些指令,让其跳转到自定义的函数中,需要注意的是,自定义函数需与原函数具有相同的签名,相同的参数,相同的返回值,相同的调用约定;

(4) 程序调用被拦截函数时,将跳转到自定义函数中执行;

(5) 执行完毕后,将保存的原指令恢复到起始地址,调用函数让其按照原来的逻辑执行。

2.  通过修改IAT拦截API

  每一个导入的dll文件对应一个IMAGE_IMPORT_DESCRIPTOR结构:

 

 
  1. typedef struct _IMAGE_IMPORT_DESCRIPTOR {

  2. union {

  3. DWORD Characteristics; // 0 for terminating null import descriptor

  4. DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)

  5. } DUMMYUNIONNAME;

  6. DWORD TimeDateStamp; // 0 if not bound,

  7. // -1 if bound, and real date\time stamp

  8. // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)

  9. // O.W. date/time stamp of DLL bound to (Old BIND)

  10.  
  11. DWORD ForwarderChain; // -1 if no forwarders

  12. DWORD Name;

  13. DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)

  14. } IMAGE_IMPORT_DESCRIPTOR;

其中成员变量FirstThunk指向一个IMAGE_THUNK_DATA结构体数组,数组中每一项对应一个导入函数:

 

 
  1. typedef struct _IMAGE_THUNK_DATA32 {

  2. union {

  3. DWORD ForwarderString; // PBYTE

  4. DWORD Function; // PDWORD

  5. DWORD Ordinal;

  6. DWORD AddressOfData; // PIMAGE_IMPORT_BY_NAME

  7. } u1;

  8. } IMAGE_THUNK_DATA32;

  9. typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;

  10. typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA;

  11. typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA;

因此,IAT HOOK的主要思路为:

 

(1) 遍历IMAGE_IMPORT_DESCRIPTOR数组,找到name为需要hook的dll;

(2) 遍历FirstThunk指向的IMAGE_THUNK_DATA,判断Function是否为待hook的API,若是,则替换为新的API.

以下是《Windows核心编程》中作者给出的实现函数:

 

 
  1. void ReplaceIATEntryInOneMod(PCSTR pszCalleeModName, //被调模块

  2. PROC pfnCurrent, //待HOOK原函数

  3. PROC pfnNew, //替换新函数

  4. HMODULE hmodCaller //调用新函数的模块

  5. ) {

  6.  
  7. // Get the address of the module's import section

  8. ULONG ulSize;

  9.  
  10. // An exception was triggered by Explorer (when browsing the content of

  11. // a folder) into imagehlp.dll. It looks like one module was unloaded...

  12. // Maybe some threading problem: the list of modules from Toolhelp might

  13. // not be accurate if FreeLibrary is called during the enumeration.

  14. PIMAGE_IMPORT_DESCRIPTOR pImportDesc = NULL;

  15. __try {

  16. pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData(

  17. hmodCaller, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);

  18. }

  19. __except (InvalidReadExceptionFilter(GetExceptionInformation())) {

  20. // Nothing to do in here, thread continues to run normally

  21. // with NULL for pImportDesc

  22. }

  23.  
  24. if (pImportDesc == NULL)

  25. return; // This module has no import section or is no longer loaded

  26.  
  27. // Find the import descriptor containing references to callee's functions

  28. for (; pImportDesc->Name; pImportDesc++) {

  29. PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name);

  30. if (lstrcmpiA(pszModName, pszCalleeModName) == 0) {

  31.  
  32. // Get caller's import address table (IAT) for the callee's functions

  33. PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)

  34. ((PBYTE) hmodCaller + pImportDesc->FirstThunk);

  35.  
  36. // Replace current function address with new function address

  37. for (; pThunk->u1.Function; pThunk++) {

  38.  
  39. // Get the address of the function address

  40. PROC* ppfn = (PROC*) &pThunk->u1.Function;

  41.  
  42. // Is this the function we're looking for?

  43. BOOL bFound = (*ppfn == pfnCurrent);

  44. if (bFound) {

  45. if (!WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew,

  46. sizeof(pfnNew), NULL) && (ERROR_NOACCESS == GetLastError())) {

  47. DWORD dwOldProtect;

  48. if (VirtualProtect(ppfn, sizeof(pfnNew), PAGE_WRITECOPY,

  49. &dwOldProtect)) {

  50. WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew,

  51. sizeof(pfnNew), NULL);

  52. VirtualProtect(ppfn, sizeof(pfnNew), dwOldProtect,

  53. &dwOldProtect);

  54. }

  55. }

  56. return; // We did it, get out

  57. }

  58. }

  59. } // Each import section is parsed until the right entry is found and patched

  60. }

  61. }

  62.  
关注
打赏
1604459285
查看更多评论
立即登录/注册

微信扫码登录

0.1466s