先上源码:
#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); // 定义一个容器,该容器用来接收,进程信息 processentry32w processinfo = { 0 }; processinfo.dwsize = sizeof(processentry32w); // 根据进程名称,循环判断是否是指定的进程 do { if (_tcscmp(processinfo.szexefile, processname) == 0) { // 释放进程快照,防止内存泄露 closehandle(processall); // 如果是返回指定进程句柄 return processinfo.th32processid; } // 一个迭代函数 } while (process32next(processall, &processinfo)); // 释放进程快照,防止内存泄露 closehandle(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) { closehandle(handle); return null; } zeromemory(&moduleentry, sizeof(moduleentry32)); moduleentry.dwsize = sizeof(moduleentry32); if (!module32first(handle, &moduleentry)) { closehandle(handle); return null; } do { if (_tcscmp(moduleentry.szmodule, modulename) == 0) { // 释放进程快照,防止内存泄露 closehandle(handle); return moduleentry.hmodule; } } while (module32next(handle, &moduleentry)); closehandle(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 (dword == 0) { messagebox(null, text("没有找到指定进程"), text("错误"), 0); return; } // 打开指定进程 handle hprocess = openprocess(process_all_access, false, 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 lpbaseaddress, // 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] lpsecurity_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); // 释放指定的模块 closehandle(hthread); closehandle(hprocess); } /// <summary> /// 把指定进程中的dll卸载掉 /// </summary> /// <param name="processname"></param> /// <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, false, 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); // 释放指定的模块 closehandle(hthread); closehandle(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://users//qiaoas//documents//visual studio 2015//projects//consoleapplication1//debug//wx_read_write.dll" }; switch (umsg) { case wm_initdialog: break; case wm_close: enddialog(hwnddlg, 0); // 关闭窗体 break; case 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 false; } /// <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 宏定义的源码:
winbaseapi _ret_maybenull_ hmodule winapi loadlibrarya( _in_ lpcstr lplibfilename ); winbaseapi _ret_maybenull_ hmodule winapi loadlibraryw( _in_ lpcwstr lplibfilename ); #ifdef unicode #define loadlibrary loadlibraryw #else #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.ctvol.com)!!>以前的文章或继续浏览下面的相关文章希望大家以后多多支持<计算机技术网(www.ctvol.com)!!>!
需要了解更多c/c++开发分享C++ DLL注入工具(完整源码),都可以关注C/C++技术分享栏目—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/1045912.html