pykd/snippets/veh.py
SND\kernelnet_cp 772dd6cac7 [0.2.x] added : snippet for printing VEH
git-svn-id: https://pykd.svn.codeplex.com/svn@84933 9b283d60-5439-405e-af05-b73fd8c4d996
2017-11-08 17:42:50 +04:00

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()