Wacon CTF

https://global.wacon.world/challenges

Adult Artist

https://github.com/JuliaPoo/Artfuscator

这个题的生成使用的是 Artfuscator 工具,观察了一下生成的101 cases,里面的所有的计算都是线性的计算操作

image-20230904215514714

nop掉无用的指令

import idautils
import idc

def my_nop(addr, endaddr):
    while addr < endaddr:
        patch_byte(addr, 0x90)
        addr += 1

pattern = "2E C4 E2 71 96 84 9A 0C 80 0E 08"
cur_addr = 0x80491FF
end_addr = 0x80E69F5

while cur_addr < end_addr:
    cur_addr = idc.find_binary(cur_addr,SEARCH_DOWN,pattern)
    print("patch address: " + str(cur_addr)) # 打印提示信息
    if cur_addr == idc.BADADDR:
        break
    else:
        my_nop(cur_addr,cur_addr + 11)
    cur_addr = idc.next_head(cur_addr)

image-20230905103531527

from unicorn import *
from capstone import *
from unicorn.x86_const import *

import struct

import sys
import hashlib

# xor add sub ror rol bswap

def bswap(value):
    return ((value & 0xFF) << 24) | (((value >> 8) & 0xFF) << 16) | (((value >> 16) & 0xFF) << 8) | ((value >> 24) & 0xFF)

def rol(value, shift):
    shift %= 32 
    return ((value << shift) | (value >> (32 - shift))) & 0xFFFFFFFF

def ror(value, shift):
    shift %= 32
    return ((value >> shift) | (value << (32 - shift))) & 0xFFFFFFFF


binary = open('./masterpiece', 'rb').read()
#file = open("./print.txt",'w')

dump_insns = []
md = Cs(CS_ARCH_X86, CS_MODE_32)

BASE_ADDRESS = 0x8048000
TEXT_BEG = 0x8049000 - BASE_ADDRESS
TEXT_END = 0x80E6A0D - BASE_ADDRESS
SEG_TEXT = binary[TEXT_BEG:TEXT_END]

DATA_BEG = 0x80E8000 - BASE_ADDRESS
DATA_END = 0x80E82A8 - BASE_ADDRESS
SEG_DATA = binary[DATA_BEG:DATA_END]

ARR_ADDR = 0x80E8018
CMP_ADDR = 0x80E8118



def get_r_eax(index):
    cmp_data_offset = CMP_ADDR - BASE_ADDRESS - DATA_BEG + index * 4
    ret ,= struct.unpack('<I',SEG_DATA[cmp_data_offset:cmp_data_offset + 4])
    return ret

def get_byte(index):
    return SEG_DATA[ARR_ADDR - DATA_BEG - BASE_ADDRESS + index]

arr_list = []
for i in range(256):
    arr_list.append(get_byte(i))

cmp_list = []
for i in range(100):
    cmp_list.append(get_r_eax(i))


# code to be emulated

EMU_ADDRESS_BEG = 0x80491FF
EMU_ADDRESS_END = 0x80E69F5

def start(round):
    global dump_insns
    dump_insns = []

    try:

        # Initialize emulator

        mu = Uc(UC_ARCH_X86, UC_MODE_32)

        # map 8KB memory for this emulation

        mu.mem_map(BASE_ADDRESS, 2 * 1024 * 1024 )

        # write machine code to be emulated to memory

        mu.mem_write(TEXT_BEG + BASE_ADDRESS, SEG_TEXT)
        mu.mem_write(DATA_BEG + BASE_ADDRESS, SEG_DATA)

        # initialize machine registers

        mu.reg_write(UC_X86_REG_EAX, 0x0)
        mu.reg_write(UC_X86_REG_ECX, round)

        #hook code (capstone)
        mu.hook_add(UC_HOOK_CODE, hook_code)

        # emulate machine code in infinite time

        mu.emu_start(EMU_ADDRESS_BEG, EMU_ADDRESS_END)

    except UcError as e:
        print("ERROR: %s" % e)    

# callback for tracing instructions

def hook_code(uc, address, size, user_data):
    global md, dump_insns
    offset = address - TEXT_BEG - BASE_ADDRESS
    code = SEG_TEXT[offset:offset + size]
    insn = next(md.disasm(code, address))
    
    if insn.mnemonic not in ['nop', 'jmp']:
        dump_insns.append(insn)
        #file.write("0x%x:\t%s\t%s\n" %(insn.address, insn.mnemonic, insn.op_str))

flag = b''

def solve(r_eax):
    r_ecx = 0
    #逆序
    for insn in reversed(dump_insns):
        if 'eax' not in insn.op_str and 'al' not in insn.op_str and 'ah' not in insn.op_str:
            print(insn.mnemonic, insn.op_str)
            continue
        match (insn.mnemonic, insn.op_str):
            case ('inc', op_str):
                if('eax' == op_str):
                    r_eax -= 1
            case ('dec', op_str):
                if('eax' == op_str):
                    r_eax += 1
            case ('ror', op_str):
                reg, val = op_str.split(', ')
                if('eax' == reg):
                    r_eax = rol(r_eax, int(val, 16))
            case ('rol', op_str):
                reg, val = op_str.split(', ')
                if('eax' == reg):
                    r_eax = ror(r_eax, int(val, 16))
            case ('add', op_str):
                reg, val = op_str.split(', ')
                if('eax' == reg):
                    r_eax -= int(val, 16)
            case ('sub', op_str):
                reg, val = op_str.split(', ')
                if('eax' == reg):
                    r_eax += int(val, 16)
            case ('not', op_str):
                if('eax' == op_str):
                    r_eax ^= 0xffffffff
            case ('xor', op_str):
                reg, val = op_str.split(', ')
                if('eax' == reg):
                    r_eax ^= int(val, 16)
            case ('bswap', op_str):
                if('eax' == op_str):
                    r_eax = bswap(r_eax)
            case ('mov', op_str):
                #mov     cl, ah
                #mov     ah, byte_80E8018[ecx]
                #mov     cl, al
                #mov     al, byte_80E8018[ecx]
                op1, op2 = op_str.split(', ')
                if('cl' == op1):
                    if('al' == op2):
                        r_eax = (r_eax & 0xffffff00) | r_ecx
                    elif('ah' == op2):
                        r_eax = (r_eax & 0xffff00ff) | (r_ecx << 8)
                elif ('al' == op1) and ('byte ptr [ecx + 0x80e8018]' == op2):
                    r_ecx = arr_list.index(r_eax & 0xff)
                elif ('ah' == op1) and ('byte ptr [ecx + 0x80e8018]' == op2):
                    r_ecx = arr_list.index((r_eax >> 8) & 0xff)
        r_eax &= 0xffffffff
    
    return struct.pack('<I', r_eax)

for i, cmp_dword in enumerate(cmp_list):
    start(i)
    flag += solve(cmp_dword)

print("WACON2023{" + hashlib.sha256(flag).hexdigest() + "}")

#WACON2023{583f7c0189b232225e07c755f734c82029f58113c60f4eab75ab31159b568f49}

Baby Artist

学到新知识 piet图片用颜色来编写代码

https://github.com/boothby/repiet

image-20230905105718345

repiet ./chall.bmp -o baby_artist.python -b python -O 3

整理分块的表达式:

相等表达式

image-20230905131547067

a[index+1] - a[index] = curr

image-20230905131927945

a[index] % curr = 0 a[index] / curr = 0

image-20230905132028879

手动逆感觉就行

flag = [125, 63, 121, 114, 116, 95, 52, 78, 110, 52, 119, 95, 95, 33, 103, 110, 49, 87, 52, 114, 68, 95, 110, 85, 102, 123, 51, 50, 48, 50, 78, 79, 67, 65, 87]

right_flag = b''
for i in reversed(flag):
    right_flag += bytes([i])

print(right_flag.decode())
#WACON2023{fUn_Dr4W1ng!__w4nN4_try?}

Terrible Flavor