(d3ctf)d3syscall赛题复现

程序逻辑分析

先打开d3syscall文件,发现.init_array的初始化函数中释放了my_module文件,查找了kallsyms中的sys_call_table地址,并将其作为参数magic初始化内核模块my_module。

dump下来my_module进行分析

在init_module中,程序先保存了0x14f-0x153处的sys_call_table内容(至于为什么没有0x154…我只能猜是出题人忘了),保存cr0,然后更改cr0寄存器的bit16为0(WP写保护位)使sys_call_table所在的内存页可写,劫持0x14f-0x154的syscall为模块内部的函数,最后还原cr0。

由此我们分析若干syscall handler,分析过程中要注意传入syscall的参数rdi, rsi, rdx等被放置在了栈上,rdi指向栈的一个位置,因此handler一开始取[rdi+xxh]值的操作就是在找参数。通过简单的分析很好猜出来对应关系,或者搜一下__fentry__/找找内核实现/内核调试应该也能出。

分析可知模块内部实现了一个简单的vm,syscall number对应操作如下:

14fh: mov

150h: 算术运算

151h: push

152h: pop

153h: 清空寄存器

154h: 检查栈上内容是否符合要求

假设vm的四个通用寄存器为r0-r3,分析sub_13f5

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
mov r0, rdi
mov r1, rsi
push r1
mov r2, r0
mov r1, 3
shl r2, r1
mov r1, 0x51e7647e
add r2, r1
mov r3, r0
mov r1, 3
mul r3, r1
mov r1, 0xe0b4140a
add r3, r1
xor r2, r3
mov r3, r0
mov r1, 0xe6978f27
add r3, r1
xor r2, r3
pop r1
add r1, r2
push r1
push r0
mov r2, r1
mov r0, 6
shl r2, r0
mov r0, 0x53a35337
add r2, r0
mov r3, r1
mov r0, 5
mul r3, r0
mov r0, 0x9840294d
add r3, r0
xor r2, r3
mov r3, r1
mov r0, 0x5eae4751
sub r3, r0
xor r2, r3
pop r0
add r0, r2
push r0
clear r0, r1, r2, r3

肉眼翻译为C代码

1
2
3
4
5
6
void sub_13f5(__int64 x, __int64 y){
__int64 tmp1 = y+(((x<<3)+0x51e7647e)^(x*3+0xe0b4140a)^(x+0xe6978f27));
push(tmp1);
__int64 tmp2 = x+(((tmp1<<6)+0x53a35337)^(tmp1*5+0x9840294d)^(tmp1-0x5eae4751));
push(tmp2);
}

所以可以通过栈上的tmp1, tmp2值和计算出x,再由tmp1和x计算出y

解题脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
from Crypto.Util.number import long_to_bytes
def calc(tmp1, tmp2):
x = tmp2-c_uint64(((tmp1<<6)+0x53a35337)^(tmp1*5+0x9840294d)^(tmp1-0x5eae4751)).value
x = c_uint64(x).value
y = tmp1-c_uint64((((x<<3)+0x51e7647e)^(x*3+0xe0b4140a)^(x+0xe6978f27))).value
y = c_uint64(y).value
return long_to_bytes(x)[::-1]+long_to_bytes(y)[::-1]

result=b''
result+=calc(0xB0800699CB89CC89,0x4764FD523FA00B19)
result+=calc(0x396A7E6DF099D700,0xB115D56BCDEAF50A)
result+=calc(0x2521513C985791F4,0xB03C06AF93AD0BE)
print(result)