def second_stage(ql: Qiling): disk = QlDisk("rootfs/8086/petya/out_1M.raw", 0x80) #nonce = get_nonce(disk) verfication_data = disk.read_sectors(0x37, 1) nonce_data = disk.read_sectors(0x36, 1) ql.reg.sp -= 0x200 verification_data_address = ql.reg.sp ql.reg.sp -= 0x200 nonce_address = ql.reg.sp + 0x21 ql.reg.sp -= 0x20 key_address = ql.reg.sp ql.mem.write(verification_data_address, verfication_data) ql.mem.write(nonce_address - 0x21, nonce_data) ql.arch.stack_push(0x200) ql.arch.stack_push(verification_data_address) ql.arch.stack_push(0) ql.arch.stack_push(nonce_address) ql.arch.stack_push(key_address) for x in product(list(accepted_chars), repeat=2): ctx = ql.save() # 3xMxjxXxLxoxmxAx key = b"3xMxjxXxLxoxmx" + ("".join(x)).encode("utf-8") print(f"Trying: {key}") if one_round(ql, key, key_address): print(f"Key: {key}") return key else: ql.restore(ctx) return None
def first_stage(): ql = Qiling(["rootfs/8086/petya/petya.DOS_MBR"], "rootfs/8086", console=False, verbose=QL_VERBOSE.DEBUG) ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/petya/out_1M.raw", 0x80)) # Workaround for `until` in uc_emu_start not working with dynamic loaded code. ql.hook_code(stop, begin=petya_2nd_stage_start, end=petya_2nd_stage_start) ql.run() return ql
def first_stage(): ql = Qiling(["rootfs/8086/petya/mbr.bin"], "rootfs/8086", console=False, output="debug", log_dir=".") ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/petya/out_1M.raw", 0x80)) # Workaround for `until` in uc_emu_start not working with dynamic loaded code. ql.hook_code(stop, begin=petya_2nd_stage_start, end=petya_2nd_stage_start) ql.run() return ql
def first_stage(): ql = Qiling(["rootfs/8086/doogie/doogie.DOS_MBR"], "rootfs/8086", console=False) ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/doogie/doogie.DOS_MBR", 0x80)) # Doogie suggests that the datetime should be 1990-02-06. ql.set_api((0x1a, 4), set_required_datetime, QL_INTERCEPT.EXIT) # A workaround to stop the program. hk = ql.hook_code(stop, begin=0x8018, end=0x8018) ql.run() ql.hook_del(hk) return ql
def run(self): path = self.ql.path self.ticks_per_second = float( self.ql.profile.get("KERNEL", "ticks_per_second")) if (str(path)).endswith(".DOS_COM") or ( str(path)).endswith(".DOS_EXE"): # pure com self.cs = int(self.ql.profile.get("COM", "start_cs"), 16) self.ip = int(self.ql.profile.get("COM", "start_ip"), 16) self.sp = int(self.ql.profile.get("COM", "start_sp"), 16) self.stack_size = int(self.ql.profile.get("COM", "stack_size"), 16) self.ql.reg.cs = self.cs self.ql.reg.ds = self.cs self.ql.reg.es = self.cs self.ql.reg.ss = self.cs self.ql.reg.ip = self.ip self.ql.reg.sp = self.sp self.start_address = self.cs * 16 + self.ip self.base_address = int(self.ql.profile.get("COM", "base_address"), 16) self.stack_address = int(self.ql.reg.ss * 16 + self.ql.reg.sp) self.ql.mem.map(0, 0x100000, info="[FULL]") with open(path, "rb+") as f: bs = f.read() self.ql.mem.write(self.start_address, bs) self.load_address = self.base_address self.ql.os.entry_point = self.start_address elif (str(path)).endswith(".DOS_MBR"): # MBR self.start_address = 0x7C00 with open(path, "rb+") as f: bs = f.read() if not self.ql.os.fs_mapper.has_mapping(0x80): self.ql.os.fs_mapper.add_fs_mapping(0x80, QlDisk(path, 0x80)) # Map all available address. self.ql.mem.map(0x0, 0x1000000) self.ql.mem.write(self.start_address, bs) self.cs = 0 self.ql.reg.ds = self.cs self.ql.reg.es = self.cs self.ql.reg.ss = self.cs # 0x80 -> first drive. # https://en.wikipedia.org/wiki/Master_boot_record#BIOS_to_MBR_interface self.ql.reg.dx = 0x80 self.ip = self.start_address self.load_address = self.start_address self.ql.os.entry_point = self.start_address else: raise NotImplementedError() sys.excepthook = self.excepthook
def third_stage(keys): # To setup terminal again, we have to restart the whole program. ql = Qiling(["rootfs/8086/doogie/doogie.DOS_MBR"], "rootfs/8086", console=False) ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/doogie/doogie.DOS_MBR", 0x80)) ql.set_api((0x1a, 4), set_required_datetime, QL_INTERCEPT.EXIT) hk = ql.hook_code(stop, begin=0x8018, end=0x8018) ql.run() ql.hook_del(hk) # Snapshot API. ctx = ql.save() for key in keys: show_once(ql, key) ql.restore(ctx)
def third_stage(key): def pass_red(ql, addr, data): curses.ungetch(ord("\n")) curses.ungetch(ord("\r")) def input_key(ql, addr, data): for i in key[::-1]: curses.ungetch(i) curses.ungetch(ord("\n")) curses.ungetch(ord("\r")) ql = Qiling(["rootfs/8086/petya/petya.DOS_MBR"], "rootfs/8086", console=False, verbose=QL_VERBOSE.DEBUG) ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/petya/out_1M.raw", 0x80)) ql.hook_code(pass_red, begin=0x886d, end=0x886d) ql.hook_code(input_key, begin=0x85f0, end=0x85f0) ql.hook_code(stop, begin=0x6806, end=0x6806) ql.run()
def third_stage(key): def pass_red(ql, addr, data): curses.ungetch(ord("\n")) curses.ungetch(ord("\r")) def input_key(ql, addr, data): for i in key[::-1]: curses.ungetch(i) curses.ungetch(ord("\n")) curses.ungetch(ord("\r")) ql = Qiling(["rootfs/8086/petya/mbr.bin"], "rootfs/8086", console=False, output="debug", log_dir=".") ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/petya/out_1M.raw", 0x80)) ql.hook_code(pass_red, begin=0x886d, end=0x886d) ql.hook_code(input_key, begin=0x85f0, end=0x85f0) ql.hook_code(stop, begin=0x6806, end=0x6806) ql.run()
def run(self): path = self.ql.path profile = self.ql.profile # bare com file if path.endswith(".DOS_COM"): with open(path, "rb") as f: content = f.read() cs = int(profile.get("COM", "start_cs"), 0) ip = int(profile.get("COM", "start_ip"), 0) sp = int(profile.get("COM", "start_sp"), 0) ss = cs base_address = (cs << 4) + ip # com file with a dos header elif path.endswith(".DOS_EXE"): with open(path, "rb") as f: content = f.read() com = ComParser(self.ql, content) cs = com.init_cs ip = com.init_ip sp = com.init_sp ss = com.init_ss base_address = 0 content = content[0x80:] elif path.endswith(".DOS_MBR"): with open(path, "rb") as f: content = f.read() cs = 0x0000 ip = 0x7c00 sp = 0xfff0 ss = cs base_address = (cs << 4) + ip # https://en.wikipedia.org/wiki/Master_boot_record#BIOS_to_MBR_interface if not self.ql.os.fs_mapper.has_mapping(0x80): self.ql.os.fs_mapper.add_fs_mapping(0x80, QlDisk(path, 0x80)) # 0x80 -> first drive self.ql.arch.regs.dx = 0x80 else: raise NotImplementedError() self.ql.arch.regs.cs = cs self.ql.arch.regs.ds = cs self.ql.arch.regs.es = cs self.ql.arch.regs.ss = ss self.ql.arch.regs.ip = ip self.ql.arch.regs.sp = sp self.stack_address = (ss << 4) + sp self.start_address = (cs << 4) + ip self.stack_size = int(profile.get("COM", "stack_size"), 0) self.ticks_per_second = profile.getfloat("KERNEL", "ticks_per_second") # map the entire system memory self.ql.mem.map(0, 0x100000, info="[FULL]") self.ql.mem.write(base_address, content) self.load_address = base_address self.ql.os.entry_point = self.start_address sys.excepthook = self.excepthook
#!/usr/bin/env python3 # # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # Built on top of Unicorn emulator (www.unicorn-engine.org) import sys sys.path.append("..") from qiling import * from qiling.os.disk import QlDisk if __name__ == "__main__": ql = Qiling(["rootfs/8086/petya/mbr.bin"], "rootfs/8086", console=False, output="debug", log_dir=".") # Note: # This image is only intended for PoC since the core petya code resides in the # specific sectors of a harddisk. It doesn't contain any data, either encryted # or unencrypted. ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/petya/out_1M.raw", 0x80)) ql.run()