Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/byakugan/tenketsu.cpp
Views: 11765
#include <windows.h>1#include <stdlib.h>23#include "byakugan.h"4#include "tenketsu.h"5#include "heapStructs.h"67#define BUFSIZE 409689// UNDOCUMENTED FUNCTIONS TO ADD10//11// RtlAllocateMemoryBlockLookaside12// RtlFreeMemoryBlockLookaside13//14// RtlCreateMemoryBlockLookaside15// RtlDestroyMemoryBlockLookaside16//17// RtlExtendMemoryBlockLookaside18// RtlResetMemoryBlockLookaside1920PCSTR undocdFunc[] = { "ntdll!RtlpCoalesceFreeBlocks", NULL };21ULONG undocdAddr[sizeof (undocdFunc)+1];2223struct HeapState heapModel;24BOOLEAN running = FALSE;2526// Two things that fucking rock? Bunnies and Jaguars. Werd.272829int hookRtlHeap(BYTE type, char *fileName) {30HRESULT Status;31HANDLE process;32DWORD pid;33HANDLE processHandle = 0;34HANDLE threadHandle = 0;35LPVOID stringAddress = NULL;36LPCSTR dllName = "C:\\windbg\\injectsu.dll";37ULONG64 funcAddr64;38ULONG *funcAddr, i;3940heapModel.state = heapModel.state ^ type;4142if (running) {43dprintf("[Byakugan] Hooks are already injected.\n");44return (0);45}4647running = TRUE;4849dprintf("[Byakugan] Beginning data gathering thread... ");50if(tenkListener()) {51dprintf("\n[Byakugan] Failed to create heap info back channel :(\n");52VirtualFreeEx(processHandle, stringAddress, strlen(dllName), MEM_DECOMMIT);53CloseHandle(processHandle);54return (-1);55}56dprintf("Success!\n[Byakugan] Injecting Tenketsu Heap Monitoring DLL... ");5758Status = g_ExtSystem->GetCurrentProcessSystemId(&pid);59if (Status != S_OK)60return (-1);6162if(!(processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid))){63dprintf("\n[Byakugan] Unable to OpenProcess().\n");64return (-1);65}6667if(!(stringAddress = VirtualAllocEx(processHandle, NULL, strlen(dllName), MEM_COMMIT, PAGE_EXECUTE_READWRITE))){68printf("\n[Byakugan] VirtualAllocEx() failed.\n");69CloseHandle(processHandle);70return (-1);71}7273if(!WriteProcessMemory(processHandle, (LPVOID)stringAddress, dllName, strlen(dllName), NULL)){74dprintf("\n[Byakugan] WriteProcessMemory() failed.\n");75VirtualFreeEx(processHandle, stringAddress, strlen(dllName), MEM_DECOMMIT);76CloseHandle(processHandle);77return (-1);78}7980dprintf("Success!\n");8182// Resolve undocumented functions!83i = 0;84g_ExtSymbols->Reload("/f ntdll.dll");85dprintf("[Byakugan] Resolving undocumented Heap functions...\n");86while (undocdFunc[i] != NULL) {87if (g_ExtSymbols->GetOffsetByName(undocdFunc[i], &funcAddr64) == E_FAIL)88funcAddr64 = NULL;89funcAddr = (ULONG *) &funcAddr64;90if (*funcAddr != NULL)91dprintf("[T] Resolved undocumented function '%s' @ 0x%08x.\n", undocdFunc[i], *funcAddr);92else93dprintf("[T] Unable to resolve undocumented function '%s' :(\n", undocdFunc[i]);94undocdAddr[i] = *funcAddr;95i++;96}97undocdAddr[i] = NULL;9899100if(!(threadHandle = CreateRemoteThread(processHandle, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(LoadLibrary("kernel32.dll"), "LoadLibraryA"), \101(LPVOID)stringAddress, 0, NULL))){102dprintf("\n[Byakugan] CreateRemoteThread() failed.\n");103VirtualFreeEx(processHandle, stringAddress, strlen(dllName), MEM_DECOMMIT);104CloseHandle(processHandle);105return (-1);106}107108CloseHandle(threadHandle);109CloseHandle(processHandle);110111// Set up the log file112if (type == 2) {113heapModel.hLogFile = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);114if (!heapModel.hLogFile) {115dprintf("[T] Unable to open file \"%s\" for writing. :(\n");116}117}118119return (0);120}121122int tenkListener(void) {123BOOL fConnected;124DWORD dwThreadId;125HANDLE hPipe, hThread;126LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\tenketsu");127128129hPipe = CreateNamedPipe( lpszPipename,130PIPE_ACCESS_DUPLEX,131PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,132PIPE_UNLIMITED_INSTANCES,133BUFSIZE,134BUFSIZE,135NMPWAIT_USE_DEFAULT_WAIT,136NULL);137138if (hPipe == INVALID_HANDLE_VALUE) {139dprintf("[Byakugan] CreateNamedPipe() failed.\n");140return (-1);141}142143144hThread = CreateThread( NULL,1450,146tenkBackChannel,147(LPVOID) hPipe,1480,149&dwThreadId);150151if (hThread == NULL) {152dprintf("[Byakugan] CreateThread() failed.\n");153return (-1);154}155156157CloseHandle(hThread);158159160161return (0);162}163164DWORD WINAPI tenkBackChannel(LPVOID lpvParam) {165HANDLE hPipe;166TCHAR buf[BUFSIZE+1];167ULONG bytesRead, bytesWritten;168BOOL fSuccess;169ULONG64 funcAddr64;170ULONG *funcAddr, i;171172173struct AllocateStruct *aStruct = (struct AllocateStruct *)buf;174struct ReallocateStruct *rStruct = (struct ReallocateStruct *)buf;175struct FreeStruct *fStruct = (struct FreeStruct *)buf;176struct CreateStruct *cStruct = (struct CreateStruct *)buf;177struct DestroyStruct *dStruct = (struct DestroyStruct *)buf;178struct CoalesceStruct *cfbStruct = (struct CoalesceStruct *)buf;179180181hPipe = (HANDLE) lpvParam;182183dprintf("[Byakugan] Waiting for named pipe connection...\n");184185for(;!ConnectNamedPipe(hPipe, NULL) == TRUE;) { dprintf("[B] waiting for connection...\n"); }186187dprintf("[Byakugan] Connected to back channel. :)\n");188189// Load addresses from symbols if possible for undoumented interfaces190i = 0;191while (undocdFunc[i] != NULL) {192dprintf("[T] Sending address of %s\n", undocdFunc[i]);193fSuccess = WriteFile(hPipe, &(undocdAddr[i]), sizeof(ULONG), &bytesWritten, NULL);194if (!fSuccess || bytesWritten != sizeof(ULONG))195dprintf("[T] Failed to send address of %s\n", undocdFunc[i]);196i++;197}198//FlushFileBuffers(hPipe);199dprintf("[T] Sent addresses of %d undocumented functions.\n", i);200201initializeHeapModel(&heapModel);202203#undef THREEDHEAPFU_ENABLED //Place this in setup.bat204205#if 0 //#ifdef THREEDHEAPFU_ENABLED206//Create a heap event proxy, play these back out to 3dheapfu207LPTSTR lpszProxyPipename = TEXT("\\\\.\\pipe\\tenketsuProxy");208BOOL fProxySuccess;209DWORD dwProxyMode = PIPE_READMODE_MESSAGE;210ULONG bytesProxyWritten;211static BOOL fDontAttemptProxyWrite = false;212213HANDLE hProxyPipe = CreateFile(lpszProxyPipename,214GENERIC_READ | GENERIC_WRITE,2150,216NULL,217OPEN_EXISTING,2180,219NULL);220221if (hProxyPipe == INVALID_HANDLE_VALUE)222dprintf("hProxyPipe == invalid handle\n");223else224dprintf("hProxyPipe == good\n");225SetNamedPipeHandleState(hProxyPipe, &dwProxyMode, NULL, NULL); //?226227#endif228229while (1) {230fSuccess = ReadFile( hPipe,231buf,232BUFSIZE*sizeof(TCHAR),233&bytesRead,234NULL);235if (!fSuccess || bytesRead == 0) {236dprintf("[Byakugan] ReadFile failed, or read 0 bytes.\n");237continue;238}239#if 0 //#ifdef THREEDHEAPFU_ENABLED240//dprintf("jc: receieved an event of size %d. Forwarding on to ProxyPipe\n", bytesRead);241//WriteFile(hPipe, &freeinfo, sizeof(struct FreeStruct), &bytesWritten, NULL);242243if (!fDontAttemptProxyWrite)244{245fProxySuccess = WriteFile(hProxyPipe, buf, bytesRead, &bytesProxyWritten, NULL);246if (bytesRead != bytesProxyWritten)247{248dprintf("Partial write to proxy on last event! ;(\n");249dprintf("event size was %d. wrote %d\n", bytesRead, bytesProxyWritten);250dprintf("Disabling message proxying until explicitly enabled.\n");251fDontAttemptProxyWrite = true;252}253}254255#endif256switch ( *((BYTE *) buf) ) {257case ALLOCATESTRUCT:258//dprintf("[T] New Chunk @ 0x%08x\n", aStruct->ret);259//dprintf("Heap: 0x%08x\tFlags: 0x%08x\tSize: 0x%08x\n\n",260// aStruct->heapHandle, aStruct->flags, aStruct->size);261if (heapModel.state & MODEL) heapAllocate(&heapModel, aStruct);262if (heapModel.state & LOG) logAllocate(&heapModel, aStruct);263break;264265case REALLOCATESTRUCT:266//dprintf("[T] Realloc'd Chunk @ 0x%08x\n", rStruct->ret);267//dprintf("Heap: 0x%08x\tFlags: 0x%08x\tSize: 0x%08x\n",268// rStruct->heapHandle, rStruct->flags, rStruct->size);269//if (rStruct->ret != (PVOID) rStruct->memoryPointer)270// dprintf("Replaces chunk @ 0x%08x\n", rStruct->memoryPointer);271//dprintf("\n");272if (heapModel.state & MODEL) heapReallocate(&heapModel, rStruct);273if (heapModel.state & LOG) logReallocate(&heapModel, rStruct);274break;275276case FREESTRUCT:277//dprintf("[T] Free'd Chunk @ 0x%08x\n", fStruct->memoryPointer);278//dprintf("Heap: 0x%08x\tFlags: 0x%08x\n\n", fStruct->heapHandle, fStruct->flags);279if (heapModel.state & MODEL) heapFree(&heapModel, fStruct);280if (heapModel.state & LOG) logFree(&heapModel, fStruct);281break;282283case CREATESTRUCT:284dprintf("[T] New Heap: 0x%08x\n", cStruct->ret);285dprintf("Base: 0x%08x\tReserve: 0x%08x\tFlags: 0x%08x\n",286cStruct->base, cStruct->reserve, cStruct->flags);287//dprintf("Commit: 0x%08x\tLock: 0x%08x\n\n", cStruct->commit, cStruct->lock);288if (heapModel.state & MODEL) heapCreate(&heapModel, cStruct);289break;290291case DESTROYSTRUCT:292dprintf("[T] Heap Destroyed: 0x%08x\n\n", dStruct->heapHandle);293if (heapModel.state & MODEL) heapDestroy(&heapModel, dStruct);294break;295296case COALESCESTRUCT:297//dprintf("[T] Free Block Consolidation (returned 0x%08x)\n", cfbStruct->ret);298//dprintf("Heap: 0x%08x\tArg2: 0x%08x\tArg3: 0x%08x\tArg4: 0x%08x\n\n",299// cfbStruct->heapHandle, cfbStruct->arg2, cfbStruct->arg3, cfbStruct->arg4);300if (heapModel.state & MODEL) heapCoalesce(&heapModel, cfbStruct);301break;302303default:304dprintf("[Byakugan] Tenketsu: Unrecognized data was returned.\n");305}306307}308309310return (0);311}312313void tenkHelp() {314dprintf(HELPSTRING);315dprintf("Tenketsu Commands:\n");316dprintf("\tmodel\t- Load tenketsu heap visualization libraries and begin modeling\n");317dprintf("\tlog\t- Load tenketsu heap visualization libraries and begin logging\n");318dprintf("\tlistHeaps\t- List all currently tracked heaps and their information\n");319dprintf("\tlistChunks <heap base>\t- List all chunks associated with a givend heap\n");320dprintf("\tvalidate <heap base> - check the chunk chain and find corrupted chunk headers\n");321}322323void tenkListHeaps() {324struct HPool *curHeap;325ULONG i;326327dprintf("[T] Currently tracking %d heaps:\n", heapModel.numHeaps);328for (i = 0; i < heapModel.numHeaps; i++) {329curHeap = &(heapModel.heaps[i]);330if (curHeap->inUse == FALSE)331continue;332dprintf("\tBase: 0x%08x\tNumber of Chunks: %d\n", curHeap->base, curHeap->numChunks);333dprintf("\tFlags: 0x%08x\tReserve: 0x%08x\n",334curHeap->flags, curHeap->reserve, curHeap->commit);335dprintf("\tLock: 0x%08x\n\n", curHeap->lock);336}337}338339void tenkValidate(PVOID heapHandle) {340struct HPool *heap;341struct DestroyStruct dStruct;342struct HeapChunk *curChunk;343ULONG chunkPtr;344ULONG i, nextIndex;345BOOL screwed = FALSE;346347heap = getHeap(&heapModel, heapHandle);348349i = heap->inUseHead;350while (i != NULLNODE) {351if (CHUNK(i).free) {352// CHUNK(i).nextInUse must be equal to the next ptr353if(!ReadMemory((ULONG64)(CHUNK(i).addr)+4, (PVOID) &chunkPtr, 4, NULL)) {354dprintf("[T] Unable to read memory at address 0x%08x\n!");355return;356}357358// Find next free chunk - continue if there are no more359nextIndex = CHUNK(i).nextInUse;360while (nextIndex != NULLNODE && !(CHUNK(nextIndex).free))361nextIndex = CHUNK(nextIndex).nextInUse;362if (nextIndex == NULLNODE) {363i = CHUNK(i).nextInUse;364continue;365}366367// Validate next free chunk368if (CHUNK(nextIndex).addr != (PVOID) chunkPtr) {369dprintf("[T] Corruped next pointer for chunk at 0x%08x\n", CHUNK(i).addr);370dprintf(">\tGot: 0x%08x\tExpected: 0x%08x\n", chunkPtr, CHUNK(nextIndex).addr);371screwed = TRUE;372}373374// next free chunk prev, must equal CHUNK(i).addr375if(!ReadMemory((ULONG64)CHUNK(nextIndex).addr, (PVOID) &chunkPtr, 4, NULL)) {376dprintf("[T] Unable to read memory at address 0x%08x\n!");377return;378}379if ((PVOID) chunkPtr != CHUNK(i).addr) {380dprintf("[T] Corruped prev pointer for chunk at 0x%08x\n", CHUNK(nextIndex).addr);381dprintf(">\tGot: 0x%08x\tExpected: 0x%08x\n", chunkPtr, CHUNK(i).addr);382screwed = TRUE;383}384385386} else {387}388i = CHUNK(i).nextInUse;389}390391dprintf("[T] Validation complete: ");392if (!screwed)393dprintf("all known free chunks are correct\n");394else395dprintf("errors found\n");396}397398void tenkListChunks(PVOID heapHandle) {399struct HPool *heap;400struct DestroyStruct dStruct;401struct HeapChunk *curChunk;402ULONG i;403404heap = getHeap(&heapModel, heapHandle);405dprintf("[T] Currently tracking %d chunks for heap 0x%08x\n",406heap->numChunks, heap->base);407408i = heap->inUseHead;409while (i != NULLNODE) {410if (CHUNK(i).inUse) {411dprintf("\tAddress: 0x%08x\tSize: 0x%08x", CHUNK(i).addr, CHUNK(i).size);412dprintf("\tFlags: 0x%08x\t%s\n\n", CHUNK(i).flags,413(CHUNK(i).free)?"FREE'D":"IN USE");414}415i = CHUNK(i).nextInUse;416}417418if (heap->numChunks == 0) {419dStruct.heapHandle = heap->base;420heapDestroy(&heapModel, &dStruct);421}422}423424425