IDA Tracing

Last updated on January 16, 2024 pm

利用IDA的Tracing功能跟踪函数调用流程

题源AIS3,一道OLLVM控制流平坦化的题目

主逻辑很简单

带一个43的参数运行,然后进入state_machine进行运算,最后与k_target数组逐字符比较,进入state_machine函数。

截屏2024-01-16 21.36.09

很明显的控制流平坦化,调用了大量的state_xxx函数,每个state_xxx函数操作也很简单,就是普通加减法。

截屏2024-01-16 21.38.08

现在就需要确定这些state_xxx函数的调用流程,这里就可以采取IDA自带的tracing功能,需要在调试的时候才能使用

截屏2024-01-16 21.41.03

如下就得到了所有的调用函数流程,为了更直观清晰,可以应用一点过滤器什么的,以便只得到call而不用ret

截屏2024-01-16 21.42.58

过滤后,导出文件

截屏2024-01-16 21.44.24

同时可以使用ctrl+F5得到整个程序的伪代码

截屏2024-01-16 21.45.32

然后就可以使用python进行处理,这里选择先手动将伪代码多余部分删除,只留下state_xxx函数

截屏2024-01-16 21.46.31

现在就可以更方便使用python进行处理,完整脚本如下

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
call_file = open('trace.txt', 'r')

lines = call_file.readlines()

func_arr = []
for i in lines:
info = i.split('\t')
info_call_func = info[2]
func = info_call_func.split(' ')[1]
func_arr.append(func)

# print(func_arr)

code_file = open('stateful.c', 'r')
lines = code_file.readlines()

opcode = []
for i in func_arr:
index = lines.index("_BYTE *__fastcall " + i + "(_BYTE *a1)\n")
opcode.append(lines[index + 5].strip().replace("*a1", "a1[0]").replace(";",""))

# 以下是逆操作
opcode = opcode[::-1]
for i in opcode:
index = i.index("=")
if i[index - 1] == '+':
print(i[:index - 1] + "-" + i[index:])
continue
if i[index - 1] == '-':
print(i[:index - 1] + "+" + i[index:])
continue

解密脚本如下

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
a1 = [15, 119, 236, 51, 68, 22, 19, 89, 29, 66, 132, 117, 95, 228, 131, 192, 59, 193, 149, 207, 219, 51, 108, 210, 237,
114, 95, 13, 116, 65, 91, 115, 160, 51, 83, 36, 2, 89, 116, 96, 51, 204, 125]

a1[5] -= a1[37] + a1[20]
a1[8] -= a1[14] + a1[16]
a1[17] -= a1[38] + a1[24]
a1[15] -= a1[40] + a1[8]
a1[37] -= a1[12] + a1[16]
a1[4] -= a1[6] + a1[22]
a1[10] += a1[12] + a1[22]
a1[18] -= a1[26] + a1[31]
a1[23] -= a1[30] + a1[39]
a1[4] -= a1[27] + a1[25]
a1[37] -= a1[27] + a1[18]
a1[41] += a1[3] + a1[34]
a1[13] -= a1[26] + a1[8]
a1[2] -= a1[34] + a1[25]
a1[0] -= a1[28] + a1[31]
a1[4] -= a1[7] + a1[25]
a1[18] -= a1[29] + a1[15]
a1[21] += a1[13] + a1[42]
a1[21] -= a1[34] + a1[15]
a1[7] -= a1[10] + a1[0]
a1[13] -= a1[25] + a1[28]
a1[32] -= a1[5] + a1[25]
a1[31] -= a1[1] + a1[16]
a1[1] -= a1[16] + a1[40]
a1[30] += a1[13] + a1[2]
a1[1] -= a1[15] + a1[6]
a1[7] -= a1[21] + a1[0]
a1[24] -= a1[20] + a1[5]
a1[36] -= a1[11] + a1[15]
a1[0] -= a1[33] + a1[16]
a1[19] -= a1[10] + a1[16]
a1[1] += a1[29] + a1[13]
a1[30] += a1[33] + a1[8]
a1[15] -= a1[22] + a1[10]
a1[20] -= a1[19] + a1[24]
a1[27] -= a1[18] + a1[20]
a1[39] += a1[25] + a1[38]
a1[23] -= a1[7] + a1[34]
a1[37] += a1[29] + a1[3]
a1[5] -= a1[40] + a1[4]
a1[17] -= a1[0] + a1[7]
a1[9] -= a1[11] + a1[3]
a1[31] -= a1[34] + a1[16]
a1[16] -= a1[25] + a1[11]
a1[14] += a1[32] + a1[6]
a1[6] -= a1[10] + a1[41]
a1[2] -= a1[11] + a1[8]
a1[0] += a1[18] + a1[31]
a1[9] += a1[2] + a1[22]
a1[14] -= a1[35] + a1[8]

for i in a1:
print(chr(i & 0xff), end='')
#AIS3{4re_YOu_@_sTATEfUl_0r_StAT3L3S$_ctF3R}

最后要记得&0xff,因为源程序是字节型。

总结

  1. 可以利用IDA的tracing功能得到函数调用流程并download下来
  2. 可以利用ctrl+F5得到完整伪代码
  3. 结合1,2并利用python,提取里面的规律得到完整加密流程
  4. 搓!

IDA Tracing
http://example.com/2024/01/16/ida_tracing/
Author
yring
Posted on
January 16, 2024
Licensed under