测试代码:
typedef NTSTATUS(NTAPI *ntalloc64t)(HANDLE, PULONG64, ULONG64, PULONG64, ULONG, ULONG);
#define NtCurrentProcess() ( (HANDLE)(PULONG64) -1 ) ;
int _tmain(int argc, _TCHAR* argv[])
{
ULONG64 dwSize = 0x1000;
ntalloc64t ntalloc64f = (ntalloc64t)(GetProcAddress(GetModuleHandleA("ntdll"), "NtWow64AllocateVirtualMemory64"));
PVOID pvBaseAddress;
pvBaseAddress = (PVOID)NULL;
long kk = ntalloc64f((HANDLE)GetCurrentProcess(), (PULONG64)&pvBaseAddress, 0, (PULONG64)&dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
}
我在WOW64下运行。这将返回0xc0000008,这意味着句柄无效。将-1作为句柄传递时也不起作用,这应该指示WinAPI使用当前进程。
答案 0 :(得分:3)
NtWow64AllocateVirtualMemory64
未记录,但您可以假设其参数与NtAllocateVirtualMemory
几乎相同,并且MSDN对基本地址参数说明了这一点:
指向将接收已分配页面区域的基址的变量的指针。 如果此参数的初始值为非NULL,则从指定的虚拟地址开始分配区域,向下舍入到下一个主机页面大小地址边界。如果此参数的初始值为NULL,则操作系统将确定分配区域的位置。
你正在隐藏你的演员的错误; (PULONG64)&pvBaseAddress
指向来自堆栈某处的pvBaseAddress = (PVOID)NULL
和 32个未定义位的32位零,如果这些位不是全零,那么您要求的是特定的基址可能没有!
删除尽可能多的演员阵容,它应该开始工作:
typedef NTSTATUS(NTAPI *ntalloc64t)(HANDLE, PULONG64, ULONG64, PULONG64, ULONG, ULONG);
ntalloc64t ntalloc64f = (ntalloc64t) GetProcAddress(GetModuleHandleA("ntdll"), "NtWow64AllocateVirtualMemory64");
// TODO: if (!ntalloc64f) not wow64, handle error...
HANDLE hTargetProcess = OpenProcess(...);
ULONG64 base = 0, size = 0x1000;
long nts = ntalloc64f(hTargetProcess, &base, 0, &size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
printf("status=%d base=%I64x size=%I64x\n", nts, base, size);
答案 1 :(得分:1)
当我们从32位ntdll.dll调用NtWow64AllocateVirtualMemory64
时(它只存在于wow64 ntdll.dll中)whNtWow64AllocateVirtualMemory64
(64位函数)在wow64.dll
内调用。我从win10汇编代码重建:
struct Wow64AllocateVirtualMemory64_Stack {
ULONG ProcessHandle;// !!! unsigned !!
ULONG BaseAddress;
ULONG64 ZeroBits;
ULONG RegionSize;
ULONG AllocationType;
ULONG Protection;
};
NTSTATUS
NTAPI
whNtWow64AllocateVirtualMemory64(Wow64AllocateVirtualMemory64_Stack* p)
{
return NtAllocateVirtualMemory(
(HANDLE)(ULONG_PTR)p->ProcessHandle,
(void**)(ULONG_PTR)p->BaseAddress,
p->ZeroBits,
(PSIZE_T)(ULONG_PTR)p->RegionSize,
p->AllocationType,
p->Protection);
}
这里的关键点是HANDLE
在32位代码中是32位大小,在64位代码中是64位大小。因此,32位句柄值必须扩展为64位代码中的64位句柄。但它可以零或符号扩展。当然,当我们扩展正32bit值(实际处理句柄) - 没有什么不同,结果将是相同的。但是当我们扩展负值-1
时 - 零延伸的结果将是0xFFFFFFFF
(这是无效的句柄)。符号扩展的结果 - 将是0xFFFFFFFFFFFFFFFF
- 纠正当前进程的伪句柄。 windows 10使用零扩展句柄:
结果我们不能在这里使用-1(GetCurrentProcess()
)
win8使用sign-extend句柄:
但是没有任何意义使用这个api在wow64进程中分配内存。确实 - 如果我们接受任何内存基地址,或者< 4GB - 我们可以使用NtAllocateVirtualMemory
或VirtualAlloc[Ex]
。所以这个功能只有在我们想要在基地址> = 4Gb分配内存的情况下才有意义。但这在wow64过程中是不可能的。 - 系统保留所有高于> = 4G的内存空间。 wow64bit进程的典型内存映射(使用/LARGEADDRESSAWARE
选项)
这里只显示64位ntdll.dll,并保留所有其他内存。
没有/LARGEADDRESSAWARE
选项保留范围从7FFF0000
开始。此保留的内存也无法释放 - 在通话NtFreeVirtualMemory
(从64位进程)我收到STATUS_INVALID_PAGE_PROTECTION
错误。
所以没有意义使用这个api来分配内部自我(和任何另一个wow64进程)。只有我们想要在64位进程中分配内存而不是简单地分配,但是在高于4GB的范围内。我甚至不知道这可能需要哪个目标 - 为什么< 4GB内存基数,可以通常NtAllocateVirtualMemory
或VirtualAlloc[Ex]
分配。并且很有趣,没有相关的NtWow64FreeVirtualMemory64
api - 所以不可能的免费分配记忆。当然可能写入base-Independed(并且因此没有导入)64位代码,嵌入在32位进程中,通过64个调用门调用它,这段代码可以从64位ntdll调用函数(并且只能从它调用)并返回。这是可能的,但已经是另一个故事了