mirror of
https://github.com/ivellioscolin/pykd.git
synced 2025-04-21 21:03:23 +08:00
245 lines
10 KiB
Python
245 lines
10 KiB
Python
import sys
|
|
import re
|
|
|
|
from pykd import *
|
|
|
|
tbuilder = typeBuilder()
|
|
|
|
IMAGE_RUNTIME_FUNCTION_ENTRY = tbuilder.createStruct( "IMAGE_RUNTIME_FUNCTION_ENTRY", 1 )
|
|
IMAGE_RUNTIME_FUNCTION_ENTRY.append( "BeginAddress", tbuilder.UInt4B )
|
|
IMAGE_RUNTIME_FUNCTION_ENTRY.append( "EndAddress", tbuilder.UInt4B )
|
|
IMAGE_RUNTIME_FUNCTION_ENTRY.append( "UnwindData", tbuilder.UInt4B )
|
|
|
|
PIMAGE_RUNTIME_FUNCTION_ENTRY = IMAGE_RUNTIME_FUNCTION_ENTRY.ptrTo()
|
|
|
|
IMAGE_DOS_HEADER = tbuilder.createStruct( "IMAGE_DOS_HEADER", 1 )
|
|
IMAGE_DOS_HEADER.append("e_magic", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_cblp", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_cp", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_crlc", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_cparhdr", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_minalloc", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_maxalloc", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_ss", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_sp", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_csum", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_ip", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_cs", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_lfarlc", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_ovno", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_res", tbuilder.UInt2B.arrayOf(4) )
|
|
IMAGE_DOS_HEADER.append("e_oemid", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_oeminfo", tbuilder.UInt2B )
|
|
IMAGE_DOS_HEADER.append("e_res2", tbuilder.UInt2B.arrayOf(10) )
|
|
IMAGE_DOS_HEADER.append("e_lfanew", tbuilder.UInt4B )
|
|
|
|
IMAGE_DATA_DIRECTORY = tbuilder.createStruct( "IMAGE_DATA_DIRECTORY", 1 )
|
|
IMAGE_DATA_DIRECTORY.append("VirtualAddress", tbuilder.UInt4B)
|
|
IMAGE_DATA_DIRECTORY.append("Size", tbuilder.UInt4B)
|
|
|
|
IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16
|
|
|
|
IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3
|
|
|
|
IMAGE_OPTIONAL_HEADER64 = tbuilder.createStruct( "IMAGE_OPTIONAL_HEADER64", 1 )
|
|
IMAGE_OPTIONAL_HEADER64.append( "Magic", tbuilder.UInt2B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "MajorLinkerVersion", tbuilder.UInt1B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "MinorLinkerVersion", tbuilder.UInt1B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "SizeOfCode", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "SizeOfInitializedData", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "SizeOfUninitializedData", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "AddressOfEntryPoint", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "BaseOfCode", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "ImageBase", tbuilder.UInt8B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "SectionAlignment", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "FileAlignment", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "MajorOperatingSystemVersion", tbuilder.UInt2B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "MinorOperatingSystemVersion", tbuilder.UInt2B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "MajorImageVersion", tbuilder.UInt2B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "MinorImageVersion", tbuilder.UInt2B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "MajorSubsystemVersion", tbuilder.UInt2B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "MinorSubsystemVersion", tbuilder.UInt2B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "Win32VersionValue", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "SizeOfImage", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "SizeOfHeaders", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "CheckSum", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "Subsystem", tbuilder.UInt2B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "DllCharacteristics", tbuilder.UInt2B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "SizeOfStackReserve", tbuilder.UInt8B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "SizeOfStackCommit", tbuilder.UInt8B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "SizeOfHeapReserve", tbuilder.UInt8B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "SizeOfHeapCommit", tbuilder.UInt8B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "LoaderFlags", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "NumberOfRvaAndSizes", tbuilder.UInt4B)
|
|
IMAGE_OPTIONAL_HEADER64.append( "DataDirectory", IMAGE_DATA_DIRECTORY.arrayOf(IMAGE_NUMBEROF_DIRECTORY_ENTRIES) )
|
|
|
|
IMAGE_FILE_HEADER = tbuilder.createStruct( "IMAGE_FILE_HEADER", 1 )
|
|
IMAGE_FILE_HEADER.append( "Machine", tbuilder.UInt2B)
|
|
IMAGE_FILE_HEADER.append( "NumberOfSections", tbuilder.UInt2B)
|
|
IMAGE_FILE_HEADER.append( "TimeDateStamp", tbuilder.UInt4B)
|
|
IMAGE_FILE_HEADER.append( "PointerToSymbolTable", tbuilder.UInt4B)
|
|
IMAGE_FILE_HEADER.append( "NumberOfSymbols", tbuilder.UInt4B)
|
|
IMAGE_FILE_HEADER.append( "SizeOfOptionalHeader", tbuilder.UInt2B)
|
|
IMAGE_FILE_HEADER.append( "Characteristics", tbuilder.UInt2B)
|
|
|
|
IMAGE_NT_HEADERS64 = tbuilder.createStruct( "IMAGE_NT_HEADERS64", 1 )
|
|
IMAGE_NT_HEADERS64.append( "Signature", tbuilder.UInt4B)
|
|
IMAGE_NT_HEADERS64.append( "FileHeader", IMAGE_FILE_HEADER )
|
|
IMAGE_NT_HEADERS64.append( "OptionalHeader", IMAGE_OPTIONAL_HEADER64 )
|
|
|
|
#def findRuntimeFunctionEntry(addr):
|
|
# pass
|
|
|
|
def findRuntimeFunctionTable( mod ):
|
|
|
|
dosHeader = typedVar( IMAGE_DOS_HEADER, mod )
|
|
ntHeader = typedVar( IMAGE_NT_HEADERS64, mod + dosHeader.e_lfanew )
|
|
runtimeTablePtr = mod + ntHeader.OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXCEPTION ].VirtualAddress
|
|
functionCount = ntHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size / IMAGE_RUNTIME_FUNCTION_ENTRY.size()
|
|
|
|
runtimeTable = typedVarArray( runtimeTablePtr, IMAGE_RUNTIME_FUNCTION_ENTRY, functionCount )
|
|
|
|
return runtimeTable
|
|
|
|
def getInstruction( funcaddr, prologOffset ):
|
|
dasm = disasm( funcaddr )
|
|
while dasm.current() < funcaddr + prologOffset:
|
|
instr = dasm.instruction()
|
|
offset = dasm.current()
|
|
dasm.disasm()
|
|
|
|
match = re.match( r"^[0-9a-f`]+\s+[0-9a-f]+\s+(\w+\s+(?:qword ptr |dword ptr )?[^\s]+)(?:\s+[^\s]+)?$", instr )
|
|
if match:
|
|
return ( offset, match.group(1) )
|
|
|
|
return ( offset, instr )
|
|
|
|
def uwopSaveNonvol( arg ):
|
|
code, data = arg
|
|
data.next()
|
|
return "4 - UWOP_SAVE_NONVOL"
|
|
|
|
def uwopAllocLarge( arg ):
|
|
code, data = arg
|
|
operationInfo = ( code >> 12 ) & 0xF
|
|
if operationInfo == 0:
|
|
data.next()
|
|
else:
|
|
data.next()
|
|
data.next()
|
|
return "1 - UWOP_ALLOC_LARGE"
|
|
|
|
def printUnwindCodes( funcaddr, data, prefixstr = "", postfixstr = "" ):
|
|
|
|
try:
|
|
|
|
while True:
|
|
|
|
unwindCode = data.next()
|
|
|
|
prologOffset = ( unwindCode ) & 0xFF
|
|
unwindOperation = ( unwindCode >> 8 ) & 0xF
|
|
operationInfo = ( unwindCode >> 12 ) & 0xF
|
|
|
|
unwindCodeStr = {
|
|
0 : lambda x : "0 - UWOP_PUSH_NONVOL",
|
|
1 : lambda x : uwopAllocLarge(x),
|
|
2 : lambda x : "2 - UWOP_ALLOC_SMALL",
|
|
3 : lambda x : "3 - UWOP_SET_FPREG",
|
|
4 : lambda x : uwopSaveNonvol(x),
|
|
10 : lambda x : "10 - UWOP_PUSH_MACHFRAME",
|
|
}.get( unwindOperation, "%d - unknown unwind operation" % unwindOperation )( (unwindCode, data ) )
|
|
|
|
instrOffset, instrMnem = getInstruction( funcaddr, prologOffset )
|
|
|
|
dprint( prefixstr )
|
|
dprint(hex(instrOffset) )
|
|
dprint("\t")
|
|
dprint( unwindCodeStr )
|
|
dprint("\t")
|
|
dprint( instrMnem )
|
|
dprint( postfixstr )
|
|
dprintln("")
|
|
|
|
except StopIteration:
|
|
pass
|
|
|
|
def getUnwindFlags( flags ):
|
|
|
|
return {
|
|
0 : "0",
|
|
1 : "1 - EHANDLER",
|
|
2 : "2 - UHANDLER",
|
|
4 : "4 - CHAININFO"
|
|
}.get(flags, "%x - Unknown flag" % flags)
|
|
|
|
def printUnwindInfo( modaddr, funcaddr, unwindInfo ):
|
|
dprintln( "Unwind Info:" )
|
|
|
|
version = ptrByte( unwindInfo ) & 7
|
|
flags = ( ptrByte( unwindInfo ) >> 3 ) & 0x1F
|
|
sizeOfProlog = ptrByte( unwindInfo + 1 )
|
|
countOfCodes = ptrByte( unwindInfo + 2 )
|
|
frameRegsiter = ptrByte( unwindInfo + 3 ) & 0xF
|
|
frameOffset = ( ptrByte( unwindInfo + 3 ) >> 4 ) & 0xF
|
|
unwindCodes = loadWords( unwindInfo + 4, countOfCodes )
|
|
|
|
dprintln( "\tversion: %d" % version )
|
|
dprintln( "\tflags: " + getUnwindFlags( flags ) )
|
|
dprintln( "\tsize of prolog %d" % sizeOfProlog )
|
|
dprintln( "\tcount of unwind code slots %d" % countOfCodes )
|
|
|
|
if frameRegsiter > 0:
|
|
dprintln( "\tframe regsiter: %s" % reg(frameRegsiter).name() )
|
|
dprintln( "\tframe offset: %d" % ( 16 * frameOffset ) )
|
|
|
|
dprintln( "\n\tUnwind codes:" )
|
|
|
|
printUnwindCodes( funcaddr, iter(unwindCodes), "\t\t" )
|
|
|
|
if flags == 1:
|
|
dprintln( "\n\tException handler:" )
|
|
addr = modaddr + ptrDWord( unwindInfo + 3 + 2*countOfCodes)
|
|
dprintln( "\t\t" + findSymbol(addr) )
|
|
|
|
|
|
def printVEHInfo(addr):
|
|
|
|
dprintln( "\nVEH Info\n" )
|
|
dprintln( "Function address: %x" % addr )
|
|
dprintln( "Function symbolic name: " + findSymbol(addr) )
|
|
|
|
funcModule = module(addr)
|
|
dprintln( "Module: %s %x-%x" % ( funcModule.name(), funcModule.begin(), funcModule.end() ) )
|
|
|
|
runtimeFunctionTable = findRuntimeFunctionTable(funcModule)
|
|
dprintln( "Found runtime function table at %x with %d elements" % ( runtimeFunctionTable[0].getAddress(), len(runtimeFunctionTable) ) )
|
|
|
|
runtimeFunction = filter( lambda x: funcModule + x.BeginAddress == addr, runtimeFunctionTable )[0]
|
|
dprintln( "runtime function info for function:" )
|
|
dprintln( "\tBegin Address: %x ( RVA = %x )" % ( funcModule + runtimeFunction.BeginAddress, runtimeFunction.BeginAddress ) )
|
|
dprintln( "\tEnd Address: %x ( RVA = %x )" % ( funcModule + runtimeFunction.EndAddress, runtimeFunction.EndAddress ) )
|
|
dprintln( "\tUnwind Info: %x ( RVA = %x )" % ( funcModule + runtimeFunction.UnwindData, runtimeFunction.UnwindData ) )
|
|
|
|
printUnwindInfo( funcModule, addr, funcModule + runtimeFunction.UnwindData )
|
|
|
|
def printUsage():
|
|
pass
|
|
|
|
def main():
|
|
if len(sys.argv) <=1 :
|
|
printUsage()
|
|
return
|
|
|
|
if not is64bitSystem():
|
|
dprintln("for 64-bit system only")
|
|
return
|
|
|
|
funcAddr = expr( sys.argv[1] )
|
|
printVEHInfo( funcAddr )
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|
|
|
|
|