#include <windows.h>
#include <detours.h>
#define NTSTATUS ULONG

#include "../heapStructs.h"

/* NoxHeapINT(ELLiGENCE) - because heap stupidity means no 0day
 * (or Tenketsu)
 * ------------------------------------------------------------
 * By Lin0xx / Pusscat
 * ------------------------------------------------------------
 * This dll is intended to be injected into a target
 * application whose heap allocations, reallocations, and frees
 * need to be tracked.  The end goal for this program is to be
 * able to communicate to a visualization server that will draw
 * the heap as it is in real time.  This view of the heap can
 * then be diff'd via walking the heap by finding the heap base
 * in the process environment block.  By doing this, one will
 * be able to understand how an application is molding the heap
 * along with the nature of the overflow in question.  
 */

#define NTSTATUS	ULONG
#define BUFSIZE		4096
/* UNDOCUMENTED HEAP STRUCTURES */

typedef struct _RTL_HEAP_DEFINITION {
  ULONG                   Length;
  ULONG                   Unknown1;
  ULONG                   Unknown2;
  ULONG                   Unknown3;
  ULONG                   Unknown4;
  ULONG                   Unknown5;
  ULONG                   Unknown6;
  ULONG                   Unknown7;
  ULONG                   Unknown8;
  ULONG                   Unknown9;
  ULONG                   Unknown10;
  ULONG                   Unknown11;
  ULONG                   Unknown12;
} RTL_HEAP_DEFINITION, *PRTL_HEAP_DEFINITION;


LPTSTR	lpszPipename	= TEXT("\\\\.\\pipe\\tenketsu"); 
HANDLE	hPipe;			
DWORD	dwMode			= PIPE_READMODE_MESSAGE;
DWORD	bytesWritten;

/* Functions to be hooked */
PVOID (WINAPI *realRtlAllocateHeap)(PVOID heapHandle, ULONG flags, ULONG size);
PVOID (WINAPI *realRtlReallocateHeap)(PVOID heapHandle, ULONG flags, PVOID memoryPointer, ULONG size);
PVOID (WINAPI *realRtlFreeHeap)(PVOID heapHandle, ULONG flags, PVOID memoryPointer);

PVOID (WINAPI *realRtlCreateHeap)(ULONG flags, PVOID base, ULONG reserve, ULONG commit, BOOLEAN lock, PRTL_HEAP_DEFINITION RtlHeapParams);

NTSTATUS (WINAPI *realRtlDestroyHeap)(PVOID heapHandle);
PVOID (WINAPI *realRtlpCoalesceFreeBlocks)(PVOID, ULONG, ULONG, ULONG);

/* TO ADD:
 * RtlAllocateMemoryBlockLookaside
 * RtlpCoalesceFreeBlocks
 */

/* End hooking section */

PVOID WINAPI noxRtlFreeHeap(PVOID heapHandle, ULONG flags, PVOID memoryPointer){
	PVOID	ret;
	struct FreeStruct	freeinfo;

	ret = (*realRtlFreeHeap)(heapHandle, flags, memoryPointer);

	freeinfo.type			= FREESTRUCT;
	freeinfo.heapHandle		= heapHandle;
	freeinfo.flags			= flags;
	freeinfo.memoryPointer	= memoryPointer;
	freeinfo.ret			= ret;

	__asm 
	{ 
		push ebx
		mov ebx, [ebp+4]
		mov freeinfo.caller, ebx
		pop ebx
	}

	WriteFile(hPipe, &freeinfo, sizeof(struct FreeStruct), &bytesWritten, NULL);
	
	return (ret);

}

PVOID WINAPI noxRtlReallocateHeap(PVOID heapHandle, ULONG flags, PVOID memoryPointer, ULONG size){
	PVOID	ret;
	struct	ReallocateStruct	reallocinfo;
	
	ret = (*realRtlReallocateHeap)(heapHandle, flags, memoryPointer, size);
    reallocinfo.type          = REALLOCATESTRUCT;
    reallocinfo.heapHandle    = heapHandle;
    reallocinfo.flags         = flags;
    reallocinfo.memoryPointer = memoryPointer;
    reallocinfo.size          = size;
    reallocinfo.ret           = ret;

    __asm 
    { 
        push ebx 
        mov ebx, [ebp+4]            
        mov reallocinfo.caller, ebx
        pop ebx 
    }

    WriteFile(hPipe, &reallocinfo, sizeof(struct ReallocateStruct), &bytesWritten, NULL);

	return (ret);
}

PVOID WINAPI noxRtlAllocateHeap(PVOID heapHandle, ULONG flags, ULONG size){
	PVOID	ret;
	struct	AllocateStruct allocinfo;

	ret = (*realRtlAllocateHeap)(heapHandle, flags, size);

	allocinfo.type			= ALLOCATESTRUCT;
	allocinfo.heapHandle	= heapHandle;
	allocinfo.flags			= flags;
	allocinfo.size			= size;
	allocinfo.ret			= ret;

    __asm 
    { 
        push ebx 
        mov ebx, [ebp+4]            
        mov allocinfo.caller, ebx
        pop ebx 
    }

	WriteFile(hPipe, &allocinfo, sizeof(struct AllocateStruct), &bytesWritten, NULL);

	return (ret);
}

PVOID WINAPI noxRtlCreateHeap(	ULONG flags, 
								PVOID base, 
								ULONG reserve, 
								ULONG commit, 
								BOOLEAN lock, 
								PRTL_HEAP_DEFINITION RtlHeapParams) {
	PVOID	ret;
	struct	CreateStruct	createinfo;

	ret = (*realRtlCreateHeap)(flags, base, reserve, commit, lock, RtlHeapParams);

	createinfo.type				= CREATESTRUCT;
	createinfo.flags			= flags;
	createinfo.base				= base;
	createinfo.reserve			= reserve;
	createinfo.commit			= commit;
	createinfo.lock				= lock;
	createinfo.RtlHeapParams	= RtlHeapParams;
	createinfo.ret				= ret;

	WriteFile(hPipe, &createinfo, sizeof(struct CreateStruct), &bytesWritten, NULL);

	return (ret);
}

NTSTATUS WINAPI noxRtlDestroyHeap(PVOID heapHandle) {
	NTSTATUS	ret;
	struct 	DestroyStruct	destroyinfo;

	ret = (*realRtlDestroyHeap)(heapHandle);

	destroyinfo.type		= DESTROYSTRUCT;
	destroyinfo.heapHandle	= heapHandle;
	destroyinfo.ret			= ret;

	WriteFile(hPipe, &destroyinfo, sizeof(struct DestroyStruct), &bytesWritten, NULL);
	
	return (ret);
}

// PLACEHOLDER FUNCTION
PVOID WINAPI noxRtlpCoalesceFreeBlocks(PVOID heapHandle, ULONG arg2, ULONG arg3, ULONG arg4) {
	struct CoalesceStruct	coalesceinfo;
	PVOID					ret;

	coalesceinfo.type		= COALESCESTRUCT;
	coalesceinfo.heapHandle	= heapHandle;
	coalesceinfo.arg2		= arg2;
	coalesceinfo.arg3		= arg3;
	coalesceinfo.arg4		= arg4;

	WriteFile(hPipe, &coalesceinfo, sizeof(struct CoalesceStruct), &bytesWritten, NULL);

	ret = (*realRtlpCoalesceFreeBlocks)(heapHandle, arg2, arg3, arg4);

	return (ret);
}

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD attachReason, LPVOID reserved) {
	ULONG		bytesRead;
	TCHAR		buf[BUFSIZE];
	NTSTATUS	fSuccess;

	if(attachReason == DLL_PROCESS_ATTACH){
		DetourTransactionBegin();
		DetourUpdateThread(GetCurrentThread());

		/* There's no other way to find these addresses than dynamically */
		realRtlAllocateHeap = DetourFindFunction("ntdll.dll", "RtlAllocateHeap");
		realRtlReallocateHeap = DetourFindFunction("ntdll.dll", "RtlReAllocateHeap");
		realRtlFreeHeap = DetourFindFunction("ntdll.dll", "RtlFreeHeap");
		realRtlCreateHeap = DetourFindFunction("ntdll.dll", "RtlCreateHeap");
		realRtlDestroyHeap = DetourFindFunction("ntdll.dll", "RtlDestroyHeap");
	
		

		/* Start hooking */
		DetourAttach(&(PVOID)realRtlAllocateHeap, noxRtlAllocateHeap);
		DetourAttach(&(PVOID)realRtlReallocateHeap, noxRtlReallocateHeap);
		DetourAttach(&(PVOID)realRtlFreeHeap, noxRtlFreeHeap);
		DetourAttach(&(PVOID)realRtlCreateHeap, noxRtlCreateHeap);
		DetourAttach(&(PVOID)realRtlDestroyHeap, noxRtlDestroyHeap);
		//while (1) {
			hPipe = CreateFile(	lpszPipename,
								GENERIC_READ | GENERIC_WRITE,
								0,
								NULL,
								OPEN_EXISTING,
								0,
								NULL);

			if (hPipe == INVALID_HANDLE_VALUE)	// got a handle, so we're done
				__asm {int 3}

		//	WaitNamedPipe(lpszPipename, 2000);	// Wait two seconds before retry
		//}
		SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL);
		
		// Get addresses of unexposed heap functions if the debugger has symbols
		ReadFile(	hPipe,
                    &realRtlpCoalesceFreeBlocks,
                    //BUFSIZE*sizeof(TCHAR),
                    4,
					&bytesRead,
                    NULL);
		if (realRtlpCoalesceFreeBlocks != NULL)
			DetourAttach(&(PVOID)realRtlpCoalesceFreeBlocks, noxRtlpCoalesceFreeBlocks);
		
		//FlushFileBuffers(hPipe);

		DetourTransactionCommit();

	}

	if(attachReason == DLL_PROCESS_DETACH){
		DetourTransactionBegin();
		DetourUpdateThread(GetCurrentThread());
		
		/* Start unhooking */
		DetourDetach(&(PVOID)realRtlAllocateHeap, noxRtlAllocateHeap);
		DetourDetach(&(PVOID)realRtlReallocateHeap, noxRtlReallocateHeap);
		DetourDetach(&(PVOID)realRtlFreeHeap, noxRtlFreeHeap);
		DetourDetach(&(PVOID)realRtlCreateHeap, noxRtlCreateHeap);
		DetourDetach(&(PVOID)realRtlDestroyHeap, noxRtlDestroyHeap);

		DetourTransactionCommit();
	}

	return TRUE;
}


