写在前面
我很后悔在最后的阶段没有愿意多进行尝试, 不然一血应该属于从看到题目发布时就开始解题的我.
文件分析
这次的代码是一个Arduino程序,用于控制七段显示器的亮灭。代码中定义了一个名为data的数组,其中存储了每个LED灯对应的引脚编号(A-G和DP)。COM引脚被设置为5V。
// Set A-G, DP as OUTPUT pins, COM is 5V
int data[] = {0, 0, 0,2,4,5,6,7,8,0,2,3,5,6,8,0,2,3,4,0,2,4,5,7,8,0,2,4,5,6,7,8,0,2,3,4,0,2,4,5,6,7,8,0,4,5,6,7,8,0,2,3,4,0,2,4,5,7,8,0,2,3,4,0,4,5,6,7,8,0,2,4,5,6,7,8,0,2,3,4,5,6,7,8,0,2,4,5,6,7,8,0,3,4,0,2,3,4,0,2,3,5,6,8,0,2,4,5,6,7,8,0,3,4,7,8,0,2,3,4,0,2,3,4,0,2,4,5,6,7,8,0,3,4,0,2,3,4,0,2,3,5,6,8,0,2,4,5,6,7,8,0,2,4,5,7,8,0,2,4,5,7,8,0,2,6,7,8,0,2,4,5,6,7,8,0,2,3,4,5,7,8,0,2,3,4,0,2,3,4,5,8,0,2,4,5,7,8,0,2,6,7,8,0,2,3,4,0,2,3,4,5,8,0,2,4,5,6,7,8,0,2,6,7,8,0,2,4,5,7,8,0,2,6,7,8,0,2,4,5,6,7,8,0,2,4,5,7,8,0,2,4,5,6,7,8,0,3,4,0,2,3,4,0,2,3,4,5,8,0,2,3,4,0,2,3,4,5,7,8,0,2,3,4,0,3,4,5,6,8};
在setup()函数中,使用for循环将2到9号引脚设置为输出模式。
void setup() {
for(int i=2; i<=9;i++) pinMode(i, OUTPUT);
}
在loop()函数中,使用for循环遍历data数组中的每个元素。如果data[i]等于0,则调用clear()函数使对应的LED灯熄灭;否则,将对应的LED灯设置为低电平(LOW)。
void loop() {
for (int i=0; i<sizeof(data) / 2; i++) data[i] == 0 ? clear() : digitalWrite(data[i], LOW);
}
clear()函数的作用是使指定的LED灯熄灭一段时间(1秒),然后将其设置为高电平(HIGH)。
void clear() {
delay(1000);
for(int i=2; i<=9;i++) digitalWrite(i, HIGH);
delay(1000);
}
编写代码
用python可以快速模拟以上内容
test = open("test","a")
the_main = ["■","■","■","■","■","■","■","■"]
light = the_main.copy()
word = ""
loop_num = 0
data = [0, 0, 0,2,4,5,6,7,8,0,2,3,5,6,8,0,2,3,4,0,2,4,5,7,8,0,2,4,5,6,7,8,0,2,3,4,0,2,4,5,6,7,8,0,4,5,6,7,8,0,2,3,4,0,2,4,5,7,8,0,2,3,4,0,4,5,6,7,8,0,2,4,5,6,7,8,0,2,3,4,5,6,7,8,0,2,4,5,6,7,8,0,3,4,0,2,3,4,0,2,3,5,6,8,0,2,4,5,6,7,8,0,3,4,7,8,0,2,3,4,0,2,3,4,0,2,4,5,6,7,8,0,3,4,0,2,3,4,0,2,3,5,6,8,0,2,4,5,6,7,8,0,2,4,5,7,8,0,2,4,5,7,8,0,2,6,7,8,0,2,4,5,6,7,8,0,2,3,4,5,7,8,0,2,3,4,0,2,3,4,5,8,0,2,4,5,7,8,0,2,6,7,8,0,2,3,4,0,2,3,4,5,8,0,2,4,5,6,7,8,0,2,6,7,8,0,2,4,5,7,8,0,2,6,7,8,0,2,4,5,6,7,8,0,2,4,5,7,8,0,2,4,5,6,7,8,0,3,4,0,2,3,4,0,2,3,4,5,8,0,2,3,4,0,2,3,4,5,7,8,0,2,3,4,0,3,4,5,6,8][2:]
for i in data:
if i == 0:
loop_num += 1
b = "".join(light)#.replace("▢","1").replace("■","0")[::-1]
print(b)
if b == "▢■▢▢▢▢▢■":
a = 6
elif b == "▢▢■▢▢■▢■":
a = 2
elif b == "▢■▢▢■▢▢■":
a = 5
elif b == "▢▢▢■■■■■":
a = 7
elif b == "■■▢▢▢▢▢■":
a = "b"
elif b == "▢▢▢▢▢▢▢■":
a = 8
elif b == "▢■■■▢▢▢■":
a = "f"
elif b == "■▢▢■■■■■":
a = 1
elif b == "▢▢▢▢■■▢■":
a = 3
elif b == "▢▢▢▢■▢▢■":
a = 9
elif b == "■▢▢■■▢▢■":
a = 4
else:
a = ""
#a = int(a,2)
#a = chr(a)
#test.write(a)
light = the_main.copy()
if loop_num == 2:
loop_num = 0
test.write("\\x")
a = str(a)
word += a
test.write(a)
else:
light[i-2] = "▢"
#print(light)
#print("".join(light))
test.write("d")
word += "d"
test.close()
print(word)
将得到的文件test
复制进python为字符串,可以得到flag.
原理解析
七段显示器服从指令SEG, 通过对给出数组data进行for循环, 将2-9电位信息以■▢
形式进行输出. 当data指向0时执行源代码的clear()函数的暂停重置指令, 故在python中使用if判别输出当前结果, 并通过if-elif-else进行SEG转换, 得到数据word, 并以"\xXX"形式储存为test文件, python中"\xXX"格式用于转换数据十六进制数据.
最后是结尾的"d", 我们可以在tinkercad进行Arduino的仿真模拟进行测试, 将一个Arduino与7段显示器如下所示进行连接, 并输入代码(为提升效率, 以下将delay暂停时长缩短为1/10).
开始模拟后, 我们可以发现在结尾多出了一个在python模拟中未出现的新字符"d", 这是因为python代码中以for循环中的data指向0为结束获取数据, 而题目的程序中在结尾并未添加0, 导致出现了数据丢失, 当时我拿着51个字符表示非常疑惑, 再加上flag头的bugku{}没能成功对应上"flag{}"字符的各种编码形式, 导致我陷入过很长一段时间的错误思考, 痛失一血.
将缺少的"d"进行补全, 在字符串中便可以轻松找到特殊字符组合"7b"和"7d", 即十六进制编码的"{}"符号, 进行解码, 成功拿下flag