January 16, 2022

SUCTF2019-hardcpp

0x00 日常查壳

无壳64位

image-20220116002514227

0x01 去平坦化

标准的平坦化控制流,装去平坦的可以参考我的之前写的一篇(晚点移植过来)

https://blog.csdn.net/weixin_50166464/article/details/121635877

image-20220116002641902

1
2
3
4
5
workon env1 			
#进入虚拟环境

python deflat.py -f /home/p0z/Desktop/hardCpp --addr 0x4007E0
#python delat.py -f 文件名 --addr main函数开始地址

0x02 去平坦后混淆

去平坦化后,可以发现很奇怪,可以发现这些判断是进不去的,具体随我思路看

image-20220116003942433

这个x和y都是.bss段,意思就是未初始化的全局变量,那么就是为0,于是上面那图的很多判断都进不去

可以看下这篇文章讲data和bss段的详细介绍,https://zhuanlan.zhihu.com/p/28659560

image-20220116004207366

每段都是类似这样的,jnz肯定会执行,于是我们的去混淆就是,每当碰到标识为ds:x的时候

  1. 然后把下面的jnz改成jmp (这样就是直接跳转不用判断)
  2. 再把jnz后的那条指令jmp nop掉(不nop掉也行)

image-20220116010208605

还要注意一下这边的jnz指令是 0F 85

image-20220116012007120

参考这篇文章:https://codeantenna.com/a/juuDUaGf62

(针对ida7.0之后的脚本)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
st = 0x4007E0
end = 0x401154

def patch_nop(start, end):
for i in range(start, end):
ida_bytes.patch_byte(i, 0x90)

def next_instr(addr): #get_item_size 获取指令或数据长度,这个函数的作用就是去往下一条指令
return addr + idc.get_item_size(addr)

addr = st
while (addr < end):
next = next_instr(addr)
if "ds:x" in idc.GetDisasm(addr): #idc.GetDisasm(addr)得到addr的反汇编语句
while (True):
addr = next
next = next_instr(addr)
if "jnz" in idc.GetDisasm(addr):
dest = idc.get_operand_value(addr, 0) #得到操作数,即指令后的数 例如 jz 偏移地址 于是get_oprand_value获得偏移地址
ida_bytes.patch_byte(addr, 0xE9) #改addr地址的机器码为jmp
ida_bytes.patch_byte(addr + 5, 0x90) #addr + 5的位置改成nop
offset = dest - (addr + 5) #调整为正确的偏移地址 也就是相对偏移地址 - 当前指令后的地址
ida_bytes.patch_dword(addr + 1, offset) #把偏移地址放到 jmp xxxx nop
print("patch bcf: 0x%x" % addr)
addr = next
patch_nop(next, next + 3) #把无用的jmp xxx全部nop掉
break
else:
addr = next

然后就成功去掉了!

image-20220116010851596

0x03 正式分析main函数

函数有点多 但其实大部分都比较简单(可以边动调边看作用和返回值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // al
char v4; // al
char v5; // al
char v6; // al
char v8[8]; // [rsp+A0h] [rbp-90h] BYREF
char v9[8]; // [rsp+A8h] [rbp-88h] BYREF
char v10[8]; // [rsp+B0h] [rbp-80h] BYREF
char v11[8]; // [rsp+B8h] [rbp-78h] BYREF
char t0[8]; // [rsp+C0h] [rbp-70h] BYREF
char v13[7]; // [rsp+C8h] [rbp-68h] BYREF
char t1; // [rsp+CFh] [rbp-61h]
int i; // [rsp+D0h] [rbp-60h]
int v16; // [rsp+D4h] [rbp-5Ch]
int v17; // [rsp+D8h] [rbp-58h]
int v18; // [rsp+DCh] [rbp-54h]
char s; // [rsp+E0h] [rbp-50h] BYREF
char v20[23]; // [rsp+E1h] [rbp-4Fh] BYREF
char v21[8]; // [rsp+F8h] [rbp-38h] BYREF
char v22[8]; // [rsp+100h] [rbp-30h] BYREF
char v23[8]; // [rsp+108h] [rbp-28h] BYREF
char v24[4]; // [rsp+110h] [rbp-20h] BYREF
int v25; // [rsp+114h] [rbp-1Ch]
const char **v26; // [rsp+118h] [rbp-18h]
int v27; // [rsp+120h] [rbp-10h]
int v28; // [rsp+124h] [rbp-Ch]
int v29; // [rsp+128h] [rbp-8h]
bool v30; // [rsp+12Eh] [rbp-2h]

v28 = 0;
v27 = argc;
v26 = argv;
v25 = time(0LL);
puts("func(?)=\"01abfc750a0c942167651c40d088531d\"?");
s = getchar();
fgets(v20, 21, stdin);
v18 = time(0LL);
v17 = v18 - v25;
v29 = v18 - v25;
v16 = strlen(&s);
v30 = v16 != 21;
for ( i = 1; i < 21; ++i )
{
do
{
t1 = v17 ^ *(&s + i);
v13[0] = ret_a2((__int64)v23, t1);
t0[0] = ret_a22((__int64)v21, *(&s + v17 + i - 1));
v3 = MOD(t0, 7);
t1 = ADD((__int64)v13, v3);
v11[0] = ret_a222((__int64)v24, t1);
v10[0] = ret_a222((__int64)v24, *(&s + v17 + i - 1));
v4 = XOR(v10, 18);
v9[0] = ret_a2222((__int64)v22, v4);
v5 = MUL(v9, 3);
v8[0] = ret_a2((__int64)v23, v5);
v6 = ADD((__int64)v8, 2);
t1 = XOR(v11, v6);
}
while ( enc[i - 1] != t1 );
}
puts("You win");
return 0;
}

还要关于我的ubuntu动调报错

image-20220116012230486

这篇文章解决了我的缺少库问题

https://askubuntu.com/questions/1219027/problem-with-shared-library-libc-so-1-on-kubuntu-18-04

1
sudo apt install libc++-dev

可以打个草稿跟一下就会比较容易

image-20220116011803611

image-20220116011814554

0x04 GetFlag!

关于flag[0]就是关于一开始的提示,要不然无法解出

image-20220116012432211

image-20220116012441315

EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from base64 import encode


ef = [0xF3, 0x2E, 0x18, 0x36, 0xE1, 0x4C, 0x22, 0xD1, 0xF9, 0x8C, 0x40, 0x76, 0xF4, 0x0E, 0x00, 0x05, 0xA3, 0x90, 0x0E, 0xA5]
f = [0 for i in range(21)]
f[0] = ord('#')

for i in range(1, 21):
f[i] = ((ef[i - 1] ^ ((f[i - 1] ^ 18) * 3 + 2) & 0xFF ) - (f[i - 1] % 7)) #要注意* 3 + 2容易超过一字节限制 所以加个0xFF
# print(ef[i - 1], end="^")
# print(((f[i - 1] ^ 18) * 3 + 2) & 0xFF, end = " = ")
# print((ef[i - 1] ^ (((f[i - 1] ^ 18) * 3 + 2)) & 0xFF), end = " ")
print(chr(f[i]) , end="")

GetFlag!(总算脱离了1分题)

image-20220116012527931

DASCTF X SU
🍬
HFCTF2022
🍪

About this Post

This post is written by P.Z, licensed under CC BY-NC 4.0.