[Reverse1] Tales of the Arrow
[Reverse1] Tales of the Arrow
来源:TQLCTF高校赛
类型:Reverse
当咸鱼太久,突然要打CTF,啥都不会,边刷题边学吧。先来点偏算法的逆向题。
文章目录
- [Reverse1] Tales of the Arrow
- 题目描述
- 读懂源python代码
- 突破口
题目描述
GodV: How to reverse if it is already reversed? Zoe: You need a good direction, and reverse it again. Flag: tqlctf{.+}
题目文件见文章首部附件。
读懂源python代码
很多python代码都不熟练了,需复习一下。
bytes(字符串,编码方式)
,将字符串转化为字节对象''.join(<list>)
,将一个字符串列表拼接为一整个字符串,且间隔为’’{0:08b}".format(x)
,0
表示第零位参数,:
表示格式化开始,08b
表示格式化为二进制且长度为8位,不够长度的左侧补0。randint(<inta>,<intb>)
,返回[a,b]之间的随机整数,可以取到a和b
突破口
(1)id_bytes = bytes(id, "ascii")
可以推测输入的id可以按ascii显示,即都为可视字符,查ascii编码可知,可视字符的首位都为0。所以bits的样式中每8位的首位都为0。
(2)分析get_lit(i),可知当get_lit(i)>0,则bits第i位一定为1,<0则为0。同时可以根据get_lit(i)的值逆推出i,即若x=get_lit(i),则i = 绝对值x - 1。
(3)分析最后的for循环,输出结果第一位为n,第二位N,从第三位开始每三个为一组。必定有一个true_lit和两个rand_true(符号不定,可能为-rand_true或rand_true),显然我们无法区分true_lit和rand_true,但若有已知bits一些位数上的值时,我们可以通过逆推true_lit和rand_true对应的bits位置的值,来判断其是否是**-rand_true**,那么如果判断出了有两个-rand_true则另外一个数一定是true_lit!
根据(1)中的分析,首位都为0,则可以根据已知的部分bits位置的值推出其他true_lit,进而确定其他bits位置的真实值,随后再根据更新后的bits,再继续推其他位置的bits值,不断循环最终得到完整的bits,最后将bits按每8位转化为ascii字符并连接起来得到flag.
# -*- coding: utf-8 -*-
# @Author : zilong
# @Time : 2025/7/10 17:24with open('output.txt', 'r') as f:data = f.read().split('\n') # 返回一个字符串列表,每行一个元素n = int(data[0])
N = int(data[1])flagList = ['_' for i in range(n)]
for i in range(n):if i % 8 == 0:flagList[i] = '0'
print(''.join(flagList))def get_bits_index(lit):lit = abs(lit)return lit-1while '_' in flagList:for i in range(2, N * 3, 3):opp_neg = [0] * 3for j in range(3): # 遍历一组数(3个数)if int(data[i+j]) > 0 and flagList[get_bits_index(int(data[i+j]))] == '0':opp_neg[j] = 1elif int(data[i+j]) < 0 and flagList[get_bits_index(int(data[i+j]))] == '1':opp_neg[j] = 1if sum(opp_neg) == 2:true_lit = int(data[i + opp_neg.index(0)])true_id = get_bits_index(true_lit)if true_lit < 0:flagList[true_id] = '0'else:flagList[true_id] = '1'if '_' not in flagList:break
flag = ""
for i in range(0, n, 8):flag += chr(int(''.join(flagList[i:i+8]), 2))
print(flag)