文章标题 原创 翻译 转载 文章内容 dll本身是不能运行的,它可以被可执行文件调用来执行,这种是主动去调用dll,反过来也可以将dll注入到指定进程地址空间去执行。 # 注入程序 使用命令行的方式提供了注入dll和卸载dll两个方法 ``` // inject.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> #include <Windows.h> #include <TlHelp32.h> #include <Psapi.h> #include <tchar.h> #include <algorithm> #include <sstream> std::wstring NormalizePath(const std::wstring &path) { const int BUFSIZE = 4096; TCHAR buffer[BUFSIZE] = TEXT(""); TCHAR **lppPart = { NULL }; DWORD ret = GetFullPathName(path.c_str(), BUFSIZE, buffer, lppPart); if (ret == 0) { return L""; } return buffer; } bool PathEqual(const std::wstring &path1, const std::wstring &path2) { std::wstring p1 = NormalizePath(path1); std::wstring p2 = NormalizePath(path2); if (p1.size() != p2.size()) { return false; } std::transform(p1.begin(), p1.end(), p1.begin(), ::tolower); std::transform(p2.begin(), p2.end(), p2.begin(), ::tolower); return p1 == p2; } // 将指定路径的dll注入到进程 DWORD Inject(DWORD processId, const std::wstring &injectDllPath) { HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId); if (!handle) { return GetLastError(); } bool success = false; do { LPVOID alloc_address = VirtualAllocEx(handle, NULL, injectDllPath.length(), MEM_COMMIT, PAGE_READWRITE); if (!alloc_address) { break; } // 宽字符一定要乘以2 if (!WriteProcessMemory(handle, alloc_address, injectDllPath.c_str(), injectDllPath.length() * sizeof(TCHAR), NULL)) { break; } HMODULE kernel_handle = GetModuleHandle(L"Kernel32.dll"); if (!kernel_handle) { break; } // 注意,这里必须指定为宽字符函数 FARPROC loadLibrary = GetProcAddress(kernel_handle, "LoadLibraryW"); if (!loadLibrary) { break; } if (CreateRemoteThread(handle, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibrary, alloc_address, 0, NULL) != NULL) { success = true; } } while (0); CloseHandle(handle); return success ? 0 : GetLastError(); } DWORD Uninject(DWORD processId, const std::wstring &injectDllPath) { HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processId); if (hSnap == INVALID_HANDLE_VALUE) { return GetLastError(); } MODULEENTRY32 me32; me32.dwSize = sizeof(me32); BOOL dllFound = FALSE; //查找匹配的进程名称 BOOL bRet = Module32First(hSnap, &me32); while (bRet) { std::wstring exePath(me32.szExePath); if (PathEqual(injectDllPath, exePath)) { dllFound = TRUE; break; } bRet = Module32Next(hSnap, &me32); } CloseHandle(hSnap); if (!dllFound) { return 1; } HMODULE kernel_handle = GetModuleHandle(L"Kernel32.dll"); if (!kernel_handle) { return 2; } FARPROC freeLibrary = GetProcAddress(kernel_handle, "FreeLibrary"); if (!freeLibrary) { return 3; } HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId); if (hProcess == NULL) { return 4; } HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)freeLibrary, me32.hModule, 0, NULL); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); CloseHandle(hProcess); return 0; } int wmain(int argc, wchar_t* argv[]) { std::wstring method; DWORD processId = 0; std::wstring dllPath; bool ready = false; if (argc >= 4) { method = argv[1]; processId = _wtoi(argv[2]); dllPath = argv[3]; if ((method == L"inject" || method == L"uninject") && processId > 0 && !dllPath.empty()) { ready = true; } } if (!ready) { std::cout << "Params Error!" << std::endl; std::cout << "Usage:" << std::endl; std::cout << "my.exe inject processId dllAbsolutePath" << std::endl; std::cout << "my.exe uninject processId dllAbsolutePath" << std::endl; return 1; } DWORD result = -1; if (method == L"inject") { Uninject(processId, dllPath); result = Inject(processId, dllPath); } else if (method == L"uninject") { result = Uninject(processId, dllPath); } if (result == 0) { std::wcout << method << L" success\n"; } else { std::wcout << method << L" failed, errcode:" << result << std::endl; } std::cout << "Exit\n"; } ``` # 使用方法 my.exe inject processId dllAbsolutePath my.exe uninject processId dllAbsolutePath * processId:被注入到的进程ID * dllAbsolutePath:注入的dll绝对路径!!! # dll测试代码 注入后会显示一个hello的弹框,当然如果你要做些复杂的事情可以创建一个线程来长期运行。 ``` void work() { MessageBox(NULL, L"hello", L"dll inject test", MB_OK); } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { //CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)work, NULL, NULL, 0); work(); break; } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } ``` 文章类别 Python Mobile Android Java Shell Life Database Bug Windows IOS Tools Boost Node.js Mac Product Tips C/C++ Golang Javascript React Qt MQ MongoDB Design Web Linux LLM ChatGPT RAG AI 提交