其他分享
首页 > 其他分享> > reverse-for-the-holy-grail-350

reverse-for-the-holy-grail-350

作者:互联网

reverse-for-the-holy-....

名字太长不打了

收集信息

给的文件是64位elf文件,无壳

静态分析

打开后代码密密麻麻一堆,看起来是c++写的

image-20220427111010637

大致分析逻辑,name和quest都没啥用,password存入userin中,看起来是个全局变量

image-20220427111255092

要求这两个函数的返回值 >= 0,其他的咱就不管了。

在linux下gdb动态调试之后可以确定:v7两个值分别是input的字串及其长度

image-20220427160105779

可见对任一项k,需要满足k & 223 <= 0x56 || k = 63[1],也就是说不能是0x57 - 0x59

这个很容易满足。

来到stringmod函数,这个程序的主要加密函数

image-20220427160512179

它首先是检测了0, 3, 6, 9, 12, 15这六位的值,等于说告诉了我们这六位

firstchar的长度就6位,接着往下看

image-20220427160639880

异或,注意到每次异或的值是可以直接循环算出的,与字串无关。但这里不知道到底检测多少位

image-20220427160814633

如图,从注释(我写的)可得知,这整个程序检测了前18位,估计我们要输入的字串是18位。

然后这里循环检测了另外12位。

第2、5、8...位是直接检测的,可以直接得到;第1、4、7有取模运算,采用爆破应对。注意这里是异或后进行的检测。

写脚本得答案

思路是先直接求出异或后的其中12(0、2、3、5...)位,再爆破出1、4、7...位, 然后异或得到flag

master = [471, 12, 580, 606, 147, 108]
third = [751, 708, 732, 711, 734, 764]
first = [65, 105, 110, 69, 111, 97]

password = [0 for i in range(18)]

k = 666
temp = []
for i in range(18):
    temp.append(k)
    k += k % 5

#  第一轮  循环  初始化    0、3、6、9...位
for i in range(18):
    if i % 3 == 0:
        password[i] = first[int(i / 3)]
        password[i] ^= temp[i]


#
for i in range(18):
    if i % 3 == 2:
        password[i] = third[int(i / 3)]

#
for i in range(1, 18, 3):
    for k in range(20, 127):
        if (k ^ temp[i]) * password[i - 1] % password[i + 1] == master[int(i / 3)]:
            password[i] = (k ^ temp[i])
            break


#异或
for i in range(18):
        password[i] ^= temp[i]
        password[i] = chr(password[i])

print("tuctf{" + ''.join(password) + "}")

注意在最后全部异或回来之前,password列表的值并非在char的表示范围内。

总结

  1. valid函数是第一个检测,没看懂可能纠结很久,事实上在ascii表中,可见字符为0x21 - 0x7e
    条件是 k & 223 <= 0x5A || k = '?', 事实上,这里'?'也是满足前者的,& 223 其实就是小写转大写的方法,这里只有0x5B - 0x5F 和 0x7B - 0x7F(二进制方法很容易想明白的)不满足,都是符号,一般情况可以在爆破过程中剔除掉,也可以不剔除试试看先。

我就在这里浪费了好些时间

标签:reverse,holy,18,range,异或,temp,grail,检测,password
来源: https://www.cnblogs.com/AAAAAtevor/p/16199656.html