BUUCTF-Dig the way

无壳,拖进 ida 看一下(下图为已经分析过的)

大概看一下整体的逻辑就是,从 data 文件中读入数据存入 Str,后续对 v7 数组调用 v11 处的三个 func 进行一系列操作后,再调用 get_key 函数计算 flag,调用此函数的条件为 v8 为 0。接下来就具体分析一下吧。

首先是三个 func,看看他们都干了啥

  • func0

很明显就是交接换两个数

  • func1

没什么好说的,就是返回 abs(a1[a2] + a1[a3]) - abs(a1[a3]) - abs(a1[a2]) + 2 的值

  • func2

返回 abs(a1[a3]) - abs(a1[a3] + a1[a2]) + abs(a1[a2]) + 2 的值,依旧对两个数进行一系列绝对值操作,容易看出此函数返回值必定大于等于 2

接下来就是获取 flag 前的操作,直接跳过非重点部分分析一下重点,即下图部分

i 从 0 开始,计数器 cntt 从 1 开始,while 循环中内容共执行三次,三次依次调用 func0,func1,func2,三个函数对 v7[v9],v7[v10] 进行操作,返回值依次填入 v7[1],v7[2],v7[3]。详细情况见上图注释。

最终对执行 get_key 函数起决定作用的是 v8 的值,v8 初始值为 3,但是并没有明显的对 v8 数值起到影响的操作,观察一下循环中对于 v7 数组的操作,第三次操作对 v7[3] 进行了赋值,但是 v7[3] 并没有出现在定义中,观察数据地址(见下图),简单处理分析后发现 v7[3] 即是 v8

但是问题来了,func2 的返回值根据之前的分析恒大于等于2,不可能取到符合条件的 0,不知道咋办了嘻嘻,搜了一下 wp 醍醐灌顶 orz

func2 的返回值虽不可以取到 0,但是 func1 的返回值是可以取 0 的,所以可以利用第一次循环中的 func0 函数将 func1 与 func2 进行一次对换,使最终赋值 v7[3] 即 v8 的为 func2 的返回值即 0。

结合先前分析的数据地址(上图),func1 即 v11[1] 可以表示为 v7[7],func2 即 v11[2] 可以表示为 v7[8],所以第一次 while 循环中,v9 应当为 7, v10 应当为 8,这样就可以实现两个函数的交换了。

这样,while 循环中执行过程如下:

1、 i = 0, cntt = 1, v9 = 7, v10 = 8, v7[1] = swap(v7[7], v7[8]) = 1
2、 i = 1, cntt = 2, v9 = 1, v10 = 2, v7[2] = abs(v7[1]) + abs(v7[2]) - abs(v7[1] + v7[2]) + 2 = 1 + 2 - (1 + 2) + 2 = 2
3、 i = 2, cntt = 3, v9 = 2, v10 = 3, v7[3] = abs(v7[2] + v7[3]) - abs(v7[2]) - abs(v7[3]) + 2 = abs(2 + v7[3]) - 2 - abs(v7[3]) + 2= 0,所以 v7[3] 即 v8 初始取 -1 就可以使终值 = 0

因此,构造的 data 文件中,需要赋初值的有 v8 = -1,v9 = 7,v10 = 8

具体该如何构造呢,看到输入部分

读取 data 文件中内容后存入了 Str,结合之前分析的数据地址

Str 占 20 个字节,后续每个数据占 4 字节

db 定义字节类型变量,一个字节数据占 1 个字节单元
dw 定义字类型变量,一个字数据占 2 个字节单元
dd 定义双字类型变量,一个双字数据占 4 个字节单元

计算得到 v8 起始位置为 32 字节处,占 4 个字节,-1 可以表示为 FF FF FF FF,v9、v10以此类推,winhex 创造以下文件并赋值

移到文件夹中运行程序,得到 flag{8cda1bdb68a72a392a3968a71bdb8cda}

posted @ 2024-01-27 12:41  Moominn  阅读(66)  评论(0编辑  收藏  举报