• LyScript 通过PEB结构解析堆基址


    LyScript中默认并没有提供获取进程堆基址的函数,不过却提供了获取PEB/TEB的函数,以PEB获取为例,可以调用dbg.get_peb_address(local_pid)用户传入当前进程的PID号,通常PID号可以使用dbg.get_process_id()函数得到,当得到了PEB进程环境块的基地址,那么获取堆基址就变得很简单了。

    首先以获取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 MyDebug
    
    if __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 @$peb
    ntdll!_PEB+0x090 ProcessHeaps
    
    0:000> dd 7c99ffe0 l8
    7c99ffe0  00150000 00250000 00260000 00000000
    7c99fff0  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_address
    
    if __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 MyDebug
    import struct
    
    class _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 MyDebug
    import struct
    import string
    
    DEBUG = False
    
    class _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_Next
    
    if __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 MyDebug
    import struct
    import 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_buffer
    
    def readLong(address):
        return dbg.read_memory_dword(address)
    
    # 得到进程PEB
    class _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()
    

    输出效果:

  • 相关阅读:
    WEB引入Google思源黑体
    Linux安装最新版Node.js
    JS判断值是否是数字
    高效jQuery的奥秘
    一个Web前端工程师或程序员的发展方向,未来困境及穷途末路
    javascript 模块化 (切记:学习思想)
    学习 正则表达式 js java c# python 通用
    Promise如何解决回调地狱
    VSCode 开发插件 推荐
    js移动端自适应动态设置html的fontsize
  • 原文地址:https://www.cnblogs.com/LyShark/p/16683857.html
Copyright © 2020-2023  润新知