From 67ae85b84030bfb72369645693353b918cdc7a18 Mon Sep 17 00:00:00 2001 From: Asher Baker Date: Sun, 29 Jul 2012 02:51:50 +0100 Subject: [PATCH] Added some useful IDA scripts (NPOTB). --- tools/ida_scripts/makesig.idc | 126 +++++++++++++++++++++++++++++++ tools/ida_scripts/vtable_dump.py | 120 +++++++++++++++++++++++++++++ 2 files changed, 246 insertions(+) create mode 100644 tools/ida_scripts/makesig.idc create mode 100644 tools/ida_scripts/vtable_dump.py diff --git a/tools/ida_scripts/makesig.idc b/tools/ida_scripts/makesig.idc new file mode 100644 index 00000000..fe609a96 --- /dev/null +++ b/tools/ida_scripts/makesig.idc @@ -0,0 +1,126 @@ +#include + +/* makesig.idc: IDA script to automatically create and wildcard a function signature. + * Copyright 2012, Asher Baker + * + * This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source distribution. +*/ + +static main() +{ + Wait(); // We won't work until autoanalysis is complete + + SetStatus(IDA_STATUS_WORK); + + auto pAddress = ScreenEA(); + pAddress = GetFunctionAttr(pAddress, FUNCATTR_START); + if (pAddress == BADADDR) + { + Warning("Make sure you are in a function!"); + SetStatus(IDA_STATUS_READY); + return; + } + + auto sig; + auto pFunctionEnd = GetFunctionAttr(pAddress, FUNCATTR_END); + + while (pAddress != BADADDR) + { + auto pInfo = DecodeInstruction(pAddress); + if (!pInfo) + { + Warning("Something went terribly wrong D:"); + SetStatus(IDA_STATUS_READY); + return; + } + + // isCode(GetFlags(pAddress)) == Opcode + // isTail(GetFlags(pAddress)) == Operand + // ((GetFlags(pAddress) & MS_CODE) == FF_IMMD) == :iiam: + + auto bDone = 0; + + if (pInfo.n == 1) + { + if (pInfo.Op0.type == o_near || pInfo.Op0.type == o_far) + { + sig = sprintf("%s%02X %s", sig, Byte(pAddress), PrintWildcards(GetDTSize(pInfo.Op0.dtyp))); + bDone = 1; + } + } + + if (!bDone) { // unknown, just wildcard addresses + auto i; + for (i = 0; i < pInfo.size; i++) + { + auto pLoc = pAddress + i; + if (GetFixupTgtType(pLoc) == FIXUP_OFF32) + { + sig = sprintf("%s%s", sig, PrintWildcards(4)); + i = i + 3; + } else { + sig = sprintf("%s%02X ", sig, Byte(pLoc)); + } + } + } + + if (IsGoodSig(sig)) + break; + + pAddress = NextHead(pAddress, pFunctionEnd); + } + + Message("%s\n", sig); + + SetStatus(IDA_STATUS_READY); + return; +} + +static GetDTSize(dtyp) +{ + if (dtyp == dt_byte) + { + return 1; + } else if (dtyp == dt_word) { + return 2; + } else if (dtyp == dt_dword) { + return 4; + } else if (dtyp == dt_float) { + return 4; + } else if (dtyp == dt_double) { + return 8; + } else { + Warning("Unknown type size (%d)", dtyp); + return -1; + } +} + +static PrintWildcards(count) +{ + auto i, string; + for (i = 0; i < count; i++) + { + string = sprintf("%s? ", string); + } + return string; +} + +static IsGoodSig(sig) +{ + auto count, addr; + addr = FindBinary(addr, SEARCH_DOWN|SEARCH_NEXT, sig); + while (addr != BADADDR) + { + count = count + 1; + addr = FindBinary(addr, SEARCH_DOWN|SEARCH_NEXT, sig); + } + return (count == 1); +} \ No newline at end of file diff --git a/tools/ida_scripts/vtable_dump.py b/tools/ida_scripts/vtable_dump.py new file mode 100644 index 00000000..9a4b5000 --- /dev/null +++ b/tools/ida_scripts/vtable_dump.py @@ -0,0 +1,120 @@ +"""vtable_dump.py: IDAPython script to dump a linux vtable (and a reconstructed windows one) from a binary.""" + +""" +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. +""" + +__author__ = "Asher Baker" +__copyright__ = "Copyright 2012, Asher Baker" +__license__ = "zlib/libpng" + +import re + +def Analyze(): + SetStatus(IDA_STATUS_WORK) + + if GetLongPrm(INF_COMPILER).id != COMP_GNU: + Warning("This script is for binaries compiled with GCC only.") + SetStatus(IDA_STATUS_READY) + return + + ea = ScreenEA() + + if not isHead(GetFlags(ea)): + ea = PrevHead(ea) + + # Param needed to support old IDAPython versions + end = NextHead(ea, 4294967295) + + name = Demangle(Name(ea), GetLongPrm(INF_LONG_DN)) + if ea == BADADDR or name is None or not re.search(r"vf?table(?: |'\{)for", name): + Warning("No vtable selected!\nSelect vtable block first.") + SetStatus(IDA_STATUS_READY) + return + + linux_vtable = [] + temp_windows_vtable = [] + + # Extract vtable + while ea < end: + offset = Dword(ea) + + # A vtable starts with some metadata, if it's missing... + if isCode(GetFlags(offset)): + Warning("Something went wrong!") + SetStatus(IDA_STATUS_READY) + return + + # Skip thisoffs and typeinfo address + ea += 8 + + while ea < end and isCode(GetFlags(Dword(ea))): + name = Demangle(Name(Dword(ea)), GetLongPrm(INF_LONG_DN)) + + if offset == 0: + linux_vtable.append(name) + temp_windows_vtable.append(name) + else: + # MI entry, strip "`non-virtual thunk to'" and remove from list + # But not if it's a dtor... what the hell is this. + if (name.find("`non-virtual thunk to'") != -1) and name.find("::~") == -1: + name = name[22:] + #print "Stripping '%s' from windows vtable." % (name) + temp_windows_vtable.remove(name) + + ea += 4 + + for i, v in enumerate(temp_windows_vtable): + if v.find("::~") != -1: + #print "Found destructor at index %d: %s" % (i, v) + del temp_windows_vtable[i] + break + + windows_vtable = [] + overload_stack = [] + prev_function = "" + prev_symbol = "" + for v in temp_windows_vtable: + function = v.split("(", 1)[0] + + if function == prev_function: + # If we don't have a stack, we need to push the last function on first + if len(overload_stack) == 0: + # We will have added this in the previous run, remove it again... + windows_vtable.pop() + #print "Storing '%s' (!)" % (prev_symbol) + overload_stack.append(prev_symbol) + #print "Storing '%s'" % (v) + overload_stack.append(v) + else: + # If we've moved onto something new, dump the stack first + if len(overload_stack) > 0: + #print overload_stack + while len(overload_stack) > 0: + windows_vtable.append(overload_stack.pop()) + + windows_vtable.append(v) + + prev_function = function + prev_symbol = v + + print "Lin Win Function" + for i, v in enumerate(linux_vtable): + winindex = windows_vtable.index(v) if v in windows_vtable else None + if winindex is not None: + print "%3d %3d %s" % (i, winindex, v) + else: + print "%3d %s" % (i, v) + + SetStatus(IDA_STATUS_READY) + +if __name__ == '__main__': + Analyze() \ No newline at end of file