def disassemble(shellcode, mode=32): ''' Does disassembly with distorm3 and handles the string joining ''' if mode == 32: disasm = distorm3.Decode(0x0, shellcode, distorm3.Decode32Bits) elif mode == 64: disasm = distorm3.Decode(0x0, shellcode, distorm3.Decode64Bits) elif mode == 16: disasm = distorm3.Decode(0x0, shellcode, distorm3.Decode16Bits) disassembly = '' for line in disasm: hexvals = hex_regex.findall(line[2]) if len(hexvals) > 0 and ('PUSH' in line[2] or 'MOV' in line[2]): line = list(line) # Why you give me tuple Distorm? if len(hexvals[0][2:]) > 2: line[2] = line[2] + '\t; ' + hexvals[0][2:].decode('hex') else: line[2] = line[2] + '\t; ' + str(int(hexvals[0], 16)) disassembly += "0x%08x (%02x) %-20s %s" % (line[0], line[1], line[3], line[2]) + "\n" return disassembly
def find_function_address(self, proc_as, ret_addr): """ Calculates the function address given a return address. Disassembles code to get through the double indirection introduced by the Linux PLT. @param proc_as: Process address space @param ret_addr: Return address @return The function address or None """ if distorm_loaded: decode_as = self.decode_as retaddr_assembly = distorm3.Decode(ret_addr - 5, proc_as.read(ret_addr - 5, 5), decode_as) if len(retaddr_assembly) == 0: return None #print(retaddr_assembly) retaddr_assembly = retaddr_assembly[0] # We're only getting 1 instruction # retaddr_assembly[2] = "CALL 0x400620" instr = retaddr_assembly[2].split(' ') #print(instr) if instr[0] == 'CALL': try: target = int(instr[1][2:], 16) except ValueError: return None bytes = proc_as.read(target, 6) if not bytes: # We're not sure if this is the function address return target plt_instructions = distorm3.Decode(target, bytes, decode_as) plt_assembly = plt_instructions[0] # 1 instruction #print(plt_assembly) instr2 = plt_assembly[2].split(' ') #print(instr2) if instr2[0] == 'JMP': final_addr = None if instr2[1] == 'DWORD': target2 = int(instr2[2][3:-1], 16) elif instr2[1] == 'QWORD': # if QWORD target2 = int(instr2[2][7:-1], 16) else: # if 0xADDRESS final_addr = int(instr2[1][2:],16) if not final_addr: final_addr = target + 6 + target2 debug.info("Found function address from instruction {} at offset 0x{:016x}".format(instr2, target)) return read_address(proc_as, final_addr) elif instr2[0] == 'PUSH' and instr2[1] == 'RBP': # This is an internal function debug.info("Found function address from instruction {} at offset 0x{:016x}".format(instr, target)) return target else: # In case push rbp is removed debug.info("Found function address from instruction {} at offset 0x{:016x}".format(instr, target)) return target return None else: return None
def _extract_gadget(self, pc, data, mode): """ Returns the gadget found with the given data """ disasm = distorm3.Decode(pc, data, mode) instr_list = [] addr_list = [] for d in disasm: addr = d[0] size = d[1] inst = d[2].lower() opcodes = d[3] ### if inst in blacklist: # @Performance: Needed because the above does not work as intended if any(True for bl in self.blacklist if bl in inst): return None, None instr_list.append(inst) addr_list.append(addr) ### if inst in ends: # @Performance: Needed because the above does not work as intended # (the above does exact matching and ret 0x20 or something similar does not get flagged) if any(True for end in self.ends if end in inst): return addr_list, instr_list # Did not find an end return None, None
def asm_to_dasm(asm_shellcode): max_instr_len = 3 if args.two_byte_stager != 'disabled': max_instr_len = 2 ## assemble payload = nasm_assemble(asm_shellcode, asm_tmp_bin) ## disassemble dasm = distorm3.Decode(0, payload, distorm3.Decode32Bits) ## perform some simple sanity checks for i in range(0, len(dasm)): instr = dasm[ i] # 0: offset, 1: len, 2: mnemonic 3: opcodes (hexlified) ## 1) check if all opcodes are <= 2 or 3 bytes except mov REG32, IMM32 if instr[LEN] > max_instr_len and not instr_is_mov_reg32_imm32( instr[OPCODE]): raise Exception(("[-] Instruction \"{:s}\" is greater than {:d} " + "bytes (currently unsupported)").format( instr[MNEMONIC], max_instr_len)) ## 2) Jccs have to be preceded by test/cmp/... for 3 byte stager if args.two_byte_stager != 'disabled' and instr_is_jcc( instr[MNEMONIC]): pre_instr = dasm[i - 1] ## preceding instr if not instr_is_compare(pre_instr[MNEMONIC]): ## add your allowed preceding instr here #if not pre_instr[MNEMONIC].startswith("TEST") and not pre_instr[MNEMONIC].startswith("CMP"): raise Exception( "[-] Conditional jumps have to be " + "preceded immediately by flag-setting instruction") return dasm
def get_gadgets(): gadget = [] gadget2 = [] interesting_gadgets = [] # chain = [] off = [] # address of gadget for i in range(START, END): lst1 = [] lst2 = [] flag = 0 # change i+20 if gadgets not found decoded = distorm3.Decode(VA + i, data[i:i + 20], MODE) addr = [] inst = [] for x in decoded: addr.append(x[0]) inst.append(x[2]) for x, y in zip(inst, addr): lst1.append("0x%.4x: %s" % (y, x)) lst2.append(x) if "RET" in x: flag = 1 break if flag: tmp = "\n".join(lst1) tmp2 = "; ".join(lst2) if "DB " in tmp: # If the disassembly process failed continue if tmp in gadget: # Checking if its not already found continue off.append(lst1[0].split()[0]) gadget.append(tmp) gadget2.append(tmp2) # gadgets in a single line return off, gadget, gadget2
def disassemble( self, address = None, lines = None ): """ Display unassembley (disassembly) of memory Gets: unsigned long address unsigned long lines """ if not IS_DISTORM_SUPPORTED: raise Exception("Distrom not found, please install the distorm3 module") if( None == address ): self.getCurrentContext() address = self.context.rip if( None != lines ): bytes_to_read = [lines * 8, 100][lines * 8 < 100] # Thats should be enough, and if not who cares. else: bytes_to_read = 100 # That's a magic number # First read the relavent data. # Remove all break points, so we wont read them self._uninstallAllBreakPoints() data = self.readMemory( address, bytes_to_read ) self._reinstallAllBreakPoints() # Now disassemble with distorm. data = distorm3.Decode( address, data, distorm3.Decode32Bits ) # Print the result data[:lines] for opcode in data: print("0x{0:08X} ({1:02X}) {2:<20s} {3:s}".format(opcode[0], opcode[1], opcode[3], opcode[2])) return
def decode(self, addr, data): if not isinstance(data, tuple): raise TypeError("expected tuple of integers for data, got %s" % type(data)) str_data = "".join([chr(x) for x in data]) for ds_inst in distorm3.Decode(addr, str_data, self.decode_size): yield self.make_instr(ds_inst)
def canonicalize_distorm(self): decoded = distorm3.Decode(self.addr, self.bytes, self.arch.distorm_bits) assert len(decoded) == 1 decoded = decoded[0] assert decoded[0] == self.addr assert decoded[1] == len(self.bytes) self.canonicalsyntax = decoded[2]
def disasm(self, addr, length=0x100, decodeType=1): if IS_DISASSEMBLER_FOUND: for opcode in distorm3.Decode(addr, self.readMemory(addr, length), decodeType): print('{0:x} {1:24s} {2:s}'.format(opcode[0], opcode[3], opcode[2])) else: raise Exception("No disassembler module")
def bytes_to_code(bytestring): instructions = [ ' db ' + ', '.join('0x%02x' % c for c in bytestring[i:i + w]) + ' ' * (18 - len(opcodes) * 3) + ' ; ' + instr for i, w, instr, opcodes in distorm3.Decode(0, bytestring, distorm3.Decode32Bits) ] return "\n".join(instructions)
def main(): if (len(sys.argv) != 2) and (len(sys.argv) != 3): print os.path.split( sys.argv[0])[1] + " <PE file name> <new image base in hex>" return None filename = sys.argv[1] NewImageBase = None if (len(sys.argv) == 3): NewImageBase = int(sys.argv[2], 16) PEObj = PEFile(filename, NewImageBase) print "diSlib, http://ragestorm.net/distorm/\n" print "Image Base: 0x%08x, Code Size: 0x%x" % (PEObj.ImageBase, PEObj.CodeSize) print "Entry Point RVA: %08x" % PEObj.EntryPoint print "Sections:" for i in PEObj.Sections[:-1]: print "%d.Name: %s, VA: %x, Size: %x, Flags: %x" % ( i.Index + 1, i.Name, i.VA, i.Size, i.Flags) if PEObj.Imports: print "Imports:" for i in PEObj.Imports: print i try: if PEObj.Exports: print "Exports:" for i in PEObj.Exports: print i except: # Ignore corrupted exports. pass if PEObj.Relocs: print "Relocations:" for i in PEObj.Relocs: print i try: # If diStorm isn't available, we won't disassemble anything. import distorm3 DecodeType = distorm3.Decode32Bits if (PEObj.MachineType == IMAGE_FILE_MACHINE_AMD64): DecodeType = distorm3.Decode64Bits # Find code section and disassemble entry point routine. TextSec = PEObj.GetSectionByVA(PEObj.EntryPoint) if TextSec == None: return l = distorm3.Decode( PEObj.ImageBase + PEObj.EntryPoint, TextSec.Data[PEObj.EntryPoint - TextSec.VA:][:4 * 1024], DecodeType) for i in l: print "0x%08x (%02x) %-20s %s" % (i[0], i[1], i[3], i[2]) if ((i[2][:3] == "RET") or (i[2] == "INT 3") or (i[2][:3] == "JMP")): break except: pass
def shell_insert_bytes(sl, ni, bytes, label=-1, jmp_label=-1): l = distorm3.Decode(0, bytes, distorm3.Decode32Bits) tsize = 0 for (offset, size, instr, hexdump) in l: i = _instr(bytes[offset:offset + size], size, 0) i.label = label i.jmp_label = jmp_label sl.insert(ni, i) ni += 1 tsize += size recalc_jmps(sl, ni)
def print_disasm(sl): ni = 0 ioff = 0 for i in sl: if i.is_data == 0: l = distorm3.Decode(ioff, i.bytes, distorm3.Decode32Bits) for (offset, size, instr, hexdump) in l: print '%-4i %.8x: %-32s %s' % (ni, offset, hexdump, instr) ni += 1 ioff += size else: print '%-4i %.8x:' % (ni, ioff), print_string_hex(i.bytes) print '' ioff += i.size
def get_addressing_modes(): opcode = b'\x03' result = [] # for all modrm possibilities for modrm in range(256): # get all address_code possibitilities, including sib if applicable has_sib = ((modrm & 0b111 == 4) and ((modrm >> 6) & 0b11 != 0b11)) if has_sib: address_codes = [bytes([modrm, sib]) for sib in range(256)] else: address_codes = [bytes([modrm])] # for all the resulting address codes for address_code in address_codes: # create dummy instruction and dissassembly to find ops bytestring = opcode + address_code + (15 * b'\0') _, num_bytes, instr, _ = distorm3.Decode(0, bytestring, distorm3.Decode32Bits)[0] op1, op2 = instr[3:].strip().split(', ') # extract / parse info disp_num_bytes = num_bytes - 2 - has_sib if op2[0] == '[': groups = re.match( r'\[(?P<b>...)(\+(?P<i>...))?(\*(?P<s>[248]))?(\+0x0)?\]', op2).groupdict() op2_dict = { 'type': 'mem', 'base': groups['b'].lower(), 'index': groups['i'].lower() if groups['i'] is not None else None, 'scale': int(groups['s'] or '1'), 'disp': disp_num_bytes * 8, } else: op2_dict = { 'type': 'reg', 'reg': op2.lower(), } info = { 'address_code': address_code, 'has_sib': has_sib, 'op1': op1.lower(), 'op2': op2_dict, } result.append(info) print('ops', op1, ':', op2, 'res', info) return result
def DecodeAsm(ea, codeChunk): global g_cpu_mode # binascii.hexlify(d) disasm = distorm3.Decode(ea, codeChunk, g_cpu_mode) gmap = [] gtxt = "" for (addr, _, inst, _) in disasm: inst = inst.lower() gtxt += "%s\n" % (inst) gmap.append((addr,inst)) if inst.find("ret") != -1: break return (gmap, gtxt)
def load_shell(bin, range): ret = [] rbin = [] ibin = [] if range != '': cr = 0 for r in range.split(','): rr = r.split('-') br = int(rr[0]) er = int(rr[1]) #print 'from', int(rr[0]), 'to', int(rr[1]) if br > cr: rbin.append(bin[cr:br]) ibin.append(1) rbin.append(bin[br:er]) ibin.append(0) cr = er if cr == 0: rbin.append(bin[:]) ibin.append(0) elif cr < len(bin): rbin.append(bin[cr:]) ibin.append(1) else: rbin.append(bin[:]) ibin.append(0) i = 0 for t in rbin: #print len(t), ':', ibin[i] i += 1 i = 0 for rb in rbin: if ibin[i] == 0: l = distorm3.Decode(0, rb, distorm3.Decode32Bits) for (offset, size, instr, hexdump) in l: ret.append(_instr(rb[offset:offset + size], size, 0)) else: ret.append(_instr(rb[:], len(rb), 1)) i += 1 parse_shell(ret) return ret[:]
def print_disasm(sl): ni = 0 ioff = 0 for i in sl: if i.is_data == 0: #if i.label >= 0 or i.jmp_label >= 0: # print 'label:', i.label, 'jmp_label:', i.jmp_label l = distorm3.Decode(ioff, i.bytes, distorm3.Decode32Bits) for (offset, size, instr, hexdump) in l: print('%-4i %.8x: %-32s %s' % (ni, offset, hexdump, instr)) ni += 1 ioff += size else: print('%-4i %.8x:' % (ni, ioff), ) print_string_hex(i.bytes) print('') ioff += i.size
def find_locals_size(self, proc_as, frames): """ Find the size of the locals of the function, similar to GDB's prologue analysis. Buggy and not actually used. @param proc_as: Process address space @param frames: a list of stack frames @return None """ if not distorm_loaded: return for frame in frames: if frame.function: instr = distorm3.Decode(frame.function, proc_as.read(frame.function, 8), self.decode_as) if self.is_function_header(instr) and len(instr) > 2: test = instr[2][2].split(' ') if test[0] == 'SUB' and test[1] == 'RSP,': frame.locals_size = int(test[2][2:], 16)
def disas_str(addr, data, sixtyfour=False): parser = optparse.OptionParser() if sixtyfour == True: parser.set_defaults(dt=distorm3.Decode64Bits) else: parser.set_defaults(dt=distorm3.Decode32Bits) options, args = parser.parse_args(sys.argv) out_insn = [] disas = distorm3.Decode(addr, data, options.dt) for (offset, size, instruction, hexdump) in disas: out_insn.append(instruction) return out_insn
def is_return_address(self, address, process_info): """ Checks if the address is a return address by checking if the preceding instruction is a 'CALL'. @param address: An address @param process_info: process info object @return True or False """ proc_as = process_info.proc_as size = 5 if distorm_loaded and process_info.is_code_pointer(address): offset = address - size instr = distorm3.Decode(offset, proc_as.read(offset, size), self.decode_as) # last instr, third tuple item (instr string), first 7 letters # if instr[-1][2][:7] == 'CALL 0x': # print(instr[-1][2]) if len(instr) > 0: return instr[-1][2][:4] == 'CALL' # there's also call <register> return False
def disas_str(addr, data, sixtyfour=False): parser = optparse.OptionParser() if sixtyfour == True: parser.set_defaults(dt=distorm3.Decode64Bits) else: parser.set_defaults(dt=distorm3.Decode32Bits) # this duplication is dirty, should be fixed parser.add_option("--section") parser.add_option("--single", action="store_true") options, args = parser.parse_args(sys.argv) out_insn = [] disas = distorm3.Decode(addr, data, options.dt) for (offset, size, instruction, hexdump) in disas: out_insn.append(instruction) return out_insn
def DecodeAsm(pc, d): global X86_MODE disasm = distorm3.Decode(pc, d, X86_MODE) k = [] l = "" ist = "" for d in disasm: #print d addr = d[0] size = d[1] inst = d[2].lower() t = "0x%x %s" % (addr, inst) l += t + "\n" ist += "%s\n" % (inst) k.append((addr, inst)) if inst.find('ret') != -1: break return (l, k, ist)
def disas(buf, array_name='', row_width=16, fancy=False, sixtyfour=False): parser = optparse.OptionParser() if sixtyfour == True: parser.set_defaults(dt=distorm3.Decode64Bits) else: parser.set_defaults(dt=distorm3.Decode32Bits) options, args = parser.parse_args([]) disas = distorm3.Decode(0, buf, options.dt) out = '' for (offset, size, instruction, hexdump) in disas: tmp = '' if fancy: tmp += colors.fg('cyan') tmp += "%.8x: " % (offset) if fancy: tmp += colors.fg('red') tmp += hexdump tmp += " " * (20 - len(hexdump)) if fancy: tmp += colors.fg('green') tmp += instruction if fancy: tmp += colors.end() out += " " + tmp + "\n" return out.lower()
def generate_asm_js_constants(payload_bin): max_instr_len = 3 offset = 1 if args.two_byte_stager != 'disabled': max_instr_len = 2 offset = 0 hex_payload = hexlify(payload_bin) constants = [] # payload starts in the middle/ after 1st byte dasm = distorm3.Decode(0, payload_bin[offset:], distorm3.Decode32Bits) ## FIXME: current transformation may result in long jumps for instr in dasm: if instr[LEN] > max_instr_len and not instr_is_mov_reg32_imm32( instr[OPCODE]): raise Exception("[-] Transformed instruction " + instr[MNEMONIC] + " is too long. FIXME") ## 3-byte payload if args.two_byte_stager == 'disabled': ## 5 byte chunks for i in range(0, len(hex_payload), 10): #print hex_payload[i:i+10] constants += [hex_payload[i:i + 10][2:]] ## strip 1st byte ## assume mov and insert if constants[-1][-2:] != test_al: ## replace least sig, byte in mov REG32, IMM32 with masking byte #print constants[-1] constants[-1] = "".join(list(constants[-1])[:-2]) + test_al #print constants[-1] else: for i in range(0, len(hex_payload), 8 + byte_distance * 2): constants += [hex_payload[i:i + 8]] ## strip 1st byte #print constants[-1] while len(constants[-1]) < 8: constants[-1] += "90" return constants
def do_ezrop(text): i = 0 while i < len(text['data']): if text['data'][i] == "\xc3": block_len = 10 while block_len > 1: start = i - block_len end = start + block_len + 1 disas = distorm3.Decode(text['addr'] + start, text['data'][start:end], options.dt) if disas[len(disas) - 1][2] == "RET" and match_disas( disas, sys.argv[2]) and ok_disas(disas): found_start = False for (offset, size, instruction, hexdump) in disas: if instruction.find(sys.argv[2]) != -1: found_start = True if found_start == True: out = colors.fg('cyan') out += "%.8x: " % (offset) out += colors.fg('red') out += hexdump out += " " * (20 - len(hexdump)) out += colors.fg('green') out += instruction + colors.end() print out print "=" * 50 i = i + block_len break block_len = block_len - 1 i = i + 1
def is_return_address(self, address, process_info): """ Checks if the address is a return address by checking if the preceding instruction is a 'CALL'. @param address: An address @param process_info: process info object @return True or False #这是使用了 distrom3 插件 查看当前地址address是否为返回地址 (这个函数最终没有使用,可以借鉴) """ proc_as = process_info.get_process_address_space() size = 5 # print type(size) ,type(address) start_code_address = process_info.mm.start_code end_code_address = process_info.mm.end_code if distorm_loaded and start_code_address < address < end_code_address: #and process_info.is_code_pointer(address): offset = address - size instr = distorm3.Decode(offset, proc_as.read(offset, size), self.decode_as) # last instr, third tuple item (instr string), first 7 letters if instr[-1][2][:7] == 'CALL 0x': print(instr[-1][2]) if len(instr) > 0: return instr[-1][2][:4] == 'CALL' # there's also call <register> return False
def extract_gadgets(offset, rawcode): global _args decoded = distorm.Decode( offset, rawcode, _args.arch) # returns: (offset, size, instr, hexdump) line = "" gadget = "" disasm = [] for d in decoded: addr = d[0] size = d[1] asm = d[2].lower() inst = "0x{:x} {}".format( addr, asm) # instruction: 0x000000 mov eax, ecx line += inst + "\n" # string of all instructions gadget += asm + "\n" # the gadget in itself, as a string disasm.append((addr, asm)) # list of each instruction if (gadget.find('ret') != -1): break return (line, disasm, gadget)
def is_return_address(address): # Load 1 instruction (Debian) # # hardcoding 4 bytes size = 4 bytestr = proc_as.read(address - size, size) # Instruction in the form of 'CALL RSP+0x18' single_instr = distorm3.Decode(address - size, bytestr, self.decode_as) if len(single_instr) == 1 and single_instr[0][2][:4] == 'CALL': # we use this one # print(single_instr) part = single_instr[0][2].split('[')[1] if part[:4] == 'RSP+': # take the part after the +, slice off the 0x, and convert to an int rspoffset = int(part.split('+')[1][2:-1],16) return rspoffset # Arch linux/Ubuntu # load 3 instructions, something like this: # mov 0x18(%rsp), %rax (size 5) # mov (%rax), %rdx (size 3) # callq *reg (size 2) # hardcoding 10 bytes size = 10 bytestr = proc_as.read(address - size, size) possible = ['RCX', 'RAX'] instr = distorm3.Decode(address - size, bytestr, self.decode_as) # print(instr[-1][2]) checkother = False if 0 < len(instr) < 3: pass elif len(instr) == 3: # check all 3 checkother = True else: return False last_instr = instr[-1][2].split(' ') register = None #print(last_instr) if last_instr[0] == 'CALL' and last_instr[1] in possible: #print(last_instr) register = last_instr[1] else: # print(last_instr) return None # Find the offset if checkother: mov = 'MOV ' + register confirmed = True movinstr = None saveinstr = None if mov in instr[0][2]: movinstr = instr[0][2] saveinstr = instr[1][2] elif mov in instr[1][2]: saveinstr = instr[0][2] movinstr = instr[1][2] else: # that's weird confirmed = False if movinstr != None: part = movinstr.split('[')[1] if part[:4] == 'RSP+': # take the part after the +, slice off the 0x, and convert to an int rspoffset = int(part.split('+')[1][2:-1],16) return rspoffset return False
def invoke(self, arg, from_tty): if ScriptUtils.current_arch == type_defs.INFERIOR_ARCH.ARCH_64: disas_option = distorm3.Decode64Bits else: disas_option = distorm3.Decode32Bits referenced_strings_dict = shelve.open( SysUtils.get_referenced_strings_file(pid), writeback=True) referenced_jumps_dict = shelve.open( SysUtils.get_referenced_jumps_file(pid), writeback=True) referenced_calls_dict = shelve.open( SysUtils.get_referenced_calls_file(pid), writeback=True) region_list, discard_invalid_strings = receive_from_pince() dissect_code_status_file = SysUtils.get_dissect_code_status_file(pid) region_count = len(region_list) self.memory = open(ScriptUtils.mem_file, "rb") buffer = 0x130000 # Has the best record of 13.6 sec. Tested on 0ad with Intel i7-4702MQ CPU and 8GB RAM ref_str_count = len(referenced_strings_dict) ref_jmp_count = len(referenced_jumps_dict) ref_call_count = len(referenced_calls_dict) for region_index, region in enumerate(region_list): region_info = region.addr, "Region " + str( region_index + 1) + " of " + str(region_count) start_addr, end_addr = region.addr.split("-") start_addr = int( start_addr, 16 ) # Becomes address of the last disassembled instruction later on end_addr = int(end_addr, 16) region_finished = False while not region_finished: remaining_space = end_addr - start_addr if remaining_space < buffer: offset = remaining_space region_finished = True else: offset = buffer status_info = region_info + ( hex(start_addr) + "-" + hex(start_addr + offset), ref_str_count, ref_jmp_count, ref_call_count) pickle.dump(status_info, open(dissect_code_status_file, "wb")) try: self.memory.seek(start_addr) except (OSError, ValueError): break code = self.memory.read(offset) disas_data = distorm3.Decode(start_addr, code, disas_option) if not region_finished: last_disas_addr = disas_data[-4][0] for index in range(4): del disas_data[ -1] # Get rid of last 4 instructions to ensure correct bytecode translation else: last_disas_addr = 0 for (instruction_offset, size, instruction, hexdump) in disas_data: if isinstance(instruction, bytes): instruction = instruction.decode() if instruction.startswith("J") or instruction.startswith( "LOOP"): found = common_regexes.dissect_code_valid_address.search( instruction) if found: referenced_address_str = common_regexes.hex_number.search( found.group(0)).group(0) referenced_address_int = int( referenced_address_str, 16) if self.is_memory_valid(referenced_address_int): instruction_only = common_regexes.alphanumerics.search( instruction).group(0).casefold() try: referenced_jumps_dict[ referenced_address_str][ instruction_offset] = instruction_only except KeyError: referenced_jumps_dict[ referenced_address_str] = {} referenced_jumps_dict[ referenced_address_str][ instruction_offset] = instruction_only ref_jmp_count += 1 elif instruction.startswith("CALL"): found = common_regexes.dissect_code_valid_address.search( instruction) if found: referenced_address_str = common_regexes.hex_number.search( found.group(0)).group(0) referenced_address_int = int( referenced_address_str, 16) if self.is_memory_valid(referenced_address_int): try: referenced_calls_dict[ referenced_address_str].add( instruction_offset) except KeyError: referenced_calls_dict[ referenced_address_str] = set() referenced_calls_dict[ referenced_address_str].add( instruction_offset) ref_call_count += 1 else: found = common_regexes.dissect_code_valid_address.search( instruction) if found: referenced_address_str = common_regexes.hex_number.search( found.group(0)).group(0) referenced_address_int = int( referenced_address_str, 16) if self.is_memory_valid(referenced_address_int, discard_invalid_strings): try: referenced_strings_dict[ referenced_address_str].add( instruction_offset) except KeyError: referenced_strings_dict[ referenced_address_str] = set() referenced_strings_dict[ referenced_address_str].add( instruction_offset) ref_str_count += 1 start_addr = last_disas_addr self.memory.close()
def solve(): shellcode = getShellcode() print map(binascii.hexlify, shellcode) shellcode = map(ord, shellcode) actions = [] actions = [(3, 'H', False, False), (3, 'H', False, False), (3, 'HH', False, False), (3, 'H', False, False), (3, 'HHH', False, False), (3, 'HHH', False, False), (80, 'S', False, True), (3, 'HH', False, False), (3, 'HH', False, False), (3, 'HH', False, False), (3, 'HHHH', False, False), (3, 'HH', False, False), (3, 'HH', False, False), (3, 'HH', False, False), (80, 'S', False, True), (3, 'S', False, False), (80, 'S', False, True), (3, 'HHH', False, False), (3, 'HH', False, False), (3, 'HHH', False, False), (3, 'S', False, False), (3, 'S', False, False), (3, 'H', False, False), (3, 'HH', False, False), (80, 'S', False, True), (21, 'S', True, False), (3, 'H', False, False), (3, 'S', False, False), (4, 'S', True, True), (117, 'S', True, False), (80, 'S', False, True), (3, 'HHH', False, False), (3, 'HH', False, False), (3, 'HHH', False, False), (80, 'S', False, True), (3, 'S', False, False), (4, 'S', True, True), (3, 'HH', False, False), (3, 'H', False, False), (3, 'H', False, False), (36, 'S', True, True), (61, 'S', True, False), (3, 'HH', False, False), (3, 'HHH', False, False), (3, 'HHH', False, False), (3, 'HH', False, False), (3, 'HH', False, False), (3, 'HHH', False, False), (3, 'H', False, False), (3, 'HHHH', False, False), (3, 'HH', False, False), (3, 'S', False, False), (3, 'HH', False, False), (3, 'S', False, False), (80, 'S', False, True), (3, 'H', False, False), (3, 'HH', False, False), (3, 'HH', False, False), (49, 'S', True, True), (64, 'S', True, False), (3, 'HHH', False, False), (3, 'H', False, False), (3, 'H', False, False), (3, 'HHH', False, False), (3, 'HH', False, False), (3, 'HHH', False, False)] tb = [] for action in actions: sc = 0 if action[2]: sc = action[0] else: sc = 0x100 - action[0] tb.append(sc) res = ''.join(map(chr, tb)) for i in ds3.Decode(0, res, ds3.Decode32Bits): print i[2] print len(actions) sys.exit(0) name = 'abcd' step = 0 while True: step += 1 print actions nx = doRun(name, actions, shellcode) if nx: print "finished" break