Updated IDAPython vtable dump script (NPOTB).
This commit is contained in:
parent
b52f696d49
commit
a8021e0d79
@ -18,6 +18,79 @@ __license__ = "zlib/libpng"
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
"""
|
||||||
|
Output Format:"
|
||||||
|
VTable for <1>: (<2>, <3>)
|
||||||
|
Lin Win Function
|
||||||
|
<4><5> <6> <7>
|
||||||
|
<4><5> <6> <7>
|
||||||
|
...
|
||||||
|
<4><5> <6> <7>
|
||||||
|
|
||||||
|
1: Classname
|
||||||
|
2: VTable Offset
|
||||||
|
3: Linux This Pointer Offset
|
||||||
|
4: "T" if the function is a MI thunk
|
||||||
|
5: Linux VTable Index
|
||||||
|
6: Windows VTable Index
|
||||||
|
7: Function Signature
|
||||||
|
"""
|
||||||
|
|
||||||
|
catchclass = False
|
||||||
|
innerclass = ""
|
||||||
|
|
||||||
|
classname = None
|
||||||
|
offsetdata = {}
|
||||||
|
|
||||||
|
def ExtractTypeInfo(ea, level = 0):
|
||||||
|
global catchclass
|
||||||
|
global innerclass
|
||||||
|
global classname
|
||||||
|
global offsetdata
|
||||||
|
|
||||||
|
# Param needed to support old IDAPython versions
|
||||||
|
end = NextHead(ea, 4294967295)
|
||||||
|
|
||||||
|
# Skip vtable
|
||||||
|
ea += 4
|
||||||
|
|
||||||
|
# Get type name
|
||||||
|
name = Demangle("_Z" + GetString(Dword(ea)), GetLongPrm(INF_LONG_DN))
|
||||||
|
ea += 4
|
||||||
|
|
||||||
|
if classname is None and level == 0:
|
||||||
|
classname = name
|
||||||
|
|
||||||
|
if catchclass:
|
||||||
|
innerclass = name
|
||||||
|
catchclass = False
|
||||||
|
|
||||||
|
print "%*s%s" % (level, "", name)
|
||||||
|
|
||||||
|
if not ea < end: # Base Type
|
||||||
|
pass
|
||||||
|
elif isData(GetFlags(Dword(ea))): # Single Inheritance
|
||||||
|
ExtractTypeInfo(Dword(ea), level + 1)
|
||||||
|
ea += 4
|
||||||
|
else: # Multiple Inheritance
|
||||||
|
ea += 8
|
||||||
|
while ea < end:
|
||||||
|
catchclass = True
|
||||||
|
ExtractTypeInfo(Dword(ea), level + 1)
|
||||||
|
ea += 4
|
||||||
|
offset = Dword(ea)
|
||||||
|
ea += 4
|
||||||
|
#print "%*s Offset: 0x%06X" % (level, "", offset >> 8)
|
||||||
|
if (offset >> 8) != 0:
|
||||||
|
offsetdata[offset >> 8] = innerclass
|
||||||
|
|
||||||
|
# Source: http://stackoverflow.com/a/9147327
|
||||||
|
def twos_comp(val, bits):
|
||||||
|
"""compute the 2's compliment of int value val"""
|
||||||
|
if (val & (1 << (bits - 1))) != 0:
|
||||||
|
val = val - (1 << bits)
|
||||||
|
return val
|
||||||
|
|
||||||
def Analyze():
|
def Analyze():
|
||||||
SetStatus(IDA_STATUS_WORK)
|
SetStatus(IDA_STATUS_WORK)
|
||||||
|
|
||||||
@ -29,7 +102,8 @@ def Analyze():
|
|||||||
ea = ScreenEA()
|
ea = ScreenEA()
|
||||||
|
|
||||||
if not isHead(GetFlags(ea)):
|
if not isHead(GetFlags(ea)):
|
||||||
ea = PrevHead(ea)
|
# Param needed to support old IDAPython versions
|
||||||
|
ea = PrevHead(ea, 0)
|
||||||
|
|
||||||
# Param needed to support old IDAPython versions
|
# Param needed to support old IDAPython versions
|
||||||
end = NextHead(ea, 4294967295)
|
end = NextHead(ea, 4294967295)
|
||||||
@ -43,18 +117,23 @@ def Analyze():
|
|||||||
linux_vtable = []
|
linux_vtable = []
|
||||||
temp_windows_vtable = []
|
temp_windows_vtable = []
|
||||||
|
|
||||||
|
other_linux_vtables = {}
|
||||||
|
other_thunk_linux_vtables = {}
|
||||||
|
temp_other_windows_vtables = {}
|
||||||
|
|
||||||
# Extract vtable
|
# Extract vtable
|
||||||
while ea < end:
|
while ea < end:
|
||||||
offset = Dword(ea)
|
# Read thisoffs
|
||||||
|
offset = -twos_comp(Dword(ea), 32)
|
||||||
|
ea += 4
|
||||||
|
|
||||||
# A vtable starts with some metadata, if it's missing...
|
# Read typeinfo address
|
||||||
if isCode(GetFlags(offset)):
|
typeinfo = Dword(ea)
|
||||||
Warning("Something went wrong!")
|
ea += 4
|
||||||
SetStatus(IDA_STATUS_READY)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Skip thisoffs and typeinfo address
|
if offset == 0: # We only need to read this once
|
||||||
ea += 8
|
print "Inheritance Tree:"
|
||||||
|
ExtractTypeInfo(typeinfo)
|
||||||
|
|
||||||
while ea < end and isCode(GetFlags(Dword(ea))):
|
while ea < end and isCode(GetFlags(Dword(ea))):
|
||||||
name = Demangle(Name(Dword(ea)), GetLongPrm(INF_LONG_DN))
|
name = Demangle(Name(Dword(ea)), GetLongPrm(INF_LONG_DN))
|
||||||
@ -63,9 +142,22 @@ def Analyze():
|
|||||||
linux_vtable.append(name)
|
linux_vtable.append(name)
|
||||||
temp_windows_vtable.append(name)
|
temp_windows_vtable.append(name)
|
||||||
else:
|
else:
|
||||||
|
if offset not in other_linux_vtables:
|
||||||
|
other_linux_vtables[offset] = []
|
||||||
|
temp_other_windows_vtables[offset] = []
|
||||||
|
other_thunk_linux_vtables[offset] = []
|
||||||
|
|
||||||
|
if "`non-virtual thunk to'" in name:
|
||||||
|
other_linux_vtables[offset].append(name[22:])
|
||||||
|
other_thunk_linux_vtables[offset].append(name[22:])
|
||||||
|
temp_other_windows_vtables[offset].append(name[22:])
|
||||||
|
else:
|
||||||
|
other_linux_vtables[offset].append(name)
|
||||||
|
temp_other_windows_vtables[offset].append(name)
|
||||||
|
|
||||||
# MI entry, strip "`non-virtual thunk to'" and remove from list
|
# MI entry, strip "`non-virtual thunk to'" and remove from list
|
||||||
# But not if it's a dtor... what the hell is this.
|
# But not if it's a dtor... what the hell is this.
|
||||||
if (name.find("`non-virtual thunk to'") != -1) and name.find("::~") == -1:
|
if "`non-virtual thunk to'" in name and "::~" not in name:
|
||||||
name = name[22:]
|
name = name[22:]
|
||||||
#print "Stripping '%s' from windows vtable." % (name)
|
#print "Stripping '%s' from windows vtable." % (name)
|
||||||
temp_windows_vtable.remove(name)
|
temp_windows_vtable.remove(name)
|
||||||
@ -73,7 +165,7 @@ def Analyze():
|
|||||||
ea += 4
|
ea += 4
|
||||||
|
|
||||||
for i, v in enumerate(temp_windows_vtable):
|
for i, v in enumerate(temp_windows_vtable):
|
||||||
if v.find("::~") != -1:
|
if "::~" in v:
|
||||||
#print "Found destructor at index %d: %s" % (i, v)
|
#print "Found destructor at index %d: %s" % (i, v)
|
||||||
del temp_windows_vtable[i]
|
del temp_windows_vtable[i]
|
||||||
break
|
break
|
||||||
@ -96,16 +188,19 @@ def Analyze():
|
|||||||
overload_stack.append(v)
|
overload_stack.append(v)
|
||||||
else:
|
else:
|
||||||
# If we've moved onto something new, dump the stack first
|
# If we've moved onto something new, dump the stack first
|
||||||
if len(overload_stack) > 0:
|
while len(overload_stack) > 0:
|
||||||
#print overload_stack
|
windows_vtable.append(overload_stack.pop())
|
||||||
while len(overload_stack) > 0:
|
|
||||||
windows_vtable.append(overload_stack.pop())
|
|
||||||
|
|
||||||
windows_vtable.append(v)
|
windows_vtable.append(v)
|
||||||
|
|
||||||
prev_function = function
|
prev_function = function
|
||||||
prev_symbol = v
|
prev_symbol = v
|
||||||
|
|
||||||
|
# If there is anything left in the stack, dump it
|
||||||
|
while len(overload_stack) > 0:
|
||||||
|
windows_vtable.append(overload_stack.pop())
|
||||||
|
|
||||||
|
print "\nVTable for %s: (0, 0)" % (classname)
|
||||||
print "Lin Win Function"
|
print "Lin Win Function"
|
||||||
for i, v in enumerate(linux_vtable):
|
for i, v in enumerate(linux_vtable):
|
||||||
winindex = windows_vtable.index(v) if v in windows_vtable else None
|
winindex = windows_vtable.index(v) if v in windows_vtable else None
|
||||||
@ -114,7 +209,45 @@ def Analyze():
|
|||||||
else:
|
else:
|
||||||
print "%3d %s" % (i, v)
|
print "%3d %s" % (i, v)
|
||||||
|
|
||||||
|
for k in temp_other_windows_vtables:
|
||||||
|
for i, v in enumerate(temp_other_windows_vtables[k]):
|
||||||
|
if v.find("::~") != -1:
|
||||||
|
#print "Found destructor at index %d: %s" % (i, v)
|
||||||
|
del temp_other_windows_vtables[k][i]
|
||||||
|
break
|
||||||
|
|
||||||
|
other_windows_vtables = {}
|
||||||
|
for k in temp_other_windows_vtables:
|
||||||
|
other_windows_vtables[k] = []
|
||||||
|
overload_stack = []
|
||||||
|
prev_function = ""
|
||||||
|
prev_symbol = ""
|
||||||
|
for v in temp_other_windows_vtables[k]:
|
||||||
|
function = v.split("(", 1)[0]
|
||||||
|
if function == prev_function:
|
||||||
|
if len(overload_stack) == 0:
|
||||||
|
other_windows_vtables[k].pop()
|
||||||
|
overload_stack.append(prev_symbol)
|
||||||
|
overload_stack.append(v)
|
||||||
|
else:
|
||||||
|
if len(overload_stack) > 0:
|
||||||
|
while len(overload_stack) > 0:
|
||||||
|
other_windows_vtables[k].append(overload_stack.pop())
|
||||||
|
other_windows_vtables[k].append(v)
|
||||||
|
prev_function = function
|
||||||
|
prev_symbol = v
|
||||||
|
|
||||||
|
for k in other_linux_vtables:
|
||||||
|
print "\nVTable for %s: (%d, %d)" % (offsetdata[k], offsetdata.keys().index(k) + 1, k)
|
||||||
|
print "Lin Win Function"
|
||||||
|
for i, v in enumerate(other_linux_vtables[k]):
|
||||||
|
winindex = other_windows_vtables[k].index(v)
|
||||||
|
if v not in other_thunk_linux_vtables[k]:
|
||||||
|
print "%3d %3d %s" % (i, winindex, v)
|
||||||
|
else:
|
||||||
|
print "T%2d %3d %s" % (i, winindex, v)
|
||||||
|
|
||||||
SetStatus(IDA_STATUS_READY)
|
SetStatus(IDA_STATUS_READY)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
Analyze()
|
Analyze()
|
||||||
|
Loading…
Reference in New Issue
Block a user