Posted August 21, 20214 yr Custom Protector CrackMe It is written in FASM, anti-debugging methods are used. You need to get the keys that were used to encrypt the hash being checked (Enter the necessary values in the input field to get "Success", and throw these values here) File Information Submitter Twaoperder Submitted 08/21/2021 Category CrackMe View File
May 29, 20223 yr Solution Used tools: x64dbg, Triton The anti-debugging and obfuscation is straightforward: consisting solely of int3s and junk code. Below is the cleaned version of main, just about 30 lines of assembly. Main reads 8 inputs, stores them to their registers and executes the hash function. The hash function itself is clean (no obfuscation or anti-debugging), and cannot be simplified further (according to Triton). The tricky part is to find the 8 keys to generate the correct "hash". I used Triton for that. For some reason, Triton ignores the restriction on x64's div instruction sizes, a real machine errors with a #DE when tying to divide a number too large. I had to specify a additional code path constraint for RDX for that single instruction. Then the result is correct and executes on a real machine. The solver using Triton: #!/usr/bin/env python ## -*- coding: utf-8 -*- import sys from triton import * from tabulate import tabulate # int64 f(rax, r8, r9, r10, r11, r12, r13, r14) CODE=b"\x4D\x31\xFF\x48\xC1\xC0\x08\x3C\x00\x75\x50\x49\x0F\xBA\xEF\x3C\x50\x4C\x89\xC0\x49\xF7\xE1\x49\x89\xC0\x58\x49\xF7\xD0\x4D\x01\xE8\x49\x81\xF0\x0F\x0F\x0F\x0F\x49\x81\xC0\x0F\x0F\x0F\x0F\x48\xC1\xE0\x04\x48\xC1\xC0\x10\x4C\x01\xC0\x4C\x31\xD8\x48\xC1\xE8\x02\x4C\x01\xF0\x48\xC1\xE8\x03\x48\xC1\xC8\x06\x4D\x01\xD8\x4C\x01\xC0\x4D\x8D\x7F\x01\x80\xFC\xAA\x76\xE9\x48\x0F\xBA\xE0\x3C\x73\x05\x48\x0F\xBA\xF0\x3C\x4D\x31\xC8\x49\xF7\xD0\x4D\x01\xE8\x49\x81\xF0\x0F\x0F\x0F\x0F\x49\xC1\xE0\x08\x49\x81\xC0\xEF\xEF\xEF\x0F\x48\xC1\xE8\x04\x48\xC1\xC0\x10\x4C\x01\xC0\x4C\x31\xD8\x49\xF7\xF4\x49\xC1\xC7\x20\x4C\x01\xD8\x48\xF7\xD0\x4C\x01\xC0\x48\xC1\xC0\x03\x4C\x31\xD0\x4D\x01\xF0\x4C\x01\xC0\x4D\x8D\x7F\x01\x80\xFC\x55\x76\xE4\x49\xC1\xCF\x20\x48\xBB\x06\x73\x32\x60\xF3\x49\xB3\xD1\x39\xD8\xC3" def emulate(ctx, pc): while pc: opcode = ctx.getConcreteMemoryAreaValue(pc, 16) instruction = Instruction(pc, opcode) ctx.processing(instruction) if instruction.isSymbolized(): print("\033[92m" + str(instruction) + "\033[0m") else: print(instruction) pc = ctx.getRegisterAst(ctx.registers.rip).evaluate() if pc == 0x1090: # constrain RDX to avoid #DE on a real machine (RDX:RAX too big) ctx.pushPathConstraint(ctx.getRegisterAst(ctx.registers.rdx) < 0x1000) return def main(): ctx = TritonContext(ARCH.X86_64) ast = ctx.getAstContext() # Triton Settings ctx.setMode(MODE.CONSTANT_FOLDING, True) ctx.setMode(MODE.ALIGNED_MEMORY, True) ctx.setMode(MODE.AST_OPTIMIZATIONS, True) ctx.setMode(MODE.CONCRETIZE_UNDEFINED_REGISTERS, True) ctx.setSolver(SOLVER.Z3) # declare inputs ctx.symbolizeRegister(ctx.registers.rax, "rax") ctx.symbolizeRegister(ctx.registers.r8, "r8") ctx.symbolizeRegister(ctx.registers.r9, "r9") ctx.symbolizeRegister(ctx.registers.r10, "r10") ctx.symbolizeRegister(ctx.registers.r11, "r11") ctx.symbolizeRegister(ctx.registers.r12, "r12") ctx.symbolizeRegister(ctx.registers.r13, "r13") ctx.symbolizeRegister(ctx.registers.r14, "r14") ctx.symbolizeRegister(ctx.registers.r15, "r15") print('Emulating...') ctx.setConcreteMemoryAreaValue(0x1000, CODE) emulate(ctx, 0x1000) eaxAST = ctx.getSymbolicRegister(ctx.registers.eax).getAst() #print("raxAST = ", ast.unroll(eaxAST)) # hashes in eax (generated) and ebx (loaded) must be equal ctx.pushPathConstraint(ctx.getRegisterAst(ctx.registers.zf) == 1) print("solving...") model = ctx.getModel(ctx.getPathPredicate()) print(tabulate(sorted(model.items()))) print(tabulate(sorted({k: v.getValue() for k, v in model.items()}.items()))) return 0 if __name__ == '__main__': sys.exit(main()) solver.py
Create an account or sign in to comment