Jump to content

Custom Protector CrackMe


Twaoperder
Go to solution Solved by dtor135,

Recommended Posts

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)


 

Link to comment
  • 9 months later...
  • Solution
dtor135

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.

dis.png.93bcece02aa3b6abb9582bff6d1086eb.png

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.

keys.png.7ce39dc41db4c9407c21735d5d061c32.png

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

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...