首页 > 代码库 > 在地址0上分配内存

在地址0上分配内存

在 NULL 地址上分配内存看似是不可行的 ,因为对于内存分配函数  

NTSTATUS ZwAllocateVirtualMemory(
  _In_     HANDLE ProcessHandle,
  _Inout_  PVOID *BaseAddress,
  _In_     ULONG_PTR ZeroBits,
  _Inout_  PSIZE_T RegionSize,
  _In_     ULONG AllocationType,
  _In_     ULONG Protect
);

你将 BaseAddress 指向 0 传入,这个函数会认为你是想在任意可用的地址上分配内存,而不是0 (系统不会把0地址内存当中可用到 )。绕过的方法就是指定 AllocationType 为MEM_TOP_DOWN 也就是从上向下分配内存 ,此时指定 BaseAddress 为一个 低地址,例如 1,同时指定分配内存的大小 大于这个值 ,例如 8192(一个内存页),这样分配成功后 地址范围就是 0xFFFFE001 (-8191) 到 1 把 0 地址包含在内了,此时再去尝试向 NULL 指针执行的地址写数据,会发现程序不会异常了 。

    这个说到底是微软实现该函数的时候没有考虑全面导致一些安全措施被绕过 (0地址分配内存,应用层可以在高地址(内核空间)分配内存),在最新的系统补丁中微软已经修复了这个漏洞。

    该技巧主要利用在漏洞的利用上,例如使用 null 指针,或者函数失败返回负数,程序没有检查返回值,把这个负数当中指针来使用。这些情况可以使用这个技巧来利用漏洞。

 测试代码

// testnull.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>

typedef NTSTATUS ( __stdcall *P_ZwAllocateVirtualMemory)(
	_In_     HANDLE ProcessHandle,
	_Inout_  PVOID *BaseAddress,
	_In_     ULONG_PTR ZeroBits,
	_Inout_  PSIZE_T RegionSize,
	_In_     ULONG AllocationType,
	_In_     ULONG Protect
	);


int _tmain(int argc, _TCHAR* argv[])
{
	HMODULE hnt = LoadLibraryA("ntdll.dll");
	P_ZwAllocateVirtualMemory pfZwAllocateVirtualMemory = (P_ZwAllocateVirtualMemory)GetProcAddress(hnt, "ZwAllocateVirtualMemory");
	ULONG base = 1;
	PVOID *p = (PVOID *)&base;
	SIZE_T s = 8192;
	ULONG eax = pfZwAllocateVirtualMemory((HANDLE)-1, p, 0, &s, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);
	if (eax != 0)
	{
		printf("error %08x ",eax);
	}

	char *c = 0;
	*c = ‘x‘; //不会异常
	return 0;
}


在地址0上分配内存