【驱动开发】:进程注入相关问题
进程注入相关问题
OBERVIEW
1.为什么要把dll注入到某些进程中?
将DLL(动态链接库)注入到另一个进程中,通常是为了扩展或修改目标进程的行为,而无需修改其原始代码。这种技术在多种场景中都有应用:
DLL注入是一种强大的技术,不当的DLL注入可能导致程序不稳定甚至系统崩溃。
- 增强功能:通过向应用程序注入自定义的DLL,可以为其添加原本不具有的新功能。例如,某些第三方插件系统就是基于这种方式工作的。
- 调试和逆向工程:开发者可以通过注入DLL来监视、分析或调试一个正在运行的应用程序。这对于了解软件的工作原理或者查找并修复错误非常有用。
- 自动化操作:一些自动化工具可能需要直接与应用程序内部交互,这时可以通过注入DLL的方式来实现所需的操作。
- 安全软件:防病毒软件和防火墙可能会使用DLL注入技术来监控特定进程的行为,以检测潜在的安全威胁。
- 破解软件:利用DLL注入来篡改软件行为,比如绕过授权验证等。
2.进程注入有哪些方式?
dll注入是指将一个动态库加载到另一个进程的地址空间中,从而达到扩展或修改该进程的目的,
注入方式如下:
- CreateRemoteThread:最常用的动态库注入方式,通过在目标进程中创建线程来调用LoadLibrary函数,从而加载指定的动态库。
- SetWindowsHookEx:利用windows的钩子机制进行动态库注入,常用于拦截和处理特定类型的windows消息。
- AppInit_DLLs:通过修改注册表键
KEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs可以指定随用户32位应用程序一起加载的dll,64位系统需要修改相应的64位注册表路径。 - 内存映射文件:通过共享内存的方式让dll动态库代码被目标进程执行。
- 远程进程的PEB(Process Environment Block)操作:直接操作目标进程的环境块来加载dll(复杂且不稳定)
注入的主要步骤:
- 打开目标进程:使用
OpenProcess函数获取目标进程的句柄,需要有适当的权限才能成功执行这一步。 - 分配内存:使用
VirtualAllocEx函数为目标进程分配足够的内存空间,用于存储DLL的路径名称。 - 写入DLL路径:利用
WriteProcessMemory函数将DLL的完整路径名写入到之前分配的内存空间中。 - 获取LoadLibrary地址:找到
kernel32.dll中的LoadLibraryA(或LoadLibraryW)函数的地址,这个函数负责加载DLL。 - 创建远程线程:使用
CreateRemoteThread函数,在目标进程中创建一个新线程,并将LoadLibrary的地址作为线程入口点,同时传递前面写入的DLL路径地址作为参数。 - 等待加载完成:可选择等待远程线程完成,即等待DLL加载完毕。
- 清理资源:如果不需要了,记得释放分配的内存和关闭打开的进程句柄等。
3.进程如何防止被注入?
反注入,即防止其他进程或恶意软件将dll注入到自己的地址空间中,是一个复杂的过程。
因为windows操作系统本身提供了多种机制允许动态库加载,这同时也为注入提供了途径,常见的防御措施和技术来防止DLL注入:
- 代码完整性检查:
- 定期检查自身的内存空间,确保没有未授权的代码被插入。如果发现异常,可以采取措施如重启进程、记录日志等。
- 保护进程的内存空间:
- 使用
VirtualProtectEx函数将关键内存区域设置为不可写(只读),从而增加DLL注入的难度。 - 设置DEP(数据执行保护)和ASLR(地址空间布局随机化),这些技术可以帮助减少攻击面。
- 使用
- 监控模块加载:
- 利用API Hooking技术拦截对
LoadLibrary系列函数(如LoadLibraryA,LoadLibraryW,LoadLibraryExA,LoadLibraryExW)的调用,验证即将加载的DLL是否经过授权。 - 注册并实现
AppDomain.CurrentDomain.AssemblyResolve事件处理程序(针对.NET应用程序),控制外部DLL的加载。
- 利用API Hooking技术拦截对
- 增强权限管理:
- 确保应用以最低权限运行,减少潜在攻击者利用漏洞进行DLL注入的机会。
- 对于敏感操作考虑使用更严格的安全模型,比如Windows服务在较低权限下运行。
- 使用安全开发实践:
- 遵循安全编码指南,避免缓冲区溢出等常见漏洞,这些漏洞可能被用来作为注入点。
- 进行定期的安全审计和渗透测试,识别并修复可能存在的安全隐患。
- 利用操作系统特性:
- Windows 10引入了受保护的进程功能,能够极大地限制其他进程对自身进程空间的操作,包括DLL注入。
- 对于驱动级保护,可以探索微软的Protected Process Light (PPL) 或 Protected Process (PP)机制。
需要注意,没有任何方法能提供绝对的安全保证。攻击者总是寻找新的方法绕过现有的防护措施。因此保持系统和应用程序更新,及时修补已知漏洞是至关重要的。此外结合使用上述多种策略可以显著提高防护效果。
4.进程和镜像的区别?
在 Windows 内核中,进程Process 和 镜像Image 是两个非常相关但完全不同的概念,理解它们的区别对于理解 DLL 注入、驱动开发等底层工作非常关键。
进程:是指一个正在运行的程序实例,代表着独立的执行环境,其拥有自己的:虚拟地址空间、句柄表、安全上下文、多个线程
当调用 CreateProcess() 或类似 API 时,系统会执行以下步骤:
-
创建进程对象(EPROCESS)
-
创建初始线程(ETHREAD)
-
开始加载可执行文件到内存中(但此时不一定完全执行)
-
触发进程创建通知回调(驱动层可注册)
驱动可以通过
PsSetCreateProcessNotifyRoutine注册回调函数,在每次有进程被创建或销毁时收到通知
镜像:镜像是指可执行文件或dll动态库,被加载到内存中的映射数据结构。其包括 .text代码段、.data数据段、.reloc重定位表、rdata只读数据
- 镜像 = 文件在磁盘上的内容 + 被加载到进程地址空间中
每当系统加载一个模块.exe \ .dll时,会触发镜像加载回调,这是由 PsSetLoadImageNotifyRoutine 注册的驱动来响应的。其可以监控:
- 主exe加载
- 系统dll加载(如ntdll.dll、kernal32.dll)
- 自定义dll加载
| 属性 | 进程 | 镜像 |
|---|---|---|
| 对应结构体 | EPROCESS | 无单独结构,通常为 LDR_DATA_TABLE_ENTRY 列表节点 |
| 触发通知 | PsSetCreateProcessNotifyRoutine | PsSetLoadImageNotifyRoutine |
| 生命周期 | 从进程创建到退出 | 每个模块加载到进程地址空间中 |
| 关注的内容 | 进程ID、权限、句柄表、地址空间等 | 加载模块的路径、加载地址、是否系统DLL等 |
| 是否可注入点 | 是:设置全局状态,准备注入等 | 是:DLL加载稳定后触发注入(如kernel32加载时) |
| 多次出现可能性 | 每个PID唯一 | 一个进程中可加载多个镜像 |
5.常见的CPU架构/指令集
系统架构(System Architecture)= 操作系统(OS)+ CPU架构(ISA),其定义了程序在哪个系统和cpu上能够运行 以及如何运行。
- 硬件平台架构:x86 / x64 / ARM 等
- 操作系统架构:32 位或 64 位
- 用户程序架构:是否运行在兼容层,如 Wow64、QEMU
常见cpu指令集架构:Instruction Set Architecture, ISA
| 架构名称 | 位数 | 类型 | 代表CPU | 特点 |
|---|---|---|---|---|
| x86 | 32-bit | CISC | Intel/AMD 早期处理器 | 指令复杂、向后兼容 DOS/Win9x |
| x64/AMD64 | 64-bit | CISC | Intel Core, Ryzen 等 | 向下兼容 x86,更强大的寄存器与寻址 |
| ARMv7 | 32-bit | RISC | 老Android 手机、树莓派 | 节能,但能力有限 |
| ARM64/AArch64 | 64-bit | RISC | 手机/嵌入式设备/Apple M 芯片 | 高能效低功耗、精简指令集、适合移动场景 |
Windows常见系统架构:
| 硬件架构 | 操作系统架构 | 应用程序 | 场景 |
|---|---|---|---|
| x86 | 32 位 Windows | 32 位程序 | 传统老系统(WinXP、Win7-32) |
| x64/AMD64 | 64 位 Windows | 64 位程序 | 主流 PC 系统(Win10/11) |
| x64/AMD64 | 64 位 Windows | 32 位程序 | 通过 Wow64 仿真运行 |
| ARM64 | Windows on ARM | ARM64 程序 | 原生 ARM 架构应用(如 UWP) |
| ARM64 | Windows on ARM | x86/x64 程序 | 借助仿真器(ARM64EC、x64 仿真) |
- Windows x64 系统能通过 WOW64 子系统 运行 x86 应用。
- Windows ARM64 系统(如Surface Pro X)支持运行 ARM64 原生程序 + x86/x64 模拟程序。
- 注入dll\驱动时必须与目标的应用程序架构一致。
Linux常见系统架构:
| 硬件架构 | 支持情况 | 常见发行版 | 场景 |
|---|---|---|---|
| x86 | 已经式微 | Debian 32-bit、旧版 Ubuntu | 老PC、虚拟机 |
| x64/AMD64 | 主流架构 | Ubuntu, Fedora, Arch, CentOS | 主流PC、服务器 |
| ARMv7 | 轻量支持 | Raspbian, Ubuntu Mate | 树莓派、老Android 手机 |
| ARM64/AArch64 | 强力支持 | Ubuntu ARM64, Fedora ARM, Alpine ARM | 树莓派4/5、安卓盒子、M1/M2 Mac、新手机、嵌入设备 |
- Linux 借助
QEMU可在不同平台上 跨架构 运行程序,例如在 x64 上运行 ARM 程序。 - ARM 平台(如树莓派)可以运行混合 32/64 位用户程序(如 ARM64 核心 + ARMv7 程序)
6.为什么会有x86/x64/ARM64的划分?
因为计算机的硬件(CPU)只能执行特定格式的机器指令,这些格式由指令集(ISA)决定,
架构之分源于CPU的指令集差异,不同架构的程序机器码完全不同,不可通用。程序必须匹配操作系统和硬件架构,除非通过兼容层或仿真器。
不同的指令集ISA的不同点:
- 指令长度不同
- 寄存器数量和用途不同
- 调用约定、内存模型不同
- 汇编语言和机器码完全不同
所以由于cpu被设计使用某种指令集ISA(x86、x64、arm64),所以操作系统内核必须要能够执行该架构指令(调度进程、管理内存),最后应用程序必须编译为对应架构的机器码,最终对应架构的应用程序才能在,对应架构的操作系统上运行、被对应架构的cpu执行。

7.应用程序为什么要匹配对应的cpu架构?
如果将一段编译为 ARM64 的程序,放在一台 x64 架构的机器上运行,会发生什么?
答:直接崩溃(非法指令)。因为:
- ARM64 的二进制指令完全无法被 x64 CPU 理解;
- 操作系统也无法加载该架构格式的 ELF/PE 可执行文件;
- CPU 会抛出 “非法指令”(Invalid Opcode)。
因此必须有:
- 与 CPU 架构匹配的 操作系统
- 操作系统内部提供该架构的 加载器、调度器
- 与系统架构一致的 应用程序
8.同一份程序如何交叉编译成多个架构?
交叉编译是指在一种架构上(如 x64 PC),生成另一种架构(ARM、MIPS)的可执行文件的过程。
借助交叉编译器(cross-compiler)可以实现应用程序的交叉编译:
如主机架构:x86_64进行交叉编译:
- aarch64-linux-gnu-gcc:生成arm64程序
- arm-linux-gnueabihf-gcc:生成arm32程序
- x86_64-w64-mingw32-gcc:生成Windows x64程序(从Linux)
- riscv64-linux-gnu-gcc:生成RISC-V程序
# 主要步骤
# 安装交叉编译工具链
# 交叉编译
# 检查目标架构
# 输出: ELF 64-bit LSB executable, ARM aarch64 ...
# 输出: PE32+ executable (console) x86-64 ...
# 1.Linux C 程序交叉编译为 ARM64
sudo apt install gcc-aarch64-linux-gnu
aarch64-linux-gnu-gcc hello.c -o hello_arm64
file hello_arm64
# 2.Linux 下交叉编译 Windows 程序
sudo apt install mingw-w64
x86_64-w64-mingw32-gcc hello.c -o hello.exe
file hello.exe
或者使用cmake支持多架构交叉编译:
mkdir build_arm64 && cd build_arm64
cmake .. \
-DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \
-DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++
make
9.驱动/注入如何针对不同系统架构适配?
驱动或注入类程序在不同系统架构上运行时,必须适配对应的体系结构差异,这是系统级开发关键的一环,与操作系统最紧耦合的工作。
- 驱动适配:INF支持多平台,使用条件编译,针对不同内核结构处理
- 注入适配:区分 x86/x64/WOW64,准备对应架构的 shellcode/DLL
- 编译适配:使用交叉编译或多目标编译,准备多版本的驱动/注入代码
- 接口适配:系统调用号、结构体偏移、PEB/TEB 等都可能架构相关
- 流程适配:注入流程(如 APC/RemoteThread)在不同架构下有差异
驱动适配
-
编译平台和目标架构区分:
-
用WDK做驱动开发时需要配置
TargetPlatformVersion和TargetArchitecture<Configuration> <TargetPlatformVersion>10.0.19041.0</TargetPlatformVersion> <TargetArchitecture>x64</TargetArchitecture> </Configuration> -
编译多个架构版本的驱动(x86.sys、x64.sys、arm64.sys)
-
使用 INF 文件中设置架构区段:
-
-
条件编译与架构差异处理
#ifdef _M_X64 // 64位专属处理,比如 EPROCESS 偏移、系统调用结构体等 #elif defined(_M_IX86) // 32位处理 #elif defined(_M_ARM64) // ARM64 架构处理(Windows 11 ARM 平台) #endif -
不同架构的内核结构体不一样:
EPROCESS、ETHREAD、PEB、TEB结构体字段在不同架构偏移不同- 不同架构有不同内核线程/地址空间实现(如 ARM 没有 segmentation)
- 用调试器获取对应字段偏移(WinDbg、ReClass、Ghidra)
- 构建多个版本或动态获取偏移(如使用符号解析)
注入适配
- 区分目标进程架构
- 注入代码必须与目标进程架构一致
- 64 位进程:只能注入 64 位 DLL(不能注入 32 位 DLL)
- 32 位进程:只能注入 32 位 DLL(不能注入 64 位 DLL)
- WOW64 的注入方式与普通进程略有不同(需要特殊处理)
- Windows ARM 支持:
- 64 位 ARM 应用 -> 注入 ARM64 DLL
- 32 位 ARM 应用 -> 注入 ARM32 DLL
- 通过 x86 仿真支持 32 位 x86 应用(WOW64 仿真)-> 注入 x86 DLL
10.驱动分层
驱动分层win
Windows 采用 WDM(Windows Driver Model) 作为驱动程序的基础框架,其核心分层结构如下:
┌───────────────────────────────────────────────┐
│ 用户模式驱动 │
│ (WDF UMDF、WMI、性能计数器、打印驱动等) │
├───────────────────────────────────────────────┤
│ 内核模式驱动 │
│ ┌───────────────────────────────────────────┐ │
│ │ 过滤驱动层 │ │
│ │ (安全过滤、加密过滤、性能监控过滤等) │ │
│ ├───────────────────────────────────────────┤ │
│ │ 功能驱动层 │ │
│ │ (实现设备核心功能,如网卡驱动、声卡驱动) │ │
│ ├───────────────────────────────────────────┤ │
│ │ 总线驱动层 │ │
│ │ (管理设备连接,如PCIe总线、USB总线) │ │
│ └───────────────────────────────────────────┘ │
├───────────────────────────────────────────────┤
│ 硬件抽象层 (HAL) │
│ (屏蔽不同硬件平台差异,如x86、ARM、服务器平台) │
├───────────────────────────────────────────────┤
│ 硬件 │
│ (CPU、内存、外设控制器、I/O端口等物理设备) │
└───────────────────────────────────────────────┘
- 过滤驱动(Filter Driver):
- 位于功能驱动之上,用于扩展或修改设备行为(如 BitLocker 加密过滤、防病毒软件的文件系统过滤)
- 功能驱动(Function Driver):
- 实现设备的核心功能(如硬盘读写、网卡数据收发)是驱动栈的核心。
- 总线驱动(Bus Driver):
- 管理设备与系统的物理连接(如 USB 总线枚举设备、PCIe 分配中断和内存地址)
- 硬件抽象层:
- 将底层硬件差异(如不同CPU架构的中断处理)抽象为统一接口,使内核上层无需关心具体硬件平台。
驱动分层Linux
Linux 采用模块化驱动架构,通过内核模块(Kernel Module)实现分层,核心结构如下:
┌───────────────────────────────────────────────┐
│ 用户空间程序 │
│ (应用程序、系统工具、库函数如libusb、CUDA等) │
├───────────────────────────────────────────────┤
│ 系统调用接口 │
│ (用户空间与内核空间的桥梁,如open()、read()、ioctl()) │
├───────────────────────────────────────────────┤
│ 内核空间驱动 │
│ ┌───────────────────────────────────────────┐ │
│ │ 虚拟文件系统 (VFS) │ │
│ │ (统一文件、设备、网络的访问接口) │ │
│ ├───────────────────────────────────────────┤ │
│ │ 设备类驱动层 │ │
│ │ (块设备、字符设备、网络设备等抽象接口) │ │
│ ├───────────────────────────────────────────┤ │
│ │ 总线驱动层 │ │
│ │ (PCI、USB、I2C、SPI等总线控制器驱动) │ │
│ ├───────────────────────────────────────────┤ │
│ │ 硬件抽象层 (HDA) │ │
│ │ (部分设备类型特有,如ALSA音频抽象) │ │
│ └───────────────────────────────────────────┘ │
├───────────────────────────────────────────────┤
│ 硬件 │
│ (同Windows,物理设备与控制器) │
└───────────────────────────────────────────────┘
- 虚拟文件系统(VFS):
- Linux 驱动的核心抽象层,将所有设备(硬盘、键盘、网卡等)统一为 “文件” 接口,应用程序通过
open()、read()等系统调用访问任何设备。
- Linux 驱动的核心抽象层,将所有设备(硬盘、键盘、网卡等)统一为 “文件” 接口,应用程序通过
- 设备类驱动(Device Class Driver):
- 按设备类型划分(如块设备驱动处理硬盘,网络设备驱动处理网卡),提供与 VFS 对接的标准接口(如
file_operations结构体)
- 按设备类型划分(如块设备驱动处理硬盘,网络设备驱动处理网卡),提供与 VFS 对接的标准接口(如
- 总线驱动(Bus Driver):
- 管理设备连接和资源分配(如 USB 主机控制器驱动枚举 USB 设备,分配地址)。
- 硬件抽象层(HDA):
- 部分复杂设备(如音频、图形)的特有抽象层,进一步屏蔽硬件差异(如 ALSA 驱动为不同声卡提供统一 API)
驱动分层优势
驱动程序分层架构,通过清晰的层次划分使得操作系统可以:
- 支持海量多样化的硬件设备(每年新增数万种外设);
- 快速迭代驱动功能(如更新网卡驱动支持 5G,无需修改上层应用);
- 提高系统安全性和稳定性(通过隔离和抽象)。
无论是 Windows、Linux 还是嵌入式系统如 RTOS,分层驱动模型始终是操作系统设计的基石
参考网址
- Hook技术:
- https://www.cnblogs.com/LyShark/p/11692436.html
- https://cloud.tencent.com/developer/article/2091105
- https://www.cnblogs.com/from-zero/p/14793057.html
- 进程注入:注入进程的24种方式:
- https://www.cnblogs.com/LittleHann/p/6336950.html
- 驱动开发:
- win驱动:https://blog.csdn.net/m0_46239139/article/details/136086822
- linux驱动:https://blog.csdn.net/qq21497936/article/details/130534343
- 驱动调试:
- win驱动调试:https://blog.csdn.net/qq_40277608/article/details/109765965
- linux驱动调试:
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)