#!/usr/bin/env python """ (c) Adrian Furtuna seastorm44@yahoo.com """ __VERSION__ = '0.1' import immlib from immutils import * import getopt # Globals imm = immlib.Debugger() maxBack = 5 maxFw = 5 moduleFilter = "" filterRet = 0 filterExec = 0 def banner(): imm.Log("", address = 0) imm.Log("", address = 0) imm.Log("========================================", address = 0) imm.Log("= BDASM - a backward disassembler =", address = 0) imm.Log("= by Adrian Furtuna =", address = 0) imm.Log("= http://stormsecurity.wordpress.com =", address = 0) imm.Log("========================================", address = 0) imm.Log("", address = 0) imm.updateLog() def usage(): banner() imm.Log("Usage:", address = 0) imm.Log("", address = 0) imm.Log("!bdasm []", address = 0) imm.Log(" Operations:", address = 0) imm.Log(" -a
Disassemble around
", address = 0) imm.Log(" -i Find all occurences of and disassemble around", address = 0) imm.Log(" -o Find all occurences of and disassemble around", address = 0) imm.Log(" Options:", address = 0) imm.Log(" -b Disassemble maximum instructions backward (default = 5)", address = 0) imm.Log(" -f Disassemble maximum instructions forward (default = 5)", address = 0) imm.Log(" -m Show results only from ", address = 0) imm.Log(" -r Show results only if forward instructions contain RET", address = 0) imm.Log(" -e Show results only if memory page is executable", address = 0) imm.Log("", address = 0) def printInstruction(opcode, emph): if emph == 0: spaceBack = " " * 18 else: spaceBack = " " * 14 spaceBack = spaceBack + "*** " spaceFw = " " * (40 - len(opcode.getDisasm())) logString = spaceBack + "%s" + spaceFw + "%s" imm.Log(logString % (opcode.getDisasm(), opcode.getDump()), address = opcode.getAddress()) def disasmAtAddress(address): try: page = imm.getMemoryPagebyAddress( address ) access = page.getAccess( human = True ) if filterExec == 1 and not "EXEC" in access: #imm.Log("Memory page at address %08x is not executable. Skip" % address, address = 0) return except: imm.Log("Exception at getting access rights for address %08x" % address, address=0) return module = imm.findModule(address) if module: module = module[0].lower() else: module = "None" # Filter result by module name if len(moduleFilter) > 0 and module.find(moduleFilter) < 0: return nextAddress = address + imm.Disasm(address).getOpSize() # Searching for opcodes forward opcFw = [] good = 0 opcFw.append(imm.Disasm(address)) for i in range(0,maxFw): disasm = imm.Disasm(nextAddress) nextAddress = nextAddress + disasm.getOpSize() opcFw.append(disasm) if disasm.isRet(): good = 1 if filterRet == 1 and good == 0: #imm.Log("Instructions forward do not contain RET. Skip", address = 0) return else: disasm = imm.Disasm(address) disasmStr = disasm.getDisasm() imm.Log("Found instruction %s [opcode: %s] at address %08x %s %s" % (disasmStr, disasm.getDump(), address, access, module), address = address) imm.Log("", address=0) #Searching for opcodes before opcBack = [] disasmBack(address, 0, maxBack, opcBack, opcFw) imm.Log("", address=0) def findOpcode(opcode): results = imm.Search(opcode) for address in results: disasmAtAddress(address) def findInstruction(instr): opcode = imm.Assemble(instr) if len(opcode) == 0: imm.Log("Cannot assemble instruction %s" % instr) return findOpcode(opcode) def printList(list, size, list2): revList = list[0:size] revList.reverse() for i in range(0, size): disasm = revList[i] printInstruction(disasm, 0) if len(list2) > 0: disasm = list2[0] printInstruction(disasm, 1) for i in range(1,len(list2)): disasm = list2[i] printInstruction(disasm, 0) def disasmBack(address, instrCrt, instrPrev, list, list2): #imm.Log("Dissassembling at %08x instrCrt=%i" % (address, instrCrt), address = address) if instrCrt >= instrPrev: #imm.Log("Max instr reached", address=0) printList(list, instrCrt, list2) imm.Log("", address = 0) return found = 0 for numBytes in range (1,10): searchAddress = address - numBytes disasm = imm.Disasm(searchAddress) #imm.Log("try: %s %s [%i -- %i] instrCrt=%i" % # (disasm.getDisasm(), disasm.getDump(), disasm.getOpSize(), numBytes, instrCrt), address = searchAddress) if disasm.getOpSize() == numBytes: #imm.Log("ok: %s %s" % (disasm.getDisasm(), disasm.getDump()), address = searchAddress) found = 1 list.insert(instrCrt, disasm) #imm.Log("inserting at pos %i" % instrCrt) disasmBack(searchAddress, instrCrt+1, instrPrev, list, list2) if found == 0: # No instruction found backward and instrCrt < instrPrev #imm.Log("No more instr backw", address = 0) printList(list, instrCrt, list2) imm.Log("", address = 0) def hexToByte(hexStr): bytes = [] for i in range(0, len(hexStr), 2): bytes.append(chr(int(hexStr[i:i+2], 16))) return ''.join( bytes ) # ######################################################### # MAIN # ######################################################### def main(args): global maxBack global maxFw global moduleFilter global filterRet global filterExec if len(args) == 0: usage() return "Please see usage instructions" banner() try: opts, xxx = getopt.getopt(args, "a:i:o:b:f:m:er") except getopt.GetoptError: return "Wrong arguments (Check usage on the Log window)" # Check first the optional arguments for opt, val in opts: if opt == '-b': try: maxBack = int( val ) except ValueError: usage() return "Wrong argument (%s) % " % val elif opt == '-f': try: maxFw = int( val ) except ValueError: usage() return "Wrong argument (%s) % " % val elif opt == '-m': imm.Log(" Filter MODULE on", address = 0) moduleFilter = val.lower() elif opt == '-r': imm.Log(" Filter RET on", address = 0) filterRet = 1 elif opt == '-e': imm.Log(" Filter EXEC on", address = 0) filterExec = 1 imm.Log("", address = 0) # Iterate through input arguments and do the desired operation for opt, val in opts: if opt == '-a': try: address = int( val, 16 ) except ValueError: usage() return "Wrong address (%s) " % val imm.Log("Disassembling at address %08x ..." % address, address = address) disasmAtAddress(address) break elif opt == '-i': instr = val.replace('_', ' ') imm.Log("Searching for instruction: %s ..." % instr, address = 0) findInstruction(instr) break elif opt == '-o': if len(val) < 2 or len(val) % 2 != 0: usage() return "Wrong opcode (%s)" % val opcode = hexToByte(val) imm.Log("Searching for opcode: %s ..." % val, address = 0) findOpcode(hexToByte(val)) break imm.Log("Finished", address = 0) return "See results in Log window" #findOpcode("\x81\xc4", 5, 5) #add esp, xxxx #findOpcode("\x81\xd4", 5, 5) #adc esp, xxxx #findOpcode("\x83\xc4", 10, 10) #add esp, xx #findOpcode("\x83\xd4", 10, 10) #adc esp, xx #findOpcode("\x81\xc5", 5, 5) #add ebp, xxxx #findOpcode("\x83\xc5", 5, 5) #add ebp, xx #opcode1 = "\x8b\xe0"; #mov esp,eax #findInstruction("add esp, dword ptr[ebp]", 5, 5) #findInstruction("mov esp,eax", 5, 5) #findInstruction("mov esp,ebx", 5, 5) #findInstruction("mov esp,ecx") #findInstruction("mov esp,edx") #findInstruction("pop esp", 5, 5) #findInstruction("popa", 5, 5) #findInstruction("xchg eax,esp", 5, 5) #findInstruction("xchg ecx,esp", 5, 5) #printAssembled("call dword [esp + 400]"); #findOpcode("\xff\x94\x24") #7c90122d ff942400050000 call dword ptr [esp+500h] #findOpcode("\xff\x95") #7c90123a ff9500050000 call dword ptr [ebp+500h] #findOpcode("\x05\x00", 1, 10) #7c901240 0500030000 add eax,300h #printAssembled("mov esp,eax")