zipkey 发表于 2024-4-28 22:43

D^3CTF2024逆向Writeup

## 写在前面
第一次在52发帖,写的有问题的地方还请师傅们见谅

逆向部分题目很不错,VM题的伪随机控制流和迷宫题异常处理设置很巧妙,还剩两道没力气逆了,以后再补

## ezjunk

花指令,直接NOP掉,反编译main函数





加密部分是xxtea,观察调用时传入的参数,a2是sum,来自`loc_4015C3+2`,a3是delta,来自`loc_401A1C`,a4是key,来自`off_404350 + 400`

delta在main里面,刚好是patch掉的部分,需要记录patch前的数据,sum在另一个函数里面,先去掉花指令



找到sum所在的地方,这部分在main运行前执行,LoadLibraryA没用,可以忽略,IsDebuggerPresent检测调试器,根据是否被调试设置key,patch掉反调试,记录patch前的sum值

写xxtea解密

```python
#!/usr/bin/env python

flag =

k2 = 0xE8017300
k3 = 0xFF58F981
key =

for i in range(0, 7, 2):
    v6 = flag
    v7 = flag
    a2 = k2
    for _ in range(32)
      a2 = a2 + 0x100000000 - k3
      a2 &= 0xFFFFFFFF
    for _ in range(32):
      a2 += k3
      a2 &= 0xFFFFFFFF
      v6 = v6 + 0x100000000 - (((v7 + ((v7 << 5) ^ (v7 >> 6))) ^ (key[(a2>>11)&3]+a2) ^ 0x33) & 0xFFFFFFFF)
      v6 &= 0xFFFFFFFF
      v7 = v7 + 0x100000000 - (((v6 + ((v6 << 4) ^ (v6 >> 5))) ^ (key+a2) ^ 0x44) & 0xFFFFFFFF)
      v7 &= 0xFFFFFFFF
    flag = v6
    flag = v7
    print(hex(v7), hex(v6))

for f in flag:
    print(f.to_bytes(4, "little").decode(), end='')
# fakeflag{Is_there_anywhere_else}
```

跑出来发现是假flag`fakeflag{Is_there_anywhere_else}`,main里面是假校验,

分析发现注册了一个退出时调用的函数`sub_4016BC`,NOP去混淆反编译



这里才是真check,对xxtea加密后的flag移位异或,再跟真ans校验

移位的时候根据最高为决定移位后是否异或`0x84A6972F`,逆向看的时候注意最低位,异或`0x84A6972F`后最低位为1,否则为0,所以解密根据最低位判断是否异或`0x84A6972F`

```python
flag =

for i in range(8):
    for _ in range(32):
      v0 = flag
      if ((v0 & 1) == 1):
            v0 ^= 0x84A6972F
            v0 = v0 >> 1
            v0 |= 0x80000000
      else:
            v0 = v0 >> 1
      flag = v0
```

继续xxtea解密得到真flag`d3ctf{ea3yjunk_c0d3_4nd_ea5y_re}`

## RandomVm

srand设置随机数种子`0xD33B470`,假随机,可以直接把rand跑出来



大量函数都是上面的结构,先进行一段操作,再设置跳转表,rand一个随机数选择下一个执行的函数

每个函数对应一条虚拟机指令,控制流由跳转表和rand控制,需要分析每个函数的功能与跳转关系,100+函数手动分析是不可能的,用IDA Python解析一下

从入口开始解析,通过解析汇编指令获取跳转表,同时记录每个函数反编译的虚拟机指令

```python
import idc
import idaapi

start = 0x717F

funcs = {}
# 递归找函数关系
def recur(addr):
    print(hex(addr))
    if (addr == 0x241A):
      return
    ea = addr
    value_dic = {}
    while (True):
      ins = idc.generate_disasm_line(ea, 0)
      if (ins.startswith("mov")):
            op0 = idc.print_operand(ea, 0)
            op1 = idc.print_operand(ea, 1)
            # 过滤eax rax
            if (op0 in "er"):
                op0 = op0
            if (op1 in "er"):
                op1 = op1
            value_dic = op1
            value_dic = op1
            if (op0.startswith("[rbp+var_")):
                if (op1[-1] != 'h'):
                  value_dic = value_dic
      # print(hex(ea), ins)
      if (ins == "call    _rand" and len(value_dic) >= 10):
            break
      ins_len = idc.create_insn(ea)
      ea += ins_len
    # xor
    print(value_dic)
    xor_ins = idc.print_operand(ea+0x36, 1)[:-1]
    xor = int(xor_ins, 16)
    nexts = []
    for i in ["60", "58", "50", "48", "40", "38", "30", "28", "20", "18"]:
      next = int(value_dic"][:-1], 16)
      next = ((next ^ xor) + addr) & 0xFFFFFFFFFFFFFFFF
      nexts.append(next)
    funcs = nexts
    for next in nexts:
      if (next not in funcs):
            recur(next)

ea = start
idc.set_name(ea, "main_main")
recur(ea)
print(funcs)

for ea in funcs:
    src = str(idaapi.decompile(ea)).split('\n')
    print(f"{hex(ea)}: \"{src}\",")
```

分析后得到所有函数的关系,以及每个函数对应的虚拟机指令,手动优化一下

```python
ops = {
0x717f: (, "array = 0;"),
0x6bc8: (, "*((_BYTE *)&flag + (unsigned __int8)r1) = ((int)*((unsigned __int8 *)&flag + (unsigned __int8)r1) >> array) | (*((_BYTE *)&flag + (unsigned __int8)r1) << (8 - array));"),
0x55a9: (, "array = 0;"),
0x5c94: (, "--r0;"),
0x1cd0: (, "array = syscall((char)array, (unsigned int)(char)array, &array, (unsigned int)(char)array);"),
0x3f0e: (, "++r0;"),
0x2917: (, "*((_BYTE *)&flag + (unsigned __int8)r1) ^= array;"),
0x340a: (, "array = syscall((char)array, (unsigned int)(char)array, &array, (unsigned int)(char)array);"),
0x25b1: (, "*((_BYTE *)&flag + (unsigned __int8)r1) = array;"),
0x24db: (, "array = 0;"),
0x5754: (, "--array;"),
0x3876: (, "++array;"),
0x2cd4: (, "++array;"),
0x63d2: (, "++array;"),
0x1b12: (, "++array;"),
0x6154: (, "++array;"),
0x6ed7: (, "++array;"),
0x209a: (, "++array;"),
0x5002: (, "++array;"),
0x5f5c: (, "++array;"),
0x7462: (, "++array;"),
0x4570: (, "++array;"),
0x65c5: (, "++array;"),
0x2337: (, "++array;"),
0x4f23: (, "++array;"),
0x16f8: (, "--r0;"),
0x6fb6: (, "++array;"),
0x40cb: (, "++array;"),
0x3725: (, "*((_BYTE *)&flag + (unsigned __int8)r1) = ((int)*((unsigned __int8 *)&flag + (unsigned __int8)r1) >> array) | (*((_BYTE *)&flag + (unsigned __int8)r1) << (8 - array));"),
0x5e5b: (, "++array;"),
0x196d: (, "++array;"),
0x604e: (, "++array;"),
0x2182: (, "++array;"),
0x52ed: (, "++array;"),
0x3b11: (, "++array;"),
0x6d19: (, "++array;"),
0x6df8: (, "++array;"),
0x464f: (, "++array;"),
0x5927: (, "*((_BYTE *)&flag + (unsigned __int8)r1) = ((int)*((unsigned __int8 *)&flag + (unsigned __int8)r1) >> array) | (*((_BYTE *)&flag + (unsigned __int8)r1) << (8 - array));"),
0x2b07: (, "array = 0;"),
0x3d82: (, "++r0;"),
0x3959: (, "++r0;"),
0x53cc: (, "array = 0;"),
0x472e: (, "++array;"),
0x4e18: (, "++array;"),
0x679b: (, "++array;"),
0x1bf1: (, "++array;"),
0x3137: (, "++array;"),
0x1610: (, "++array;"),
0x2e92: (, "++array;"),
0x188f: (, "++array;"),
0x62f3: (, "++array;"),
0x66a4: (, "++array;"),
0x2db3: (, "++array;"),
0x43c2: (, "++array;"),
0x4a13: (, "++array;"),
0x3058: (, "++array;"),
0x5aa9: (, "++array;"),
0x3216: (, "++array;"),
0x7375: (, "++r0;"),
0x26a4: (, "array = 0;"),
0x2f84: (, "++r0;"),
0x136e: (, "*((_BYTE *)&flag + (unsigned __int8)r1) ^= array;"),
0x2a19: (, "*((_BYTE *)&flag + (unsigned __int8)r1) = array;"),
0x3bf0: (, "array = 0;"),
0x481b: (, "++r0;"),
0x48fe: (, "*((_BYTE *)&flag + (unsigned __int8)r1) ^= array;"),
0x1fb5: (, "array = *((_BYTE *)&flag + (unsigned __int8)r1);"),
0x2425: (, "++r1;"),
0x3308: (, "*((_BYTE *)&flag + (unsigned __int8)r1) ^= array;"),
0x724c: (, "*((_BYTE *)&flag + (unsigned __int8)r1) ^= array;"),
0x64d3: (, "++r0;"),
0x5d6d: (, "array = *((_BYTE *)&flag + (unsigned __int8)r1);"),
0x3e48: (, "++r1;"),
0x5676: (, "++r0;"),
0x1ee8: (, "array = 0;"),
0x6a77: (, "*((_BYTE *)&flag + (unsigned __int8)r1) = ((int)*((unsigned __int8 *)&flag + (unsigned __int8)r1) >> array) | (*((_BYTE *)&flag + (unsigned __int8)r1) << (8 - array));"),
0x51ff: (, "if ( (char)array < 0 ) rand();"),
0x284a: (, "array = 0;"),
0x69b1: (, "--r1;"),
0x78f1: (, "array = 0;"),
0x7638: (, "--array;"),
0x44aa: (, "--r1;"),
0x2261: (, "if ( (char)array < 0 ) rand();"),
0x7095: (, "array = 0;"),
0x7717: (, "--array;"),
0x17be: (, "array = 0;"),
0x3565: (, "if ( (char)array < 0 ) rand();"),
0x363b: (, "array = 0;"),
0x2771: (, "++r1;"),
0x12a8: (, "++r1;"),
0x41aa: (, "array = syscall((char)array, (unsigned int)(char)array, &array, (unsigned int)(char)array);"),
0x1a4c: (, "--r0;"),
0x1e22: (, "--r0;"),
0x42fc: (, "++r0;"),
0x6233: (, "--r0;"),
0x3cbc: (, "--r0;"),
0x1470: (, "--r0;"),
0x153a: (, "array = 0;"),
0x3a4b: (, "++r0;"),
0x4c8c: (, "++r0;"),
0x2bdd: (, "--array;"),
0x7541: (, "++r0;"),
0x4d52: (, "++r1;"),
0x7809: (, "--r0;"),
0x5baf: (, "array = *((_BYTE *)&flag + (unsigned __int8)r1);"),
0x5833: (, "array = 0;"),
0x11c9: (, "++array;"),
0x5103: (, "++array;"),
0x54ca: (, "++array;"),
0x68a6: (, "++array;"),
0x4b0f: (, "*((_BYTE *)&flag + (unsigned __int8)r1) = ((int)*((unsigned __int8 *)&flag + (unsigned __int8)r1) >> array) | (*((_BYTE *)&flag + (unsigned __int8)r1) << (8 - array));"),
0x3fd4: (, "++array;")
}
```

虚拟机指令有下面几种

```python
"""
array = 0
array += 1
array -= 1
r0 += 1
r0 -= 1
r1 += 1
r1 -= 1
flag = (flag >> array) | (flag << (8 - array))
array = syscall(array, array, &array, array)
flag ^= array
flag = array
array = flag
if (array < 0) rand();
"""
```

除了基本的数据处理外,使用syscall实现系统调用,还有if分支根据`array`决定是否跳过一个随机数,即控制执行流

```python
pc = 0x717F
i = 0
skips =
while (pc != 0x241A):
    print(i, hex(pc), ops)
    if (i in skips):
      i += 1
    r = rands
    i += 1
    pc = ops
```

根据跑出来的随机数解析一下控制流,类似于下面这种需要手动设置一下skip跳过一个随机数

```python
"""
16 0x284a   array = 0;
17 0x7717   --array;
18 0x3565   if ( (char)array < 0 ) rand();
"""
```

虚拟指令里面用`syscall(0)`输入1个字符,进行一些移位异或操作

```python
"""
array = 0
array = 0
array = 1
10    array = getchar()
flag ^= array
flag = array
array = 3
flag = (flag >> 3 | (flag << 5)
flag ^= 3
"""
```

还有`syscall(101, 0, 0, 0)`,即`ptrace`反调试检测,需要注意在无调试的情况下,第一次调用ptrace返回值为0,if不跳过rand,但是后续继续调用ptrace会返回-1,if需要跳过rand

```python
"""
array = 101
array = 0
array = 0
array = 0
array = 0
array = syscall(101, 0, 0, 0) # ptrace反调试, 0
"""
```

输入完12个字符后,最后还有一段异或操作,人肉解析一下,纯体力活

```python
"""
array = 0
array = 0
array = 1
10    array = getchar()
flag ^= array
flag = array
array = 3
flag = (flag >> 3 | (flag << 5)
flag ^= 3

array = 0
array = 0
array = 1
40      array = getchar()
flag ^= array
flag = array

array = 101
array = 0
array = 0
array = 0
array = 0
array = syscall(101, 0, 0, 0) # ptrace反调试, 0

array = 5
flag = (flag >> 5 | (flag << 3)

array = 0
array = 0
array = 1
191   array = getchar()    # array = 1
flag ^= array
flag = array

array = 101
array = 0
array = 0
array = 0
array = 0
array = syscall(101, 0, 0, 0) # ptrace反调试, -1

array = 6
flag = (flag >> 6 | (flag << 2)

array = 0
array = 0
array = 1
332   array = getchar()    # array = 1
flag ^= array
falg = array

array = 7
flag = (flag >> 7 | (flag << 1)
flag ^= 7

array = 0
arry = 0
array = 1
362   array = getchar()   # array = 1
flag ^= array
flag = array

array = 4
flag = (flag >> 4 | (flag << 4)
flag ^= 4

array = 0
array = 0
array = 1
389   array = getchar()   # array = 1
flag ^= array
flag = array

array = 4
flag = (flag >> 4 | (flag << 4)

array = 0
array = 0
array = 1
415   array = getchar()   # array = 1
flag ^= array
flag = array

array = 7
flag = (flag >> 7 | (flag << 1)
flag ^= 7

array = 0
array = 0
array = 1
441   array = getchar()   # array = 1
flag ^= array
flag = array

array = 7
flag = (flag >> 7 | (flag << 1)

array = 0
array = 0
array = 1
470    array = getchar()   # array = 1
flag ^= array
flag = array

flag = (flag >> 2 | (flag << 6)

615   c = getchar()
flag ^= c
flag = c

flag = (flag >> 4) | (flag << 4)

645   c = getchar()
flag ^= c
flag = c

flag = (flag >> 4) | (flag << 4)

667   c = getchar()
flag ^= c
flag = c

flag = (flag >> 7) | (flag << 1)
flag ^= 7


flag ^= flag
.
.
.
flag ^= flag
"""
```

逆一下加密算法

```python
flag =
for i in range(12, 1, -1):
    flag ^= flag

flag ^= 7
flag = (flag << 7) | (flag >> 1)
flag &= 0xFF

flag ^= flag
flag = (flag << 4) | (flag >> 4)
flag &= 0xFF

flag ^= flag
flag = (flag << 4) | (flag >> 4)
flag &= 0xFF

flag ^= flag
flag = (flag << 2) | (flag >> 6)
flag &= 0xFF

flag ^= flag
flag = (flag << 7) | (flag >> 1)
flag &= 0xFF

flag ^= flag
flag ^= 7
flag = (flag << 7) | (flag >> 1)
flag &= 0xFF

flag ^= flag
flag = (flag << 4) | (flag >> 4)
flag &= 0xFF

flag ^= flag
flag ^= 4
flag = (flag << 4) | (flag >> 4)
flag &= 0xFF

flag ^= flag
flag ^= 7
flag = (flag << 7) | (flag >> 1)
flag &= 0xFF

flag ^= flag
flag = (flag << 6) | (flag >> 2)
flag &= 0xFF

flag ^= flag
flag = (flag << 5) | (flag >> 3)
flag &= 0xFF

flag ^= flag
flag ^= 3
flag = (flag << 3) | (flag >> 5)
flag &= 0xFF

# flag ^= flag
print(bytes(flag))
```

解密拿到flag`d3ctf{m3owJumpVmvM}`

## forest

main里面检查flag格式,把输入的17个字符转换称01字符串,末尾加0

重点在`sub_CE1F50`里面,把一段内存设置为可执行,然后触发`int 3`异常,使用`sub_CE1A00`函数(execption_handle)处理异常



```c
unsigned int __thiscall execption_handle(unsigned int **this)
{
unsigned int result; // eax
unsigned int *v3; // ecx
unsigned int *v4; // eax
_DWORD *v5; // eax
int v6; // ecx
unsigned int v7; // edx
void **v8; // ecx
int v9; // esi
int i; // ecx
int v11; // edx
int v12; // eax
int v13; // esi
int v14; // edx
void **v15; // eax
int v16; //
int v17; //
_DWORD *v18; //

GetCurrentThreadId();
result = **this;
if ( result <= 0xC0000005 )
{
    if ( result != 0xC0000005 )
    {
      if ( result != 0x80000003 )
      {
      if ( result != 0x80000004 )
          return result;
      v3 = this;
      if ( ((v3 - (_DWORD)&code) & 0x3F) == 7 && v3 == 1 )
          v3 += 0x17;
      v4 = this;
      goto LABEL_33;
      }
      if ( byte_CE6028 )
      {
      byte_CE6028 = 0;
      R2 = (int)malloc(4u);
      R1 = (int)malloc(4u);
      v5 = malloc(4u);
      v6 = R1;
      v7 = kk;
      v18 = v5;
      R0 = (int)v5;
      *(_DWORD *)R1 = 0;
      *v5 = 0;
      v17 = v6;
      if ( (unsigned int)len > v7 )
      {
          v8 = &flag;
          if ( HIDWORD(len) >= 0x10 )
            v8 = (void **)flag;
          v16 = R2;
          v9 = 0;
          *(_DWORD *)R2 = *((_BYTE *)v8 + v7) != 0x30;
          kk = v7 + 1;
          for ( i = 0; i < 0x483D; ++i )
          {
            if ( *((_BYTE *)&code + i) == 0xFF
            && *((_BYTE *)&code + i + 1) == 0xFF
            && *((_BYTE *)&code + i + 2) == 0xFF
            && *((_BYTE *)&code + i + 3) == 0xFF )
            {
            v11 = v9 % 5;
            if ( v9 % 5 == 1 || v11 == 3 )
            {
                v12 = v17;                      // R1
            }
            else if ( v11 == 2 || v11 == 4 )
            {
                v12 = (int)v18;               // R0
            }
            else
            {
                v12 = v16;                      // R2
            }
            *(_DWORD *)((char *)&code + i) = v12;
            ++v9;
            i += 3;
            }
          }
          this = (unsigned int)&code;
          this |= 0x100u;
          return -1;
      }
LABEL_39:
      sub_CE28B0();
      }
      return(0);
    }
    right();
}
if ( result != 0xC0000096 )
    return result;
v13 = kk;
v14 = *(_DWORD *)R1 + 17 * *(_DWORD *)R0;
if ( kk >= (unsigned int)len )
{
    return(1);
    goto LABEL_39;
}
v15 = &flag;
if ( HIDWORD(len) >= 0x10 )
    v15 = (void **)flag;
*(_DWORD *)R2 = *((_BYTE *)v15 + kk) != 0x30;
kk = v13 + 1;
this = (unsigned int)&code + 0x40 * v14;
v4 = this;
LABEL_33:
v4 |= 0x100u;
return -1;
}
```

在execption_handle中根据异常码进行处理

```c
// ksarm.h
#define STATUS_ACCESS_VIOLATION 0xc0000005
#define STAUSBREAKPOINT 0x80000003
#define STATUS_SINGLE_STEP 0x80000004
#define STATUS_PRIVILEGED_INSTRUCTION 0xc0000096
```

第一次`int 3`触发断点异常`0x80000003`,对应下面的异常处理代码

```c
if (byte_CE6028)
{
    byte_CE6028 = 0;
    R2 = (int)malloc(4u);
    R1 = (int)malloc(4u);
    v5 = malloc(4u);
    v6 = R1;
    v7 = kk;
    v18 = v5;
    R0 = (int)v5;
    *(_DWORD *)R1 = 0;
    *v5 = 0;
    v17 = v6;
    if ((unsigned int)len > v7)
    {
      v8 = &flag;
      if (HIDWORD(len) >= 0x10)
            v8 = (void **)flag;
      v16 = R2;
      v9 = 0;
      *(_DWORD *)R2 = *((_BYTE *)v8 + v7) != 0x30;
      kk = v7 + 1;
      for (i = 0; i < 0x483D; ++i)
      {
            if (*((_BYTE *)&code + i) == 0xFF && *((_BYTE *)&code + i + 1) == 0xFF && *((_BYTE *)&code + i + 2) == 0xFF && *((_BYTE *)&code + i + 3) == 0xFF)
            {
                v11 = v9 % 5;
                if (v9 % 5 == 1 || v11 == 3)
                {
                  v12 = v17; // R1
                }
                else if (v11 == 2 || v11 == 4)
                {
                  v12 = (int)v18; // R0
                }
                else
                {
                  v12 = v16; // R2
                }
                *(_DWORD *)((char *)&code + i) = v12;
                ++v9;
                i += 3;
            }
      }
      this = (unsigned int)&code;
      this |= 0x100u;
      return -1;
    }
LABEL_39:
    sub_CE28B0();
}
```

这段代码只能执行一次,后续再触发`0x80000003`异常程序会结束运行,代码里面malloc了3个变量,并使用这3个变量替换code(前面修改了可执行权限的内存)中的`0xFFFFFFFF`

R2的初值由`*(_DWORD *)R2 = *((_BYTE *)v8 + v7) != 0x30;`决定,这里是flag的第一个字符

将code初始化之后,`this = (unsigned int)&code;`修改线程结构体的EIP,使异常处理结束后程序进入到code中执行

分析一下code部分代码,code代码中包含很多的代码块,每一块的长度为0x40,根据前面修改的规律可以知道在code块中R0、R1、R2的位置固定



代码块中还有cli指令,由于cli指令是特权指令,ring3无法执行,因此运行到cli指令会触发`0xc0000096`异常,分析对应的处理代码

```c
v13 = kk;
v14 = *(_DWORD *)R1 + 17 * *(_DWORD *)R0;
if (kk >= (unsigned int)len)
{
    return (1);
    goto LABEL_39;
}
v15 = &flag;
if (HIDWORD(len) >= 0x10)
    v15 = (void **)flag;
*(_DWORD *)R2 = *((_BYTE *)v15 + kk) != 0x30;
kk = v13 + 1;
this = (unsigned int)&code + 0x40 * v14;
v4 = this;
v4 |= 0x100u;
```

cli指令触发异常后,根据`R1+17*R0`的值确定下一个执行的代码块,修改EIP进入新的代码块,并且根据flag的01字符设置R2

结合code中的内容,在code代码中会设置R0、R1的值,接着使用cli触发异常,根据R0、R1的值选择下一个代码块,R2中储存了flag的一个bit

调试发现在code中还会触发`0x80000004`异常





跟踪一下发现这个异常是TF标志位造成的,TF标志位为1时,执行一条指令后就会触发`0x80000004`异常,在execption_handle中,返回时会设置`v4 |= 0x100u;`,这里设置的就是TF标志位

TF标志位触发异常后,会确定异常发生的位置,当异常发生位置为7,即`mov eax, `执行后,根据eax寄存器的确定是否进行跳转

```c
if (result != 0x80000004)
    return result;
v3 = this;
if (((v3 - (_DWORD)&code) & 0x3F) == 7 && v3 == 1)
    v3 += 0x17;
v4 = this;
v4 |= 0x100u;
```



结合跳转的位置和code中的代码,这里实际是根据R2进行调整,如果R2,即flag为1,跳转到下一个cli块中设置R1、R0,综合分析知道这里是根据flag的01值决定下一个代码块,在每一个代码块中有两个可跳转的位置

使用IDA Python解析代码块,获取每个代码块中的两个跳转位置

```python
import idc
import idaapi

image_base = idaapi.get_imagebase()
code_off = 0x6030
code_size = 0x4840


start = image_base + code_off
end = image_base + code_off + code_size

op_ls = [(-1, -1) for _ in range(0x121)]
for idx in range(0x121):
    ea = start + idx * 0x40
    print(f"[{hex(ea)}]: ")
    ins = idc.generate_disasm_line(ea, 0)
    if (ins.startswith("mov   eax, 0FFFFFFFFh")):
      op1 = idc.print_operand(ea+0x0C, 1)
      if (op1[-1] == 'h'):
            op1 = int(op1[:-1], 16)
      else:
            op1 = int(op1)
      op2 = idc.print_operand(ea+0x17, 1)
      if (op2[-1] == 'h'):
            op2 = int(op2[:-1], 16)
      else:
            op2 = int(op2)
      op3 = idc.print_operand(ea+0x23, 1)
      if (op3[-1] == 'h'):
            op3 = int(op3[:-1], 16)
      else:
            op3 = int(op3)
      op4 = idc.print_operand(ea+0x2E, 1)
      if (op4[-1] == 'h'):
            op4 = int(op4[:-1], 16)
      else:
            op4 = int(op4)
      ins = (op1+17*op2, op3+17*op4)
    elif (ins.startswith("int   3")):
      ins = (-1, -1)
    print(ins)
    op_ls = ins

print(op_ls)
```

在解析时发现除了上面正常的代码块,还有下面几种代码块

```python
"""
int   3
add   , ebx
mov   eax, 1; mov   dword ptr , 39393939h
add   , ecx
"""
```

其中`int 3`触发`0x80000003`异常,由于该异常只能处理一次,所有遇到`int 3`的代码块会直接die掉

剩余3条指令会触发`0xC0000005`异常,该异常会进入right,输出正确信息

分析后可以知道本题其实是一道迷宫题,根据输入的flag决定走的路径,走到出口胜利

先找一下实际可到达的出口

```python
op_ls = [(11, 41), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (193, 52), (7, 7), (216, 43), (116, 13), (120, 189), (82, 244), (12, 12), (8, 15), (-1, -1), (-1, -1), (72, 95), (233, 272), (211, 194), (-1, -1), (59, 230), (237, 89), (60, 190), (23, 23), (243, 232), 'add   , ebx', (207, 224), 'mov   eax, 1', (31, 61), (151, 179), (12, 180), (-1, -1), (76, 147), (-1, -1), (153, 196), (279, 271), (-1, -1), (276, 7), (38, 38), (39, 39), (48, 171), (-1, -1), (236, 251), (16, 192), (-1, -1), (125, 165), (46, 46), (260, 27), (45, 3), (174, 190), (219, 92), (51, 51), (-1, -1), 'add   , ecx', (54, 54), (280, 204), (20, 135), (57, 57), (58, 58), (59, 59), (60, 60), (223, 235), (113, 265), (55, 278), (87, 6), (19, 214), (100, 36), (-1, -1), (68, 68), (69, 69), (70, 70), (130, 24), (258, 44), (73, 73), (74, 74), (75, 75), (76, 76), (77, 77), (122, 240), (79, 79), (80, 80), (-1, -1), (67, 26), (83, 83), (117, 118), (85, 85), (-1, -1), (-1, -1), (106, 73), (89, 89), (-1, -1), (-1, -1), (119, 129), (93, 93), (85, 167), (-1, -1), (96, 96), (97, 97), (123, 225), (259, 173), (229, 226), (101, 101), (269, 68), (169, 182), (104, 104), (105, 105), (154, 50), (-1, -1), (108, 108), (23, 112), (140, 99), (111, 111), (210, 202), (113, 113), (274, 56), (-1, -1), (-1, -1), (261, 42), (118, 118), (32, 115), (267, 209), (121, 121), (122, 122), (123, 123), (231, 256), (125, 125), (126, 126), (57, 206), (145, 245), (129, 129), (130, 130), (131, 131), (-1, -1), (133, 133), (155, 162), (135, 135), (136, 136), (-1, -1), (-1, -1), (-1, -1), (140, 140), (78, 197), (134, 163), (200, 103), (71, 218), (185, 283), (-1, -1), (139, 34), (188, 104), (-1, -1), (150, 150), (151, 151), (102, 253), (246, 157), (154, 154), (155, 155), 'add   , ebp', (93, 255), (158, 158), (38, 144), (281, 286), (28, 146), (186, 285), (163, 163), (138, 174), (69, 37), (166, 166), (241, 111), (168, 168), (169, 169), (-1, -1), (171, 171), (58, 148), (173, 173), (205, 64), (175, 175), (176, 176), (177, 177), 'add   ds:0F215EE7Ch, ecx', (181, 75), (128, 264), (257, 270), (160, 176), (221, 175), (101, 141), (220, 47), (88, 91), (195, 114), (158, 247), (189, 189), (80, 142), (287, 133), (-1, -1), (14, 161), (242, 166), (195, 195), (196, 196), (197, 197), 'add   , edi', (131, 65), (200, 200), (190, 130), (199, 96), (183, 105), (204, 204), (-1, -1), (35, 74), (-1, -1), (168, 109), (209, 209), (210, 210), (-1, -1), (-1, -1), (213, 213), (239, 108), (215, 215), (-1, -1), (217, 217), (218, 218), (219, 219), (220, 220), (136, 10), (222, 222), (107, 266), (66, 273), (1, 21), (-1, -1), (227, 227), (228, 228), (263, 170), (5, 191), (62, 46), (232, 232), (-1, -1), (103, 36), (-1, -1), (236, 236), (184, 2), (-1, -1), (98, 137), (126, 277), (217, 250), (172, 228), (102, 70), (-1, -1), (245, 245), (246, 246), (17, 86), (248, 248), (104, 38), (83, 268), (39, 187), (270, 128), (253, 253), (22, 149), (4, 94), (256, 256), (257, 257), (222, 84), (215, 288), (260, 260), (-1, -1), (254, 248), (164, 132), (264, 264), (54, 262), (33, 9), (253, 18), (213, 203), (30, 97), (40, 227), (271, 271), (79, 127), (-1, -1), (274, 274), (131, 241), (212, 63), (77, 143), (-1, -1), (121, 110), (124, 150), (281, 281), (282, 282), (-1, -1), 'add   edi, esp', (285, 285), (51, 29), (282, 208), (159, 177)]


for i in range(0x121):
    if (type(op_ls) != str):
      continue
    for j in range(0x121):
      if (type(op_ls) == str):
            continue
      if (i in op_ls):
            print(f"[{i}]: {op_ls}")
            break
```

真出口在` mov eax, 1; mov dword ptr , 39393939h`

dfs走迷宫找出口记录路径

```python
def dfs(cur, path=[]):
    # print(cur, path)
    if (cur == 27):
      print(path)
      return
    elif (type(op_ls) == str):
      return
    l = op_ls
    if (l != -1 and l not in path):
      new_path = path.copy()
      new_path.append(cur)
      dfs(l, new_path)
    r = op_ls
    if (r != -1 and r not in path):
      new_path = path.copy()
      new_path.append(cur)
      dfs(r, new_path)

dfs(0, [])
```

只有一条路,长度正好是`17 * 8`,把路径转换为flag

```python
path =

last = 0
flag = ""
for cur in path:
    if (cur == op_ls):
      flag += "0"
    else:
      flag += "1"
    last = cur
print(int(flag, 2).to_bytes(17))
# d3ctf{0ut_of_th3ForesT#}
```

最后得到题目flag`d3ctf{0ut_of_th3ForesT#}`

Lty20000423 发表于 2024-4-29 11:45

赞一个,向大佬学习

T2ao 发表于 2024-4-29 12:52

太强了,学到了学到了

H1725 发表于 2024-4-29 14:17

求大神一个滴滴

pwndasys 发表于 2024-4-29 15:26

大佬方便提供一些题目附件吗

whit 发表于 2024-4-29 15:29

谢谢分享

hahawa456 发表于 2024-4-29 15:32

不明觉厉

shenghuo2 发表于 2024-4-29 15:35

wp还没截止吧{:1_904:}

zipkey 发表于 2024-4-29 15:51

pwndasys 发表于 2024-4-29 15:26
大佬方便提供一些题目附件吗

比赛平台目前还可以下载附件{:1_893:}

pwndasys 发表于 2024-4-29 16:24

zipkey 发表于 2024-4-29 15:51
比赛平台目前还可以下载附件

大佬我没有注册账号,所以恳请大佬发下附件
页: [1] 2 3
查看完整版本: D^3CTF2024逆向Writeup