FlareOn1 -- 5get_it

用 DIE 打开,是一个 dll

1

用 ida 打开,简单分析一下,是一个记录键盘按键的程序。里面的每个虚拟键码都有一个函数返回字符串

2

那么 flag 在哪里呢?看到左边函数窗口里看到有一个 DialogFunc,按 X 查找交叉引用,最后找到按下 "m" 对应的函数

3
image

执行 sub_10001240 的条件是 dword_100194FC > 0。
dword_100194FC 的初始值是 0,再找 dword_100194FC 的交叉引用,看看哪里把它改成了 1,最后找到了 "o" 对应的函数

image

按照这个方法,逐步追溯每个变量改变的条件,所有按键对应的的字符连起来就是 flag

import idautils
import idaapi
import idc
import copy

target_var_ea = 0x100194FC
target_var_value = 1
asc_string = 'm'

init_func_ea = 0x10001060

print("*********************************")

def get_initial_status(func_ea):
    status = dict()

    for ea in idautils.FuncItems(func_ea):
        insn = idaapi.insn_t()
        idaapi.decode_insn(insn, ea)
        if insn.itype == idaapi.NN_mov and insn.ops[0].type == idaapi.o_mem and insn.ops[1].type == idaapi.o_imm:
            status[insn.ops[0].addr] = insn.ops[1].value

    return status

init_status = get_initial_status(init_func_ea)
current_staus = copy.deepcopy(init_status)

def get_target_status(func, target_ea):
    status = dict()

    flowchart = idaapi.FlowChart(func)
    target_block = None

    # 找到目标地址所在的块
    for block in flowchart:
        if block.start_ea <= target_ea < block.end_ea:
            target_block = block
            break

    # 获取函数返回值
    mov_eax_addr = idc.prev_head( # mov eax, imm
        idc.prev_head(            # pop ebp
            idc.prev_head(        # ret
                func.end_ea)))

    insn = idaapi.insn_t()
    idaapi.decode_insn(insn, mov_eax_addr)

    asc_addr = 0
    if insn.itype == idaapi.NN_mov and insn.ops[0].type == idaapi.o_reg and insn.ops[1].type == idaapi.o_imm:
        asc_addr = insn.ops[1].value
    else:
        raise Exception("not \"mov eax, imm\"")

    # 反向遍历块,获取运行到目标地址所需要的所有条件
    while True:
        pre_blocks = target_block.preds()
        pre_count = 0

        for block in pre_blocks:
            pre_count += 1
            if pre_count > 1:
                raise Exception("too many preds")

            cmp = idaapi.insn_t()
            idaapi.decode_insn(cmp, idc.prev_head(idc.prev_head(block.end_ea)))
            jcc = idaapi.insn_t()
            idaapi.decode_insn(jcc, idc.prev_head(block.end_ea))

            if cmp.itype == idaapi.NN_cmp and cmp.ops[0].type == idaapi.o_mem and cmp.ops[1].type == idaapi.o_imm and cmp.ops[1].value == 0 and jcc.itype == idaapi.NN_jle:
                if jcc.ops[0].addr == target_block.start_ea:
                    status[cmp.ops[0].addr] = 0
                else:
                    status[cmp.ops[0].addr] = 1
            else:
                raise Exception("not \"cmp mem, 0\" and \"jle addr\"")

            target_block = block

        if pre_count == 0:
            break

    # 返回结果
    return status, asc_addr

start_at = 0
while start_at == 0:

    # 遍历所有引用目标变量的地方
    target_count = 0
    for xref in idautils.XrefsTo(target_var_ea):
        insn = idaapi.insn_t()
        idaapi.decode_insn(insn, xref.frm)

        # 找到达到目标状态的 mov
        if insn.itype == idaapi.NN_mov and insn.ops[1].type == idaapi.o_imm and insn.ops[1].value == target_var_value:
            target_count += 1
            if target_count > 1:
                raise Exception("too many targets")

            func = idaapi.get_func(xref.frm)
            status, asc_addr = get_target_status(func, xref.frm)
            print(status)
            print(idc.get_strlit_contents(asc_addr))
            asc_string = idc.get_strlit_contents(asc_addr).decode() + asc_string

            # 对比初始状态,找到变化的量
            change_count = 0
            for addr in status:
                if addr in init_status:
                    if init_status[addr] != status[addr]:
                        change_count += 1
                        if change_count > 1:
                            # raise Exception("too many changes")
                            break

                        print(f'change: {addr:x} -> {status[addr]}')
                        target_var_ea = addr
                        target_var_value = status[addr]
                else:
                    raise Exception("uninitialzed var")

            if change_count == 0:
                start_at = func.start_ea
                print(f'start at {start_at:x} ({idc.get_func_name(start_at)})')

print(asc_string)

image

l0ggingdoturdot5tr0ke5atflaredashondotcom
l0gging.ur.5tr0ke5@flare-on.com
提交,都不对。
上网搜一下,答案是 l0gging.Ur.5tr0ke5@flare-on.com

这里只是通过虚拟键码判断,没有区分大小写,也没有处理 Shift 和 CapsLock,所以没弄清楚为什么 U 会是大写……

posted @ 2025-10-02 20:16  矛盾空间  阅读(23)  评论(0)    收藏  举报