def main(): global dse, todo, current sys.setrecursionlimit(2000) # oof # Parse arguments parser = Sandbox_Win_x86_64.parser(description="PE sandboxer") parser.add_argument("filename", help="PE Filename") options = parser.parse_args() options.dependencies = True # So we dont need to reimplement qt sb = Sandbox_Win_x86_64(LocationDB(), options.filename, options, custom_methods=qt_methods) sb.jitter.add_breakpoint(end_ptr, stop_exec) # End condition # Setup the qt string memory and a pointer to it sb.jitter.vm.add_memory_page(0x10000018, PAGE_READ | PAGE_WRITE, pck64(0x20000000)) # Hooking in here sb.jitter.vm.add_memory_page(0x20000000, PAGE_READ | PAGE_WRITE, qtstring) # The initial qstring sb.jitter.vm.add_memory_page(0x10000020, PAGE_READ | PAGE_WRITE, b'\x00') # The result sb.jitter.cpu.R15 = 0x10000000 sb.jitter.cpu.RSP = sb.jitter.stack_base + 0x8000 # Setup and attach the DSE dse = DSEPC(sb.machine, sb.loc_db, produce_solution=DSEPC.PRODUCE_SOLUTION_PATH_COV) sb.jitter.init_run(0x140004B61) dse.attach(sb.jitter) dse.update_state_from_concrete() dse.symbolize_memory(interval([(flag_ptr, flag_ptr + 0x20)])) # Printable unicode only for address in range(flag_ptr, flag_ptr + 0x20, 0x2): z3_mem = dse.z3_trans.from_expr( dse.eval_expr(ExprMem(ExprInt(address, 64), 16))) unicode_constraint = z3.And( \ z3.UGE(z3_mem, dse.z3_trans.from_expr(ExprInt(0x0020, 16))), \ z3.ULE(z3_mem, dse.z3_trans.from_expr(ExprInt(0x007E, 16))) \ ) dse.cur_solver.add(unicode_constraint) snapshot = dse.take_snapshot() # Begin run todo = [b'\x41\x00' * 0x10] while todo: dse.restore_snapshot(snapshot) current = todo.pop() sb.jitter.vm.set_mem(flag_ptr, current) # Update the password in jitter memory print('-' * 40 + f' CONCRETE: {unicode_string(current)}') sb.jitter.continue_run()
# Handle return def code_sentinelle(jitter): jitter.run = False return False ret_addr = 0x1337beef jitter.add_breakpoint(ret_addr, code_sentinelle) jitter.push_uint32_t(ret_addr) # Init the jitter jitter.init_run(run_addr) # Init a DSE instance with a given strategy dse = DSEPathConstraint(machine, loc_db, produce_solution=strategy) dse.attach(jitter) # Concretize everything except the argument dse.update_state_from_concrete() regs = jitter.lifter.arch.regs arg = ExprId("ARG", 32) arg_addr = ExprMem(ExprInt(jitter.cpu.ESP + 4, regs.ESP.size), arg.size) dse.update_state({ # @[ESP + 4] = ARG arg_addr: arg }) # Explore solutions todo = set([ExprInt(0, arg.size)]) done = set() snapshot = dse.take_snapshot()
todo = set([b""]) # Set of file content to test # Instantiate the DSE engine machine = Machine("x86_64") # Convert strategy to the correct value strategy = { "code-cov": DSEPathConstraint.PRODUCE_SOLUTION_CODE_COV, "branch-cov": DSEPathConstraint.PRODUCE_SOLUTION_BRANCH_COV, "path-cov": DSEPathConstraint.PRODUCE_SOLUTION_PATH_COV, }[options.strategy] dse = DSEPathConstraint(machine, loc_db, produce_solution=strategy) # Attach to the jitter dse.attach(sb.jitter) # Update the jitter state: df is read, but never set # Approaches: specific or generic # - Specific: # df_value = ExprInt(sb.jitter.cpu.df, dse.ir_arch.arch.regs.df.size) # dse.update_state({ # dse.ir_arch.arch.regs.df: df_value # }) # - Generic: dse.update_state_from_concrete() # Add constraint on file size, we don't want to generate too big FILE z3_file_size = dse.z3_trans.from_expr(FILE_size) dse.cur_solver.add(0 < z3_file_size) dse.cur_solver.add(z3_file_size < 0x10)
todo = set([b""]) # Set of file content to test # Instantiate the DSE engine machine = Machine("x86_64") # Convert strategy to the correct value strategy = { "code-cov": DSEPathConstraint.PRODUCE_SOLUTION_CODE_COV, "branch-cov": DSEPathConstraint.PRODUCE_SOLUTION_BRANCH_COV, "path-cov": DSEPathConstraint.PRODUCE_SOLUTION_PATH_COV, }[options.strategy] dse = DSEPathConstraint(machine, produce_solution=strategy) # Attach to the jitter dse.attach(sb.jitter) # Update the jitter state: df is read, but never set # Approaches: specific or generic # - Specific: # df_value = ExprInt(sb.jitter.cpu.df, dse.ir_arch.arch.regs.df.size) # dse.update_state({ # dse.ir_arch.arch.regs.df: df_value # }) # - Generic: dse.update_state_from_concrete() # Add constraint on file size, we don't want to generate too big FILE z3_file_size = dse.z3_trans.from_expr(FILE_size) dse.cur_solver.add(0 < z3_file_size) dse.cur_solver.add(z3_file_size < 0x10)
# Handle return def code_sentinelle(jitter): jitter.run = False return False ret_addr = 0x1337beef jitter.add_breakpoint(ret_addr, code_sentinelle) jitter.push_uint32_t(ret_addr) # Init the jitter jitter.init_run(run_addr) # Init a DSE instance with a given strategy dse = DSEPathConstraint(machine, produce_solution=strategy) dse.attach(jitter) # Concretize everything except the argument dse.update_state_from_concrete() regs = jitter.ir_arch.arch.regs arg = ExprId("ARG", 32) arg_addr = ExprMem(ExprInt(jitter.cpu.ESP + 4, regs.ESP.size), arg.size) dse.update_state({ # @[ESP + 4] = ARG arg_addr: arg }) # Explore solutions todo = set([ExprInt(0, arg.size)]) done = set() snapshot = dse.take_snapshot()