def __init__(self): super(AsmBase, self).__init__() # Initialize keystone and capstone as soon as an instance # of this plugin will be created. if not keystone: self.log.debug('Keystone is required for ' + self.__class__.__name__) return if not capstone: self.log.debug('Capstone is required for ' + self.__class__.__name__) return if getattr(self, 'args', None) and self.args and getattr(self.args, 'bigendian', None) \ and self.args.bigendian: self.ks = keystone.Ks( self.keystone_arch, self.keystone_mode + keystone.KS_MODE_BIG_ENDIAN) self.cs = capstone.Cs(self.capstone_arch, capstone.CS_MODE_BIG_ENDIAN) else: self.ks = keystone.Ks( self.keystone_arch, self.keystone_mode + keystone.KS_MODE_LITTLE_ENDIAN) self.cs = capstone.Cs(self.capstone_arch, capstone.CS_MODE_LITTLE_ENDIAN)
def __init__(self, is_thumb): self.__is_thumb = is_thumb if (is_thumb): self.__cs = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB) self.__ks = keystone.Ks(keystone.KS_ARCH_ARM, keystone.KS_MODE_THUMB) else: self.__cs = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_ARM) self.__ks = keystone.Ks(keystone.KS_ARCH_ARM, keystone.KS_MODE_ARM)
def asm(asm_code, addr=0, arch=None): import keystone asm_code = Latin1_encode(asm_code) if arch is None: arch = context.arch if arch == 'i386': asmer = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_32) elif arch == "amd64": asmer = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_64) l = "" for i in asmer.asm(asm_code, addr)[0]: l += chr(i) return Latin1_decode(Latin1_encode(l.strip('\n')))
def keystone_thumb(self): if _keystone is None: l.warning("Keystone is not installed!") return None if self._ks_thumb is None: self._ks_thumb = _keystone.Ks(self.ks_arch, _keystone.KS_MODE_THUMB) return self._ks_thumb
def assemble(asm_code, mode): """ Helper function to assemble code receive in parameter `asm_code` using Keystone. @param asm_code : bytearray of N instructions, separated by ';' @param mode : defines the mode to use Keystone with @return a tuple of bytecodes as bytearray, along with the number of instruction compiled. If failed, the bytearray will be empty, the count of instruction will be the negative number for the faulty line. """ arch, mode, endian = get_arch_mode("keystone", mode) ks = keystone.Ks(arch, mode | endian) if is_x86(mode) and mode.syntax == Syntax.ATT: ks.syntax = keystone.KS_OPT_SYNTAX_ATT bytecode = [] insns = asm_code.split(b';') for i, insn in enumerate(insns): try: code, cnt = ks.asm(insn) if cnt == 0: return (b'', -(i + 1)) bytecode.append(bytearray(code)) except keystone.keystone.KsError as kse: return (b'', -(i + 1)) return (b''.join(bytecode), i + 1)
def __init__(self, archstring, debug=False): self.debug = debug self.arch = globals()[archstring]() self.ks = keystone.Ks(self.arch.ks_arch[0], self.arch.ks_arch[1]) self.mu = unicorn.Uc(self.arch.uc_arch[0], self.arch.uc_arch[1]) self.md = capstone.Cs(self.arch.cs_arch[0], self.arch.cs_arch[1]) self.pc_reg = self.arch.pc_reg self.state_reg = self.arch.state_reg self.cpu_regs = self.arch.cpu_regs self.mem_regs = {} self.mem_addrs = {} self.mu.mem_map(self.arch.code_addr, self.arch.code_mem) self._mem_invalid_hook = self.mu.hook_add( UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, self._invalid_mem) #self._mem_invalid_hook2 = self.mu.hook_add(UC_HOOK_MEM_FETCH_UNMAPPED, self._invalid_mem_fetch) self._code_hook = self.mu.hook_add( UC_HOOK_CODE, self._code_hook, None, self.arch.code_addr, self.arch.code_addr + self.arch.code_mem) self.pages = set() # TODO: have to figure out how to remove this state... :( self.rw_struct = [[0, 0], [None, None, None], False] self._mem_rw_hook = self.mu.hook_add( UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ, self._mem_hook, self.rw_struct) pass
def asm(code, bitness=64, vma=0): """asm(code, bitness = 64, vma = 0) assembles the assembly code at vma""" ks = keystone.Ks( keystone.KS_ARCH_X86, keystone.KS_MODE_64 if bitness == 64 else keystone.KS_MODE_32) encoding, count = ks.asm(code, vma) return encoding
def asm(self, arch, mode): try: ks = keystone.Ks(self._arch(arch), self._mode(mode)) return ks.asm("\n".join(self.pcode)) except keystone.KsError as e: print("ERROR: %s" % e) sys.exit(1)
def main(args): egghunter = ntaccess_hunter(args.tag) if not args.seh else seh_hunter( args.tag) eng = ks.Ks(ks.KS_ARCH_X86, ks.KS_MODE_32) encoding, count = eng.asm(egghunter) final = "" final += 'egghunter = b"' for enc in encoding: final += "\\x{0:02x}".format(enc) final += '"' sentry = False for bad in args.bad_chars: if bad in final: print(f"[!] Found 0x{bad}") sentry = True if sentry: print(f'[=] {final[14:-1]}', file=sys.stderr) raise SystemExit("[!] Remove bad characters and try again") print(f"[+] egghunter created!") print(f"[=] len: {len(encoding)} bytes") print(f"[=] tag: {args.tag * 2}") print(f"[=] ver: {['NtAccessCheckAndAuditAlarm', 'SEH'][args.seh]}\n") print(final)
def assemble(self, code, arch=x86, format=Format.HEX): if 'keystone' not in globals(): raise RopperError('Keystone is not installed! Please install Keystone. \nLook at http://keystone-engine.org') ks = keystone.Ks(arch.ksarch[0], arch.ksarch[1]) try: byte_list = ks.asm(code.encode('ascii'))[0] except BaseException as e: raise RopperError(e) if not byte_list: return "invalid" to_return = byte_list if format == Format.STRING: to_return = '"' for byte in byte_list: to_return += '\\x%02x' % byte to_return += '"' elif format == Format.HEX: to_return = '' for byte in byte_list: to_return += '%02x' % byte elif format == Format.RAW: to_return = '' for byte in byte_list: to_return += '%s' % chr(byte) return to_return
def asm(self, string, addr=0, as_bytes=True, thumb=False): """ Compile the assembly instruction represented by string using Keystone :param string: The textual assembly instructions, separated by semicolons :param addr: The address at which the text should be assembled, to deal with PC-relative access. Default 0 :param as_bytes: Set to False to return a list of integers instead of a python byte string :param thumb: If working with an ARM processor, set to True to assemble in thumb mode. :return: The assembled bytecode """ if _keystone is None: l.warning("Keystone is not found!") return None if self.ks_arch is None: raise ArchError("Arch %s does not support assembly with Keystone" % self.name) if self._ks is None or self._ks_thumb != thumb: self._ks_thumb = thumb mode = _keystone.KS_MODE_THUMB if thumb else _keystone.KS_MODE_ARM self._ks = _keystone.Ks(self.ks_arch, self.ks_mode + mode) try: encoding, _ = self._ks.asm(string, addr, as_bytes) # pylint: disable=too-many-function-args except TypeError: bytelist, _ = self._ks.asm(string, addr) if as_bytes: encoding = ''.join(chr(c) for c in bytelist) if not isinstance(encoding, bytes): l.warning("Cheap hack to create bytestring from Keystone!") encoding = encoding.encode() else: encoding = bytelist return encoding
def __init__(self): '''初始化 instance 初始化模拟器参数 only x86''' # Initialize emulator in X86-32bit mode self.vm = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32 | unicorn.UC_MODE_LITTLE_ENDIAN) self.asb = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_32 | keystone.KS_MODE_LITTLE_ENDIAN) self.disas = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32 | capstone.CS_MODE_LITTLE_ENDIAN) self.__reinit__()
def load_library(self, arch, libso, libc_time_offset, libc_dlopen_offset): """ Load library by hooking time() to a stub that calls dlopen to load library :param arch: currently arm64 only :param libso: so filename or path to load. :param libc_time_offset: time function offset to libc :param libc_dlopen_offset: dlopen function offset to libc """ try: import keystone asm = keystone.Ks(keystone.KS_ARCH_ARM64, keystone.KS_MODE_LITTLE_ENDIAN) has_runned_flag_addr = self.find_code_cave(4, perm='rw') if has_runned_flag_addr == 0: raise Exception('failed to find data cave') # print(f'has_runned_flag_addr: {has_runned_flag_addr:x}, {victim.get_ptr_info(has_runned_flag_addr)}') #### get the payload length with random address shellcode_len = 0 if arch == 'arm64': shellcode_len = len( asm.asm(self.get_dlopen_payload_arm64(0, 0, 0, libso), addr=0, as_bytes=True)[0]) else: raise Exception('load library only support arm64 currently') if shellcode_len == 0: raise Exception('failed to generate payload') #### now find a code cave shellcode_addr = self.find_code_cave( shellcode_len, not_addrs=(has_runned_flag_addr, )) if shellcode_addr == 0: raise Exception('failed to find code cave') # print(f'shellcode_addr: {shellcode_addr:x}, {victim.get_ptr_info(shellcode_addr)}') #### get the real payload time_addr = self.find('/libc.so')[0].addr + libc_time_offset dlopen_addr = self.mem.readptr( self.find('/libc.so')[0].addr + libc_dlopen_offset) shellcode = asm.asm(self.get_dlopen_payload_arm64( time_addr, has_runned_flag_addr, dlopen_addr, libso), addr=shellcode_addr, as_bytes=True)[0] trampoline = asm.asm(f""" b #{shellcode_addr} """, addr=time_addr, as_bytes=True)[0] # prepare stub self.mem.writebuf(shellcode_addr, shellcode) # detour self.mem.writebuf(time_addr, trampoline) return True except ImportError: print('python dependency keystone is required') return False
def __init__(self): self.simplifications = set() self.tc = triton.TritonContext() self.tc.setArchitecture(triton.ARCH.X86_64) self.tc.setMode(triton.MODE.ALIGNED_MEMORY, True) self.ks = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_64) self.tc.addCallback(self.simplify, triton.CALLBACK.SYMBOLIC_SIMPLIFICATION) self.tc.setMode(triton.MODE.SYMBOLIZE_INDEX_ROTATION, True) self.pc = self.tc.registers.rip self.sp = self.tc.registers.rsp self.psize = triton.CPUSIZE.QWORD self.ret = self.tc.registers.rax self.tc.setAstRepresentationMode(triton.AST_REPRESENTATION.PYTHON) self.regs = [ self.tc.registers.rdi, self.tc.registers.rsi, self.tc.registers.rdx, self.tc.registers.rcx, self.tc.registers.r8, self.tc.registers.r9 ] self.syscall_regs = [ self.tc.registers.rax, self.tc.registers.rbx, self.tc.registers.rcx, self.tc.registers.rdx, self.tc.registers.rsi, self.tc.registers.rdi, ] self.ret_types = set([triton.OPCODE.X86.RET]) self.call_types = set([triton.OPCODE.X86.CALL, triton.OPCODE.X86.LCALL]) self.conditional_branch_types = set([ triton.OPCODE.X86.JA, triton.OPCODE.X86.JBE, triton.OPCODE.X86.JECXZ, triton.OPCODE.X86.JL, triton.OPCODE.X86.JNE, triton.OPCODE.X86.JNS, triton.OPCODE.X86.JRCXZ, triton.OPCODE.X86.JAE, triton.OPCODE.X86.JCXZ, triton.OPCODE.X86.JG, triton.OPCODE.X86.JLE, triton.OPCODE.X86.JNO, triton.OPCODE.X86.JO, triton.OPCODE.X86.JS, triton.OPCODE.X86.JB, triton.OPCODE.X86.JE, triton.OPCODE.X86.JGE, triton.OPCODE.X86.JNP, triton.OPCODE.X86.JP ]) self.branch_types = set() self.branch_types.update(self.conditional_branch_types) self.branch_types.add(triton.OPCODE.X86.JMP)
def assemble(code, addr=0, mode=keystone.KS_MODE_32): """ assemble asm code for inline hook """ ks = keystone.Ks(keystone.KS_ARCH_X86, mode) encoding, count = ks.asm(code, addr) buf = ''.join(chr(c) for c in encoding) return buf, count
def create_assembler(): ''' create an assembler using some standard options. ''' try: return keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_32) except AttributeError: # DANGER logger.warning('failed to load keystone-engine') return None
def __init__(self, program, flags=None): self.program = program # if flags == None: # flags = ['-w'] # if '-w' not in flags: # flags.append('-w') if flags != None and isinstance(flags, list): self.r2 = r2pipe.open(self.program, flags=flags) else: self.r2 = r2pipe.open(self.program) # self.r2.cmd("aa") i_json = self.r2.cmdj('ij') self.os = i_json['bin']['os'] self.arch = i_json['bin']['arch'] self.bits = i_json['bin']['bits'] self.pic = i_json['bin']['pic'] self.endian = i_json['bin']['endian'] if self.arch == 'x86': if self.bits == 64: self.archinfo = archinfo.ArchAMD64 else: self.archinfo = archinfo.ArchX86 elif self.arch == 'mips': if self.bits == 32: self.archinfo = archinfo.ArchMIPS32 elif self.bits == 64: self.archinfo = archinfo.ArchMIPS64 elif self.arch == 'arm': self.archinfo = archinfo.ArchARM elif self.arch == 'ppc': if self.bits == 32: self.archinfo = archinfo.ArchPPC32 elif self.bits == 64: self.archinfo = archinfo.ArchPPC64 elif self.arch == 'aarch64': self.archinfo = archinfo.AArch64 else: self.archinfo = None if self.archinfo is not None: if self.endian == "little": self.archinfo.memory_endess = archinfo.Endness.LE else: self.archinfo.memory_endess = archinfo.Endness.BE if self.archinfo != None: self.md = capstone.Cs(self.archinfo.cs_arch, self.archinfo.cs_mode) self.cs = keystone.Ks(self.archinfo.ks_arch, self.archinfo.ks_mode) else: self.md = None
def get_ks(arch, arch_bits): # TODO: What architectures are supported by KS? if arch == "x86": ks_arch = ks.KS_ARCH_X86 if arch_bits == 32: ks_mode = ks.KS_MODE_32 else: ks_mode = ks.KS_MODE_64 else: return None return ks.Ks(ks_arch, ks_mode)
def assemble_x86_64(code): try: ks = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_64) encoding, count = ks.asm(code) print("%s = %s (number of statements: %u)" %(code, encoding, count)) return encoding except keystone.KsError as e: print("ERROR: %s" %e) return None
def keystone(self): """ A Keystone instance for this arch """ if self._ks is None: if _keystone is None: raise Exception("Keystone is not installed!") if self.ks_arch is None: raise ArchError("Arch %s does not support disassembly with Keystone" % self.name) self._ks = _keystone.Ks(self.ks_arch, self.ks_mode) self._configure_keystone() return self._ks
def patch_code(self, instructions='ret;', va=0): """ put instruction(s), at the end of the basic block specified""" #TODO: get capstone instruction at the end of the basic_block try: k = ks.Ks(ks.KS_ARCH_X86, ks.KS_MODE_32) encoding, count = k.asm(instructions) except ks.KsError as e: l.error("Error! %s", e) raise if not self.set_bytes_at_rva(va, ''.join(map(chr, encoding))): raise Exception('Cannot patch bytes at %x!', va)
def __init__(self, ir, ks=None): self.ir = ir self.cp = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64) if ks is None: # Setup keystone self.ks = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_64) self.ks.syntax = keystone.KS_OPT_SYNTAX_ATT else: self.ks = ks self.prepare_for_rewriting()
def assemble(asm_code, mode): arch, mode, endian = get_arch_mode("keystone", mode) ks = keystone.Ks(arch, mode | endian) if mode in (Architecture.X86_16_ATT, Architecture.X86_32_ATT, Architecture.X86_64_ATT): ks.syntax = keystone.KS_OPT_SYNTAX_ATT try: code, cnt = ks.asm(asm_code) code = bytes(bytearray(code)) except keystone.keystone.KsError: code, cnt = (b"", -1) return (code, cnt)
def assemble(asm_code, mode): arch, mode, endian = get_arch_mode("keystone", mode) ks = keystone.Ks(arch, mode | endian) if is_x86(mode) and mode.syntax == Syntax.ATT: ks.syntax = keystone.KS_OPT_SYNTAX_ATT try: code, cnt = ks.asm(asm_code) if cnt == 0: code = b"" code = bytes(bytearray(code)) except keystone.keystone.KsError: code, cnt = (b"", -1) return (code, cnt)
def load(fp, _isa, base=0, offset=0): """load a single executable extent from a file""" _isa = isa.correlate(copy.deepcopy(_isa)) # first, assemble fp.seek(offset, os.SEEK_CUR) assembled = bytes( keystone.Ks( _isa["keystone"]["arch"], _isa["keystone"]["endianness"] + _isa["keystone"]["mode"]).asm(fp.read())[0]) # disassemble return MachineCodeIO.load(io.BytesIO(assembled), _isa, base)
def get_function(code): import keystone as ks ksa = ks.Ks(ks.KS_ARCH_X86, ks.KS_MODE_64) ksa.syntax = ks.KS_OPT_SYNTAX_ATT asm, count = ksa.asm(code) asm = bytes(asm) func = Function("DYNCODE", 0x1000, len(asm), asm) container = Container() container.add_function(func) return container
def dump(fp, extent): """load a single executable extent to a file""" _isa = isa.correlate(copy.deepcopy(extent["isa"])) # dump assembly b = io.BytesIO() AssemblyIO.dump(b, extent) # assemble fp.write( bytes( keystone.Ks( _isa["keystone"]["arch"], _isa["keystone"]["endianness"] + _isa["keystone"]["mode"]).asm(b.getvalue())[0]))
def main(args): egghunter = ntaccess_hunter(args.tag) if not args.seh else seh_hunter( args.tag) eng = ks.Ks(ks.KS_ARCH_X86, ks.KS_MODE_32) if args.seh: encoding, count = eng.asm(egghunter) else: print("[+] Egghunter assembly code + coresponding bytes") asm_blocks = "" prev_size = 0 for line in egghunter.splitlines(): asm_blocks += line + "\n" encoding, count = eng.asm(asm_blocks) if encoding: enc_opcode = "" for byte in encoding[prev_size:]: enc_opcode += "0x{0:02x} ".format(byte) prev_size += 1 spacer = 30 - len(line) print("%s %s %s" % (line, (" " * spacer), enc_opcode)) final = "" final += 'egghunter = b"' for enc in encoding: final += "\\x{0:02x}".format(enc) final += '"' sentry = False for bad in args.bad_chars: if bad in final: print(f"[!] Found 0x{bad}") sentry = True if sentry: print(f"[=] {final[14:-1]}", file=sys.stderr) raise SystemExit("[!] Remove bad characters and try again") print(f"[+] egghunter created!") print(f"[=] len: {len(encoding)} bytes") print(f"[=] tag: {args.tag * 2}") print(f"[=] ver: {['NtAccessCheckAndAuditAlarm', 'SEH'][args.seh]}\n") print(final)
def assemble(self, func_name, *args): sp = bytes(' ', 'utf8') instr = bytes() i = 0 while i < len(args): a = str(args[i]) if i == 0 and (not a.startswith("'") or not a.startswith('"')): raise Exception('provide a valid instruction set') if a.startswith("'") or a.startswith('"'): a = a[1:] b = False if a.endswith("'") or a.endswith('"'): a = a[:len(a) - 1] b = True instr += bytes(a, 'utf8') if not b: instr += sp i += 1 if b: break if str(args[i]) == '!': self.keystone_instance = None if self.keystone_instance is None: self.ks_arch = getattr(keystone, self.prompt_ks_arch()) self.ks_mode = getattr(keystone, self.prompt_ks_mode()) self.core_instance.get_module('configs_module').push_config( 'ks_arch', self.ks_arch) self.core_instance.get_module('configs_module').push_config( 'ks_mode', self.ks_mode) self.keystone_instance = keystone.Ks(self.ks_arch, self.ks_mode) try: encoding, count = self.keystone_instance.asm(instr) h = '' for i in range(0, len(encoding)): h += hex(encoding[i])[2:] print("%s = %s (number of statements: %u)" % (str(instr), h, count)) except keystone.KsError as e: print("ERROR: %s" % e)
def trigger_write_instruction(self, item): if not self.dwarf.keystone_installed: details = '' try: import keystone.keystone_const except Exception as e: details = str(e) utils.show_message_box( 'keystone-engine not found. Install it to enable instructions patching', details=details) return accept, inst, arch, mode = WriteInstructionDialog().show_dialog( input_content='%s %s' % (self.item(item.row(), 1).text(), self.item(item.row(), 2).text()), arch=self.ks_arch, mode=self.ks_mode) self.ks_arch = 'KS_ARCH_' + arch.upper() self.ks_mode = 'KS_MODE_' + mode.upper() if accept and len(inst) > 0: import keystone try: ks = keystone.Ks( getattr(keystone.keystone_const, self.ks_arch), getattr(keystone.keystone_const, self.ks_mode)) encoding, count = ks.asm(inst) asm_widget = self.item(item.row(), 0) offset = asm_widget.get_offset() if self.dwarf.dwarf_api('writeBytes', [asm_widget.get_address(), encoding]): new_data = bytearray(self.range.data) for i in range(0, len(encoding)): try: new_data[self.asm_data_start + offset + i] = encoding[i] except Exception as e: if isinstance(e, IndexError): break self.range.data = bytes(new_data) self.disa() except Exception as e: self.dwarf.log(e)