[逆向工程]C++实现DLL注入:原理、实现与防御全解析(二十五)

[逆向工程]C++实现DLL注入:原理、实现与防御全解析(二十五)

引言

DLL注入(DLL Injection)是Windows系统下实现进程间通信、功能扩展、监控调试的核心技术之一。本文将从原理分析、代码实现、实战调试到防御方案,全方位讲解如何用C++实现DLL注入,并提供可直接编译的完整项目代码。

一、资源准备

1.资源准备

gmp.exe 被注入的程序

injector.exe 注入器

mandaohook.dll 需注入的dll

2.任务目标

将编写好的mandaohook.dll通过injector.exe注入器注入到gmp.exe可运行程序中。gmp.exe是一个密码学工具箱。

二、DLL注入的核心原理

DLL注入的本质是强制目标进程加载指定的DLL文件,其核心流程为:

  1. 获取目标进程句柄:通过进程ID或进程名定位目标
  2. 在目标进程中分配内存:用于存储DLL路径
  3. 写入DLL路径:将DLL的完整路径写入目标内存
  4. 创建远程线程:通过LoadLibrary加载DLL

三、关键API函数解析

API函数作用描述关键参数说明
OpenProcess打开目标进程dwProcessId:目标进程ID
VirtualAllocEx在目标进程分配内存lpAddress:分配内存地址
WriteProcessMemory向目标内存写入数据lpBaseAddress:目标内存地址
CreateRemoteThread在目标进程创建远程线程lpStartAddress:线程入口点
GetProcAddress获取LoadLibrary函数地址lpProcName:函数名

四、完整C++实现代码

1. 注入器代码(Injector.cpp)
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
#include <memory>// 自动释放资源模板
template<typename T>
struct HandleDeleter {void operator()(T* handle) const {if (handle) CloseHandle(handle);}
};
using UniqueHandle = std::unique_ptr<void, HandleDeleter<void>>;// 查找进程ID(优化版)
DWORD FindProcessId(const wchar_t* processName) {PROCESSENTRY32W pe = { sizeof(pe) };UniqueHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));if (!snapshot.get()) return 0;if (Process32FirstW(snapshot.get(), &pe)) {do {if (_wcsicmp(processName, pe.szExeFile) == 0) {return pe.th32ProcessID;}} while (Process32NextW(snapshot.get(), &pe));}return 0;
}// 注入主函数
int main() {// 1. 查找进程const DWORD pid = FindProcessId(L"gmp.exe");if (!pid) {std::wcerr << L"错误:未找到进程!" << std::endl;return EXIT_FAILURE;}// 2. 打开进程UniqueHandle hProcess(OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,FALSE, pid));if (!hProcess) {std::wcerr << L"打开进程失败(代码:" << GetLastError() << L")" << std::endl;return EXIT_FAILURE;}// 3. 获取DLL路径wchar_t dllPath[MAX_PATH];if (!GetFullPathNameW(L"mandaohook.dll", MAX_PATH, dllPath, nullptr)) {std::wcerr << L"获取路径失败(代码:" << GetLastError() << L")" << std::endl;return EXIT_FAILURE;}// 4. 分配内存const size_t pathSize = (wcslen(dllPath) + 1) * sizeof(wchar_t);UniqueHandle pRemoteMem(VirtualAllocEx(hProcess.get(), nullptr, pathSize, MEM_COMMIT, PAGE_READWRITE));if (!pRemoteMem) {std::wcerr << L"内存分配失败(代码:" << GetLastError() << L")" << std::endl;return EXIT_FAILURE;}// 5. 写入路径if (!WriteProcessMemory(hProcess.get(), pRemoteMem.get(), dllPath, pathSize, nullptr)) {std::wcerr << L"写入内存失败(代码:" << GetLastError() << L")" << std::endl;return EXIT_FAILURE;}// 6. 获取LoadLibrary地址const auto pLoadLibrary = reinterpret_cast<LPTHREAD_START_ROUTINE>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW"));if (!pLoadLibrary) {std::wcerr << L"获取函数地址失败(代码:" << GetLastError() << L")" << std::endl;return EXIT_FAILURE;}// 7. 创建远程线程UniqueHandle hThread(CreateRemoteThread(hProcess.get(), nullptr, 0,pLoadLibrary, pRemoteMem.get(), 0, nullptr));if (!hThread) {std::wcerr << L"创建线程失败(代码:" << GetLastError() << L")" << std::endl;return EXIT_FAILURE;}// 8. 等待注入完成WaitForSingleObject(hThread.get(), INFINITE);std::wcout << L"注入成功!" << std::endl;return EXIT_SUCCESS; 
}

编译:

g++ -shared -o mandaohook.dll mandaohook.cpp -luser32 -lgdi32 -Wall

在这里插入图片描述

2.目标DLL头文件(mandaohook.h)
#pragma once
#include <Windows.h>LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam);
3. 目标DLL代码(mandaohook.cpp)
/*********************** myhook.cpp ***********************/
#include "mandaohook.h"// 全局变量
HHOOK g_hHook = NULL;
HWND g_hNotepadppWnd = NULL;// 前向声明线程函数
DWORD WINAPI ThreadProc(LPVOID lpParameter);//-----------------------------------------------------------------------------
// DLL入口函数
//-----------------------------------------------------------------------------
BOOL APIENTRY DllMain(HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:// 创建线程避免阻塞DllMainCreateThread(nullptr, 0, ThreadProc, hModule, 0, nullptr);break;case DLL_PROCESS_DETACH:if (g_hHook) {UnhookWindowsHookEx(g_hHook);g_hHook = nullptr;}break;}return TRUE;
}// 线程处理函数
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{HMODULE hModule = (HMODULE)lpParameter;// 使用 OutputDebugStringW 输出调试信息OutputDebugStringW(L"DLL成功注入gmp.exe!");MessageBoxW(nullptr, L"DLL成功注入gmp.exe!", L"提示", MB_OK);g_hNotepadppWnd = FindWindowExW(nullptr, nullptr, L"gmp.exe", nullptr);if (g_hNotepadppWnd) {g_hHook = SetWindowsHookExW(WH_KEYBOARD_LL,HookProc,hModule,0);}return 0;
}//-----------------------------------------------------------------------------
// 钩子处理函数
//-----------------------------------------------------------------------------
LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
{if (code == HC_ACTION) {const auto* pKbd = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);if (pKbd->vkCode == VK_F12 && (pKbd->flags & LLKHF_UP)) {MessageBoxW(g_hNotepadppWnd, L"安全提示:F12功能已被拦截!", L"安全防护", MB_ICONWARNING | MB_OK);return 1;}}return CallNextHookEx(g_hHook, code, wParam, lParam);
}

编译:

g++ -shared -o mandaohook.dll mandaohook.cpp -luser32 -lwininet -Wall -municode

在这里插入图片描述

五、测试结果

gmp.exe injector.exe mandaohook.dll放入同一个文件夹下:

在这里插入图片描述

1.先打开gmp.exe 工具

2.再打开DebugView

3.执行injector.exe 注入器注入

4.查看注入信息

可以先查看下gmp.exe PID
在这里插入图片描述
在这里插入图片描述

查看DebugView已注入。

六、技术难点与解决方案

1. 权限问题
  • 症状OpenProcess返回ERROR_ACCESS_DENIED
  • 解决:以管理员权限运行注入器
  • 代码实现
    #include <ShellAPI.h>
    ShellExecuteW(nullptr, L"runas", L"Injector.exe", nullptr, nullptr, SW_SHOW);
    
2. 路径转换问题
  • 症状:DLL路径包含中文字符导致写入失败
  • 解决:使用宽字符API并验证路径
    if (!PathFileExistsW(dllPath)) {// 处理路径不存在的情况
    }
    
3. 64/32位进程兼容
  • 症状:跨架构注入失败(如64位注入器操作32位进程)
  • 解决:使用Wow64DisableWow64FsRedirection
    PVOID oldValue = nullptr;
    Wow64DisableWow64FsRedirection(&oldValue);
    // 执行文件操作
    Wow64RevertWow64FsRedirection(oldValue);
    

七、防御DLL注入方案

  1. 进程保护:调用SetProcessMitigationPolicy
    PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY policy = {};
    policy.MicrosoftSignedOnly = 1;
    SetProcessMitigationPolicy(ProcessSignaturePolicy, &policy, sizeof(policy));
    
  2. 钩子检测:定期检查LoadLibrary调用栈
  3. 内存保护:启用DEP和ASLR
    #pragma comment(linker, "/DYNAMICBASE:YES")
    #pragma comment(linker, "/NXCOMPAT")
    

八、实战调试技巧

  1. 调试输出:使用OutputDebugStringW
    OutputDebugStringW(L"[DEBUG] DLL已加载");
    
  2. 日志文件:写入临时文件监控行为
    FILE* f = _wfopen(L"C:\\inject_log.txt", L"a+");
    fwprintf(f, L"PID:%d 已注入\n", GetCurrentProcessId());
    fclose(f);
    
  3. Process Monitor:监控进程的DLL加载事件

如果本教程对您有帮助,请点赞❤️收藏⭐关注支持!欢迎在评论区留言交流技术细节!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/81224.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ROS2实战】在中国地区 Ubuntu 22.04 上安装 ROS 2 Humble 教程

本文介绍如何在中国大陆环境下顺利安装 ROS 2 Humble&#xff0c;包括使用清华镜像源、解决 locale 和 GPG 密钥问题、安装 ROS 软件包以及配置自动环境加载。 &#x1f31f; ROS 2 版本简介 ROS 2 是机器人操作系统的第二代版本&#xff0c;目前主要有两个长期支持&#xff0…

嵌入式学习笔记 - STM32 ADC 模块工作模式总结

ADC 模式总结&#xff1a; 一 单ADC模式&#xff08;是指ADC1,ADC2,ADC3中只有一个ADC被使用&#xff09; ①单通道&#xff1a; 非连续模式&#xff1a;非连续的意思就是单次&#xff0c;一次转换完成后就停止转换&#xff0c;除非再次被软件或者被外部触发启动&#xff1b…

Python训练打卡Day26

函数专题1&#xff1a;函数定义与参数 知识点回顾&#xff1a; 函数的定义变量作用域&#xff1a;局部变量和全局变量函数的参数类型&#xff1a;位置参数、默认参数、不定参数传递参数的手段&#xff1a;关键词参数传递参数的顺序&#xff1a;同时出现三种参数类型时 到目前为…

使用Docker部署Nacos

sudo systemctl start docker sudo systemctl enable docker docker --version 步骤 2: 拉取 Nacos Docker 镜像 拉取 Nacos 镜像&#xff1a; 你可以从 Docker Hub 上拉取官方的 Nacos 镜像&#xff0c;使用以下命令&#xff1a; docker pull nacos/nacos-server 这会从 …

Ubuntu 添加系统调用

实验内容 通过内核编译法添加一个不用传递参数的系统调用&#xff0c;其功能可自定义。 &#xff08;1&#xff09;添加系统调用号&#xff0c;系统会根据这个号找到syscall_table中的相应表项。具体做法是在syscall_64.tbl文件中添加系统调用号和调用函数的对应关系。 &#…

Javascript:WebAPI

获取网页元素 queryselector queryselector是 JavaScript 中用于选择 DOM 元素的重要方法&#xff0c;它允许使用 CSS 选择器语法来查找页面中的元素。 一般queryselector获取的元素都是html中第一个选择器的元素 支持选择器类型&#xff1a;类选择器(.class) &#xff0c…

十二、Hive 函数

作者&#xff1a;IvanCodes 日期&#xff1a;2025年5月1日 专栏&#xff1a;Hive教程 在数据处理的广阔天地中&#xff0c;我们常常需要对数据进行转换、计算、清洗或提取特定信息。Hive 提供了强大的内置运算符和丰富的内置函数库&#xff0c;它们就像魔法师手中的魔法棒&…

Linux之Nginx安装及配置原理篇(一)

Nginx安装及配置 前情回顾 首先针对Nginx进程模型&#xff0c;我们回顾一下它的原理机制&#xff0c;我们知道它是通过Master通过fork分发任务节点给予work节点&#xff0c;然后work节点触发了event事件&#xff0c;之后通过一个access_muttex互斥锁&#xff0c;来单线程调用我…

嵌入式培训之数据结构学习(五)栈与队列

一、栈 &#xff08;一&#xff09;栈的基本概念 1、栈的定义&#xff1a; 注&#xff1a;线性表中的栈在堆区&#xff08;因为是malloc来的&#xff09;&#xff1b;系统中的栈区存储局部变量、函数形参、函数返回值地址。 2、栈顶和栈底&#xff1a; 允许插入和删除的一端…

深度学习---知识蒸馏(Knowledge Distillation, KD)

一、知识蒸馏的本质与起源 定义&#xff1a; 知识蒸馏是一种模型压缩与迁移技术&#xff0c;通过将复杂高性能的教师模型&#xff08;Teacher Model&#xff09;所学的“知识”迁移到轻量级的学生模型&#xff08;Student Model&#xff09;&#xff0c;使学生模型在参数量和计…

ARP Detection MAC-Address Static

一、ARP Detection&#xff08;ARP检测&#xff09; ✅ 定义&#xff1a; ARP检测是一种防止ARP欺骗攻击的安全机制。它通过监控或验证网络中的ARP报文&#xff0c;来判断是否存在伪造的ARP信息。 &#x1f50d; 工作原理&#xff1a; 网络设备&#xff08;如交换机&#xf…

基于 Python 的界面程序复现:标准干涉槽型设计计算及仿真

基于 Python 的界面程序复现&#xff1a;标准干涉槽型设计计算及仿真 在工业设计与制造领域&#xff0c;刀具的设计与优化是提高生产效率和产品质量的关键环节之一。本文将介绍如何使用 Python 复现一个用于标准干涉槽型设计计算及仿真的界面程序&#xff0c;旨在帮助工程师和…

Python绘制南丁格尔玫瑰图:从入门到实战

Python绘制南丁格尔玫瑰图&#xff1a;从入门到实战 引言 南丁格尔玫瑰图&#xff08;Nightingale Rose Chart&#xff09;&#xff0c;也被称为极区图&#xff08;Polar Area Chart&#xff09;&#xff0c;是一种独特的数据可视化方式。这种图表由弗洛伦斯南丁格尔&#xff…

计算机操作系统概要

不谋万世者&#xff0c;不⾜谋⼀时。不谋全局者 &#xff0c;足谋⼀域 。 ——陈澹然《寤⾔》《迁都建藩议》 操作系统 一.对文件简单操作的常用基础指令 ls ls 选项 目录或⽂件名:罗列当前⽬录下的⽂件 -l&#xff1a;以长格式显示⽂件和⽬录的详细信息 -a 或 --all&…

<PLC><视觉><机器人>基于海康威视视觉检测和UR机械臂,如何实现N点标定?

前言 本系列是关于PLC相关的博文,包括PLC编程、PLC与上位机通讯、PLC与下位驱动、仪器仪表等通讯、PLC指令解析等相关内容。 PLC品牌包括但不限于西门子、三菱等国外品牌,汇川、信捷等国内品牌。 除了PLC为主要内容外,相关设备如触摸屏(HMI)、交换机等工控产品,如果有…

从专家编码到神经网络学习:DTM 的符号操作新范式

1st author: Paul Soulos paper: Differentiable Tree Operations Promote Compositional Generalization ICML 2023 code: psoulos/dtm: Differentiable Tree Machine 1. 问题与思路 现代深度学习在连续向量空间中取得了巨大成功&#xff0c;然而在处理具有显式结构&#x…

微信小程序第三方代开发模式技术调研与实践总结

🚀 微信小程序第三方代开发模式技术调研与实践总结 📖 前言 随着企业对私有化品牌运营诉求的增加,许多大型客户希望将原本由 SaaS 平台统一提供的小程序迁移至自有主体(AppID)下运行,同时又希望继续沿用 SaaS 平台的业务服务与数据托管方式。微信开放平台提供的“小程…

开启智能未来:DeepSeek赋能行业变革之路

前言 在人工智能重构生产关系的2025年&#xff0c;DeepSeek以其革命性的推理能力和Python生态的技术延展性&#xff0c;正在重塑内容创作与数据智能的边界。本书以"工具迭代思维升维"为双轮驱动&#xff0c;构建从认知突破到商业落地的完整知识图谱。 DeepSeek的崛…

常见三维引擎坐标轴 webgl threejs cesium blender unity ue 左手坐标系、右手坐标系、坐标轴方向

平台 / 引擎坐标系类型Up&#xff08;上&#xff09;方向Forward&#xff08;前进&#xff09;方向前进方向依据说明Unity左手坐标系YZtransform.forward 是 Z 轴正方向&#xff0c;默认摄像机朝 Z 看。Unreal Engine左手坐标系ZXUE 的角色面朝 X&#xff0c;默认使用 GetActor…

Cold Diffusion: Inverting Arbitrary Image Transforms Without Noise论文阅读

冷扩散&#xff1a;无需噪声的任意图像变换反转 摘要 标准扩散模型通常涉及两个核心步骤&#xff1a;图像降质 &#xff08;添加高斯噪声&#xff09;和图像恢复 &#xff08;去噪操作&#xff09;。本文发现&#xff0c;扩散模型的生成能力并不强烈依赖于噪声的选择&#xf…