ADWORLD xxxorrr
本身题目简单
但这题值得收藏的点在于:
1.程序的逻辑
2.隐藏的函数调用(应该在哪看)
程序的逻辑
以下按照做题的逻辑顺序:
main
可以看到有一个s1 异或s的for循环
在此之前有一个sub_A90
sub_A90_cxa_atexit
这里涉及到一个cxa_atexit 函数
_cxa_atexit函数,用于将参数指定的函数在main结束之后调用
__cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL);
/*glibc内部函数,等同于atexit,
用于将参数指定的函数在main结束后调用*/
...
__cxa_atexit ((void (*) (void *)) fini, NULL, NULL);
/*和前面一句一样,因为有这两部分,
所以传入的reld_fini以及fini函数会在main结束后调用*/
cxa_atexit相关知识来源:库与运行库_圈圈来了的博客-CSDN博客
这里cxa_atexit参数就是a1 也就是sub_916函数
这意味着:
sub_916函数会在main结束之后调用
这就解释了为什么看起来像中间过程的异或for循环却在main结尾;而看起来像结尾的sub_916函数却在for之前。
了解到这后 这时候你肯定觉得只需要拿到s1 和s2 再进行异或
s1 和 s2
从这里可以看出来 s1 和s2 已经给出来了
但脚本运行后结果却不正确
隐藏函数的调用
再回过头看:
按理说s1 和s2 应该都是上传到sub_916里面
这里s1你能发现还有一个sub_84A调用了
这里sub_84A 还改变了s1的值
但奇怪的点在于并没有在main 中体现
这是为什么呢?
最后我们在init初始函数里的funcs_A59里可以看见
原来是这里调用了sub_84A
至此程序的逻辑梳理完毕:
- sub_84A 修改s1
- for循环 s1 和输入的s进行异或
- 异或后的字符串与s2比较(sub_916)
逆逻辑:
-
s1和s2异或得到修改后的输入s
-
逆sub_84A 函数得到初始flag
以上提醒我们:
得到关键数据后要仔细查看调用
脚本
ls2 = 'VNWXQQ\tF\x17FTZYY\x1FH2[k|un~n/wOzqC+&'+chr(0x89)+chr(0xFE)
ls1 = 'qasxcytgsasxcvrefghnrfghnjedfgbhn'
for i in range(len(ls1)):
print(chr(ord(ls1[i])^(2 * i+ 65)^ord(ls2[i])),end="")
# flag{c0n5truct0r5_functi0n_in_41f}