我一直试图在进程虚拟内存中运行64位DLL而不用'手动映射'它(即手动解析重定位/导入)。
计划是将代码注入目标应用程序并通过传统方式加载模块,例如LoadLibrary。
我假设LoadLibrary会自行修复模块重定位/导入,因为这就是它的目的。
加载模块后,注入的代码将使用GetModuleInformation获取有关模块的信息,将其传输到临时内存缓冲区,释放模块,在最初加载的同一地址分配内存,将其写回,然后执行切入点。
最后一步是我认为错误发生的地方。
为了测试这个理论,我有硬编码入口点地址,通过Visual Studio的“附加到进程”功能调试远程应用程序,模拟类似的环境来纠正错误的指针算法,所有这些都是为了获得一点点有关错误可能的更多信息。
以下是一些可能有用或无用的一般信息:
就直接与注射器有关的信息而言:
代码前言: 下面展示的代码不是以任何方式显示漂亮或展示良好的编程实践。查看代码时请记住这一点。它专门用于测试代码注入方法以验证其是否有效。如果您对程序布局,结构等有疑问,请随意纠正它们和/或自行重组它们。这不是我在这里的原因。除非它是导致错误的原因,那么这完全是我在这里的原因:)
注射器的代码: http://pastebin.com/FF5G9nnR
/*
Some of the code was truncated (functions not pertaining to the injection), but
I have verified the code compiles and works correctly with it's injeteme.dll counterpart
*/
#include <Windows.h>
#include <Psapi.h>
#define TARGET_PID 1124
typedef BOOL(WINAPI* pFreeLibrary)(HMODULE);
typedef HMODULE(WINAPI* pLoadLibraryA)(LPCSTR);
typedef HANDLE(WINAPI* pGetCurrentProcess)(void);
typedef BOOL(WINAPI* DLL_MAIN)(HMODULE, DWORD, LPVOID);
typedef HANDLE(WINAPI* pOpenProcess)(DWORD, BOOL, DWORD);
typedef BOOL(WINAPI* pVirtualFree)(LPVOID, SIZE_T, DWORD);
typedef int(__stdcall* pMessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
typedef LPVOID(WINAPI* pVirtualAlloc)(LPVOID, SIZE_T, DWORD, DWORD);
typedef BOOL(WINAPI* pGetModuleInformation)(HANDLE, HMODULE, LPMODULEINFO, DWORD);
typedef BOOL(WINAPI* pWriteProcessMemory)(HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T*);
//////////////////////////////////////////////////////////////////
struct IINFO
{
LPVOID stubAddr;
LPVOID retStatusPtr;
char fullModulePath[MAX_PATH];
DWORD pId, sizeOfCurrStruct;
// DEBUG
pMessageBoxA messageBox;
pOpenProcess openProcess;
pVirtualFree virtualFree;
pFreeLibrary freeLibrary;
pLoadLibraryA loadLibrary;
pVirtualAlloc virtualAlloc;
pGetCurrentProcess getCurrProc;
pWriteProcessMemory writeMemory;
pGetModuleInformation getModInfo;
};
static DWORD WINAPI stub(IINFO *iInfo)
{
HMODULE hMod;
MODULEINFO mInfo;
DLL_MAIN dllMain;
LPVOID lpNewMod, lpTempModBuff;
PIMAGE_DOS_HEADER pIDH;
PIMAGE_NT_HEADERS pINH;
iInfo->messageBox(NULL, iInfo->fullModulePath, NULL, 0);
hMod = iInfo->loadLibrary(iInfo->fullModulePath);
if (!hMod)
return 0;
if (!iInfo->getModInfo(iInfo->getCurrProc(), hMod, &mInfo, sizeof(MODULEINFO)))
return 0;
lpTempModBuff = iInfo->virtualAlloc(NULL, mInfo.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpTempModBuff)
return 0;
if (!iInfo->writeMemory(iInfo->getCurrProc(), lpTempModBuff, mInfo.lpBaseOfDll, mInfo.SizeOfImage, NULL))
return 0;
if (!iInfo->freeLibrary(hMod))
return 0;
lpNewMod = iInfo->virtualAlloc(mInfo.lpBaseOfDll, mInfo.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpNewMod)
return 0;
// using wpm since we have already acquired the function
if (!iInfo->writeMemory(iInfo->getCurrProc(), lpNewMod, lpTempModBuff, mInfo.SizeOfImage, NULL))
return 0;
if (!iInfo->virtualFree(lpTempModBuff, 0, MEM_RELEASE))
return 0;
/*if (!iInfo->virtualFree(iInfo, 0, MEM_RELEASE))
return 0;
iInfo->messageBox(NULL, NULL, NULL, 0); */
pIDH = (PIMAGE_DOS_HEADER)lpNewMod;
if (!pIDH)
return 0;
pINH = (PIMAGE_NT_HEADERS)((LPBYTE)lpNewMod + pIDH->e_lfanew);
if (!pINH)
return 0;
dllMain = (DLL_MAIN)((LPBYTE)lpNewMod + pINH->OptionalHeader.AddressOfEntryPoint);
if (!dllMain)
return 0;
iInfo->messageBox(NULL, NULL, NULL, 0);
dllMain((HINSTANCE)lpNewMod, DLL_PROCESS_ATTACH, NULL);
return 1;
}
static DWORD WINAPI stubEnd(){ return 0; }
//////////////////////////////////////////////////////////////////
int main()
{
HANDLE hThread = 0;
DWORD dwStubSize = 0;
int sucResp = 0, count = 0;
HMODULE hUser32 = 0, hNtdll = 0;
char fullPathName[] = "C:\\injectme.dll";
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, TARGET_PID);
if (!hProc || hProc == INVALID_HANDLE_VALUE)
return 0;
__int64 SizeOfStub = (LPBYTE)stubEnd - (LPBYTE)stub;
LPVOID lpStub = VirtualAllocEx(hProc, NULL, SizeOfStub, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpStub)
return 0;
hUser32 = LoadLibraryA("user32.dll");
if (!hUser32)
return 0;
hNtdll = LoadLibraryA("kernel32.dll");
if (!hNtdll)
return 0;
IINFO iInfo = {};
iInfo.retStatusPtr = &sucResp;
strcpy(iInfo.fullModulePath, fullPathName);
iInfo.sizeOfCurrStruct = sizeof(IINFO);
iInfo.stubAddr = lpStub;
iInfo.pId = GetCurrentProcessId();
iInfo.messageBox = (pMessageBoxA)GetProcAddress(hUser32, "MessageBoxA");
iInfo.openProcess = (pOpenProcess)GetProcAddress(hNtdll, "OpenProcess");
iInfo.virtualFree = (pVirtualFree)GetProcAddress(hNtdll, "VirtualFree");
iInfo.freeLibrary = (pFreeLibrary)GetProcAddress(hNtdll, "FreeLibrary");
iInfo.loadLibrary = (pLoadLibraryA)GetProcAddress(hNtdll, "LoadLibraryA");
iInfo.virtualAlloc = (pVirtualAlloc)GetProcAddress(hNtdll, "VirtualAlloc");
iInfo.getCurrProc = (pGetCurrentProcess)GetProcAddress(hNtdll, "GetCurrentProcess");
iInfo.writeMemory = (pWriteProcessMemory)GetProcAddress(hNtdll, "WriteProcessMemory");
iInfo.getModInfo = (pGetModuleInformation)GetProcAddress(hNtdll, "K32GetModuleInformation");
LPVOID lpStubInfo = VirtualAllocEx(hProc, NULL, sizeof(IINFO), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpStubInfo)
return 0;
if (!WriteProcessMemory(hProc, lpStub, stub, SizeOfStub, NULL))
return 0;
if (!WriteProcessMemory(hProc, lpStubInfo, &iInfo, sizeof(iInfo), NULL))
return 0;
hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpStub, lpStubInfo, 0, NULL);
if (!hThread || hThread == INVALID_HANDLE_VALUE)
return 0;
WaitForSingleObject(hThread, INFINITE);
return 1;
}
要注入的DLL的代码: http://pastebin.com/8WXxcpu1
#include <Windows.h>
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpParam)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
MessageBoxA(NULL, "Hello from injectme.dll!", "", MB_OK | MB_ICONINFORMATION);
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
在VS2013的调试器中逐字运行上面的代码时的错误(假设您也应用了上述设置并具有类似的环境)如下:
“wuauclt.exe中0x000007FEEA5125D4处的未处理异常:0xC0000005:访问冲突执行位置0x000007FEEA5125D4。”
在Process Hacker中查看进程“wuauclt.exe”后,我可以清楚地看到模块最初是在(通过LoadLibrary加载时)分配在0x7fef67c0000。这在上下文菜单中显示 - &gt;在其他 - &gt;卸载模块下。
双击“wuauclt.exe”后,您可以浏览应用程序的虚拟内存,以确保一切正常。我可以确认当前会话,已经在0x7fef67c0000分配了一个RWX内存缓冲区,其中包含了卸载模块的确切大小,包含injectme.dll模块。当使用CFF资源管理器挖掘injectme.dll时,入口点RVA似乎是0x132C,它没有加起来,考虑到内存中的错误距离更远。另外,我可以验证另外两个包含代码注入存根和信息结构的RWX内存缓冲区。回顾信息结构可能不需要RWX。无论如何,我不能为我的生活找出错误。
我希望你能帮助我。我非常感谢你的时间。
答案 0 :(得分:1)
我的直觉是,你对这样一个具有挑战性的项目缺乏基本的理解。你正在混合来自不同领域的概念。
Windows本身非常关注您在开发中使用的编程语言。您可以获得CLR代码(.Net)或本机代码。在这种情况下,它是x64。但Windows真的不关心strcpy
或SDL检查。这是编译器要处理的,而不是操作系统。当代码完全内联时,机会strcpy
甚至无法生存。但是你出于一些奇怪的原因显然已经关闭了优化 - 再次是编译器与操作系统的混淆。
但是,Windows 确实关心您未提及的其他概念。主要是那些将是ASLR和DEP - 地址空间布局随机化和数据执行预防。他们是阻止黑客入侵的技术,而且你是黑客。所以这并不奇怪。
我不确定“RWX”是否意味着“写入执行”,因为你应该知道这是在寻找问题.DEP的灵感来自更恰当的名字W ^ X,写XOR eXecute。
然而,更可能是ASLR的罪魁祸首。 Windows设计尝试在不可预测的地址加载DLL,因为这消除了整个类的黑客攻击。看来你正在假设一个加载地址,而Windows确实在使用另一个地址。
最后一个错误可能是您无法理解 重定位的位置。为了改善可共享页面的数量,重定位在导入地址表上完成,而不是代码本身。 IAT是一个trampoline表,因此是可执行的。你的失败也可能是失踪的IAT。