CTF-reverse-xxxorrr

题目链接

https://adworld.xctf.org.cn/challenges/list


题目详情

xxxorrr


解题报告

下载得到的文件使用ida64分析,如果报错就换ida32,得到分析结果,有main函数就先看main

main函数分析

v6

main函数中,v6的值是__readfsqword(0x28u)用于反调试

a2、a3与sub_916函数一起被作为sub_A90函数的参数

输入的字符串s与已经定义好的s1相互异或

s1

是一个定义好的字符串

sub_916函数分析

v1

v1用于反调试

除此外该函数只是对字符串s1和s2进行比对,如果相同则给出成功提示(flag引导),说明要从s1和s2着手,在main函数中对s1加密(与输入串s异或)后的结果需要和s2相同

s1&s2

发现这里的s1和main函数中的s1是同一个变量,这时碰到一个问题,sub_916函数在进行s1和s2的比对时,按照顺序结构的话,应该是先执行sub_916函数(即先比对s1和s2),再让s1和输入串s异或才对啊?可是如果是这样的执行顺序,就不可能使s1与s2相等,说明不是这样的执行顺序,应该是遗漏了某些条件,再回main函数中看看有一个还没分析的sub_A90函数

sub_A90函数分析

C 库函数 – atexit() | 菜鸟教程 (runoob.com)

这个函数直接给出了一个返回值__cxa_atexit函数,查阅资料后得知它的原型就算atexit()函数,而atexit()函数的作用是,当程序正常终止时,调用传入其中的函数

这下便恍然大悟,表面上看main函数中的sub_916函数在对字符串s1循环异或加密之前,而实际它是被作为参数传递给__cxa_atexit函数的,是在程序执行结束后才被调用

在完成以上的分析之后,博主一时也是认为稳如泰山,不曾料想按这个逆向思路去简单写了脚本却始终不能ctf,也是有了这题,让我养成一个习惯——对于关键加密串一定要仔细查看它的交叉引用!

选中s1后按x键查看交叉引用,赫然发现它在sub_84A函数也曾被引用过

sub_84A函数分析

跟进sub_84A函数,果不其然,发现这个函数也对s1进行过相关加密操作,但蒟蒻博主实在想不明白这个函数被调用的机理是什么,main函数中并没有对其调用过的痕迹,希望有清楚的大佬能够路过时指点一二!

最终我只能直接主观认为sub_84A函数是在main函数调用之前就被调用了

因此,在对比字符串s1和s2前,s1是被进行了两次加密,第一次是sub_84A函数的如下图的加密公式【s1[i] ^= 2 * i + 65】,第二次是main函数中的for循环与输入串s异或

EXP

先整理一下正向加密思路

经过加密1和加密2后的字符串s1和s2相同,逆向思路则为s2与完成第一次解密后的s1,去进行解密2

字符串s2处理

刚准备写脚本时突然发现这个s2不是常规的字符串啊,小白博主也不太明白为什么ida会这样分析,既有字符(ASCII码是十进制)又有十六进制数(h标志),所以这里得多做一步操作了——把字符串s2统一成相同的十六进制

把这些末尾有h标志的十六进制数先提取出来(注意结果要去掉h标志),各显神通吧,蒟蒻博主直接手抠了...

0x17, 0x46, 0x54, 0x5A, 0x59, 0x59, 0x1F, 0x48, 0x32, 0x5B, 0x6B, 0x7C, 0x75, 0x6E, 0x7E, 0x6E, 0x2F, 0x77, 0x4F, 0x7A, 0x71, 0x43, 0x2B, 0x26, 0x89, 0xFE, 0x00

对s2前面的字符也做相同处理,这里可以用ida的【shift+e】快捷键快速获取

凑成一个总列表

s2 = [0x56, 0x4E, 0x57, 0x58, 0x51, 0x51, 0x09, 0x46,0x17, 0x46, 0x54, 0x5A,0x59, 0x59,0x1F, 0x48, 0x32, 0x5B,
      0x6B, 0x7C,0x75, 0x6E, 0x7E, 0x6E, 0x2F, 0x77, 0x4F, 0x7A, 0x71, 0x43, 0x2B, 0x26, 0x89, 0xFE, 0x00]

最终脚本

(注意运行出的结果少一个右大括号,自行补上后提交正确)

s2 = [0x56, 0x4E, 0x57, 0x58, 0x51, 0x51, 0x09, 0x46,0x17, 0x46, 0x54, 0x5A,0x59, 0x59,0x1F, 0x48, 0x32, 0x5B,
      0x6B, 0x7C,0x75, 0x6E, 0x7E, 0x6E, 0x2F, 0x77, 0x4F, 0x7A, 0x71, 0x43, 0x2B, 0x26, 0x89, 0xFE, 0x00]
s1 = 'qasxcytgsasxcvrefghnrfghnjedfgbhn'
flag = ''
for i in range(0, 33):
    #先对s1解密1,再拿s2和解密1后的s1进行解密2,得到的字符就是flag的一部分
    #同时注意python的字符不能直接当ASCII码来用
    flag += chr(s2[i] ^ ord(s1[i]) ^ (2 * i + 65) )
print(flag)

  • 14
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值