From 99b368b5d4a5f38c2058d1e64bb1755d49f6d2b1 Mon Sep 17 00:00:00 2001 From: n0p <0x90@n0p.cc> Date: Sat, 18 Feb 2017 23:59:47 +0100 Subject: Some refactoring. --- SystemCalls.py | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 SystemCalls.py (limited to 'SystemCalls.py') diff --git a/SystemCalls.py b/SystemCalls.py new file mode 100644 index 0000000..4fcffd2 --- /dev/null +++ b/SystemCalls.py @@ -0,0 +1,297 @@ +""" IDAPython plugin to display all system calls of AMD/Intel 32/64bit + Linux userland binaries. + + Work in progress... + + The system call ABI from the following link are supported. + http://esec-lab.sogeti.com/post/2011/07/05/Linux-syscall-ABI + + by n0p +""" + +from miasm2.core.bin_stream_ida import bin_stream_ida +from miasm2.analysis.depgraph import DependencyGraph + +from utils import guess_machine + +from idaapi import * + +from SystemCalls_constants import * + + + +class SystemCallView(Choose2): + + def __init__(self, systemCalls): + + self.systemCalls = systemCalls + + Choose2.__init__(self, + "System call", + [ ["Address", 13], + ["Type", 10], + ["Number", 10], + ["Name", 20], + ["Pointer Size", 12] ]) + + self.items = list() + + self.nop_items = list() + + self.icon = 150 + + self.cmd_nop = None + + self.initialized = False + + def __fillView(self): + + self.systemCalls.searchSystemCalls() + + self.items = list() + + if len(self.systemCalls.x86) != 0: + for call in self.systemCalls.x86: + try: + callNr = int(self.systemCalls.getSystemCallNumber(call[0])[0]) + self.items.append(["0x%X" % call[0], + systemCallTypes[call[1]], + "0x%03X" % callNr, + x86SystemCalls[callNr], + "32bit"]) + except: + # No hex system call number found. + self.items.append(["0x%X" % call[0], + systemCallTypes[call[1]], + "", + "", + "32bit"]) + + if len(self.systemCalls.x86_64) != 0: + for call in self.systemCalls.x86_64: + try: + callNr = int(self.systemCalls.getSystemCallNumber(call[0])[0]) + self.items.append(["0x%X" % call[0], + systemCallTypes[call[1]], + "0x%03X" % callNr, + x86_64SystemCalls[callNr], + "64bit"]) + except: + # No hex system call number found. + self.items.append(["0x%X" % call[0], + systemCallTypes[call[1]], + "", + "", + "64bit"]) + + def OnClose(self): + pass + + def OnCommand(self, n, cmd_id): + if cmd_id == self.cmd_nop: + start_ea = int(self.items[n][0], 16) + end_ea = start_ea+ItemSize(start_ea) + + self.nop_items.append(self.items[n][0]) + + for i in xrange(start_ea, end_ea): + PatchByte(i, 0x90) + + def OnGetIcon(self, n): + if not len(self.items) > 0: + return -1 + + if self.items[n][2] == "": + # No system call number found => display red icon. + return 59 + else: + # Display green icon. + return 61 + + def OnGetLine(self, n): + return self.items[n] + + def OnGetLineAttr(self, n): + if len(self.nop_items) > 0: + if self.items[n][0] in self.nop_items: + return [0xB6B6B4, 0] + + def OnGetSize(self): + return len(self.items) + + def OnRefresh(self, n): + self.__fillView() + + def OnSelectLine(self, n): + idaapi.jumpto(int(self.items[n][0], 16)) + + def show(self): + if not self.initialized: + self.initialized = True + self.__fillView() + + if self.Show() < 0: return False + + if self.cmd_nop == None: + self.cmd_nop = self.AddCommand("NOP system call", + flags = idaapi.CHOOSER_POPUP_MENU, + icon=50) + + return True + + +class SystemCall(): + + def __init__(self): + + # Init miasm stuff. + self.machine = guess_machine() + self.mn, self.dis_engine, self.ira = self.machine.mn, self.machine.dis_engine, self.machine.ira + + self.mdis = self.dis_engine(bin_stream_ida(), dont_dis_nulstart_bloc=True) + self.ir_arch = self.ira(self.mdis.symbol_pool) + + # Populate symbols with ida names + for ad, name in Names(): + if name is None: + continue + self.mdis.symbol_pool.add_label(name, ad) + + self.x86 = list() + self.x86_64 = list() + + self.systemCallView = SystemCallView(self) + + def getSystemCallNumber(self, addr): + """ Get the value of rax/eax at the time of the system call. + """ + + sol = list() + + # Get the current function + f = get_func(addr) + + if not f: + return sol + + blocs = self.mdis.dis_multibloc(f.startEA) + + # Generate IR + for bloc in blocs: + self.ir_arch.add_bloc(bloc) + + # Check if addr is in a basic block without an entry. + if len(self.ir_arch.getby_offset(addr)) == 0: + fc = qflow_chart_t("", f, BADADDR, BADADDR, FC_PREDS) + + # Iterate through all basic blocks. + for i in xrange(0, fc.size()): + if fc[i].startEA <= addr and addr < fc[i].endEA: + # Basic block without entry found. + blocs = self.mdis.dis_multibloc(fc[i].startEA) + + # Generate IR + for bloc in blocs: + self.ir_arch.add_bloc(bloc) + + cur_bloc = list(self.ir_arch.getby_offset(addr))[0] + cur_label = cur_bloc.label + + elements = set([self.mn.regs.RAX]) + + for line_nb, l in enumerate(cur_bloc.lines): + if l.offset == addr: + break + + # Get dependency graphs + dg = DependencyGraph(self.ir_arch, follow_call=False) + graphs = dg.get(cur_label, elements, line_nb, + set([self.ir_arch.symbol_pool.getby_offset(f.startEA)])) + + while 1: + try: + graph = graphs.next() + except StopIteration: + break + + if not graph.has_loop: + sol.append(graph.emul().values()[0]) + + return sol + + def searchSystemCalls(self): + """ Looks for 'int 80', 'sysenter', 'syscall' and 'gs:[10h]' system calls. + """ + # Iterating through all segments + for segment in Segments(): + # Iterating through all instructions in each segment + for head in Heads(segment, SegEnd(segment)): + if isCode(GetFlags(head)): + inst = DecodeInstruction(head) + + if ( inst.size == 2 + and get_many_bytes(head, inst.size) + .startswith("\xCD\x80")): + # int 80h. Just on 32bit. + if not [head, 0] in self.x86: + self.x86.append([head, 0]) + + elif ( inst.size == 2 + and get_many_bytes(head, inst.size) + .startswith("\x0F\x34")): + # sysenter. Just on 32bit. + if not [head, 1] in self.x86: + self.x86.append([head, 1]) + + elif ( inst.size == 2 + and get_many_bytes(head, inst.size) + .startswith("\x0F\x05")): + # syscall. 32bit just on AMD. 64bit on AMD and Intel. + if idaapi.ph.flag & idaapi.PR_USE64: + if not [head, 2] in self.x86_64: + self.x86_64.append([head, 2]) + else: + if not [head, 2] in self.x86: + self.x86.append([head, 2]) + + elif ( inst.size == 7 + and get_many_bytes(head, inst.size) + .startswith("\x65\xFF\x15\x10\x00\x00\x00")): + # gs:[10h]. Just on 32bit. + if not [head, 3] in self.x86: + self.x86.append([head, 3]) + + def showView(self): + self.systemCallView.show() + + +class SystemCallPlugin_t(idaapi.plugin_t): + flags = 0 + comment = "" + help = "" + wanted_name = "System Calls" + wanted_hotkey = "" + + def init(self): + global systemCalls + + if idaapi.ph_get_id() == idaapi.PLFM_386: + # Check if already initialized + if not 'systemCalls' in globals(): + systemCalls = SystemCall() + + return idaapi.PLUGIN_KEEP + else: + return idaapi.PLUGIN_SKIP + + def run(self, arg): + global systemCalls + + systemCalls.showView() + + def term(self): + if 'systemCalls' in globals(): + del globals()['systemCalls'] + +def PLUGIN_ENTRY(): + return SystemCallPlugin_t() -- cgit v1.2.3