LyScript中默认并没有提供获取过程堆基址的函数,不过却提供了获取PEB/TEB的函数,以PEB获取为例,能够调用dbg.get_peb_address(local_pid)
用户传入以后过程的PID号,通常PID号能够应用dbg.get_process_id()
函数失去,当失去了PEB过程环境块的基地址,那么获取堆基址就变得很简略了。
- 插件地址:https://github.com/lyshark/Ly...
首先以获取kernel32.dll
模块基地址为例,如果应用汇编获取则代码是这样的,依据这段代码咱们触类旁通。
_asm{ push esi mov esi, dword ptr fs : [0x30] // PEB地址 mov esi, [esi + 0x0C] // PEB_LDR_DATA mov esi, [esi + 0x1C] // InInitializationOrderModuleList mov esi, [esi] // mov eax, [esi + 0x08] // 模块基址 pop esi}
应用lyscript
失去地址的代码就变得很简略了,只须要屡次读取指针变量即可失去。
from LyScript32 import MyDebugif __name__ == "__main__": dbg = MyDebug() conn = dbg.connect() # 内置函数失去过程PEB local_pid = dbg.get_process_id() peb = dbg.get_peb_address(local_pid) print("过程PEB: {}".format(hex(peb))) # esi = PEB_LDR_DATA构造体的地址 ptr = peb + 0x0c # 读取内存指针 PEB_LDR_DATA = dbg.read_memory_ptr(ptr) print("读入PEB_LDR_DATA外面的地址: {}".format(hex(PEB_LDR_DATA))) # esi = 模块链表指针InInitializationOrderModuleList ptr = PEB_LDR_DATA + 0x1c InInitializationOrderModuleList = dbg.read_memory_ptr(ptr) print("读入InInitializationOrderModuleList外面的地址: {}".format(hex(InInitializationOrderModuleList))) # 取出kernel32.dll模块基址 ptr = InInitializationOrderModuleList + 0x08 modbase = dbg.read_memory_ptr(ptr) print("kernel32.dll = {}".format(hex(modbase))) dbg.close()
读取成果如下:
如上kernel模块基地址的获取曾经实现了,那么堆基址的获取也就非常简单了,咱们只须要找到peb+0x90
的地位,将其读取进去即可。
0:000> dt _peb @$pebntdll!_PEB+0x090 ProcessHeaps0:000> dd 7c99ffe0 l87c99ffe0 00150000 00250000 00260000 000000007c99fff0 00000000 00000000 00000000 00000000
读取内存指针即可失去堆地址,将堆地址获取封装成getHeapsAddress()
函数不便后续调用。
from LyScript32 import MyDebug# 获取模块基址def getKernelModuleBase(dbg): # 内置函数失去过程PEB local_pid = dbg.get_process_id() peb = dbg.get_peb_address(local_pid) # print("过程PEB: {}".format(hex(peb))) # esi = PEB_LDR_DATA构造体的地址 ptr = peb + 0x0c # 读取内存指针 PEB_LDR_DATA = dbg.read_memory_ptr(ptr) # print("读入PEB_LDR_DATA外面的地址: {}".format(hex(PEB_LDR_DATA))) # esi = 模块链表指针InInitializationOrderModuleList ptr = PEB_LDR_DATA + 0x1c InInitializationOrderModuleList = dbg.read_memory_ptr(ptr) # print("读入InInitializationOrderModuleList外面的地址: {}".format(hex(InInitializationOrderModuleList))) # 取出kernel32.dll模块基址 ptr = InInitializationOrderModuleList + 0x08 modbase = dbg.read_memory_ptr(ptr) # print("kernel32.dll = {}".format(hex(modbase))) return modbase# 获取过程堆基址def getHeapsAddress(dbg): # 内置函数失去过程PEB local_pid = dbg.get_process_id() peb = dbg.get_peb_address(local_pid) # print("过程PEB: {}".format(hex(peb))) # 读取堆调配地址 ptr = peb + 0x90 peb_address = dbg.read_memory_ptr(ptr) # print("读取堆调配: {}".format(hex(peb_address))) heap_address = dbg.read_memory_ptr(peb_address) # print("以后过程堆基址: {}".format(hex(heap_address))) return heap_addressif __name__ == "__main__": dbg = MyDebug() conn = dbg.connect() k32 = getKernelModuleBase(dbg) print("kernel32 = {}".format(hex(k32))) heap = getHeapsAddress(dbg) print("heap 堆地址: {}".format(hex(heap))) dbg.close()
读取成果如下:
构造的解析能够封装成一个PEB类,读入前488字节,并解析。
from LyScript32 import MyDebugimport structclass _PEB(): def __init__(self, dbg): # 内置函数失去过程PEB self.base = dbg.get_peb_address(dbg.get_process_id()) self.PEB = bytearray() # 填充前488字节 for index in range(0,488): readbyte = dbg.read_memory_byte(self.base + index) self.PEB.append(readbyte) """ 0:000> !kdex2x86.strct PEB Loaded kdex2x86 extension DLL struct _PEB (sizeof=488) +000 byte InheritedAddressSpace +001 byte ReadImageFileExecOptions +002 byte BeingDebugged +003 byte SpareBool +004 void *Mutant +008 void *ImageBaseAddress +00c struct _PEB_LDR_DATA *Ldr +010 struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters +014 void *SubSystemData +018 void *ProcessHeap +01c void *FastPebLock +020 void *FastPebLockRoutine +024 void *FastPebUnlockRoutine +028 uint32 EnvironmentUpdateCount +02c void *KernelCallbackTable +030 uint32 SystemReserved[2] +038 struct _PEB_FREE_BLOCK *FreeList +03c uint32 TlsExpansionCounter +040 void *TlsBitmap +044 uint32 TlsBitmapBits[2] +04c void *ReadOnlySharedMemoryBase +050 void *ReadOnlySharedMemoryHeap +054 void **ReadOnlyStaticServerData +058 void *AnsiCodePageData +05c void *OemCodePageData +060 void *UnicodeCaseTableData +064 uint32 NumberOfProcessors +068 uint32 NtGlobalFlag +070 union _LARGE_INTEGER CriticalSectionTimeout +070 uint32 LowPart +074 int32 HighPart +070 struct __unnamed3 u +070 uint32 LowPart +074 int32 HighPart +070 int64 QuadPart +078 uint32 HeapSegmentReserve +07c uint32 HeapSegmentCommit +080 uint32 HeapDeCommitTotalFreeThreshold +084 uint32 HeapDeCommitFreeBlockThreshold +088 uint32 NumberOfHeaps +08c uint32 MaximumNumberOfHeaps +090 void **ProcessHeaps +094 void *GdiSharedHandleTable +098 void *ProcessStarterHelper +09c uint32 GdiDCAttributeList +0a0 void *LoaderLock +0a4 uint32 OSMajorVersion +0a8 uint32 OSMinorVersion +0ac uint16 OSBuildNumber +0ae uint16 OSCSDVersion +0b0 uint32 OSPlatformId +0b4 uint32 ImageSubsystem +0b8 uint32 ImageSubsystemMajorVersion +0bc uint32 ImageSubsystemMinorVersion +0c0 uint32 ImageProcessAffinityMask +0c4 uint32 GdiHandleBuffer[34] +14c function *PostProcessInitRoutine +150 void *TlsExpansionBitmap +154 uint32 TlsExpansionBitmapBits[32] +1d4 uint32 SessionId +1d8 void *AppCompatInfo +1dc struct _UNICODE_STRING CSDVersion +1dc uint16 Length +1de uint16 MaximumLength +1e0 uint16 *Buffer """ # 初始化PEB index = 0x000 self.InheritedAddressSpace = self.PEB[index] index = 0x001 self.ReadImageFileExecOptions = self.PEB[index] index = 0x002 self.BeingDebugged = self.PEB[index] index = 0x003 self.SpareBool = self.PEB[index] index = 0x004 self.Mutant = self.PEB[index:index+4] index = 0x008 self.ImageBaseAddress = self.PEB[index:index+4] index = 0x00c self.Ldr = self.PEB[index:index+4] index = 0x010 self.ProcessParameters = self.PEB[index:index+4] index = 0x014 self.SubSystemData = self.PEB[index:index+4] index = 0x018 self.ProcessHeap = self.PEB[index:index+4] index = 0x01c self.FastPebLock = self.PEB[index:index+4] index = 0x020 self.FastPebLockRoutine = self.PEB[index:index+4] index = 0x024 self.FastPebUnlockRoutine = self.PEB[index:index+4] index = 0x028 self.EnviromentUpdateCount = self.PEB[index:index+4] index = 0x02c self.KernelCallbackTable = self.PEB[index:index+4] index = 0x030 self.SystemReserved = [] for i in range(0,2): self.SystemReserved.append(self.PEB[index:index+4]) index += 4 index = 0x038 self.FreeList = self.PEB[index:index+4] index = 0x03c self.TlsExpansionCounter = self.PEB[index:index+4] index = 0x040 self.TlsBitmap = self.PEB[index:index+4] index = 0x044 self.TlsBitmapBits = [] for i in range(0,2): self.TlsBitmapBits.append(self.PEB[index:index+4]) index += 4 index = 0x04c self.ReadOnlySharedMemoryBase = self.PEB[index:index+4] index = 0x050 self.ReadOnlySharedMemoryheap = self.PEB[index:index+4] index = 0x054 self.ReadOnlyStaticServerData = self.PEB[index:index+4] index = 0x058 self.AnsiCodePageData = self.PEB[index:index+4] index = 0x05c self.OemCodePageData = self.PEB[index:index+4] index = 0x060 self.UnicodeCaseTableData = self.PEB[index:index+4] index = 0x064 self.NumberOfProcessors = self.PEB[index:index+4] index = 0x068 self.NtGlobalFlag = self.PEB[index:index+4] # 这里的4个字节会产生什么 ? index = 0x070 self.CriticalSectionTimeout_LowPart = self.PEB[index:index+4] index = 0x074 self.CriticalSectionTimeout_HighPart = self.PEB[index:index+4] index = 0x078 self.HeapSegmentReserve = self.PEB[index:index+4] index = 0x07c self.HeapSegmentCommit = self.PEB[index:index+4] index = 0x080 self.HeapDeCommitTotalFreeThreshold = self.PEB[index:index+4] index = 0x084 self.HeapDeCommitFreeBlockThreshold = self.PEB[index:index+4] index = 0x088 self.NumberOfHeaps = self.PEB[index:index+4] index = 0x08c self.MaximumNumberOfHeaps = self.PEB[index:index+4] index = 0x090 self.ProcessHeaps = self.PEB[index:index+4] index = 0x094 self.GdiSharedHandleTable = self.PEB[index:index+4] index = 0x098 self.ProcessStarterHelper = self.PEB[index:index+4] index = 0x09c self.GdiDCAttributeList = self.PEB[index:index+4] index = 0x0a0 self.LoaderLock = self.PEB[index:index+4] index = 0x0a4 self.OSMajorVersion = self.PEB[index:index+4] index = 0x0a8 self.OSMinorVersion = self.PEB[index:index+4] index = 0x0ac self.OSBuildNumber = self.PEB[index:index+2] index = 0x0ae self.OSCSDVersion = self.PEB[index:index+2] index = 0x0b0 self.OSPlatformId = self.PEB[index:index+4] index = 0x0b4 self.ImageSubsystem = self.PEB[index:index+4] index = 0x0b8 self.ImageSubsystemMajorVersion = self.PEB[index:index+4] index = 0x0bc self.ImageSubsystemMinorVersion = self.PEB[index:index+4] index = 0x0c0 self.ImageProcessAffinityMask = self.PEB[index:index+4] index = 0x0c4 # uint32 GdiHandleBuffer[34] self.GdiHandleBuffer = [] for i in range(0,34): self.GdiHandleBuffer.append(self.PEB[index:index+4]) index += 4 index = 0x14c self.PostProcessInitRoutine = self.PEB[index:index+4] index = 0x150 self.TlsExpansionBitmap = self.PEB[index:index+4] index = 0x154 # uint32 TlsExpansionBitmapBits[32] self.TlsExpansionBitmapBits = [] for i in range(0,32): self.TlsExpansionBitmapBits.append(self.PEB[index:index+4]) index += 4 index = 0x1d4 self.SessionId = self.PEB[index:index+4] index = 0x1d8 self.AppCompatInfo = self.PEB[index:index+4] index = 0x1dc # struct _UNICODE_STRING CSDVersion self.CSDVersion_Length = self.PEB[index:index+2] index += 2 self.CSDVersion_MaximumLength = self.PEB[index:index+2] index += 2 self.CSDVersion_Buffer = self.PEB[index:index+2] index += 2 def get_BeingDebugged(self): return self.BeingDebugged def get_ProcessHeaps(self): pack = struct.unpack('<L', bytes(self.ProcessHeap)) return hex(pack[0])if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() # 初始化PEB填充构造 peb = _PEB(dbg) # 获取过程调试状态 is_debug = peb.get_BeingDebugged() print("是否被调试: {}".format(is_debug)) heap = peb.get_ProcessHeaps() print("堆地址: {}".format(heap)) dbg.close()
解析成果如下:
当咱们失去了堆的起始地址当前,那么对堆地址进行深度解析就变得很容易了,只须要填充特定的构造体,即可。
from LyScript32 import MyDebugimport structimport stringDEBUG = Falseclass _PEB(): def __init__(self, dbg): # 内置函数失去过程PEB self.base = dbg.get_peb_address(dbg.get_process_id()) self.PEB = bytearray() # 填充前488字节 for index in range(0, 488): readbyte = dbg.read_memory_byte(self.base + index) self.PEB.append(readbyte) index = 0x018 self.ProcessHeap = self.PEB[index:index + 4] def get_ProcessHeaps(self): pack = struct.unpack('<L', bytes(self.ProcessHeap)) return pack[0]class GrabHeap(): def __init__(self, dbg, heap_addr): # 内置函数失去过程PEB self.base = dbg.get_peb_address(dbg.get_process_id()) self.address = heap_addr self.buffer = bytearray() def grapHeap(self): for idx in range(0, 1416): readbyte = dbg.read_memory_byte(self.address + idx) self.buffer.append(readbyte) index = 0x8 (self.Signature, self.Flags, self.ForceFlags, self.VirtualMemoryThreshold, \ self.SegmentReserve, self.SegmentCommit, self.DeCommitFreeBlockThreshold, self.DeCommitTotalBlockThreshold, \ self.TotalFreeSize, self.MaximumAllocationSize, self.ProcessHeapListIndex, self.HeaderValidateLength, \ self.HeaderValidateCopy, self.NextAvailableTagIndex, self.MaximumTagIndex, self.TagEntries, \ self.UCRSegments, self.UnusedUnCommittedRanges, self.AlignRound, self.AlignMask) = \ struct.unpack("LLLLLLLLLLHHLHHLLLLL", self.buffer[index:index + (0x50 - 8)]) index += 0x50 - 8 self.VirtualAllocedBlock = struct.unpack("LL", self.buffer[index:index + 8]) index += 8 self._Segments = struct.unpack("L" * 64, self.buffer[index:index + 64 * 4]) index += 64 * 4 self.FreeListInUseLong = struct.unpack("LLLL", self.buffer[index:index + 16]) index += 16 (self.FreeListInUseTerminate, self.AllocatorBackTraceIndex) = struct.unpack("HH", self.buffer[index: index + 4]) index += 4 (self.Reserved1, self.LargeBlocksIndex) = struct.unpack("LL", self.buffer[index: index + 8]) def get_Signature(self): return self.Signature# 段class Segment(): def __init__(self, dbg, heap_addr): self.address = heap_addr self.buffer = bytearray() # AVOID THE ENTRY ITSELF self.address += 8 for idx in range(0, 0x34): readbyte = dbg.read_memory_byte(self.address + idx) self.buffer.append(readbyte) (self.Signature, self.Flags, self.Heap, self.LargestUnCommitedRange, self.BaseAddress, \ self.NumberOfPages, self.FirstEntry, self.LastValidEntry, self.NumberOfUnCommittedPages, \ self.NumberOfUnCommittedRanges, self.UnCommittedRanges, self.AllocatorBackTraceIndex, \ self.Reserved, self.LastEntryInSegment) = struct.unpack("LLLLLLLLLLLHHL", self.buffer) if DEBUG == True: print("SEGMENT: {} Sig: {}".format(hex(self.address), hex(self.Signature))) print("Heap: {} LargetUncommit {} Base: {}" .format(hex(self.Heap), hex(self.LargestUnCommitedRange), hex(self.BaseAddress))) print("NumberOfPages {} FirstEntry: {} LastValid: {}" .format(hex(self.NumberOfPages), hex(self.FirstEntry), hex(self.LastValidEntry))) print("Uncommited: {}".format(self.UnCommittedRanges)) Pages = [] Items = bytearray() if self.UnCommittedRanges: addr = self.UnCommittedRanges if addr != 0: # 读入内存 for idx in range(0, 0x10): readbyte = dbg.read_memory_byte(self.address + idx) Items.append(readbyte) (C_Next, C_Addr, C_Size, C_Filler) = struct.unpack("LLLL", Items) print("Memory: {} Address: {} (a: {}) Size: {}" .format(hex(self.address), hex(C_Next), C_Addr, C_Size)) Pages.append(C_Addr + C_Size) addr = C_Nextif __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() # 初始化PEB填充构造 peb = _PEB(dbg) # 堆地址 process_heap = peb.get_ProcessHeaps() print("堆地址: {}".format(hex(process_heap))) # 定义Segment heap = Segment(dbg, process_heap) # 输入内容 print("Signature = {}".format(heap.Signature)) print("Flags = {}".format(heap.Flags)) print("Heap = {}".format(heap.Heap)) # 初始化堆 heap = GrabHeap(dbg, process_heap) heap.grapHeap() # 获取Signature Signature = heap.get_Signature() print("Signature = {}".format(hex(Signature))) dbg.close()
解析堆内的段:
低内存堆的输入也能够应用如上办法实现,只是在输入是须要解析的构造体程序稍多一些,但总体上原理与上方代码统一。
from LyScript32 import MyDebugimport structimport string# 读内存def readMemory(address,size): ref_buffer = bytearray() for idx in range(0, size): readbyte = dbg.read_memory_byte(address + idx) ref_buffer.append(readbyte) return ref_bufferdef readLong(address): return dbg.read_memory_dword(address)# 失去过程PEBclass _PEB(): def __init__(self, dbg): # 内置函数失去过程PEB self.base = dbg.get_peb_address(dbg.get_process_id()) self.PEB = bytearray() self.PEB = readMemory(self.base,488) # 通过偏移找到ProcessHeap index = 0x018 self.ProcessHeap = self.PEB[index:index + 4] def get_ProcessHeaps(self): pack = struct.unpack('<L', bytes(self.ProcessHeap)) return pack[0]class UserMemoryCache(): def __init__(self, addr, mem): self.address = addr (self.Next, self.Depth, self.Sequence, self.AvailableBlocks,\ self.Reserved) = struct.unpack("LHHLL", mem[ 0 : 16 ])class Bucket(): def __init__(self, addr, mem): self.address = addr (self.BlockUnits, self.SizeIndex, Flag) =\ struct.unpack("HBB", mem[:4]) # 从实践上讲,这是标记的拆散形式 self.UseAffinity = Flag & 0x1 self.DebugFlags = (Flag >1) & 0x3# 低内存堆class LFHeap(): def __init__(self, addr): mem = readMemory(addr, 0x300) index = 0 self.address = addr (self.Lock, self.field_4, self.field_8, self.field_c,\ self.field_10, field_14, self.SubSegmentZone_Flink, self.SubSegmentZone_Blink, self.ZoneBlockSize,\ self.Heap, self.SegmentChange, self.SegmentCreate,\ self.SegmentInsertInFree, self.SegmentDelete, self.CacheAllocs,\ self.CacheFrees) = struct.unpack("L" * 0x10, mem[index:index+0x40]) index += 0x40 self.UserBlockCache = [] for a in range(0,12): umc = UserMemoryCache(addr + index, mem[index:index + 0x10]) index += 0x10 self.UserBlockCache.append(umc) self.Buckets = [] for a in range(0, 128): entry = mem[index: index + 4] b = Bucket(addr + index, entry) index = index + 4 self.Buckets.append(b)if __name__ == "__main__": dbg = MyDebug() connect = dbg.connect() # 初始化PEB填充构造 peb = _PEB(dbg) # 堆地址 process_heap = peb.get_ProcessHeaps() print("堆地址: {}".format(hex(process_heap))) # 定义低内存堆类 lf_heap = LFHeap(process_heap) print("堆内存锁: {}".format(hex(lf_heap.Lock))) print("堆地址: {}".format(hex(lf_heap.Heap))) print("堆调配: {}".format(hex(lf_heap.CacheAllocs))) # 循环输入block for index in lf_heap.UserBlockCache: print("地址: {} --> 下一个地址: {}".format(hex(index.address),hex(index.Next))) for index in lf_heap.Buckets: print(index.SizeIndex,index.DebugFlags) dbg.close()
输入成果: