//////////////////////////////////////////////////////////////////// // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine // All rights reserved // This file was released under the GPLv2 on June 2015. //////////////////////////////////////////////////////////////////// #ifdef MY_USE_INTERNAL_MEMMANAGER #ifdef _X86_ __inline VOID DbgTouch(IN PVOID addr) { __asm { mov eax,addr mov al,[byte ptr eax] } } #else // NO X86 optimization , use generic C/C++ __inline VOID DbgTouch(IN PVOID addr) { UCHAR a = ((PUCHAR)addr)[0]; } #endif // _X86_ //MEM_ALLOC_DESC Allocs[MY_HEAP_MAX_BLOCKS]; MEM_FRAME_ALLOC_DESC FrameList[MY_HEAP_MAX_FRAMES]; #ifdef MEM_LOCK_BY_SPINLOCK KSPIN_LOCK FrameLock; KIRQL oldIrql; #define LockMemoryManager() KeAcquireSpinLock(&FrameLock, &oldIrql) #define UnlockMemoryManager() KeReleaseSpinLock(&FrameLock, oldIrql) __inline NTSTATUS InitLockMemoryManager() { KeInitializeSpinLock(&FrameLock); return STATUS_SUCCESS; } #define DeinitLockMemoryManager() {NOTHING;} #else //MEM_LOCK_BY_SPINLOCK ERESOURCE FrameLock; #define LockMemoryManager() ExAcquireResourceExclusiveLite(&FrameLock, TRUE) #define UnlockMemoryManager() ExReleaseResourceForThreadLite(&FrameLock, ExGetCurrentResourceThread()) #define InitLockMemoryManager() ExInitializeResourceLite(&FrameLock) #define DeinitLockMemoryManager() ExDeleteResourceLite(&FrameLock) #endif //MEM_LOCK_BY_SPINLOCK ULONG FrameCount; ULONG LastFrame; BOOLEAN MyMemInitialized = FALSE; #define MyAllocIsFrameFree(FrameList, i) \ (!(FrameList[i].LastUsed || FrameList[i].FirstFree)) #ifdef UDF_DBG ULONG MemTotalAllocated; PCHAR BreakAddr; VOID MyAllocDumpDescr( PMEM_ALLOC_DESC Allocs, ULONG i ) { BOOLEAN Used; Used = (Allocs[i].Len & MY_HEAP_FLAG_USED) ? TRUE : FALSE; UDFPrint(("block %x \t%s addr %x len %x \t", i, Used ? "used" : "free", Allocs[i].Addr, (Allocs[i].Len) & MY_HEAP_FLAG_LEN_MASK)); #ifdef MY_HEAP_TRACK_OWNERS UDFPrint(("src %x \t line %d \t", Allocs[i].Src, Allocs[i].Line)); #endif #ifdef MY_HEAP_TRACK_REF UDFPrint(("%s%s", Used ? " " : "-", Allocs[i].Tag ? Allocs[i].Tag : "")); #endif UDFPrint(("\n")); } //#define CHECK_ALLOC_FRAMES #define DUMP_MEM_FRAMES #ifdef DUMP_MEM_FRAMES ULONG MyDumpMem = FALSE; #endif //DUMP_MEM_FRAMES #define DUMP_MEM_FRAMES2 //#ifdef CHECK_ALLOC_FRAMES VOID MyAllocDumpFrame( ULONG Frame ) { ULONG i; PMEM_ALLOC_DESC Allocs; Allocs = FrameList[Frame].Frame; ULONG k=0; BOOLEAN Used; #ifdef DUMP_MEM_FRAMES if(!MyDumpMem) #endif //DUMP_MEM_FRAMES return; UDFPrint(("Dumping frame %x\n",Frame)); UDFPrint(("FirstFree %x LastUsed %x ", FrameList[Frame].FirstFree, FrameList[Frame].LastUsed)); UDFPrint(("Type %x\n", FrameList[Frame].Type)); if(Allocs) { for(i=0;i< (MY_HEAP_MAX_BLOCKS/*-1*/);i++) { Used = (Allocs[i].Len & MY_HEAP_FLAG_USED) ? TRUE : FALSE; UDFPrint(("block %x \t%s addr %x len %x \t", i, Used ? "used" : "free", Allocs[i].Addr, (Allocs[i].Len) & MY_HEAP_FLAG_LEN_MASK)); #ifdef MY_HEAP_TRACK_OWNERS UDFPrint(("src %x \t line %d \t", Allocs[i].Src, Allocs[i].Line)); #endif #ifdef MY_HEAP_TRACK_REF UDFPrint(("%s%s", Used ? " " : "-", Allocs[i].Tag ? Allocs[i].Tag : "")); #endif UDFPrint(("\n")); if(!(Allocs[i].Len) && !(Allocs[i].Addr)) { break; } if(Allocs[i].Len & MY_HEAP_FLAG_USED) k += ((Allocs[i].Len) & MY_HEAP_FLAG_LEN_MASK); } } UDFPrint((" Wasted %x bytes from %x\n", MY_HEAP_FRAME_SIZE - k, MY_HEAP_FRAME_SIZE)); } // end MyAllocDumpFrame() VOID MyAllocDumpFrames( VOID ) { ULONG i; for(i=0;i= (MY_HEAP_MAX_BLOCKS-1)) return NULL; for(i=FirstFree, Allocs = &(Allocs0[i]);i<=LastUsed;i++, Allocs++) { if( !((l = Allocs->Len) & MY_HEAP_FLAG_USED) && ((l &= MY_HEAP_FLAG_LEN_MASK) >= size) ) { // check if minimal // check for first occurence if(l < min_len || !min_len) { min_len = l; best_i = i; } if(l == size) break; } } // not enough resources if(best_i >= MY_HEAP_MAX_BLOCKS) return NULL; // mark as used Allocs = Allocs0+best_i; addr = Allocs->Addr; // create entry for unallocated tail if(Allocs->Len != size) { // this element is always FREE if(Allocs[1].Len) { if(Allocs0[MY_HEAP_MAX_BLOCKS-1].Len) return NULL; /* for(i=MY_HEAP_MAX_BLOCKS-1;i>best_i;i--) { Allocs[i] = Allocs[i-1]; }*/ RtlMoveMemory(&(Allocs[1]), &(Allocs[0]), (LastUsed-best_i+1)*sizeof(MEM_ALLOC_DESC)); } Allocs[1].Addr = Allocs->Addr + size; if(Allocs[1].Len) { Allocs[1].Len -= size; } else { Allocs[1].Len = MY_HEAP_FRAME_SIZE - (addr - Allocs0[0].Addr) - size; } // Allocs[best_i+1].Used = FALSE; // this had been done by prev. ops. FrameList[Frame].LastUsed++; } // update FirstFree pointer if(FirstFree == best_i) { for(i=best_i+1, Allocs++; (i<=LastUsed) && (Allocs->Len & MY_HEAP_FLAG_USED);i++, Allocs++) { // do nothing but scan } FrameList[Frame].FirstFree = i; Allocs = Allocs0+best_i; } Allocs->Len = size | MY_HEAP_FLAG_USED; #ifdef MY_HEAP_TRACK_OWNERS Allocs->Src = Src; Allocs->Line = Line; #endif #ifdef MY_HEAP_TRACK_REF Allocs->Tag = Tag; #endif //MY_HEAP_TRACK_REF // UDFPrint(( "Mem: Allocated %x at addr %x\n", size, (ULONG)addr )); // this will set IntegrityTag to zero *((PULONG)addr) = 0x00000000; #ifdef MY_HEAP_CHECK_BOUNDS for(i=0; i> 1; // UDFPrint(("Mem: Freeing %x\n", (ULONG)addr)); DEADDA7A // for(i=0;i> 1; if( (Allocs[i].Len & MY_HEAP_FLAG_USED) && (Allocs[i].Addr == (ULONG)addr) ) { FIF_Found: return i; } if(right - left == 1) { if( (Allocs[i+1].Len & MY_HEAP_FLAG_USED) && (Allocs[i+1].Addr == (ULONG)addr) ) { i++; goto FIF_Found; } break; } if(Allocs[i].Addr && (Allocs[i].Addr < (ULONG)addr)) { left = i; } else { right = i; } } return -1; } // end MyFindMemDescByAddr() VOID __fastcall MyFreePoolInFrame( ULONG Frame, PCHAR addr ) { LONG i, j; ULONG pc; ULONG len, len2; PMEM_ALLOC_DESC Allocs; Allocs = FrameList[Frame].Frame; pc = 0; i = MyFindMemDescByAddr(Frame, addr); if(i < 0) { UDFPrint(("Mem: <<<*** WARNING ***>>> Double deallocation at %x !!! ;( \n", addr)); MyAllocDumpFrame(Frame); BrutePoint(); return; } Allocs[i].Len &= ~MY_HEAP_FLAG_USED; len = Allocs[i].Len; // USED bit is already cleared #ifdef MY_HEAP_CHECK_BOUNDS for(j=0; j>> when somebody try to use it *((PULONG)addr) = 0xDEADDA7A; MemTotalAllocated -= len; #endif if((i0) && !((len2 = Allocs[i-1].Len) & MY_HEAP_FLAG_USED)) { // pack down len += (len2 & MY_HEAP_FLAG_LEN_MASK); pc++; i--; } if(pc) { // pack Allocs[i+pc].Addr = Allocs[i].Addr; Allocs[i+pc].Len = len; /* for(;i (ULONG)i) FrameList[Frame].FirstFree = (ULONG)i; //ASSERT(FrameList[Frame].LastUsed >= pc); if(FrameList[Frame].LastUsed < pc) { FrameList[Frame].LastUsed = 0; } else { FrameList[Frame].LastUsed -= pc; } return; } // end MyFreePoolInFrame() BOOLEAN __fastcall MyResizePoolInFrame( ULONG Frame, PCHAR addr, ULONG new_len #ifdef MY_HEAP_TRACK_REF ,PCHAR* Tag #endif //MY_HEAP_TRACK_REF ) { LONG i, j; ULONG len, len2; PMEM_ALLOC_DESC Allocs; if(FrameList[Frame].LastUsed >= (MY_HEAP_MAX_BLOCKS-1)) return FALSE; Allocs = FrameList[Frame].Frame; i = MyFindMemDescByAddr(Frame, addr); if(i < 0) { UDFPrint(("Mem: <<<*** WARNING ***>>> Double deallocation at %x !!! ;( \n", addr)); MyAllocDumpFrame(Frame); BrutePoint(); return FALSE; } if(i>=(MY_HEAP_MAX_BLOCKS-2)) return FALSE; #ifdef MY_HEAP_TRACK_REF *Tag = Allocs[i].Tag; #endif //MY_HEAP_TRACK_REF len = (Allocs[i].Len & MY_HEAP_FLAG_LEN_MASK); #ifdef MY_HEAP_CHECK_BOUNDS new_len += MY_HEAP_CHECK_BOUNDS_BSZ; for(j=0; j len ) { if(Allocs[i+1].Len & MY_HEAP_FLAG_USED) return FALSE; if(len + (Allocs[i+1].Len & MY_HEAP_FLAG_LEN_MASK) < new_len) return FALSE; Allocs[i].Len += (len2 = (new_len - len)); Allocs[i+1].Len -= len2; Allocs[i+1].Addr += len2; #ifdef MY_HEAP_CHECK_BOUNDS for(j=0; j (ULONG)i) FrameList[Frame].FirstFree = i; FrameList[Frame].LastUsed++; } else { Allocs[i+1].Len += len2; Allocs[i+1].Addr -= len2; } #ifdef UDF_DBG MemTotalAllocated -= len2; #endif } return TRUE; } // end MyResizePoolInFrame() VOID __fastcall MyAllocInitFrame( ULONG Type, ULONG Frame ) { PMEM_ALLOC_DESC Allocs; Allocs = (PMEM_ALLOC_DESC)DbgAllocatePool(NonPagedPool, sizeof(MEM_ALLOC_DESC)*(MY_HEAP_MAX_BLOCKS+1)); if(!Allocs) { UDFPrint(("Insufficient resources to allocate frame descriptor\n")); FrameList[Frame].Frame = NULL; MyAllocDumpFrames(); BrutePoint(); return; } RtlZeroMemory(Allocs, sizeof(MEM_ALLOC_DESC)*(MY_HEAP_MAX_BLOCKS+1)); // alloc heap Allocs[0].Addr = (ULONG)DbgAllocatePool((POOL_TYPE)Type, MY_HEAP_FRAME_SIZE); if(!Allocs[0].Addr) { UDFPrint(("Insufficient resources to allocate frame\n")); DbgFreePool(Allocs); FrameList[Frame].Frame = NULL; MyAllocDumpFrames(); BrutePoint(); return; } Allocs[0].Len = MY_HEAP_FRAME_SIZE; // Allocs[0].Used = FALSE; FrameList[Frame].Frame = Allocs; FrameList[Frame].LastUsed = FrameList[Frame].FirstFree = 0; FrameList[Frame].Type = Type; FrameCount++; if(LastFrame < Frame) LastFrame = Frame; } // end MyAllocInitFrame() VOID __fastcall MyAllocFreeFrame( ULONG Frame ) { // check if already deinitialized if(!FrameList[Frame].Frame) { BrutePoint(); return; } DbgFreePool((PVOID)(FrameList[Frame].Frame)[0].Addr); DbgFreePool((PVOID)(FrameList[Frame].Frame)); FrameList[Frame].Frame = NULL; FrameCount--; if(LastFrame == Frame) { LONG i; for(i=LastFrame; i>0; i--) { if(FrameList[i].Frame) break; } LastFrame = i; } } // end MyAllocFreeFrame() PCHAR #ifndef MY_HEAP_TRACK_OWNERS __fastcall #endif MyAllocatePool( ULONG type, ULONG size #ifdef MY_HEAP_TRACK_OWNERS ,USHORT Src, USHORT Line #endif #ifdef MY_HEAP_TRACK_REF ,PCHAR Tag #endif //MY_HEAP_TRACK_REF ) { ULONG i; ULONG addr; // UDFPrint(("MemFrames: %x\n",FrameCount)); if(!size || (size > MY_HEAP_FRAME_SIZE)) return NULL; #ifdef DUMP_MEM_FRAMES2 if(MyDumpMem) MyAllocDumpFrames(); #endif LockMemoryManager(); for(i=0;i= (ULONG)BreakAddr && addr < sizeof(UDF_FILE_INFO) + (ULONG)BreakAddr) { // if(addr<=(ULONG)BreakAddr && addr+sizeof(UDF_FILE_INFO) > (ULONG)BreakAddr) { // UDFPrint(("ERROR !!! Allocating in examined block\n")); // UDFPrint(("addr %x\n", addr)); // MyAllocDumpFrame(i); // BrutePoint(); // } #endif //UDF_DBG UnlockMemoryManager(); DbgTouch((PVOID)addr); return (PCHAR)addr; } } #ifdef DUMP_MEM_FRAMES2 MyAllocDumpFrames(); #endif addr = 0; for(i=0;i= (ULONG)BreakAddr && addr < sizeof(UDF_FILE_INFO) + (ULONG)BreakAddr) { // if(addr<=(ULONG)BreakAddr && addr+sizeof(UDF_FILE_INFO) > (ULONG)BreakAddr) { // UDFPrint(("ERROR !!! Allocating in examined block\n")); // UDFPrint(("addr %x\n", addr)); // MyAllocDumpFrame(i); // BrutePoint(); // } // } else { // addr = 0; #endif //UDF_DBG } #ifdef DUMP_MEM_FRAMES2 MyAllocDumpFrames(); #endif break; } } UnlockMemoryManager(); return (PCHAR)addr; } // end MyAllocatePool() LONG __fastcall MyFindFrameByAddr( PCHAR addr ) { ULONG i; // ULONG j; PMEM_ALLOC_DESC Allocs; for(i=0;i<=LastFrame; i++) { if( (Allocs = FrameList[i].Frame) && (Allocs[0].Addr <= (ULONG)addr) && (Allocs[0].Addr + MY_HEAP_FRAME_SIZE > (ULONG)addr) ) { return i; } } return -1; } VOID __fastcall MyFreePool( PCHAR addr ) { LONG i; // UDFPrint(("MemFrames: %x\n",FrameCount)); LockMemoryManager(); i = MyFindFrameByAddr(addr); if(i < 0) { UnlockMemoryManager(); UDFPrint(("Mem: <<<*** WARNING ***>>> Double deallocation at %x !!! ;( \n", addr)); BrutePoint(); return; } #ifdef UDF_DBG // BreakAddr <= addr < BreakAddr + sizeof(UDF_FILE_INFO) // if((ULONG)addr >= (ULONG)BreakAddr && (ULONG)addr < sizeof(UDF_FILE_INFO) + (ULONG)BreakAddr) { // UDFPrint(("Deallocating in examined block\n")); // UDFPrint(("addr %x\n", addr)); // MyAllocDumpFrame(i); // BrutePoint(); // BreakAddr = NULL; // } #endif //UDF_DBG MyFreePoolInFrame(i,addr); /* for(j=0;j>> Double deallocation at %x !!! ;( \n", addr)); BrutePoint(); return 0; } if(MyResizePoolInFrame(i,addr,NewLength #ifdef MY_HEAP_TRACK_REF , &Tag #endif )) { #ifdef CHECK_ALLOC_FRAMES MyAllocCheck(i); #endif (*NewBuff) = addr; DbgTouch((PVOID)addr); UnlockMemoryManager(); return NewLength; } new_buff = MyAllocatePool(FrameList[i].Type, MyAlignSize__(NewLength) #ifdef MY_HEAP_TRACK_OWNERS ,Src,Line #endif #ifdef MY_HEAP_TRACK_REF ,Tag #endif //MY_HEAP_TRACK_REF ); if(!new_buff) { UnlockMemoryManager(); return 0; } if(OldLength > NewLength) OldLength = NewLength; RtlCopyMemory(new_buff, addr, OldLength); MyFreePoolInFrame(i,addr); if(MyAllocIsFrameFree(FrameList, i)) { MyAllocFreeFrame(i); } UnlockMemoryManager(); DbgTouch((PVOID)new_buff); (*NewBuff) = new_buff; return OldLength; } // end MyReallocPool() #ifdef UDF_DBG LONG MyFindMemDescByRangeInFrame( ULONG Frame, PCHAR addr ) { ULONG i; ULONG left; ULONG right; PMEM_ALLOC_DESC Allocs; ULONG curaddr; ULONG curlen; Allocs = FrameList[Frame].Frame; // i = FrameList[Frame].LastUsed >> 1; // UDFPrint(("Mem: Freeing %x\n", (ULONG)addr)); DEADDA7A // for(i=0;i> 1; curaddr = Allocs[i].Addr; curlen = Allocs[i].Len; if( (curlen & MY_HEAP_FLAG_USED) && (curaddr <= (ULONG)addr) && ((curaddr+(curlen & MY_HEAP_FLAG_LEN_MASK)) > (ULONG)addr) ) { FIF_Found: return i; } if(right - left == 1) { if( (Allocs[i+1].Len & MY_HEAP_FLAG_USED) && (Allocs[i+1].Addr == (ULONG)addr) ) { i++; goto FIF_Found; } break; } if(Allocs[i].Addr && (Allocs[i].Addr < (ULONG)addr)) { left = i; } else { right = i; } } return -1; } // end MyFindMemDescByRangeInFrame() LONG MyFindMemBaseByAddr( PCHAR addr ) { ULONG Frame, Base, i; LockMemoryManager(); Frame = MyFindFrameByAddr(addr); if(Frame < 0) { UnlockMemoryManager(); UDFPrint(("Mem: <<<*** WARNING ***>>> Unknown base for %x !!! ;( \n", addr)); BrutePoint(); return -1; } i = MyFindMemDescByRangeInFrame(Frame, addr); Base = FrameList[Frame].Frame[i].Addr; UnlockMemoryManager(); return Base; } // end MyFindMemBaseByAddr() #endif //UDF_DBG BOOLEAN MyAllocInit(VOID) { RtlZeroMemory(&FrameList, sizeof(FrameList)); if(!OS_SUCCESS(InitLockMemoryManager())) { return FALSE; } MyAllocInitFrame(NonPagedPool, 0); LastFrame = 0; return (MyMemInitialized = TRUE); } // end MyAllocInit() VOID MyAllocRelease(VOID) { ULONG i; PMEM_ALLOC_DESC Allocs; if(!MyMemInitialized) return; LockMemoryManager(); for(i=0;i