先上源码:
#include "inject_main.h"#include "resource.h"#include <windows.h>#include <tlhelp32.h>#include <string>#include <tchar.h>using namespace std;/// <summary>/// 通过进程名称获取该进程句柄/// </summary>/// <param name="processname"></param>/// <returns>成功返回 dword,失败返回 0</returns>dword getprocessbyname(const tchar* processname) { // 获取到整个系统的进程 handle processall = createtoolhelp32snapshot(th32cs_snapprocess, null); // 定义一个容器,该容器用来接收,进程信息 procesntry32w processinfo = { 0 }; processinfo.dwsize = sizeof(procesntry32w); // 根据进程名称,循环判断是否是指定的进程 do { if (_tcscmp(processinfo.szexefile, processname) == 0) { // 释放进程快照,防止内存泄露 clohandle(processall); // 如果是返回指定进程句柄 return processinfo.th32processid; } // 一个迭代函数 } w结构特点hile (process32next(processall, &processinfo)); // 释放进程快照,防止内存泄露 clohandle(processall); return 0;}/// <summary>/// 获取指定 dll 的内存地址/// </summary>/// <param name="pid"></param>/// <param name="modulename"></param>/// <returns></returns>hmodule getprocessmodulehandle(dword pid, const tchar* modulename) { moduleentry32 moduleentry; handle handle = null; handle = createtoolhelp32snapshot(th32cs_snapmodule, pid); if (!handle) { clohandle(handle); return null; } zeromemory(&moduleentry, sizeof(moduleentry32)); moduleentry.dwsize = sizeof(moduleentry32); if (!module32first(handle, &moduleentry)) { clohandle(handle); return null; } do { if (_tcscmp(moduleentry.szmodule, modulename) == 0) { // 释放进程快照,防止内存泄露 clohandle(handle); return moduleentry.hmodule; } } while (module32next(handle, &moduleentry)); clohandle(handle); return 0;}/// <summary>/// 把指定dll注入到指定进程中/// </summary>/// <param name="processname">processname 进程名称</param>/// <param name="dllpath">dllpath dll路径</param>void injectdll(const wchar_t* processname, const char* dllpath) { // 获取指定进程的句柄 dword dword = getprocessbyname(processname); if (dw邹忌ord == 0) { messagebox(null, text("没有找到指定进程"), text("错误"), 0); return; } //前行的力量作文 打开指定进程 handle hprocess = openprocess(process_all_access, fal, dword); if (hprocess == null) { messagebox(null, text("指定进程打开失败"), text("错误"), 0); return; } /* 在指定进程的地址,开辟一块内存空间,用来保存 dll的路径信息 lpvoid virtualallocex( [in] handle hprocess, 在那个进程中开辟内存 [in, optional] lpvoid lpaddress, 开辟内存的起始地址 (null,不需要控制起始位置) [in] size_t dwsize, 开辟内存的大小(当前保存的内容是 dll的路径) [in] dword flallocationtype, 内存分配的类型。(开辟内存) [in] dword flprotect,设置内存的权限 (可读可写) ); */ lpvoid dlladdress = virtualallocex(hprocess, null, strlen(dllpath), mem_commit, page_readwrite); /* 把dll的路径,写入到刚开辟出来的内存中 bool writeprocessmemory( [in] handle hprocess, // 指定的进程 [in] lpvoid lpbaaddress, // dll路径字符串,写入的基址 [in] lpcvoid lpbuffer, // dll路径字符串,的指针 [in] size_t nsize, // 需要写入内存的字节长度 [out] size_t *lpnumberofbyteswritten // [out] 返回一个指针,不需要,null ); */ if (writeprocessmemory(hprocess, dlladdress, dllpath, strlen(dllpath), null) == 0) { messagebox(null, text("路径写入失败"), text("错误"), 0); return; } // 获取 kernel32.dll 这个模块 hmodule k32 = getmodulehandle(text("kernel32.dll")); // 在 kernel32.dll 模块中找到 loadlibrary 这个函数的内存地址 lpvoid loadadd = getprocaddress(k32, "loadlibrarya"); /* 在指定进程中,创建一个线程 并通过这个线程,调用 loadlibrary 函数 通过 loadlibrary 函数,把 dll 载入到目标进程中 handle createremotethread( [in] handle hprocess, // 指定进程 [in] lpcurity_attributes lpthreadattributes, // 设置线程安全属性,表示线程是否可以继承,null就够了 [in] size_t dwstacksize, // 堆栈的初始大小,0 表示使用可执行文件的默认大小 [in] lpthread_start_routine lpstartaddress, // 远程进程中,需要执行的那个函数的指针 [in] lpvoid lpparameter, // 目前进程中 dll路径的指针 [in] dword dwcreationflags, // 0 线程在创建后立即运行。 [out] lpdword lpthreadid // [out] 当前不需要这个返回值 ); */ handle hthread = createremotethread(hprocess, null, 0, (lpthread_start_routine)loadadd, dlladdress, 0, null); // 释放指定的模块 clohandle(hthread); clohandle(hprocess);}/// <summary>/// 把指定进程中的dll卸载掉/// </summary>/// <param name="processname"></par有效教学论文am>/// <param name="dllpath"></param>void uninjectdll(const wchar_t* processname) { // 通过进程名称获取该进程句柄 dword dword = getprocessbyname(processname); if (dword == 0) { messagebox(null, text("没有找到指定进程"), text("错误"), 0); return; } // 获取指定进程中指定模块的内存地址 hmodule hmodule = getprocessmodulehandle(dword, l"wx_read_write.dll"); // 打开指定进程 handle hprocess = openprocess(process_all_access, fal, dword); if (hprocess == null) { messagebox(null, text("指定进程打开失败"),三价铬 text("错误"), 0); return; } // 获取 kernel32.dll 这个模块 hmodule k32 = getmodulehandle(text("kernel32.dll")); // 在 kernel32.dll 模块中找到 loadlibrary 这个函数的内存地址 lpvoid loadadd = getprocaddress(k32, "freelibrary"); handle hthread = createremotethread(hprocess, null, 0, (lpthread_start_routine)loadadd, (lpvoid)hmodule, 0, null); // 释放指定的模块 clohandle(hthread); clohandle(hprocess);}/// <summary>////// </summary>/// <param name="hwnddlg"></param>/// <param name="umsg"></param>/// <param name="wparam"></param>/// <param name="lparam"></param>/// <returns></returns>int_ptr callback dialogproc(_in_ hwnd hwnddlg, _in_ uint umsg, _in_ wparam wparam, _in_ lparam lparam){ wchar_t processname[100] = l"wechat.exe"; char dllpath[400] = { "c://urs//qiaoas//documents//visual studio 2015//projects//consoleapplication1//debug//wx_read_write.dll" }; switch (umsg) { ca wm_initdialog: break; ca wm_clo: enddialog(hwnddlg, 0); // 关闭窗体 break; ca wm_command: /*getdlgitemtext(hwnddlg, text_processname, processname, sizeof(processname)); getdlgitemtext(hwnddlg, text_dllpath, (lpwstr)dllpath, sizeof(dllpath));*/ if (wparam == btn_inject_dll) { if (sizeof(processname) == 0) { messagebox(null, text("进程名称不能为空"), text("错误"), 0); } if (sizeof(dllpath) == 0) { messagebox(null, text("dll路径不能为空"), text("错误"), 0); } injectdll(processname, dllpath); // 注入dll } if (wparam == btn_uninject_dll) { uninjectdll(processname); // 卸载dll } break; default: break; } return fal;}/// <summary>/// 初始化/// </summary>/// <param name="hinstance"></param>/// <param name="hprevinstance"></param>/// <param name="lpcmdline"></param>/// <param name="ncmdshow"></param>/// <returns></returns>int apientry wwinmain(_in_ hinstance hinstance, _in_opt_ hinstance hprevinstance, _in_ lpwstr lpcmdline, _in_ int ncmdshow){ dialogbox(hinstance, makeintresource(idd_dialog1), null, &dialogproc); return 0;}
初学c++,代码可能有些地方写的不够好,但是注入卸载是完全没问题的。
注入逻辑解释:
使用createremotethread
函数可以为目标进程创建一个新的线程。
在一个进程为另一个进程创建的线程就是远程线程。
使用 loadlibrary
函数把指定的dll加载到进程中
因此就可以在创建远程线程的同时调用 loadlibrary
函数,把指定的dll
加载到目标进程中。
为什么创建远程线程的时候调用 loadlibrary 函数就能把 dll 注入到目标进程中?
loadlibrary
函数是 kernel32.dll 中的一个成员
kernel32.dll
这个dll是创建进程必须的一个dll,并且所有进程在内存中指向的 kernel32.dll 是同一个地址所以只要获取到当前进程中
loadlibrary
函数的地址就够了
为什么要在目标进程中开辟一块内存,再把dll路径写入到块内存中?
loadlibrary
函数需要一个参数,就是dll的路径把当前进程中的一个地址传到另一个进程中,鬼知道另一个进程获取这个地址中的数据时,读取到的是否是我们想要的。因此需要把
dll
的路径直接写入到目标进程中。
virtualallocex
函数,在目标进程中开辟一块空间,用来存放dll路径
writeprocessmemory
函数,把dll的路径写入进去
getmodulehandle
获取 kernel32.dll 模块
getprocaddress
获取 loadlibrarya 函数在内存中的地址
createremotethread
创建远程线程,并调用 loadlibrarya 函数
loadlibrary
、loadlibrarya
、loadlibraryw
这三者的区别。
loadlibrary
是一个宏,可以根据字符集的不同,自动决定是使用 loadlibrarya 还是 loadlibraryw
loadlibrary 宏定义的源码:
winbaapi_ret_maybenull_hmodulewinapiloadlibrarya( _in_ lpcstr lplibfilename );winbaapi_ret_maybenull_hmodulewinapiloadlibraryw( _in_ lpcwstr lplibfilename );#ifdef unicode#define loadlibrary loadlibraryw#el#define loadlibrary loadlibrarya#endif // !unicode
卸载逻辑:
使用 createremotethread 函数创建一个远程线程
调用 freelibrary 函数,卸载dll
freelibrary 函数在 kernel32.dll 模块中,逻辑同上
freelibrary 函数需要 dll 的内存地址
遍历进程快照可以获取到指定模块的内存地址
卸载和注入的思路都是一样的
确认dll是否注入到目标进程中:
方式一:使用 procexp
方式二:cheat engine
确认 kernel32.dll 中的 freelibrary 和 loadlibrarya 在多个进程中是否指向同一块内存地址:
可以通过ce查看多个进程中 kernel32.dll 的内存地址是否相同
再通过 kernel32.dll 中函数的内存地址,确认 freelibrary 和 loadlibrarya 这两个函数
到此这篇关于c++ dll注入工具(完整源码)的文章就介绍到这了,更多相关c++ dll注入工具内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!