searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

谈谈 DLL 注入的几种方式

2023-07-20 07:28:33
7
0

云游戏的键鼠捕捉用到了 Hook 这个技术,就顺便翻了一下核心编程,写下来备忘。

使用注册表注入

  • x32 : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows
  • x64 : HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Windows

这个位置下 AppInit_DLLs 和 LoadAppInit_DLLs。 将后者置为 1,然后在前者的值输入待注入 DLL 名称(多个 DLL 用 Space 分隔,第一个可以带路径,后边的不行)。

  • 优点:方法简单
  • 缺点:只有引用了 User32.dll 的才会被注入,而且被注入进程一启动就会注入,结束才会反注入,注入周期不可控

使用 Windows Hook 注入

核心方法:

  • SetWindowsHookEx
  • UnhookWindowsHookEx

设置挂钩的时候,可以指定挂钩类型、线程 ID 、回调方法、DLL 句柄。这些已经可以准确的注入到一个进程中了。通过 Set、Unhook 两个方法可以准确的控制注入周期。

  • 优点:准确的控制注入周期
  • 缺点:依赖消息循环,没消息循环的线程没法注入

远程线程注入(大杀器)

核心方法:

  • CreateRemoteThread
  • VirtualAllocEx
  • VirtualFreeEx
  • ReadProcessMemory
  • WriteProcessMemory

可以用 CreateRemoteThread 在指定进程中创建一个线程,让它执行我们自己的代码,这样可以让远程线程 Load 一个我们自己的 DLL,这就可以为所欲为了……需要注意的是,CreateRemoteThread 的参数 PTHREAD_START_ROUTINE 这个函数地址,需要调用 GetProcAddress 。如果直接传函数地址,是本进程的……显然是不对的。

PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");

而函数参数也要使用 VirtualAllocEx 来分配内存,然后 WriteProcessMemory 写入。这才是远程进程可以获取的。

  • 优点:可以为所欲为
  • 缺点:写起来有点复杂

同名 DLL 替换

如果已知一个程序必然载入一个 DLL ,则可以做一个同名 DLL 然后将方法跟原 DLL 保持一致,在方法调用中间做点其他手脚。这种如果程序校验 DLL ,就没戏。或者直接修改程序的 EXE 的导入段,这就要求对 PE 结构非常熟悉。

作为调试器注入

核心编程没说的太细,看起来要写 CPU 代码,没太细看。感觉也挺复杂,不太实用。

修改子进程的主线程开始位置代码

如果要注入的进程是子进程,可以创建它的时候挂起它,然后从 exe 模块中拿到子进程的主线程起始地址,把这里记下来,之后改成执行自己的代码,这个时候恢复子进程主线程,就可以执行自己的代码了,然后再把之前保存的执行一波。看起来也挺复杂,核心编程也没给具体例子。

API 拦截

第一种:把要拦截的 API 起始位置的几个字节保存起来,然后将此位置改写为 CPU 的 JUMP 指令,跳转到自己的方法。不过这种方法非常危险,不建议用。

第二种:修改模块导入段拦截 API

核心方法:

  • ImageDirectoryEntryToData
  • WriteProcessMemory
  • VirtualProtect

获取到模块的导入段信息,之后查找到指定方法,用自己的方法替换原来的方法。如果 WriteProcessMemory 失败,就用 VirtualProtect 修改一下页面保护属性。

0条评论
0 / 1000
Harper
17文章数
0粉丝数
Harper
17 文章 | 0 粉丝
原创

谈谈 DLL 注入的几种方式

2023-07-20 07:28:33
7
0

云游戏的键鼠捕捉用到了 Hook 这个技术,就顺便翻了一下核心编程,写下来备忘。

使用注册表注入

  • x32 : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows
  • x64 : HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Windows

这个位置下 AppInit_DLLs 和 LoadAppInit_DLLs。 将后者置为 1,然后在前者的值输入待注入 DLL 名称(多个 DLL 用 Space 分隔,第一个可以带路径,后边的不行)。

  • 优点:方法简单
  • 缺点:只有引用了 User32.dll 的才会被注入,而且被注入进程一启动就会注入,结束才会反注入,注入周期不可控

使用 Windows Hook 注入

核心方法:

  • SetWindowsHookEx
  • UnhookWindowsHookEx

设置挂钩的时候,可以指定挂钩类型、线程 ID 、回调方法、DLL 句柄。这些已经可以准确的注入到一个进程中了。通过 Set、Unhook 两个方法可以准确的控制注入周期。

  • 优点:准确的控制注入周期
  • 缺点:依赖消息循环,没消息循环的线程没法注入

远程线程注入(大杀器)

核心方法:

  • CreateRemoteThread
  • VirtualAllocEx
  • VirtualFreeEx
  • ReadProcessMemory
  • WriteProcessMemory

可以用 CreateRemoteThread 在指定进程中创建一个线程,让它执行我们自己的代码,这样可以让远程线程 Load 一个我们自己的 DLL,这就可以为所欲为了……需要注意的是,CreateRemoteThread 的参数 PTHREAD_START_ROUTINE 这个函数地址,需要调用 GetProcAddress 。如果直接传函数地址,是本进程的……显然是不对的。

PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");

而函数参数也要使用 VirtualAllocEx 来分配内存,然后 WriteProcessMemory 写入。这才是远程进程可以获取的。

  • 优点:可以为所欲为
  • 缺点:写起来有点复杂

同名 DLL 替换

如果已知一个程序必然载入一个 DLL ,则可以做一个同名 DLL 然后将方法跟原 DLL 保持一致,在方法调用中间做点其他手脚。这种如果程序校验 DLL ,就没戏。或者直接修改程序的 EXE 的导入段,这就要求对 PE 结构非常熟悉。

作为调试器注入

核心编程没说的太细,看起来要写 CPU 代码,没太细看。感觉也挺复杂,不太实用。

修改子进程的主线程开始位置代码

如果要注入的进程是子进程,可以创建它的时候挂起它,然后从 exe 模块中拿到子进程的主线程起始地址,把这里记下来,之后改成执行自己的代码,这个时候恢复子进程主线程,就可以执行自己的代码了,然后再把之前保存的执行一波。看起来也挺复杂,核心编程也没给具体例子。

API 拦截

第一种:把要拦截的 API 起始位置的几个字节保存起来,然后将此位置改写为 CPU 的 JUMP 指令,跳转到自己的方法。不过这种方法非常危险,不建议用。

第二种:修改模块导入段拦截 API

核心方法:

  • ImageDirectoryEntryToData
  • WriteProcessMemory
  • VirtualProtect

获取到模块的导入段信息,之后查找到指定方法,用自己的方法替换原来的方法。如果 WriteProcessMemory 失败,就用 VirtualProtect 修改一下页面保护属性。

文章来自个人专栏
Windows 编程
9 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0