Closed idigger closed 10 months ago
你好,感谢反馈。HexControl64.dll
会访问源DLL文件,而内存加载使用了随机文件名,所以会报错。解决的方法有两个:
CHAR currPath[MAX_PATH + 1];
GetCurrentDirectoryA(MAX_PATH, currPath);
HMODULE m = LoadLibraryMemoryExA(lpDll, 0, "HexControl64_orig.dll", currPath, 0);
2. 修补程序(不推荐,版本号2.6.6.1)
``` C++
unsigned char buf[] = { 0x00,0x85 };
HMODULE m = LoadLibraryMemoryExA(lpDll, 0, nullptr, nullptr, 0);
if (m) {
WriteProcessMemory(GetCurrentProcess(), PBYTE(m) + 0xB01ED, &buf[1], 1, nullptr);
WriteProcessMemory(GetCurrentProcess(), PBYTE(m) + 0xB03B8, &buf[0], 1, nullptr);
}
MMPP存在bug,方法1会导致程序崩溃,稍后我会更新代码
多谢回复,方法1试过,确实导致崩溃,静待佳音 顺便把 LoadLibraryMemoryExA 的参数 Flags 没有传给 LoadLibraryMemoryExW 的问题也更新一下吧
代码已经合并到master分支,本地测试能正常运行。
经测试以上情景确实不再出错了,感谢快速修复。 以下情景还是报错:系统找不到指定的文件 1、将 HexControl64_orig.dll 改名为 HexControl64_orig.dat 从内存加载 2、将 HexControl64_orig.dll 编译到资源中从内存加载(此时硬盘中不存在HexControl64_orig.dll) 以上实际就是想实现纯粹从内存中加载HexControl64_orig.dll,而不是从硬盘读出再从内存加载 麻烦看看能不能实现这个功能。
还有一种情景也是出错 3、就是将 MMPP 编译成dll 打包到程序资源中从内存加载这个 MMPP.dll,再用内存中的 MMPP 加载内存中的HexControl64_orig.dll(此需求是因为我的程序是c编的,故需先将MMPP编译成dll以便调用)
以上3种情景用MM或sRDI方法是可以实现不报错的,只是不太稳定,运行10次会有几次崩溃。
.dll
结尾,MMPP会补上扩展名。实际要访问的文件是HexControl64_orig.dat.dll
,因此会报错。HexControl64_orig.dll
的行为,与加载器无关。要实现这个目的需要修补这个文件,或者HOOK几个文件相关的API:CreateFileW; GetFileSize; ReadFile; CloseHandle
。可以参考MmpDotNet.cpp
的实现。ReflectiveLoader
函数,调用这个函数就能实现自加载,返回值是MMPP的模块句柄。
MM和RDI不报错的原因是它们没有处理PEB里的LDR链表。这也将导致进程运行不稳定。
//
// 自加载MMPP示例
//
#include "../MemoryModule/stdafx.h"
#include "../MemoryModule/LoadDllMemoryApi.h"
#include <cstdio>
#pragma comment(lib,"ntdll.lib")
PMMP_GLOBAL_DATA MmpGlobalDataPtr;
decltype(&LdrLoadDllMemoryExW)__LdrLoadDllMemoryExW;
decltype(&LdrUnloadDllMemory)__LdrUnloadDllMemory;
static void DisplayStatus() {
printf(
"\
MemoryModulePP [Version %d.%d%s]\n\n\t\
MmpFeatures = %08X\n\n\t\
LdrpModuleBaseAddressIndex = %p\n\t\
NtdllLdrEntry = %p\n\t\
RtlRbInsertNodeEx = %p\n\t\
RtlRbRemoveNode = %p\n\n\t\
LdrpInvertedFunctionTable = %p\n\n\t\
LdrpHashTable = %p\n\n\
",
MmpGlobalDataPtr->MajorVersion,
MEMORY_MODULE_GET_MINOR_VERSION(MmpGlobalDataPtr->MinorVersion),
MEMORY_MODULE_IS_PREVIEW(MmpGlobalDataPtr->MinorVersion) ? " Preview" : "",
MmpGlobalDataPtr->MmpFeatures,
MmpGlobalDataPtr->MmpBaseAddressIndex->LdrpModuleBaseAddressIndex,
MmpGlobalDataPtr->MmpBaseAddressIndex->NtdllLdrEntry,
MmpGlobalDataPtr->MmpBaseAddressIndex->_RtlRbInsertNodeEx,
MmpGlobalDataPtr->MmpBaseAddressIndex->_RtlRbRemoveNode,
MmpGlobalDataPtr->MmpInvertedFunctionTable->LdrpInvertedFunctionTable,
MmpGlobalDataPtr->MmpLdrEntry->LdrpHashTable
);
}
static PVOID ReadDllFile(LPCSTR FileName) {
LPVOID buffer;
size_t size;
FILE* f;
fopen_s(&f, FileName, "rb");
if (!f)return 0;
_fseeki64(f, 0, SEEK_END);
if (!(size = _ftelli64(f))) {
fclose(f);
return 0;
}
_fseeki64(f, 0, SEEK_SET);
buffer = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
fread(buffer, 1, size, f);
fclose(f);
return buffer;
}
PVOID ReadDllFile2(LPCSTR FileName) {
CHAR path[MAX_PATH + 4];
DWORD len = GetModuleFileNameA(nullptr, path, sizeof(path));
if (len) {
while (len && path[len] != '\\') --len;
if (len) {
strcpy_s(&path[len + 1], sizeof(path) - len - 1, FileName);
return ReadDllFile(path);
}
}
return nullptr;
}
ULONG_PTR ReflectiveLoaderOffset() {
ULONG_PTR offset = 0;
auto hm = LoadLibrary(L"MemoryModule.dll");
if (hm) {
auto pfn = GetProcAddress(hm, "ReflectiveLoader");
offset = ULONG_PTR(pfn) - ULONG_PTR(hm);
auto header = RtlImageNtHeader(hm);
auto section = IMAGE_FIRST_SECTION(header);
for (int i = 0; i < header->FileHeader.NumberOfSections; ++i, ++section) {
if (offset >= section->VirtualAddress && offset < section->VirtualAddress + section->SizeOfRawData) {
offset = ULONG_PTR(pfn) - (ULONG_PTR(hm) + section->VirtualAddress) + section->PointerToRawData;
break;
}
}
FreeLibrary(hm);
}
return offset;
}
typedef ULONG_PTR(WINAPI* LOADER)(PVOID);
int main() {
auto buffer = ReadDllFile2("MemoryModule.dll");
auto loader = LOADER(ULONG_PTR(buffer) + 0x1221); //ReflectiveLoaderOffset() -> 0x1221
auto hm = (HMODULE)loader(buffer);
MmpGlobalDataPtr = *(PMMP_GLOBAL_DATA*)GetProcAddress(hm, "MmpGlobalDataPtr");
__LdrLoadDllMemoryExW = (decltype(&LdrLoadDllMemoryExW))GetProcAddress(hm, "LdrLoadDllMemoryExW");
__LdrUnloadDllMemory = (decltype(&LdrUnloadDllMemory))GetProcAddress(hm, "LdrUnloadDllMemory");
DisplayStatus();
return 0;
}
以下程序vs2019编译后运行结果 1: 0000018FF1820000 2: 0000018FF1860000 然后崩溃,查日志异常代码: 0xc0000005 如果注释掉以下两行
MmpGlobalDataPtr = *(PMMP_GLOBAL_DATA*)GetProcAddress(hm, "MmpGlobalDataPtr");
printf("3: %p\n", MmpGlobalDataPtr);
则运行结果如下 1: 0000016A13570000 2: 0000016A135B0000 4: 0000000000000000, 0000000000000000
MemoryModule.dll / MemoryModule.lib 是vs2019编译的最新版。 不知什么原因造成的获取的地址为0
#include "../MemoryModule/stdafx.h"
#include "../MemoryModule/LoadDllMemoryApi.h"
#include <cstdio>
#pragma comment(lib,"ntdll.lib")
#pragma comment(lib,"MemoryModule.lib")
PMMP_GLOBAL_DATA MmpGlobalDataPtr;
decltype(&LdrLoadDllMemoryExW)__LdrLoadDllMemoryExW;
decltype(&LdrUnloadDllMemory)__LdrUnloadDllMemory;
static void DisplayStatus() {
printf(
"\
MemoryModulePP [Version %d.%d%s]\n\n\t\
MmpFeatures = %08X\n\n\t\
LdrpModuleBaseAddressIndex = %p\n\t\
NtdllLdrEntry = %p\n\t\
RtlRbInsertNodeEx = %p\n\t\
RtlRbRemoveNode = %p\n\n\t\
LdrpInvertedFunctionTable = %p\n\n\t\
LdrpHashTable = %p\n\n\
",
MmpGlobalDataPtr->MajorVersion,
MEMORY_MODULE_GET_MINOR_VERSION(MmpGlobalDataPtr->MinorVersion),
MEMORY_MODULE_IS_PREVIEW(MmpGlobalDataPtr->MinorVersion) ? " Preview" : "",
MmpGlobalDataPtr->MmpFeatures,
MmpGlobalDataPtr->MmpBaseAddressIndex->LdrpModuleBaseAddressIndex,
MmpGlobalDataPtr->MmpBaseAddressIndex->NtdllLdrEntry,
MmpGlobalDataPtr->MmpBaseAddressIndex->_RtlRbInsertNodeEx,
MmpGlobalDataPtr->MmpBaseAddressIndex->_RtlRbRemoveNode,
MmpGlobalDataPtr->MmpInvertedFunctionTable->LdrpInvertedFunctionTable,
MmpGlobalDataPtr->MmpLdrEntry->LdrpHashTable
);
}
static PVOID ReadDllFile(LPCSTR FileName) {
LPVOID buffer;
size_t size;
FILE* f;
fopen_s(&f, FileName, "rb");
if (!f)return 0;
_fseeki64(f, 0, SEEK_END);
if (!(size = _ftelli64(f))) {
fclose(f);
return 0;
}
_fseeki64(f, 0, SEEK_SET);
buffer = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
fread(buffer, 1, size, f);
fclose(f);
return buffer;
}
PVOID ReadDllFile2(LPCSTR FileName) {
CHAR path[MAX_PATH + 4];
DWORD len = GetModuleFileNameA(nullptr, path, sizeof(path));
if (len) {
while (len && path[len] != '\\') --len;
if (len) {
strcpy_s(&path[len + 1], sizeof(path) - len - 1, FileName);
return ReadDllFile(path);
}
}
return nullptr;
}
ULONG_PTR ReflectiveLoaderOffset() {
ULONG_PTR offset = 0;
auto hm = LoadLibrary("MemoryModule.dll");
if (hm) {
auto pfn = GetProcAddress(hm, "ReflectiveLoader");
offset = ULONG_PTR(pfn) - ULONG_PTR(hm);
auto header = RtlImageNtHeader(hm);
auto section = IMAGE_FIRST_SECTION(header);
for (int i = 0; i < header->FileHeader.NumberOfSections; ++i, ++section) {
if (offset >= section->VirtualAddress && offset < section->VirtualAddress + section->SizeOfRawData) {
offset = ULONG_PTR(pfn) - (ULONG_PTR(hm) + section->VirtualAddress) + section->PointerToRawData;
break;
}
}
FreeLibrary(hm);
}
return offset;
}
typedef ULONG_PTR(WINAPI* LOADER)(PVOID);
int main() {
auto buffer = ReadDllFile2("MemoryModule.dll");
printf("1: %p\n", buffer);
auto loader = LOADER(ULONG_PTR(buffer) + 0x96a0); //ReflectiveLoaderOffset() -> 0x96a0
auto hm = (HMODULE)loader(buffer);
printf("2: %p\n", hm);
MmpGlobalDataPtr = *(PMMP_GLOBAL_DATA*)GetProcAddress(hm, "MmpGlobalDataPtr");
printf("3: %p\n", MmpGlobalDataPtr);
__LdrLoadDllMemoryExW = (decltype(&LdrLoadDllMemoryExW))GetProcAddress(hm, "LdrLoadDllMemoryExW");
__LdrUnloadDllMemory = (decltype(&LdrUnloadDllMemory))GetProcAddress(hm, "LdrUnloadDllMemory");
printf("4: %p, %p\n", __LdrLoadDllMemoryExW, __LdrUnloadDllMemory);
//DisplayStatus();
return 0;
}
以下代码用vs2019编译运行无误 用 gcc(msys2) 或 clang 编译后运行均会崩溃
错误模块名称: MemoryModule.dll_unloaded,版本: 0.0.0.0,时间戳: 0x657d714a 异常代码: 0xc0000005 错误偏移量: 0x0000000000007be0
崩溃原因是 FreeLibrary(hm); 造成的。
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "ntdll.lib")
NTSYSAPI
PIMAGE_NT_HEADERS
NTAPI
RtlImageNtHeader(
PVOID BaseOfImage
);
ULONG_PTR ReflectiveLoaderOffset() {
ULONG_PTR offset = 0;
ULONG_PTR pfn;
HMODULE hm;
hm = LoadLibrary("MemoryModule.dll");
if (hm) {
pfn = (ULONG_PTR)GetProcAddress(hm, "ReflectiveLoader");
offset = pfn - (ULONG_PTR)hm;
PIMAGE_NT_HEADERS header = (PIMAGE_NT_HEADERS)RtlImageNtHeader(hm);
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(header);
for (int i = 0; i < header->FileHeader.NumberOfSections; ++i, ++section) {
if (offset >= section->VirtualAddress && offset < section->VirtualAddress + section->SizeOfRawData) {
offset = pfn - ((ULONG_PTR)hm + section->VirtualAddress) + section->PointerToRawData;
break;
}
}
FreeLibrary(hm);
}
else {
printf("not found MemoryModule.dll");
}
return offset;
}
int main() {
printf("\nReflectiveLoader offset -> %p\n", ReflectiveLoaderOffset());
return 0;
}
不能获取到地址的问题我没能复现,不知道你有没有改过什么地方。建议把#pragma comment(lib,"MemoryModule.lib")
这一行删除再试试。如果编译报错就把Loader.h的64~72行删除。
FreeLibrary崩溃的问题确实存在,因为MMPP会hook一些ntdll的函数,卸载后可能会发生异常。使用LoadLibrary和GetProcAddress是偷懒的做法,应该读取dll然后手动解析导出表。参考https://github.com/stephenfewer/ReflectiveDLLInjection/blob/master/inject/src/LoadLibraryR.c 的实现。
dll 版我没有改动任何地方。 我又测试了一下,你用的dll是编译的 Debug 版,确实没问题,你编译成 Release 版问题就可以复现了(可能是编译优化造成的)。 看样子以后 Debug 版和 Release 版都要测试一下才稳妥。
FreeLibrary崩溃的问题比较怪异,Vc编译的没问题,gcc和clang编译的有问题。
Release编译会忽略所有的断言,包括里面的表达式也不会求值,所以导致了MMPP没有正确初始化。
可否改一下使Release版可用。
代码已更新
修改神速,赞,Release版测试运行无误了,感谢感谢。
1: 000001C82C630000
2: 000001C82C860000
3: 000001C82C670000
4: 000001C82C868D70, 000001C82C869400
MemoryModulePP [Version 2.0]
MmpFeatures = 0000007F
LdrpModuleBaseAddressIndex = 00007FF9B8E94D98
NtdllLdrEntry = 000001C82C69DE10
RtlRbInsertNodeEx = 00007FF9B8D2F5F0
RtlRbRemoveNode = 00007FF9B8D2ED50
LdrpInvertedFunctionTable = 00007FF9B8EA8500
LdrpHashTable = 00007FF9B8E93D60
问题复现如下:
从 http://jacquelin.potier.free.fr/HeliumHexEditor 下载64位版,解压将其中的 HexControl64.dll 改为 HexControl64_orig.dll.
然后编译自己的 HexControl64.dll从内存加载HexControl64_orig.dll,主要程序如下:
运行程序 HeliumHexEditor64.exe 后HexControl64_orig.dll加载成功,但弹窗报错,关闭报错窗口可继续使用。
使用 MemoryModule 或 RDI 方法加载不会报错,但程序不稳定,启动10次会出现几次crash。
麻烦帮忙看看是哪里的问题造成的。
另外:LoadLibraryMemoryExA 的参数 Flag 没有传递给 LoadLibraryMemoryExW