使用CreateRemoteThread注入DLL
DLL:
// dllmain.cpp : Defines the entry point for the DLL application. #include "stdafx.h" #include <Windows.h> #include <stdio.h> INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved) { /* open file */ FILE *file; fopen_s(&file, "D:\\Case Folders\\2019-11-27\\CreateRemoteThread\\temp.txt", "a+"); switch (Reason) { case DLL_PROCESS_ATTACH: fprintf(file, "DLL attach function called.\n"); break; case DLL_PROCESS_DETACH: fprintf(file, "DLL detach function called.\n"); break; case DLL_THREAD_ATTACH: fprintf(file, "DLL thread attach function called.\n"); break; case DLL_THREAD_DETACH: fprintf(file, "DLL thread detach function called.\n"); break; } /* close file */ fclose(file); return TRUE; }
CreateRemoteThread program:
#include <Windows.h> #include <stdio.h> #include <TlHelp32.h> #include <tchar.h> bool Inject(DWORD pId, const char *dllName) { HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, false, pId); if (h) { LPVOID LoadLibAddr = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA"); LPVOID dereercomp = VirtualAllocEx(h, NULL, strlen(dllName), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); WriteProcessMemory(h, dereercomp, dllName, strlen(dllName), NULL); HANDLE asdc = CreateRemoteThread(h, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddr, dereercomp, 0, NULL); if (asdc == NULL) { printf("Error: the remote thread could not be created.\n"); } else { printf("Success: the remote thread was successfully created.\n"); } WaitForSingleObject(asdc, INFINITE); VirtualFreeEx(h, dereercomp, strlen(dllName), MEM_RELEASE); CloseHandle(asdc); CloseHandle(h); return true; } return false; } int _tmain(int argc, _TCHAR* argv[]) { const char* buffer = "D:\\Case Folders\\2019-11-27\\CreateRemoteThread\\inject\\Debug\\inject.dll"; /* * Get process handle passing in the process ID. */ int procID = 26824; Inject(procID, buffer); getchar(); return 0; }
检查被插入的进程是否包含inject.dll
#include <windows.h> #include <Tlhelp32.h> #include <iostream> #include <vector> #include <string> using namespace std; typedef basic_string<TCHAR, char_traits<TCHAR>, allocator<TCHAR> > tstring; int ProcessModule(DWORD); int CheckProcessModule(DWORD pid); BOOL IsModuleValid(tstring szModuleName); int dwCount = 0; vector<tstring> patch; vector<tstring> checkpatch; int main(void) { //进程创建完毕后的模块快照 ProcessModule(26824); cout << "******************当前模块*****************" << endl; for (int i = 0; i < patch.size(); i++) { cout << patch[i].c_str() << endl; } cout << endl << endl; LoadLibrary(TEXT("user32.dll"));//加载user32.dll测试 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(hStdout, FOREGROUND_GREEN | FOREGROUND_INTENSITY); //检测是否存在不同的模块 // CheckProcessModule(GetCurrentProcessId()); cout << "******************检测模块*****************" << endl; for (int j = 0; j < checkpatch.size(); j++) { cout << checkpatch[j].c_str() << endl;; } cout << endl << endl; if (patch.size() == checkpatch.size()) { cout << "没有检测到注入模块" << endl; } return 0; } //获取进程模块 int ProcessModule(DWORD pid) { HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); if (hProcessSnap) { MODULEENTRY32 me32; me32.dwSize = sizeof(MODULEENTRY32); Module32First(hProcessSnap, &me32);//获取进程第一个模块信息 do { patch.push_back(me32.szModule); //printf("模块路径:%s\n",me32.szExePath); //printf("模块名:%s\n",me32.szModule); //printf("模块基址:0x%08X\n",(DWORD)me32.modBaseAddr); } while (Module32Next(hProcessSnap, &me32)); CloseHandle(hProcessSnap); return 0; } else { cout << "获取进程快照失败" << endl;; return 0; } return 0; } int CheckProcessModule(DWORD pid) { HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); if (hProcessSnap) { MODULEENTRY32 me32; me32.dwSize = sizeof(MODULEENTRY32); Module32First(hProcessSnap, &me32);//获取进程第一个模块信息 do { checkpatch.push_back(me32.szModule); if (!IsModuleValid(me32.szModule)) { cout << "[可疑模块]:" << me32.szExePath << endl; dwCount++; } //printf("模块路径:%s\n",me32.szExePath); //printf("模块名:%s\n",me32.szModule); //printf("模块基址:0x%08X\n",(DWORD)me32.modBaseAddr); } while (Module32Next(hProcessSnap, &me32)); CloseHandle(hProcessSnap); if (dwCount) { cout << "可疑模块数:" << dwCount << endl; } return 0; } else { cout << "获取进程快照失败" << endl; return 0; } return 0; } BOOL IsModuleValid(tstring szModuleName) { // 遍历起始状态的模块列表 for (int i = 0; i < patch.size(); i++) { if (patch[i] == szModuleName) return TRUE; } return FALSE; }
部分解释:
介绍将用于将DLL注入到进程的地址空间中的整个过程。为了清楚地表明我们将要执行的操作,请看下面的图片,在该图片中,我们将向其中注入DLL的过程标有紫色,并命名为受害者。但是,我们需要澄清另外两个难题。首先,我们需要确定如果要将DLL注入到某个进程中,则必须首先拥有要注入的DLL。DLL以绿色呈现,并具有名称inject.dll。但是我们还必须有一个程序,该程序会将DLL注入受害者的地址空间。该程序以蓝色显示,名称为program.exe。
为了能够将DLL注入受害者的地址空间,program.exe必须顺序调用提供的函数。首先,它必须调用OpenProcess来获取受害者进程的句柄。之后,它必须调用GetProcAddress函数来获取kernel32.dll库中LoadLibraryA函数的地址。在这里,我们可以运行任何我们喜欢的函数,但是它必须存在于DLL中,该DLL已经加载在进程的地址空间中。我们知道每个程序都使用kernel32.dll库,因此将DLL注入到进程的地址空间中的最佳方法是查找LoadLibraryA函数并调用它。为了加载DLL,我们必须将DLL路径传递给LoadLibraryA函数,但是该名称需要存储在进程地址空间内的某个位置。明显,DLL的路径已经不太可能出现在进程的地址空间中,这就是为什么我们需要接下来的两个函数:VirtualAllocEx和WriteProcessMemory。第一个函数在进程的地址空间内分配一个新的内存范围。该内存区域的大小仅需要大到适合其内部DLL的名称即可;通常将大小四舍五入以占据至少一页。WriteProcessMemory是实际上将DLL的路径写入受害者的地址空间的函数。最后,调用CreateRemoteThread,该调用在受害者的地址空间内调用LoadLibraryA函数以向其中注入DLL。
更多信息请参考:https://resources.infosecinstitute.com/using-createremotethread-for-dll-injection-on-windows/#gref