赞
踩
麻了,之前写的博客全是收藏,没人点赞,来点赞行不行!
GitHub同步更新(已分类):DLL_Injection
Gitee同步更新(已分类)DLL_Injection
公众号:URLeisure 的复习仓库
公众号二维码见文末
以下是本篇文章正文内容,下面案例可供参考。
写在开头:感谢好友的不懈讲解!
个人水平有限,如有错误还请各位不吝赐教,在评论区指出错误或私信错误,感谢。
DLL 注入
(英语:DLL injection)是一种涉及计算机信息安全的特殊编程技术。
它可以强行使一个 进程
加载某个 动态链接库
以在其私有地址空间内运行指定 代码
(往往是恶意代码)。
DLL 注入
的常见手段是用外部 DLL 库覆盖一个程序原先的 DLL 库,目的是实现该程序的作者未预期的结果。
比如,注入的代码可以 挂钩(Hook)
系统消息或系统调用,以达到读取密码框的内容等危险目的,而一般编程手段无法达成这些目的。
能将任意代码注入任意进程的程序被称为 DLL 注入器(DLL injector)
。
Windows 操作系统中,每个进程都有自己 独立的 4G 虚拟内存空间
(保护模式),当程序真正使用时,操作系统才会分配对应的物理内存。
也就是 不同进程
有着自己 独立的地址空间
。
例如,对进程 A 中地址 0x1000000 处的数据进行修改,并不会改变进程 B 中地址 0x1000000 处的数据,甚至进程 B 中可能不存在此地址。
由于不同进程的地址空间相互独立(保护模式),我们很难编写能够与其它进程通信或控制其它进程的程序。
DLL 注入即是,存在进程 A、B,使进程 A 中的 dll 文件强行在进程 B 中加载,此时进程 A 的 dll 文件就进入了进程 B 的地址空间,并使进程 B 执行 dll 文件中的代码。
由于 dll 文件由恶意程序开发者设计,因此程序开发者可对程序 B(目标进程)进行自定义修改。
// dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "pch.h" #include "stdlib.h" #include <iostream> using namespace std; BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call){ case DLL_PROCESS_ATTACH: { // 当DLL被进程 <<第一次>> 调用时,导致DllMain函数被调用, HWND hwnd = GetActiveWindow(); MessageBox(hwnd, L"DLL已进入目标进程。", L"信息", MB_ICONINFORMATION); //弹出一个模态对话框 } } return TRUE; }
//我们注入记事本
system("start %windir%\\system32\\notepad.exe");//打开
/** *info ---> 存放快照进程信息的一个结构体 *processName ---> 进程名 * 通过获取系统快照,得到进程列表,通过进程名,遍历进程列表得到 pid */ BOOL getProcess32Info(PROCESSENTRY32* info, const TCHAR processName[]){ HANDLE handle; handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);//获得系统快照句柄 info->dwSize = sizeof(PROCESSENTRY32); Process32First(handle, info);//从快照中获取进程列表 while (Process32Next(handle, info) != FALSE){ if (wcscmp(processName, info->szExeFile) == 0){ return TRUE;//找到了 } } return FALSE; }
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, false, pid);//返回指定进程的打开句柄,并获得此进程最高权限
if (hProc == 0) return -1;
int pathSize = (wcslen(DllFullPath) + 1) * sizeof(wchar_t);//DllFullPath ---> dll 文件路径 计算所需空间大小
LPVOID buffer = VirtualAllocEx(hProc, 0, pathSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);//申请内存
if (buffer == 0) return -2;
if (!WriteProcessMemory(hProc, buffer, DllFullPath, pathSize, NULL)) return -3;//并判断是否成功
//调用Kernel32.dll中的LoadLibraryW方法用以加载DLL文件
LPVOID pFunc = GetProcAddress(GetModuleHandleA("Kernel32.dll"), "LoadLibraryW");
//创建一个在另一个进程的虚拟地址空间中运行的线程
CreateRemoteThread(hProc, 0, 0, (LPTHREAD_START_ROUTINE)pFunc, buffer, 0, 0);
dllmain.cpp(示例):
// dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "pch.h" #include "stdlib.h" #include <iostream> using namespace std; BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { // 当DLL被进程 <<第一次>> 调用时,导致DllMain函数被调用, HWND hwnd = GetActiveWindow(); MessageBox(hwnd, L"DLL已进入目标进程。", L"信息", MB_ICONINFORMATION); //弹出一个模态对话框 } } return TRUE; }
注入器代码(示例):
#include <windows.h> #include <iostream> #include <Tlhelp32.h> #include <stdio.h> #include <tchar.h> using namespace std; BOOL getProcess32Info(PROCESSENTRY32 *info, const TCHAR processName[]) { HANDLE handle; handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); info->dwSize = sizeof(PROCESSENTRY32); Process32First(handle, info); while (Process32Next(handle, info) != FALSE) { if (wcscmp(processName, info->szExeFile) == 0) { return TRUE; } } return FALSE; } int InjectDLL(const wchar_t *DllFullPath, const DWORD pid) { HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, false, pid); if (hProc == 0) return -1; int pathSize = (wcslen(DllFullPath) + 1) * sizeof(wchar_t); LPVOID buffer = VirtualAllocEx(hProc, 0, pathSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (buffer == 0) return -2; if (!WriteProcessMemory(hProc, buffer, DllFullPath, pathSize, NULL)) return -3; LPVOID pFunc = GetProcAddress(GetModuleHandleA("Kernel32.dll"), "LoadLibraryW"); CreateRemoteThread(hProc, 0, 0, (LPTHREAD_START_ROUTINE) pFunc, buffer, 0, 0); } int main() { system("start %windir%\\system32\\notepad.exe"); PROCESSENTRY32 info; if (getProcess32Info(&info, L"notepad.exe")) { InjectDLL(L"E:\\Dll1.dll", info.th32ProcessID); } else { cout << "查找失败" << endl; } return 0; }
本次 DLL 注入取巧用了 LoadLibrary
一些安全软件对 LoadLibrary 这样的 API 十分敏感,且 DLL 文件本身也容易被检测并被删除
要解决这些问题,就需要用到 反射型 DLL 注入
(没做)。
下期预告: 基于数据报套接字的并发服务器的设计与实现
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。