createremotethread能不能用于win10 64的

qq106397695 2018-05-17 11:30:13
只能注入到explorer,其他所有进程都不行,包括自己编的程序。
其他都是新产生一个进程,有attach的信息,然后暂停死掉,但无法注入原始的进程。
是不是这个API已经不能用了?
用了CREATEremotethread,loadlibraryW。
是用64编译的。
...全文
607 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq106397695 2018-05-18
  • 打赏
  • 举报
回复
谢了,也好,我用vs挂靠这个软件学习一下。
qq106397695 2018-05-18
  • 打赏
  • 举报
回复
文件获取没问题的啊。打个比方按照pid注入搜狗,进程列表本来有一个搜狗,注入之后又出现一个搜狗进程,变成了两个搜狗。 api替换已经解决了,主要是注入。
赵4老师 2018-05-18
  • 打赏
  • 举报
回复
赵4老师 2018-05-18
  • 打赏
  • 举报
回复
64 位 Windows 平台注意点之文件系统重定向 http://www.cnblogs.com/jiake/p/4981555.html 64 位 Windows 平台注意点之注册表重定向 http://www.cnblogs.com/jiake/p/4956218.html
第1章 再谈计算机内存访问 1 1.1 引言 1 1.2 内存管理概述 1 1.2.1 虚拟内存 1 1.2.2 CPU工作模式 2 1.2.3 逻辑、线性和物理地址 3 1.2.4 存储器分页管理机制 3 1.2.5 线性地址到物理地址的转换 4 1.3 虚拟内存访问 5 1.3.1 获取系统信息 5 1.3.2 在应用程序中使用虚拟内存 6 1.3.3 获取虚存状态 7 1.3.4 确定虚拟地址空间的状态 8 1.3.5 改变内存页面保护属性 9 1.3.6 进行一个进程的内存读写 10 1.4 文件的内存映射 11 1.4.1 内存映射API函数 11 1.4.2 用内存映射在多个应用程序之间共享数据 13 1.4.3 用内存映射文件读取大型文件 18 1.5 深入认识指针的真正含义 21 .1.5.1 指针的真正本质 21 1.5.2 用指针进行应用程序之间的通信 22 1.6 本章小结 26 参考文献 27 第2章 再谈PE文件结构 28 2.1 引言 28 2.2 PE文件格式概述 28 2.2.1 PE文件结构布局 28 2.2.2 PE文件内存映射 30 2.2.3 Big-endian和Little-endian 31 2.2.4 3种不同的地址 31 2.3 PE文件结构 32 2.3.1 MS-DOS头部 32 2.3.2 IMAGE_NT_HEADER头部 33 2.3.3 IMAGE_SECTION_HEADER头部 36 2.4 如何获取PE文件中的OEP 36 2.4.1 通过文件读取OEP值 37 2.4.2 通过内存映射读取OEP值 38 2.4.3 读取OEP值方法的测试 39 2.5 PE文件中的资源 40 2.5.1 查找资源在文件中的起始位置 40 2.5.2 确定PE文件中的资源 41 2.6 一个修改PE可执行文件的完整实例 43 2.6.1 如何获得MessageBoxA代码 43 2.6.2 把MessageBoxA()代码写入PE文件的完整实例 45 2.7 本章小结 53 参考文献 53 第3章 进程之间通信概述及初级技术 54 3.1 引言 54 3.2 进程通信概述 55 3.2.1 Windows进程间标准通信技术的发展 55 3.2.2 应用程序与进程 56 3.2.3 进程之间通信的类型 56 3.3 使用自定义消息通信 57 3.3.1 通过自定义消息实现进程间通信的方法 57 3.3.2 通过自定义消息实现进程间通信的实例 58 3.4 使用WM_COPYDATA消息通信 60 3.4.1 通过WM_COPYDATA消息实现进程间通信的方法 60 3.4.2 通过WM_COPYDATA消息实现进程间通信的实例 61 3.5 使用内存读写函数和内存映射文件通信 62 3.5.1 使用内存映射文件通信的方法 62 3.5.2 使用内存读写函数实现进程间通信的方法 62 3.5.3 使用内存读写函数实现进程间通信的实例 63 3.6 使用动态链接库通信 64 3.6.1 DLL概述 64 3.6.2 使用DLL通信的方法 65 3.6.3 使用DLL通信的实例 66 3.7 使用Windows剪贴板通信 67 3.7.1 使用剪贴板实现进程间通信的方法 68 3.7.2 使用剪贴板实现进程间通信的实例 68 3.8 使用动态数据交换(DDE)通信 70 3.8.1 使用DDE技术通信原理 70 3.8.2 如何使用DDEML编写程序 71 3.8.3 使用DDE通信的实例 72 3.9 本章小结 77 参考文献 77 第4章 使用消息管道、邮槽和套接字通信 78 4.1 引言 78 4.2 如何用命名管道进行进程间通信 78 4.2.1 命名管道函数 79 4.2.2 命名管道服务端与客户端之间通信的实现流程 80 4.2.3 命名管道服务端与客户端之间通信的实例 81 4.3 如何用邮槽进行进程间通信 85 4.3.1 用邮槽进行进程间通信的步骤 85 4.3.2 邮槽服务器端与客户端之间通信的实例 86 4.4 如何用Windows套接字进行进程间通信 90 4.4.1 套接字分类 90 4.4.2 流式套接字编程流程 91 4.4.3 套接字调用基本函数 92 4.4.4 Winsock程序设计 95 4.4.5 一个通用套接字类 96 4.4.6 套接字服务器端与客户端间通信的实例 101 4.5 本章小结 106 参考文献 106 第5章 使用LPC和RPC通信 107 5.1 引言 107 5.2 接口定义语言(IDL)简介 107 5.3 使用本地过程调用(LPC)通信 108 5.3.1 使用LPC通信方法介绍 108 5.3.2 使用LPC通信的实例 110 5.4 使用远程过程调用(RPC)通信 117 5.4.1 RPC运行机制 117 5.4.2 RPC 绑定模式和属性 118 5.4.3 RPC传输(Transport) 118 5.4.4 如何编写RPC应用程序 119 5.4.5 使用RPC通信的实例 120 5.5 本章小结 128 参考文献 128 第6章 使用组件模型通信 129 6.1 引言 129 6.2 COM/DCOM模型概述 129 6.2.1 COM/DCOM的特点 129 6.2.2 COM/DCOM组件模型分类 130 6.3 使用组件对象模型(COM/DCOM)通信 131 6.3.1 使用COM/DCOM通信方法介绍 131 6.3.2 基于DCOM实现远程会话的实例 136 6.4 本章小结 147 参考文献 147 第7章 进程的创建、控制和隐藏 148 7.1 引言 148 7.2 常见的几种创建进程的方法 148 7.2.1 使用WinExec() 函数 148 7.2.2 使用ShellExecute()和ShellExecuteEx()函数 149 7.2.3 使用CreateProcess()函数 151 7.2.4 使用OLE激活服务程序 154 7.3 如何获得进程句柄 155 7.3.1 获得一个进程的句柄 155 7.3.2 提升进程权限级别 156 7.4 如何实现当前进程的枚举 158 7.4.1 通过系统快照实现当前进程的枚举 158 7.4.2 通过psapi.dll提供的API函数实现当前进程的枚举 160 7.4.3 通过wtsapi32.dll提供的API函数实现当前进程的枚举 162 7.4.4 通过ntdll.dll提供的API函数实现当前进程的枚举 163 7.5 如何终止进程 164 7.5.1 如何终止本进程 165 7.5.2 如何终止外部进程 165 7.5.3 终止进程的实例 165 7.6 如何隐藏进程(注入代码) 166 7.6.1 基本原理 166 7.6.2 使用CreateRemoteThread()隐藏DLL 167 7.6.3 使用CreateRemoteThread()直接注入API函数代码 173 7.6.4 使用Windows内存映射文件注入代码 174 7.6.5 使用特洛伊DLL注入代码 174 7.6.6 使用注册表注入DLL 175 7.6.7 使用程序挂钩的方法注入代码 175 7.7 本章小结 175 参考文献 176 第8章 应用程序的静态挂钩 177 8.1 引言 177 8.2 使用C/C++语言提取可执行程序代码 177 8.2.1 在C/C++中使用内联汇编 177 8.2.2 如何使用C/C++语言提取可执行程序代码 179 8.3 如何对PE文件加壳 182 8.3.1 PE文件的加壳方法 182 8.3.2 向PE文件中静态注入代码的完整实例 183 8.4 如何实现文件脱壳 191 8.5 本章小结 192 参考文献 192 第9章 应用程序的动态挂钩 193 9.1 动态挂钩概述 193 9.2 使用Windows钩子函数挂钩 194 9.2.1 Windows钩子函数 194 9.2.2 具体实例 195 9.3 替换原API函数入口挂钩 198 9.3.1 如何替换原API函数入口实现挂钩 198 9.3.2 通用的替换原API函数入口挂钩类 199 9.3.3 使用JMP法编写的挂钩实例 201 9.4 替换IAT中的函数地址进行挂钩 202 9.4.1 如何替换IAT中的函数地址实现挂钩 202 9.4.2 通用的替换IAT中的函数地址挂钩类 203 9.4.3 使用IAT法编写的挂钩实例 207 9.5 替换Windows消息处理函数实现挂钩 208 9.5.1 Windows消息处理函数及其替换 209 9.5.2 替换Windows消息处理函数实现挂钩的实例 210 9.6 钩子DLL文件的装载 214 9.7 本章小结 216 参考文献 216 第10章 数据的编码和解码实例 217 10.1 引言 217 10.2 游程编码 218 10.2.1 CX游程压缩方法 218 10.2.2 BI_RLE8压缩方法 218 10.2.3 BI_RLE压缩方法 218 10.2.4 缩位压缩方法(Packbits) 219 10.3 Huffman编码 219 10.3.1 Huffman编码原理 219 10.3.2 Huffman编码过程 220 10.4 算术编码 221 10.4.1 算术编码算法 221 10.4.2 算术解码算法 222 10.5 LZW压缩算法 222 10.5.1 LZW压缩算法原理 223 10.5.2 用VC++实现LZW压缩算法 225 10.6 Base64编码 236 10.6.1 Base64算法原理 236 10.6.2 Base64算法的实现 238 10.7 本章小结 241 参考文献 242 第11章 可执行文件的捆绑和分离 243 11.1 引言 243 11.2 捆绑方式分类 243 11.2.1 结合式捆绑 243 11.2.2 功能式捆绑 245 11.3 文件捆绑相关技术 245 11.3.1 文件捆绑工具及实现 245 11.3.2 木马程序与捆绑 246 11.3.3 文件自身操作特点分析 246 11.4 文件属性的获取和伪装 248 11.4.1 文件属性的获取和更改 248 11.4.2 一个获取文件基本属性类 249 11.4.3 可执行程序自删除的实现 251 11.4.4 如何获取其他应用程序的图标 254 11.4.5 如何改变窗口的图标 255 11.5 被捆绑文件分离后的运行及自分解文件原理 256 11.5.1 异步执行分解法的实现 256 11.5.2 同步执行分解法的实现 256 11.5.3 自动分解法的实现 257 11.6 一个捆绑机(BindHider)软件的设计 258 11.6.1 BindHider的设计 258 11.6.2 BindHider的源代码 259 11.7 一种制作自分解文件的方法 263 11.7.1 母体程序的制作 264 11.7.2 自分解文件的制作 266 11.8 本章小结 267 参考文献 268 第12章 可执行文件的分割和合并 269 12.1 引言 269 12.2 文件分割方式 269 12.2.1 考虑文件格式的分割 269 12.2.2 设置子文件大小的分割 270 12.2.3 具有自合并功能的文件分割 271 12.2.4 依赖文件存放位置的分割 271 12.2.5 依赖磁盘大小的分割 271 12.3 如何使用多线程 272 12.3.1 线程的创建和终止 272 12.3.2 线程的控制函数 273 12.3.3 线程的通信 273 12.4 文件的简单分割与合并 274 12.4.1 文件的简单分割 274 12.4.2 文件的简单合并 275 12.5 用多线程进行文件的分割与合并的实例 277 12.5.1 文件的分割与合并方案设计 277 12.5.2 用多线程进行文件分割 279 12.5.3 用多线程进行文件合并 282 12.6 分割后文件自动合并的方案设计 286 12.6.1 控制程序的制作 286 12.6.2 用于文件自合并的控制程序的制作 287 12.6.3 一种生成自合并文件的分割软件制作 289 12.7 本章小结 292 参考文献 292 第13章 多线程下载和断点续传 293 13.1 引言 293 13.2 使用FTP进行多线程下载和断点续传 293 13.2.1 FTP协议简介 293 13.2.2 FTP的工作模式 295 13.2.3 FTP协议多线程下载和断点续传的实现 295 13.2.4 实例 306 13.3 使用HTTP进行多线程下载和断点续传 307 13.3.1 HTTP协议简介 307 13.3.2 HTTP协议的内部操作过程 308 13.3.3 HTTP协议多线程下载和断点续传的实现 311 13.3.4 实例 321 13.4 BT下载简介 323 13.4.1 BT下载与一般下载的区别 323 13.4.2 BT种子 324 13.4.3 BT的下载过程 324 13.5 本章小结 324 参考文献 325 第14章 带附件的电子邮件发送剖析 326 14.1 引言 326 14.2 电子邮件的发送方法 326 14.3 用WinSock实现SMTP协议 327 14.3.1 SMTP协议 327 14.3.2 SMTP的实现 328 14.4 邮件格式化 335 14.4.1 邮件主体格式化 335 14.4.2 邮件附件格式化 338 14.4.3 邮件格式化 341 14.5 发送电子邮件实例 346 14.6 本章小结 347 参考文献 347 第15章 特洛伊木马与反木马技术 348 15.1 引言 348 15.2 常见的木马种类 349 15.3 木马的载入方式 350 15.4 木马采用的伪装方法 351 15.5 Windows 2K/XP中无法删除文件的常用解决办法 352 15.6 一种木马病毒的检测技术 353 15.7 本章小结 358
在编写程序的过程中,我遇到了这样的需求:在基于Windows 9x 或 Windows NT4.0 的程序中,要求确定键盘、鼠标处于空闲状态的时间。查询了有关资料文档以后,发现Windows 9x和Windows NT4.0 没有提供API或系统调用来实现这样的功能。但是,在Windows 2000中提供了一个新的函数:GetLastInputInfo(),这个函数使用结构 LASTINPUTINFO 作为参数: LASTINPUTINFO lpi; lpi.cbSize = sizeof(lpi); GetLastInputInfo(&lpi); 调用函数GetLastInputInfo()以后, 结构成员lpi.dwTime 中的值便是自上次输入事件发生以后的毫秒数。这个值也就是键盘、鼠标处于空闲状态的时间。可惜的是这个函数只能在Windows 2000中使用,Windows 9x 或Windows NT4.0不提供此API函数。那么,如何在Windows 9x 或Windows NT4.0中实现GetLastInputInfo()的功能呢?笔者的方法是利用系统钩子对键盘、鼠标进行监控。 Windows中的钩子实际上是一个回调函数,当用户有输入动作的时候,Windows要调用这个函数。比较典型的系统钩子应用就是键盘钩子和鼠标钩子: HHOOK g_hHookKbd = NULL; HHOOK g_hHookMouse = NULL; 在Windows中,一个系统(相对于一个特定进程而言)钩子必须用一个动态链接库(DLL)来实现。不妨将这个动态链接库命名为IdleUI.dll。 这个动态链接库在Windows 9x和Windows NT4.0 中实现了GetLastInputInfo()的功能。IdleUI.dll中有三个函数: BOOL IdleUIInit() void IdleUITerm(); DWORD IdleUIGetLastInputTime(); IdleUIInit()是环境初始化函数,IdleUITerm()是环境清理函数,分别在MFC应用程序的InitInstance() 和 ExitInstance()中调用它们。当用IdleUIInit()做完初始化后,就可以调用第三个函数IdleUIGetLastInputTime()来获取最后一次输入事件后的时钟。从而实现与GetLastInputInfo()一样的功能。程序TestIdleUI.exe是用来测试IdleUI动态库的,程序中调用了IdleUIInit 和 IdleUITerm,同时在程序的客户区中间显示键盘、鼠标空闲的秒数。 void CMainFrame::OnPaint() { CPaintDC dc(this); CString s; DWORD nsec = (GetTickCount() - IdleUIGetLastInputTime())/1000; s.Format( "鼠标或键盘空闲 %d 秒。",nsec); CRect rc; GetClientRect(&rc); dc.DrawText(s, &rc, DT_CENTER|DT_VCENTER|DT_SINGLELINE); } 图一显示了TestIdleUI运行时的情形。 图一 TestIdleUI运行画面 为了连续的显示,TestIdleUI设置刷新定时器间隔为一秒。 void CMainFrame::OnTimer(UINT) { Invalidate(); UpdateWindow(); } 运行TestIdleUI,当键盘和鼠标什么也不做时,可以看到计时器跳动,当移动鼠标或按键时,计时器又恢复到零,这样就实现了对输入设备空闲状态的监控。实现细节请看下面对IdleUI.dll工作原理的描述: 首先调用IdleUIInit ()进行初始化,安装两个钩子:一个用于监控鼠标输入,一个用于监控键盘输入。 HHOOK g_hHookKbd; HHOOK g_hHookMouse; g_hHookKbd = SetWindowsHookEx(WH_KEYBOARD,MyKbdHook,hInst, 0); g_hHookMouse = SetWindowsHookEx(WH_MOUSE,MyMouseHook,hInst, 0); 当用户移动鼠标或按下键盘键时,Windows调用其中的一个钩子并且钩子函数开始记录时间: LRESULT CALLBACK MyMouseHook(in
Detours是微软开发的一个函数库, 用于修改运行中的程序在内存中的影像,从而即使没有源代码也能改变程序的行为。具体用途是: 拦截WIN32 API调用,将其引导到自己的子程序,从而实现WIN32 API的定制。 为一个已在运行的进程创建一新线程,装入自己的代码并运行。 ---- 本文将简介Detours的原理,Detours库函数的用法, 并利用Detours库函数在Windows NT上编写了一个程序,该程序能使有“调试程序”的用户权限的用户成为系统管理员,附录利用Detours库函数修改该程序使普通用户即可成为系统管理员 (在NT4 SP3上)。 一. Detours的原理 ---- 1. WIN32进程的内存管理 ---- 总所周知,WINDOWS NT实现了虚拟存储器,每一WIN32进程拥有4GB的虚存空间, 关于WIN32进程的虚存结构及其操作的具体细节请参阅WIN32 API手册, 以下仅指出与Detours相关的几点: ---- (1) 进程要执行的指令也放在虚存空间中 ---- (2) 可以使用QueryProtectEx函数把存放指令的页面的权限更改为可读可写可执行,再改写其内容,从而修改正在运行的程序 ---- (3) 可以使用VirtualAllocEx从一个进程为另一正运行的进程分配虚存,再使用 QueryProtectEx函数把页面的权限更改为可读可写可执行,并把要执行的指令以二进制机器码的形式写入,从而为一个正在运行的进程注入任意的代码 ---- 2. 拦截WIN32 API的原理 ---- Detours定义了三个概念: ---- (1) Target函数:要拦截的函数,通常为Windows的API。 ---- (2) Trampoline函数:Target函数的复制品。因为Detours将会改写Target函数,所以先把Target函数复制保存好,一方面仍然保存Target函数的过程调用语义,另一方面便于以后的恢复。 ---- (3) Detour 函数:用来替代Target函数的函数。 ---- Detours在Target函数的开头加入JMP Address_of_ Detour_ Function指令(共5个字节)把对Target函数的调用引导到自己的Detour函数, 把Target函数的开头的5个字节加上JMP Address_of_ Target _ Function+5作为Trampoline函数。例子如下: 拦截前:Target _ Function: ;Target函数入口,以下为假想的常见的子程序入口代码 push ebp mov ebp, esp push eax push ebx Trampoline: ;以下是Target函数的继续部分 …… 拦截后: Target _ Function: jmp Detour_Function Trampoline: ;以下是Target函数的继续部分 …… Trampoline_Function: ; Trampoline函数入口, 开头的5个字节与Target函数相同 push ebp mov ebp, esp push eax push ebx ;跳回去继续执行Target函数 jmp Target_Function+5 ---- 3. 为一个已在运行的进程装入一个DLL ---- 以下是其步骤: ---- (1) 创建一个ThreadFuction,内容仅是调用LoadLibrary。 ---- (2) 用VirtualAllocEx为一个已在运行的进程分配一片虚存,并把权限更改为可读可写可执行。 ---- (3) 把ThreadFuction的二进制机器码写入这片虚存。 ---- (4) 用CreateRemoteThread在该进程上创建一个线程,传入前面分配的虚存的起始地址作为线程函数的地址,即可为一个已在运行的进程装入一个DLL。通过DllMain 即可在一个已在运行的进程中运行自己的代码。 二. Detours库函数的用法 ---- 因为Detours软件包并没有附带帮助文件,以下接口仅从剖析源代码得出。 ---- 1. PBYTE WINAPI DetourFindFunction(PCHAR pszModule, PCHAR pszFunction) ---- 功能:从一DLL中找出一函数的入口地址 ---- 参数:pszModule是DLL名,pszFunction是函数名。 ---- 返回:名为pszModule的DLL的名为pszFunction的函数的入口地址 ---- 说明:DetourFindFunctio
远程注入DLL方法有很多种,也是很多木马病毒所使用的隐藏进程的方法,因为通过程序加载的DLL在进程管理器是没有显示的.这里介绍一种用 CreateRemoteThread 远程建立线程的方式注入DLL. 首先,我们要提升自己的权限,因为远程注入必不可免的要访问到目标进程的内存空间,如果没有足够的系统权限,将无法作任何事.下面是这个函数是用来提升我们想要的权限用的. function EnableDebugPriv: Boolean; var hToken: THandle; tp: TTokenPrivileges; rl: Cardinal; begin Result := false; //打开进程令牌环 OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken); //获得进程本地唯一ID if LookupPrivilegeValue(nil, 'SeDebugPrivilege', tp.Privileges[0].Luid) then begin tp.PrivilegeCount := 1; tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; //调整权限 Result := AdjustTokenPrivileges(hToken, false, tp, SizeOf(tp), nil, rl); end; end; 关于 OpenProcessToken() 和 AdjustTokenPrivileges() 两个 API 的简单介绍: OpenProcessToken():获得进程访问令牌的句柄. function OpenProcessToken( ProcessHandle: THandle; //要修改访问权限的进程句柄 DesiredAccess: DWORD; //指定你要进行的操作类型 var TokenHandle: THandle//返回的访问令牌指针 ): BOOL; AdjustTokenPrivileges() :调整进程的权限. function AdjustTokenPrivileges( TokenHandle: THandle; // 访问令牌的句柄 DisableAllPrivileges: BOOL; // 决定是进行权限修改还是除能(Disable)所有权限 const NewState: TTokenPrivileges; { 指明要修改的权限,是一个指向TOKEN_PRIVILEGES结构的指针,该结构包含一个数组, 数据组的每个项指明了权限的类型和要进行的操作; } BufferLength: DWORD; //结构PreviousState的长度,如果PreviousState为空,该参数应为 0 var PreviousState: TTokenPrivileges; // 指向TOKEN_PRIVILEGES结构的指针,存放修改前的访问权限的信息 var ReturnLength: DWORD //实际PreviousState结构返回的大小 ) : BOOL; 远程注入DLL其实是通过 CreateRemoteThread 建立一个远程线程调用 LoadLibrary 函数来加载我们指定的DLL,可是如何能让远程线程知道我要加载DLL呢,要知道在Win32系统下,每个进程都拥有自己的4G虚拟地址空间,各个进程之间都是相互独立的。所我们需要在远程进程的内存空间里申请一块内存空间,写入我们的需要注入的 DLL 的路径. 需要用到的 API 函数有: OpenProcess():打开目标进程,得到目标进程的操作权限,详细参看MSDN function OpenProcess( dwDesiredAccess: DWORD; // 希望获得的访问权限 bInheritHandle: BOOL; // 指明是否希望所获得的句柄可以继承 dwProcessId: DWORD // 要访问的进程ID ): THandle; VirtualAllocEx():用于在目标进程内存空间中申请内存空间以写入DLL的文件名 function VirtualAllocEx( hProcess: THandle; // 申请内存所在的进程句柄 lpAddress: Pointer; // 保留页面的内存地址;一般用nil自动分配 dwSize, // 欲分配的内存大小,字节单位;注意实际分 配的内存大小是页内存大小的整数倍 flAllocationType: DWORD; flProtect: DWORD ): Pointer; WriteProcessMemory():往申请到的空间中写入DLL的文件名 function WriteProcessMemory( hProcess: THandle; //要写入内存数据的目标进程句柄 const lpBaseAddress: Pointer; //要写入的目标进程的内存指针, 需以 VirtualAllocEx() 来申请 lpBuffer: Pointer; //要写入的数据 nSize: DWORD; //写入数据的大小 var lpNumberOfBytesWritten: DWORD //实际写入的大小 ): BOOL; 然后就可以调用 CreateRemoteThread 建立远程线程调用 LoadLibrary 函数来加载我们指定的DLL. CreateRemoteThread() //在一个远程进程中建立线程 function CreateRemoteThread( hProcess: THandle; //远程进程的句柄 lpThreadAttributes: Pointer; //线程安全描述字,指向SECURITY_ATTRIBUTES结构的指针 dwStackSize: DWORD; //线程栈大小,以字节表示 lpStartAddress: TFNThreadStartRoutine; // 一个TFNThreadStartRoutine类型的指针,指向在远程进程中执行的函数地址 lpParameter: Pointer; //传入参数的指针 dwCreationFlags: DWORD; //创建线程的其它标志 var lpThreadId: DWORD //线程身份标志,如果为0, 则不返回 ): THandle; 整个远程注入DLL的具体实现代码如下: function InjectDll(const DllFullPath: string; const dwRemoteProcessId: Cardinal): Boolean; var hRemoteProcess, hRemoteThread: THandle; pszLibFileRemote: Pointer; pszLibAFilename: PwideChar; pfnStartAddr: TFNThreadStartRoutine; memSize, WriteSize, lpThreadId: Cardinal; begin Result := false; // 调整权限,使程序可以访问其他进程的内存空间 if EnableDebugPriv then begin //打开远程线程 PROCESS_ALL_ACCESS 参数表示打开所有的权限 hRemoteProcess := OpenProcess(PROCESS_ALL_ACCESS, false, dwRemoteProcessId); try // 为注入的dll文件路径分配内存大小,由于为WideChar,故要乘2 GetMem(pszLibAFilename, Length(DllFullPath) * 2 + 1); // 之所以要转换成 WideChar, 是因为当DLL位于有中文字符的路径下时不会出错 StringToWideChar(DllFullPath, pszLibAFilename, Length(DllFullPath) * 2 + 1); // 计算 pszLibAFilename 的长度,注意,是以字节为单元的长度 memSize := (1 + lstrlenW(pszLibAFilename)) * SizeOf(WCHAR); //使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名空间 pszLibFileRemote := VirtualAllocEx(hRemoteProcess, nil, memSize, MEM_COMMIT, PAGE_READWRITE); if Assigned(pszLibFileRemote) then begin //使用WriteProcessMemory函数将DLL的路径名写入到远程进程的内存空间 if WriteProcessMemory(hRemoteProcess, pszLibFileRemote, pszLibAFilename, memSize, WriteSize) and (WriteSize = memSize) then begin lpThreadId := 0; // 计算LoadLibraryW的入口地址 pfnStartAddr := GetProcAddress(LoadLibrary('Kernel32.dll'), 'LoadLibraryW'); // 启动远程线程LoadLbraryW,通过远程线程调用创建新的线程 hRemoteThread := CreateRemoteThread(hRemoteProcess, nil, 0, pfnStartAddr, pszLibFileRemote, 0, lpThreadId); // 如果执行成功返回 True; if (hRemoteThread 0) then Result := true; // 释放句柄 CloseHandle(hRemoteThread); end; end; finally // 释放句柄 CloseHandle(hRemoteProcess); end; end; end; 接下来要说的是如何卸载注入目标进程中的DLL,其实原理和注入DLL是完全相同的,只是远程调用调用的函数不同而已,这里要调用的是FreeLibrary,代码如下: function UnInjectDll(const DllFullPath: string; const dwRemoteProcessId: Cardinal): Boolean; // 进程注入和取消注入其实都差不多,只是运行的函数不同而已 var hRemoteProcess, hRemoteThread: THandle; pszLibFileRemote: PChar; pszLibAFilename: PwideChar; pfnStartAddr: TFNThreadStartRoutine; memSize, WriteSize, lpThreadId, dwHandle: Cardinal; begin Result := false; // 调整权限,使程序可以访问其他进程的内存空间 if EnableDebugPriv then begin //打开远程线程 PROCESS_ALL_ACCESS 参数表示打开所有的权限 hRemoteProcess := OpenProcess(PROCESS_ALL_ACCESS, false, dwRemoteProcessId); try // 为注入的dll文件路径分配内存大小,由于为WideChar,故要乘2 GetMem(pszLibAFilename, Length(DllFullPath) * 2 + 1); // 之所以要转换成 WideChar, 是因为当DLL位于有中文字符的路径下时不会出错 StringToWideChar(DllFullPath, pszLibAFilename, Length(DllFullPath) * 2 + 1); // 计算 pszLibAFilename 的长度,注意,是以字节为单元的长度 memSize := (1 + lstrlenW(pszLibAFilename)) * SizeOf(WCHAR); //使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名空间 pszLibFileRemote := VirtualAllocEx(hRemoteProcess, nil, memSize, MEM_COMMIT, PAGE_READWRITE); if Assigned(pszLibFileRemote) then begin //使用WriteProcessMemory函数将DLL的路径名写入到远程进程的内存空间 if WriteProcessMemory(hRemoteProcess, pszLibFileRemote, pszLibAFilename, memSize, WriteSize) and (WriteSize = memSize) then begin // 计算GetModuleHandleW的入口地址 pfnStartAddr := GetProcAddress(LoadLibrary('Kernel32.dll'), 'GetModuleHandleW'); //使目标进程调用GetModuleHandleW,获得DLL在目标进程中的句柄 hRemoteThread := CreateRemoteThread(hRemoteProcess, nil, 0, pfnStartAddr, pszLibFileRemote, 0, lpThreadId); // 等待GetModuleHandle运行完毕 WaitForSingleObject(hRemoteThread, INFINITE); // 获得GetModuleHandle的返回值,存在dwHandle变量中 GetExitCodeThread(hRemoteThread, dwHandle); // 计算FreeLibrary的入口地址 pfnStartAddr := GetProcAddress(LoadLibrary('Kernel32.dll'), 'FreeLibrary'); // 使目标进程调用FreeLibrary,卸载DLL hRemoteThread := CreateRemoteThread(hRemoteProcess, nil, 0, pfnStartAddr, Pointer(dwHandle), 0, lpThreadId); // 等待FreeLibrary卸载完毕 WaitForSingleObject(hRemoteThread, INFINITE); // 如果执行成功返回 True; if hRemoteProcess 0 then Result := true; // 释放目标进程中申请的空间 VirtualFreeEx(hRemoteProcess, pszLibFileRemote, Length(DllFullPath) + 1, MEM_DECOMMIT); // 释放句柄 CloseHandle(hRemoteThread); end; end; finally // 释放句柄 CloseHandle(hRemoteProcess); end; end; end;

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧