roaris / ctf-log

0 stars 0 forks source link

WaniCTF 2024 : gates #61

Open roaris opened 3 months ago

roaris commented 3 months ago

https://github.com/wani-hackase/wanictf2024-writeup/tree/main/rev/gates

本番で解けた問題だが、めちゃくちゃな方法で解いたので復習する

roaris commented 3 months ago

フラグ入力型の問題

$ ./gates
testtesttesttesttesttesttesttest
Wrong!
roaris commented 3 months ago

めちゃくちゃな方法も一応残しておく

IDAとGhidraでどういう処理がされているかはなんとなく読み取った 32文字の入力を受け取り、何かしらの変換をした後に、1文字ずつ検証していそうだと思った しかし、肝心の変換処理が読めなかったので、gdbスクリプトで、各位置毎にどの文字にしたら求めることにした 検証処理の手前にbreakpointを設定するために、ベースアドレスが知りたい シンボル情報がstripされていて、b mainと出来ないので、一度実行した後に、__libc_start_main関数にbreakpointを設定し、rdiレジスタを確認することで、main関数のアドレスを取得し、ベースアドレスを求めている

以下のプログラムをsolve.pyとして保存し、gdb gates -x solve.pyを実行する

import gdb

characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-.$@!?\{\}'
flag = [''] * 32

for c in characters:
    with open('input.txt', 'w') as f:
        tmp_flag = flag[:]

        for i in range(32):
            if tmp_flag[i] == '':
                tmp_flag[i] = c

        f.write(''.join(tmp_flag))

    gdb.execute('r < input.txt')
    gdb.execute('b __libc_start_main')
    gdb.execute('r')
    main_addr = gdb.parse_and_eval('$rdi')
    base = main_addr - 0x1080
    gdb.execute('b *' + hex(base + 0x10FD))
    gdb.execute('c')

    rax = gdb.parse_and_eval('$rax')
    rdx = gdb.parse_and_eval('$rdx')

    for i in range(32):
        if flag[i] == '':
            x = gdb.execute('x/1bx ' + hex(rax + 0x10 * i), to_string=True).split(':')[1]
            y = gdb.execute('x/1bx ' + hex(rdx + i), to_string=True).split(':')[1]

            if x == y:
                flag[i] = c
                break

print(flag)

変換処理が位置毎に独立なら、これで良いのだが、独立でない場合は上手くいかない 実際に出力は、['F', 'L', 'A', 'G', '{', 'I', 'N', 'T', 'r', '0', 'd', 'U', 'c', 't', 'i', 'o', 'n', '_', '7', '', '', 'R', '3', 'v', '', '', '$', '1', '', '', '', '}']となり、''となっている箇所が一部存在する

しかし、プログラム中のflagを更新して、再度実行すると、全ての位置で文字が求まった

import gdb

characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-.$@!?\{\}'
flag = ['F', 'L', 'A', 'G', '{', 'I', 'N', 'T', 'r', '0', 'd', 'U', 'c', 't', 'i', 'o', 'n', '_', '7', '', '', 'R', '3', 'v', '', '', '$', '1', '', '', '', '}']

for c in characters:
    with open('input.txt', 'w') as f:
        tmp_flag = flag[:]

        for i in range(32):
            if tmp_flag[i] == '':
                tmp_flag[i] = c

        f.write(''.join(tmp_flag))

    gdb.execute('r < input.txt')
    gdb.execute('b __libc_start_main')
    gdb.execute('r')
    main_addr = gdb.parse_and_eval('$rdi')
    base = main_addr - 0x1080
    gdb.execute('b *' + hex(base + 0x10FD))
    gdb.execute('c')

    rax = gdb.parse_and_eval('$rax')
    rdx = gdb.parse_and_eval('$rdx')

    for i in range(32):
        if flag[i] == '':
            x = gdb.execute('x/1bx ' + hex(rax + 0x10 * i), to_string=True).split(':')[1]
            y = gdb.execute('x/1bx ' + hex(rdx + i), to_string=True).split(':')[1]

            if x == y:
                flag[i] = c
                break

print(flag)

出力は、['F', 'L', 'A', 'G', '{', 'I', 'N', 'T', 'r', '0', 'd', 'U', 'c', 't', 'i', 'o', 'n', '_', '7', '0', '_', 'R', '3', 'v', '3', 'R', '$', '1', 'N', 'G', '1', '}']となった よくこの方法で解けたなと思う

roaris commented 3 months ago

解説には

解いた人はたぶんみんな angr 使ってる気がするが、ここでは詳しく説明しない。(ただし今回みたいにポンコツ出題者がちゃんと angr で解けるかどうかを確認しないとき解けたりするので、使い方がわからない人は勉強したほうがいい。)

とあるので、まずはangrを使ったやり方から試す

roaris commented 3 months ago

angrの使い方から勉強

「詳解セキュリティコンテスト」によると、 angrでは、シンボリック実行というものを行う シンボリック実行というのは、メモリやレジスタの一部分を具体的な値として持つのではなく、シンボルという状態として扱い、プログラムが特定の箇所に到達するための条件を導出する 導出にはSATソルバを使う

簡単なプログラムで試す

#include <stdio.h>

int check(int x) {
    return x*x*x - 30*x*x + 275*x - 750 == 0;
}

int main() {
    int x;
    scanf("%d", &x);
    if (check(x)) {
        puts("Correct!");
    } else {
        puts("Wrong...");
    }
}

angrを使って、Correct!が表示されるような入力を求める x^3-30x^2+275x-750 = (x-5)(x-10)(x-15) なので、5, 10, 15が出てきてほしい

roaris commented 3 months ago

以下のようなプログラムを書いた

import angr
import claripy

p = angr.Project('./main', load_options={'auto_load_libs': False})
x = claripy.BVS('x', 8 * 2)
state = p.factory.entry_state(stdin=x)
simgr = p.factory.simulation_manager(state)
simgr.explore(find=0x4011c3, avoid=0x4011d4)

try:
    e = simgr.found[0].solver.eval(x, cast_to=bytes)
    print(e)
except IndexError:
    print('Not found')
roaris commented 3 months ago

実行する

$ python solve.py
WARNING  | 2024-07-04 01:24:34,842 | angr.simos.simos | stdin is constrained to 2 bytes (has_end=True). If you are only providing the first 2 bytes instead of the entire stdin, please use stdin=SimFileStream(name='stdin', content=your_first_n_bytes, has_end=False).
b'05'

WARNINGの内容は分からない 無視して良いやつだろう 出力はb'05'となっている 実際、05を入力すると、Correct!と表示される

$ ./main
05
Correct!

simgr.foundの長さは1だった つまり、05以外の答えは出てきてない 方程式の解は5の他に10と15もあったが、これらを求めるためには、シンボルに制約を追加して、解を求めればよい https://docs.angr.io/en/latest/core-concepts/solver.html#constraint-solving

import angr
import claripy

p = angr.Project('./main', load_options={'auto_load_libs': False})
x = claripy.BVS('x', 8 * 2)
state = p.factory.entry_state(stdin=x)

while True:
    simgr = p.factory.simulation_manager(state)
    simgr.explore(find=0x4011c3, avoid=0x4011d4)

    try:
        e = simgr.found[0].solver.eval(x, cast_to=bytes)
        print(e)
        state.solver.add(x != e)
    except IndexError:
        print('Not found')
        break

これを実行すると、10と15も出てくる 5の後に数字以外が来るのは何でも良いので、そのパターンが全部出てくる

$ python solve.py
WARNING  | 2024-07-04 01:32:45,877 | angr.simos.simos | stdin is constrained to 2 bytes (has_end=True). If you are only providing the first 2 bytes instead of the entire stdin, please use stdin=SimFileStream(name='stdin', content=your_first_n_bytes, has_end=False).
b'05'
b'5\xf0'
b'10'
b'5\xa1'
b'+5'
b'15'
b'5\xba'
b'5\xbc'
b'5t'
b'5\x00'
b'5A'
b'5('
b'5\x8a'
b'5\x10'
b'5\x8c'
...
roaris commented 3 months ago

今回の問題を解くならこうなるだろう

import angr
import claripy

p = angr.Project('./gates', load_options={'auto_load_libs': False})
flag = claripy.BVS('flag', 8 * 32)
state = p.factory.entry_state(stdin=flag)
simgr = p.factory.simulation_manager(state)
simgr.explore(find=0x40111d, avoid=0x401105)

try:
    e = simgr.found[0].solver.eval(flag, cast_to=bytes)
    print(e)
except IndexError:
    print('Not found')

が、discordに載せられているプログラムは

import angr, claripy
import sys, logging

logging.getLogger("angr").setLevel(logging.INFO)
project = angr.Project(
    "./gates", main_opts={"base_addr": 0x00100000}, auto_load_libs=False
)
flag = claripy.BVS("flag", 0x20 * 8)
initial_state = project.factory.full_init_state(
    stdin=flag, add_options=angr.options.unicorn
)
simulation = project.factory.simgr(initial_state)

simulation.explore(
    find=lambda state: b"Correct!" in state.posix.dumps(sys.stdout.fileno()),
    avoid=lambda state: b"Wrong!" in state.posix.dumps(sys.stdout.fileno()),
)
if simulation.found:
    print(simulation.found[0].posix.dumps(sys.stdin.fileno()))

とか

import angr, claripy
p = angr.Project("./gates", main_opts={"base_addr": 0x100000}, auto_load_libs=False)

s = p.factory.entry_state(addr=0x1010bc)

vs = [claripy.BVS(f"chr{x}", 8) for x in range(32)]

for i, v in enumerate(vs):
    s.memory.store(0x10404c + (i * 0x10), 1, 1)
    s.memory.store(0x10404c + 1 + (i * 0x10), v, 1)

sm = p.factory.simgr(s, veritesting=True)
results = sm.explore(find=lambda s: b"Correct" in s.posix.dumps(1), avoid=lambda s: b"Wrong" in s.posix.dumps(1))

何をしているのか分からない... とりあえず、自分で書いたプログラムを動かしてみる 20分経っても終わらなかったら諦めよう

roaris commented 3 months ago

23分実行して出てきた angr凄いな

$ python solve_angr.py
WARNING  | 2024-07-04 01:55:37,451 | angr.simos.simos | stdin is constrained to 32 bytes (has_end=True). If you are only providing the first 32 bytes instead of the entire stdin, please use stdin=SimFileStream(name='stdin', content=your_first_n_bytes, has_end=False).
b'FLAG{INTr0dUction_70_R3v3R$1NG1}'
roaris commented 3 months ago

Ghidraのdecompile結果

undefined8 FUN_00101080(void)

{
  int iVar1;
  char *pcVar2;
  char *pcVar3;
  undefined1 *puVar4;
  undefined1 *puVar5;

  puVar4 = &DAT_0010404c;
  do {
    puVar5 = puVar4 + 0x10;
    iVar1 = getc(stdin);
    *puVar4 = 1;
    puVar4[1] = (char)iVar1;
    puVar4 = puVar5;
  } while (puVar5 != &DAT_0010424c);
  iVar1 = 0x100;
  do {
    FUN_00101220();
    iVar1 = iVar1 + -1;
  } while (iVar1 != 0);
  pcVar2 = &DAT_00104e4d;
  pcVar3 = &DAT_00104020;
  do {
    if (*pcVar2 != *pcVar3) {
      puts("Wrong!");
      return 1;
    }
    pcVar2 = pcVar2 + 0x10;
    pcVar3 = pcVar3 + 1;
  } while (pcVar2 != &DAT_0010504d);
  puts("Correct!");
  return 0;
}
void FUN_00101220(void)

{
  char cVar1;
  byte bVar2;
  char cVar3;
  undefined uVar4;
  byte bVar5;
  int iVar6;
  undefined8 *puVar7;
  long lVar8;

  puVar7 = (undefined8 *)&DAT_00104040;
  do {
    iVar6 = *(int *)puVar7;
    if (iVar6 == 3) {
      lVar8 = (long)*(int *)((long)puVar7 + 4) * 0x10;
      if (((&DAT_0010404c)[lVar8] != '\0') &&
         ((&DAT_0010404c)[(long)*(int *)(puVar7 + 1) * 0x10] != '\0')) {
        bVar5 = (&DAT_0010404d)[lVar8];
        bVar2 = (&DAT_0010404d)[(long)*(int *)(puVar7 + 1) * 0x10];
        *(undefined *)((long)puVar7 + 0xc) = 1;
        *(byte *)((long)puVar7 + 0xd) = bVar5 ^ bVar2;
      }
    }
    else if (iVar6 < 4) {
      if ((((iVar6 == 1) || (iVar6 == 2)) &&
          (lVar8 = (long)*(int *)((long)puVar7 + 4) * 0x10, (&DAT_0010404c)[lVar8] != '\0')) &&
         ((&DAT_0010404c)[(long)*(int *)(puVar7 + 1) * 0x10] != '\0')) {
        cVar3 = (&DAT_0010404d)[(long)*(int *)(puVar7 + 1) * 0x10];
        cVar1 = (&DAT_0010404d)[lVar8];
        *(undefined *)((long)puVar7 + 0xc) = 1;
        *(char *)((long)puVar7 + 0xd) = cVar3 + cVar1;
      }
    }
    else if ((iVar6 == 4) &&
            (lVar8 = (long)*(int *)((long)puVar7 + 4) * 0x10, (&DAT_0010404c)[lVar8] != '\0')) {
      uVar4 = (&DAT_0010404d)[lVar8];
      *(undefined *)((long)puVar7 + 0xc) = 1;
      *(undefined *)((long)puVar7 + 0xd) = uVar4;
    }
    puVar7 = puVar7 + 2;
  } while (puVar7 != &stdin);
  return;
}
roaris commented 3 months ago

IDAと見比べながら読み進める

puVar4 = &DAT_0010404c;
do {
  puVar5 = puVar4 + 0x10;
  iVar1 = getc(stdin);
  *puVar4 = 1;
  puVar4[1] = (char)iVar1;
  puVar4 = puVar5;
} while (puVar5 != &DAT_0010424c);

&DAT_0010404cは、IDAでは0x404cになっている image

Ghidraでも、Imagebase Offsetというものは0x404cになっている image

じゃあ&DAT_0010404cの10404cとは?

処理内容は、 0x404cに1を格納、0x404dに入力文字を格納 0x405cに1を格納、0x405dに入力文字を格納 ... 0x424cに1を格納、0x424dに入力文字を格納 としている

iVar1 = 0x100;
do {
  FUN_00101220();
  iVar1 = iVar1 + -1;
} while (iVar1 != 0);

256回、FUN_00101220()している

roaris commented 3 months ago

FUN_00101220は、16バイトの構造体の配列を扱っている、ということを分かってないと読むのがかなり難しい 本番は、構造体を扱っているだなんて微塵も考えておらず、処理内容を読めなかった

0x4040を起点として、16バイトの構造体が並んでいる つまり、0x4040 ~ 0x404Fで1つの構造体、0x4050 ~ 0x405Fで1つの構造体、... である

puVar4 = &DAT_0010404c;
do {
  puVar5 = puVar4 + 0x10;
  iVar1 = getc(stdin);
  *puVar4 = 1;
  puVar4[1] = (char)iVar1;
  puVar4 = puVar5;
} while (puVar5 != &DAT_0010424c);

でやっていたのは、構造体のフィールドに値を代入する処理である

roaris commented 3 months ago

FUN_00101220のdecompile結果は間違っているんじゃないかという点がある

まず、puVar7 = puVar7 + 2;は、puVar7 = puVar7 + 16;の間違いだと思う 16バイトの構造体が並んでいるんだから、普通に考えたら後者が自然だし、IDAで確認しても後者である

image

もう1つはbVar2 = (&DAT_0010404d)[(long)*(int *)(puVar7 + 1) * 0x10];である iVar6 = *(int *)puVar7;で、構造体の1バイト目\~4バイト目をint型として読み出している だから、2バイト目\~5バイト目をint型として読み出すというのはおかしい

IDAで確認すると、bVar2 = (&DAT_0010404d)[(long)*(int *)(puVar7 + 8) * 0x10];が正しい

image

while (puVar7 != &stdin)も意味不明である 0x5040なのだが、なぜ&stdin?

image

roaris commented 3 months ago
構造体の構造について考えよう 位置 使用箇所
1バイト目 ~ 4バイト目 32ビット整数 *(int *)puVar7
5バイト目 ~ 8バイト目 32ビット整数 (long)*(int *)((long)puVar7 + 4) * 0x10
9バイト目 ~ 12バイト目 32ビット整数 (long)*(int *)((long)puVar7 + 8) * 0x10
13バイト目 8ビット整数 *(undefined *)((long)puVar7 + 0xc)
14バイト目 8ビット整数 *(byte *)((long)puVar7 + 0xd)
15バイト目~16バイト目(未使用) - -

以下のようなイメージだろう

#include <stdio.h>

struct S {
    __int32_t a;
    __int32_t b;
    __int32_t c;
    __int8_t d;
    __int8_t e;
    __int16_t padding;
};

int main(void){
    struct S s = {0x12, 0x34, 0x56, 0, 0, 0};
    s.d = 1;
    s.e = getchar();
}

objdumpするとこうなる

0000000000001139 <main>:
    1139:   55                      push   rbp
    113a:   48 89 e5                mov    rbp,rsp
    113d:   48 83 ec 10             sub    rsp,0x10
    1141:   c7 45 f0 12 00 00 00    mov    DWORD PTR [rbp-0x10],0x12
    1148:   c7 45 f4 34 00 00 00    mov    DWORD PTR [rbp-0xc],0x34
    114f:   c7 45 f8 56 00 00 00    mov    DWORD PTR [rbp-0x8],0x56
    1156:   c6 45 fc 00             mov    BYTE PTR [rbp-0x4],0x0
    115a:   c6 45 fd 00             mov    BYTE PTR [rbp-0x3],0x0
    115e:   66 c7 45 fe 00 00       mov    WORD PTR [rbp-0x2],0x0
    1164:   c6 45 fc 01             mov    BYTE PTR [rbp-0x4],0x1
    1168:   e8 c3 fe ff ff          call   1030 <getchar@plt>
    116d:   88 45 fd                mov    BYTE PTR [rbp-0x3],al
    1170:   b8 00 00 00 00          mov    eax,0x0
    1175:   c9                      leave
    1176:   c3                      ret
roaris commented 3 months ago

writeupには、GhidraのData Type Managerを使って、decompile結果を読みやすくする方法が書かれているが、上手くいかなかった 配列を作るところで、長さの最大値がなぜか186になってしまう

image

roaris commented 3 months ago

ここまで整理する

0x4040を開始地点として、16バイトの構造体が256個ある

0x4040, 0x4050, ..., 0x4240を開始とする32個の構造体については、

puVar4 = &DAT_0010404c;
do {
  puVar5 = puVar4 + 0x10;
  iVar1 = getc(stdin);
  *puVar4 = 1;
  puVar4[1] = (char)iVar1;
  puVar4 = puVar5;
} while (puVar5 != &DAT_0010424c);

の処理がされる 256回、FUN_00101220()が呼ばれる FUN_00101220()では、256個の構造体を1個ずつ処理する

roaris commented 3 months ago

検証処理を確認しよう

pcVar2 = &DAT_00104e4d;
pcVar3 = &DAT_00104020;
do {
  if (*pcVar2 != *pcVar3) {
    puts("Wrong!");
    return 1;
  }
  pcVar2 = pcVar2 + 0x10;
  pcVar3 = pcVar3 + 1;
} while (pcVar2 != &DAT_0010504d);
puts("Correct!");

している

roaris commented 3 months ago

z3で解いた z3を使わなくても解けるようだが、理解できなかった

from z3 import *

# 0x4040 ~ 0x503f
data = bytes.fromhex('00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 67 00 00 01 00 00 00 00 00 00 00 20 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 C6 00 00 01 00 00 00 01 00 00 00 22 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 69 00 00 01 00 00 00 02 00 00 00 24 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 73 00 00 01 00 00 00 03 00 00 00 26 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 51 00 00 01 00 00 00 04 00 00 00 28 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 FF 00 00 01 00 00 00 05 00 00 00 2A 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 4A 00 00 01 00 00 00 06 00 00 00 2C 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 EC 00 00 01 00 00 00 07 00 00 00 2E 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 29 00 00 01 00 00 00 08 00 00 00 30 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 CD 00 00 01 00 00 00 09 00 00 00 32 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 BA 00 00 01 00 00 00 0A 00 00 00 34 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 AB 00 00 01 00 00 00 0B 00 00 00 36 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 F2 00 00 01 00 00 00 0C 00 00 00 38 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 FB 00 00 01 00 00 00 0D 00 00 00 3A 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 E3 00 00 01 00 00 00 0E 00 00 00 3C 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 46 00 00 01 00 00 00 0F 00 00 00 3E 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 7C 00 00 01 00 00 00 10 00 00 00 40 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 C2 00 00 01 00 00 00 11 00 00 00 42 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 54 00 00 01 00 00 00 12 00 00 00 44 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 F8 00 00 01 00 00 00 13 00 00 00 46 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 1B 00 00 01 00 00 00 14 00 00 00 48 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 E8 00 00 01 00 00 00 15 00 00 00 4A 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 E7 00 00 01 00 00 00 16 00 00 00 4C 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 8D 00 00 01 00 00 00 17 00 00 00 4E 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 76 00 00 01 00 00 00 18 00 00 00 50 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 5A 00 00 01 00 00 00 19 00 00 00 52 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 2E 00 00 01 00 00 00 1A 00 00 00 54 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 63 00 00 01 00 00 00 1B 00 00 00 56 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 33 00 00 01 00 00 00 1C 00 00 00 58 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 9F 00 00 01 00 00 00 1D 00 00 00 5A 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 C9 00 00 01 00 00 00 1E 00 00 00 5C 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 9A 00 00 01 00 00 00 1F 00 00 00 5E 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 66 00 00 03 00 00 00 21 00 00 00 60 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 32 00 00 03 00 00 00 23 00 00 00 62 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 0D 00 00 03 00 00 00 25 00 00 00 64 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 B7 00 00 03 00 00 00 27 00 00 00 66 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 31 00 00 03 00 00 00 29 00 00 00 68 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 58 00 00 03 00 00 00 2B 00 00 00 6A 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 A3 00 00 03 00 00 00 2D 00 00 00 6C 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 5A 00 00 03 00 00 00 2F 00 00 00 6E 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 25 00 00 03 00 00 00 31 00 00 00 70 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 5D 00 00 03 00 00 00 33 00 00 00 72 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 05 00 00 03 00 00 00 35 00 00 00 74 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 17 00 00 03 00 00 00 37 00 00 00 76 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 58 00 00 03 00 00 00 39 00 00 00 78 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 E9 00 00 03 00 00 00 3B 00 00 00 7A 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 5E 00 00 03 00 00 00 3D 00 00 00 7C 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 D4 00 00 03 00 00 00 3F 00 00 00 7E 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 AB 00 00 03 00 00 00 41 00 00 00 80 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 B2 00 00 03 00 00 00 43 00 00 00 82 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 CD 00 00 03 00 00 00 45 00 00 00 84 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 C6 00 00 03 00 00 00 47 00 00 00 86 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 9B 00 00 03 00 00 00 49 00 00 00 88 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 B4 00 00 03 00 00 00 4B 00 00 00 8A 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 54 00 00 03 00 00 00 4D 00 00 00 8C 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 11 00 00 03 00 00 00 4F 00 00 00 8E 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 0E 00 00 03 00 00 00 51 00 00 00 90 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 82 00 00 03 00 00 00 53 00 00 00 92 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 74 00 00 03 00 00 00 55 00 00 00 94 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 41 00 00 03 00 00 00 57 00 00 00 96 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 21 00 00 03 00 00 00 59 00 00 00 98 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 3D 00 00 03 00 00 00 5B 00 00 00 9A 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 DC 00 00 03 00 00 00 5D 00 00 00 9C 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 87 00 00 03 00 00 00 5F 00 00 00 9E 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 70 00 00 02 00 00 00 61 00 00 00 A0 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 E9 00 00 02 00 00 00 63 00 00 00 A2 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 3E 00 00 02 00 00 00 65 00 00 00 A4 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 A1 00 00 02 00 00 00 67 00 00 00 A6 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 41 00 00 02 00 00 00 69 00 00 00 A8 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 E1 00 00 02 00 00 00 6B 00 00 00 AA 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 FC 00 00 02 00 00 00 6D 00 00 00 AC 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 67 00 00 02 00 00 00 6F 00 00 00 AE 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 3E 00 00 02 00 00 00 71 00 00 00 B0 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 01 00 00 02 00 00 00 73 00 00 00 B2 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 7E 00 00 02 00 00 00 75 00 00 00 B4 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 97 00 00 02 00 00 00 77 00 00 00 B6 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 EA 00 00 02 00 00 00 79 00 00 00 B8 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 DC 00 00 02 00 00 00 7B 00 00 00 BA 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 6B 00 00 02 00 00 00 7D 00 00 00 BC 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 96 00 00 02 00 00 00 7F 00 00 00 BE 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 8F 00 00 02 00 00 00 81 00 00 00 C0 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 38 00 00 02 00 00 00 83 00 00 00 C2 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 5C 00 00 02 00 00 00 85 00 00 00 C4 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 2A 00 00 02 00 00 00 87 00 00 00 C6 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 EC 00 00 02 00 00 00 89 00 00 00 C8 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 B0 00 00 02 00 00 00 8B 00 00 00 CA 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 3B 00 00 02 00 00 00 8D 00 00 00 CC 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 FB 00 00 02 00 00 00 8F 00 00 00 CE 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 32 00 00 02 00 00 00 91 00 00 00 D0 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 AF 00 00 02 00 00 00 93 00 00 00 D2 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 3C 00 00 02 00 00 00 95 00 00 00 D4 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 54 00 00 02 00 00 00 97 00 00 00 D6 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 EC 00 00 02 00 00 00 99 00 00 00 D8 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 18 00 00 02 00 00 00 9B 00 00 00 DA 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 DB 00 00 02 00 00 00 9D 00 00 00 DC 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 5C 00 00 02 00 00 00 9F 00 00 00 DE 00 00 00 01 00 00 00 04 00 00 00 A1 00 00 00 A1 00 00 00 00 00 00 00 04 00 00 00 A3 00 00 00 A3 00 00 00 00 00 00 00 04 00 00 00 A5 00 00 00 A5 00 00 00 00 00 00 00 04 00 00 00 A7 00 00 00 A7 00 00 00 00 00 00 00 04 00 00 00 A9 00 00 00 A9 00 00 00 00 00 00 00 04 00 00 00 AB 00 00 00 AB 00 00 00 00 00 00 00 04 00 00 00 AD 00 00 00 AD 00 00 00 00 00 00 00 04 00 00 00 AF 00 00 00 AF 00 00 00 00 00 00 00 04 00 00 00 B1 00 00 00 B1 00 00 00 00 00 00 00 04 00 00 00 B3 00 00 00 B3 00 00 00 00 00 00 00 04 00 00 00 B5 00 00 00 B5 00 00 00 00 00 00 00 04 00 00 00 B7 00 00 00 B7 00 00 00 00 00 00 00 04 00 00 00 B9 00 00 00 B9 00 00 00 00 00 00 00 04 00 00 00 BB 00 00 00 BB 00 00 00 00 00 00 00 04 00 00 00 BD 00 00 00 BD 00 00 00 00 00 00 00 04 00 00 00 BF 00 00 00 BF 00 00 00 00 00 00 00 04 00 00 00 C1 00 00 00 C1 00 00 00 00 00 00 00 04 00 00 00 C3 00 00 00 C3 00 00 00 00 00 00 00 04 00 00 00 C5 00 00 00 C5 00 00 00 00 00 00 00 04 00 00 00 C7 00 00 00 C7 00 00 00 00 00 00 00 04 00 00 00 C9 00 00 00 C9 00 00 00 00 00 00 00 04 00 00 00 CB 00 00 00 CB 00 00 00 00 00 00 00 04 00 00 00 CD 00 00 00 CD 00 00 00 00 00 00 00 04 00 00 00 CF 00 00 00 CF 00 00 00 00 00 00 00 04 00 00 00 D1 00 00 00 D1 00 00 00 00 00 00 00 04 00 00 00 D3 00 00 00 D3 00 00 00 00 00 00 00 04 00 00 00 D5 00 00 00 D5 00 00 00 00 00 00 00 04 00 00 00 D7 00 00 00 D7 00 00 00 00 00 00 00 04 00 00 00 D9 00 00 00 D9 00 00 00 00 00 00 00 04 00 00 00 DB 00 00 00 DB 00 00 00 00 00 00 00 04 00 00 00 DD 00 00 00 DD 00 00 00 00 00 00 00 04 00 00 00 DF 00 00 00 DF 00 00 00 00 00 00 00')
# 0x4020 ~ 0x403f
expected_data = bytes.fromhex('3B 09 E5 AE 3E F1 37 81 FC A1 99 AE F7 62 7D F7 D0 CB A2 18 CD 3E 89 0D D9 DD 62 29 8C F3 01 EC')

class S:
    def __init__(self, t, i1, i2, x, y):
        self.t = t
        self.i1 = i1
        self.i2 = i2
        self.x = x
        self.y = y

array = []

for i in range(256):
    d = data[16*i:16*i+16]
    s = S(
        int.from_bytes(d[:4], 'little'),
        int.from_bytes(d[4:8], 'little'),
        int.from_bytes(d[8:12], 'little'),
        int(d[12]),
        int(d[13]),
    )
    array.append(s)

s = Solver()
input_chrs = [BitVec(f'input_chr_{i}', 8) for i in range(32)]

for i in range(32):
    array[i].x = 1
    array[i].y = input_chrs[i]

for _ in range(256):
    for i in range(256):
        t = array[i].t

        if t == 3:
            if array[array[i].i1].x != 0 and array[array[i].i2].x != 0:
                array[i].x = 1
                array[i].y = array[array[i].i1].y ^ array[array[i].i2].y
        elif t < 4:
            if (t == 1 or t == 2) and array[array[i].i1].x != 0 and array[array[i].i2].x != 0:
                array[i].x = 1
                array[i].y = array[array[i].i1].y + array[array[i].i2].y
        elif t == 4 and array[array[i].i1].x != 0:
            array[i].x = 1
            array[i].y = array[array[i].i1].y

for i in range(32):
    s.add(array[224+i].y == int(expected_data[i]))

r = s.check()

if r == sat:
    m = s.model()
    flag = ''.join(chr(m[input_chrs[i]].as_long()) for i in range(32))
    print(flag) # FLAG{INTr0dUction_70_R3v3R$1NG1}
else:
    print('not found')

バイト列は、IDAからコピーしてきた image