def _test_elf_linux_x86_snapshot_restore_common(self, reg=False, ctx=False): rootfs = "../examples/rootfs/x86_linux" cmdline = ["../examples/rootfs/x86_linux/bin/x86_hello"] snapshot = os.path.join(rootfs, 'snapshot_restore_reg_ctx.snapshot') ql = Qiling(cmdline, rootfs, verbose=QL_VERBOSE.DEBUG) X86BASE = int(ql.profile.get("OS32", "load_address"), 16) hook_address = X86BASE + 0x542 # call printf def dump(ql): nonlocal snapshot nonlocal reg nonlocal ctx ql.save(reg=reg, cpu_context=ctx, os=True, loader=True, snapshot=snapshot) ql.emu_stop() ql.hook_address(dump, hook_address) ql.run() # make sure that the ending PC is the same as the hook address because dump stops the emulater assert ql.arch.regs.arch_pc == hook_address, f"0x{ql.arch.regs.arch_pc:x} != 0x{hook_address:x}" del ql ql = Qiling(cmdline, rootfs, verbose=QL_VERBOSE.DEBUG) ql.restore(snapshot=snapshot) # ensure that the starting PC is same as the PC we stopped on when taking the snapshot assert ql.arch.regs.arch_pc == hook_address, f"0x{ql.arch.regs.arch_pc:x} != 0x{hook_address:x}" ql.run(begin=hook_address) del ql
def hook_StartServiceA(ql: Qiling, address: int, params): ql.test_set_api = True hService = params["hService"] service_handle = ql.os.handle_manager.get(hService) if service_handle.name != "amsint32": return 1 if service_handle.name not in ql.os.services: return 0 service_path = ql.os.services[service_handle.name] service_path = ql.os.path.transform_to_real_path(service_path) amsint32 = Qiling([service_path], ql.rootfs, verbose=QL_VERBOSE.DEBUG) ntoskrnl = amsint32.loader.get_image_by_name("ntoskrnl.exe") self.assertIsNotNone(ntoskrnl) init_unseen_symbols(amsint32, ntoskrnl.base + 0xb7695, b"NtTerminateProcess", 0, "ntoskrnl.exe") amsint32.log.info('Loading amsint32 driver') setattr(ql, 'amsint32_driver', amsint32) try: amsint32.run() except UcError as e: print("Load driver error: ", e) return 0 else: return 1
def _t(): if 'QL_FAST_TEST' in os.environ: return ql = Qiling(["../examples/rootfs/x86_windows/bin/al-khaser.bin"], "../examples/rootfs/x86_windows") # The hooks are to remove the prints to file. It crashes. will debug why in the future def results(ql): if ql.reg.ebx == 1: print("BAD") else: print("GOOD ") ql.reg.eip = 0x402ee4 #ql.hook_address(results, 0x00402e66) # the program alloc 4 bytes and then tries to write 0x2cc bytes. # I have no idea of why this code should work without this patch ql.patch(0x00401984, b'\xb8\x04\x00\x00\x00') def end(ql): print("We are finally done") ql.emu_stop() ql.hook_address(end, 0x004016ae) ql.run() del ql return True
def _t(): ql = Qiling(["../examples/rootfs/x8664_windows/bin/Fls.exe"], "../examples/rootfs/x8664_windows", verbose=QL_VERBOSE.DEFAULT) ql.run() del ql return True
def _t(): ql = Qiling([ "../examples/rootfs/x8664_windows/bin//x8664_clipboard_test.exe" ], "../examples/rootfs/x8664_windows") ql.run() del ql return True
def our_sandbox(path, rootfs): stdin = StringBuffer() ql = Qiling(path, rootfs, stdin=stdin) stdin.write(b"Ea5yR3versing\n") ql.hook_address(force_call_dialog_func, 0x00401016) ql.run()
def test_elf_linux_x86(self): ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_hello"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG, log_file="test.qlog") ql.run() del ql
def test_elf_hijackapi_linux_x8664(self): def my_puts_enter(ql: Qiling): params = ql.os.resolve_fcall_params(ELFTest.PARAMS_PUTS) self.test_enter_str = params["s"] def my_puts_exit(ql): self.test_exit_rdi = ql.reg.rdi ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_puts"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) ql.set_api('puts', my_puts_enter, QL_INTERCEPT.ENTER) ql.set_api('puts', my_puts_exit, QL_INTERCEPT.EXIT) ql.run() if self.test_exit_rdi == 140736282240864: self.test_exit_rdi = 0x1 self.assertEqual(0x1, self.test_exit_rdi) self.assertEqual("CCCC", self.test_enter_str) del self.test_exit_rdi del self.test_enter_str del ql
def hook_StartServiceA(ql: Qiling, address: int, params): try: hService = params["hService"] service_handle = ql.os.handle_manager.get(hService) if service_handle.name == "amsint32": if service_handle.name in ql.os.services: service_path = ql.os.services[service_handle.name] service_path = ql.os.path.transform_to_real_path(service_path) ql.amsint32_driver = Qiling([service_path], ql.rootfs, verbose=QL_VERBOSE.DEBUG) init_unseen_symbols( ql.amsint32_driver, ql.amsint32_driver.loader.dlls["ntoskrnl.exe"] + 0xb7695, b"NtTerminateProcess", 0, "ntoskrnl.exe") #ql.amsint32_driver.debugger= ":9999" try: ql.amsint32_driver.load() return 1 except UcError as e: print("Load driver error: ", e) return 0 else: return 0 else: return 1 except Exception as e: ql.log.exception("") print(e)
def __init__(self, invalid: bytes): # create a silent qiling instance self.ql = Qiling([rf"{ROOTFS}/bin/crackme.exe"], ROOTFS, verbose=QL_VERBOSE.OFF) self.ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno( )) # take over the input to the program using a fake stdin self.ql.os.stdout = pipe.NullOutStream( sys.stdout.fileno()) # disregard program output # execute program until it reaches the part that asks for input self.ql.run(end=0x401030) # record replay starting and ending points. # # since the emulation halted upon entering a function, its return address is there on # the stack. we use it to limit the emulation till function returns self.replay_starts = self.ql.arch.regs.arch_pc self.replay_ends = self.ql.stack_read(0) # instead of restarting the whole program every time a new flag character is guessed, # we will restore its state to the latest point possible, fast-forwarding a good # amount of start-up code that is not affected by the input. # # here we save the state just when the read input function is about to be called so we # could use it to jumpstart the initialization part and get to the read input immediately self.jumpstart = self.ql.save() or {} # calibrate the replay instruction count by running the code with an invalid input # first. the instruction count returned from the calibration process will be then # used as a baseline for consequent replays self.best_icount = self.__run(invalid)
def my_sandbox(file, ql_os, ql_arch, shellcode=False, profile=None): result = {} args = {} if profile: args["profile"] = f"{BASE_PATH}/profiles/{profile}" if shellcode: with open(file, "br") as f: args["shellcoder"] = f.read() args["ostype"] = ql_os args["archtype"] = ql_arch args["rootfs"] = f"{BASE_PATH}/rootfs/{ql_arch}_{ql_os}" # Std output is done to block the emulated software to print to standard output try: ql = Qiling( [file], **args, output="default", console=False, stdout=StringBuffer() ) try: ql.run() except Exception as e: result["execution_error"] = str(e) except Exception as e: result["setup_error"] = str(e) else: result.update(generate_report(ql)) finally: print(json.dumps(result))
def our_sandbox(path: str, rootfs: str): ql = Qiling([path], rootfs, verbose=QL_VERBOSE.DEFAULT) # this crackme's logic lies within the function passed to DialogBoxParamA through # the lpDialogFunc parameter. normally DialogBoxParamA would call the function # passed through that parameter, but Qiling's implementation for it doesn't do # that. # # to solve this crackme and force the "success" dialog to show, we will: # 1. set up a mock stdin and feed it with the correct flag # 1. hook DialogBoxParamA to see where its lpDialogFunc param points to # 2. set up a valid set of arguments DialogFunc expects to see # 3. call it and see it greets us with a "success" message # [step #1] # set up a mock stdin and feed it with mocked keystrokes ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) ql.os.stdin.write(b'Ea5yR3versing\n') # [step #2] # intercept DialogBoxParamA on exit ql.os.set_api('DialogBoxParamA', hook_DialogBoxParamA_onexit, QL_INTERCEPT.EXIT) ql.run()
def hook_StartServiceA(ql, address, params): # TODO: Still Fixing hService = params["hService"] service_handle = ql.os.handle_manager.get(hService) if service_handle.name == "amsint32": if service_handle.name in ql.os.services: service_path = ql.os.services[service_handle.name] service_path = ql.os.transform_to_real_path(service_path) ql.amsint32_driver = Qiling([service_path], ql.rootfs, output="disasm") init_unseen_symbols( ql.amsint32_driver, ql.amsint32_driver.loader.dlls["ntoskrnl.exe"] + 0xb7695, b"NtTerminateProcess", 0, "ntoskrnl.exe") print("load amsint32_driver") try: ql.amsint32_driver.run() return 1 except UcError as e: print("Load driver error: ", e) return 0 else: return 0 else: return 1
def sanitized_emulate(path, rootfs, fault_type, output="debug", enable_trace=False): ql = Qiling([path], rootfs, output=output) ql.env['FaultType'] = fault_type enable_sanitized_heap(ql) ql.run() if not ql.loader.heap.validate(): my_abort("Canary corruption detected")
def test_firmware_volume(): TEST_NAME = b'FirmwareVolume' enable_trace = True ql = Qiling( ['./bin/EfiFuzzTests.efi'], ".", # rootfs console=True if enable_trace else False, stdout=1 if enable_trace else None, stderr=1 if enable_trace else None, output='debug') # NVRAM environment. ql.env.update({'TestName': TEST_NAME}) rom.install(ql, "./res/$0AGD000.FL1") def validate_read_section(ql, address, params): buffer_size = read_int64(ql, params['BufferSize']) buffer = ql.mem.read(read_int64(ql, params['Buffer']), buffer_size) assert buffer.decode('utf-16').strip('\x00') == 'DxeMain.efi' return (address, params) # Hook ReadSection() to check the taint on the buffer. read_section_spy = mockito.spy(validate_read_section) ql.set_api("ReadSection", read_section_spy, QL_INTERCEPT.EXIT) # okay, ready to roll. ql.run() # Make sure that ReadSection() was intercepted once. mockito.verify(read_section_spy, times=1).__call__(*mockito.ARGS)
def test_arm_stat64(self): ql = Qiling( ["../examples/rootfs/arm_linux/bin/arm_stat64", "/bin/arm_stat64"], "../examples/rootfs/arm_linux", verbose=QL_VERBOSE.DEBUG) ql.run() del ql
def test_armoabi_le_linux_syscall_elf_static(self): # src: https://github.com/qilingframework/qiling/blob/1f1e9bc756e59a0bfc112d32735f8882b1afc165/examples/src/linux/posix_syscall.c path = ["../examples/rootfs/arm_linux/bin/posix_syscall_lsb.armoabi"] rootfs = "../examples/rootfs/arm_linux" ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG) ql.run() del ql
def test_gdbdebug_shellcode_server(self): X8664_LIN = bytes.fromhex( '31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05') ql = Qiling(code=X8664_LIN, archtype='x8664', ostype='linux') ql.debugger = 'gdb:127.0.0.1:9998' def gdb_test_client(): # yield to allow ql to launch its gdbserver time.sleep(1.337 * 2) with SimpleGdbClient('127.0.0.1', 9998) as client: client.send( 'qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;xmlRegisters=i386' ) client.send('vMustReplyEmpty') client.send('QStartNoAckMode') client.send('Hgp0.0') client.send('?') client.send('qC') client.send('g') client.send('p10') client.send('c') client.send('k') # yield to make sure ql gdbserver has enough time to receive our last command time.sleep(1.337) threading.Thread(target=gdb_test_client, daemon=True).start() ql.run() del ql
def test_elf_linux_x8664_flex_api(self): opened = [] def onenter_fopen(ql: Qiling): params = ql.os.resolve_fcall_params({ 'filename': STRING, 'mode': STRING }) # log opened filenames opened.append(params['filename']) def hook_main(ql: Qiling): # set up fopen hook when reaching main ql.set_api('fopen', onenter_fopen, QL_INTERCEPT.ENTER) ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_fetch_urandom"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEFAULT) ba = ql.loader.images[0].base ql.hook_address(hook_main, ba + 0x10e0) ql.run() del ql # test whether we interpected opening urandom self.assertListEqual(opened, [r'/dev/urandom'])
def test_pe_win_x86_return_from_main_exit_trap(self): ql = Qiling(["../examples/rootfs/x86_windows/bin/return_main.exe"], "../examples/rootfs/x86_windows", libcache=True, stop_on_exit_trap=True) ql.run() del ql
def test_x86_fake_urandom(self): class Fake_urandom(QlFsMappedObject): def read(self, size): return b"\x01" def fstat(self): return -1 def close(self): return 0 ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_fetch_urandom"], "../examples/rootfs/x86_linux", verbose=QL_VERBOSE.DEBUG) ql.add_fs_mapper("/dev/urandom", Fake_urandom()) ql.exit_code = 0 ql.exit_group_code = 0 def check_exit_group_code(ql, exit_code, *args, **kw): ql.exit_group_code = exit_code def check_exit_code(ql, exit_code, *args, **kw): ql.exit_code = exit_code ql.set_syscall("exit_group", check_exit_group_code, QL_INTERCEPT.ENTER) ql.set_syscall("exit", check_exit_code, QL_INTERCEPT.ENTER) ql.run() self.assertEqual(0, ql.exit_code) self.assertEqual(0, ql.exit_group_code) del ql
def test_pe_win_x86_hello(self): ql = Qiling(["../examples/rootfs/x86_windows/bin/x86_hello.exe"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.DEFAULT, profile="profiles/append_test.ql") ql.run() del ql
def emulate(path, rootfs, verbose=QL_VERBOSE.DEBUG, enable_trace=False): ql = Qiling([path], rootfs, verbose=verbose) if enable_trace: trace(ql) ql.run()
def test_elf_linux_mips32el_static(self): def random_generator(size=6, chars=string.ascii_uppercase + string.digits): return ''.join(random.choice(chars) for x in range(size)) ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_hello_static", random_generator(random.randint(1,99))], "../examples/rootfs/mips32el_linux") ql.run() del ql
def _t(): ql = Qiling( ["../examples/rootfs/x86_windows/bin/GetLastError.exe"], "../examples/rootfs/x86_windows") ql.run() del ql return True
def test_elf_linux_arm_custom_syscall(self): def my_syscall_write(ql, write_fd, write_buf, write_count, *args, **kw): regreturn = 0 buf = None mapaddr = ql.mem.map_anywhere(0x100000) ql.log.info("0x%x" % mapaddr) reg = ql.arch.regs.read("r0") print("reg : 0x%x" % reg) ql.arch.regs.r0 = reg try: buf = ql.mem.read(write_buf, write_count) ql.log.info("\n+++++++++\nmy write(%d,%x,%i) = %d\n+++++++++" % (write_fd, write_buf, write_count, regreturn)) ql.os.fd[write_fd].write(buf) regreturn = write_count except: regreturn = -1 ql.log.info("\n+++++++++\nmy write(%d,%x,%i) = %d\n+++++++++" % (write_fd, write_buf, write_count, regreturn)) if ql.verbose >= QL_VERBOSE.DEBUG: raise self.set_syscall = reg return regreturn ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_hello"], "../examples/rootfs/arm_linux") ql.os.set_syscall(0x04, my_syscall_write) ql.run() self.assertEqual(1, self.set_syscall) del self.set_syscall del ql
def _t(): ql = Qiling([ "../examples/rootfs/x86_windows/bin/NtQuerySystemInformation.exe" ], "../examples/rootfs/x86_windows") ql.run() del ql return True
def test_tcp_elf_linux_mips32eb(self): ql = Qiling( ["../examples/rootfs/mips32_linux/bin/mips32_tcp_test", "20005"], "../examples/rootfs/mips32_linux", multithread=True) ql.run() del ql
def _t(): if 'QL_FAST_TEST' in os.environ: return class Fake_Drive(QlFsMappedObject): def read(self, size): return random.randint(0, 256) def write(self, bs): print(bs) return def fstat(self): return -1 def close(self): return 0 ql = Qiling(["../examples/rootfs/x86_windows/bin/UselessDisk.bin"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG) ql.add_fs_mapper(r"\\.\PHYSICALDRIVE0", Fake_Drive()) ql.run() del ql return True
def hook_StartServiceA(ql: Qiling, address: int, params): hService = params["hService"] service_handle = ql.os.handle_manager.get(hService) ql.test_set_api = True if service_handle.name == "amsint32": if service_handle.name in ql.os.services: service_path = ql.os.services[service_handle.name] service_path = ql.os.path.transform_to_real_path( service_path) ql.amsint32_driver = Qiling([service_path], ql.rootfs, verbose=QL_VERBOSE.DISASM) init_unseen_symbols( ql.amsint32_driver, ql.amsint32_driver.loader.dlls["ntoskrnl.exe"] + 0xb7695, b"NtTerminateProcess", 0, "ntoskrnl.exe") print("load amsint32_driver") try: ql.amsint32_driver.run() return 1 except UcError as e: print("Load driver error: ", e) return 0 else: return 0 else: return 1