大概是一个月之前的比赛了,反正当时除了签到题之外没能做出其他题(哭
然后最近打算认真重新做一遍,然后发现有些题还是不会做(哭*2,说到底还是太菜了),所以这里只记录了几道简单题的过程。也欢迎参过赛的小伙伴们贴一下自己的解题思路一起讨论
GAME(Reverse)
关键词:python bytecode,python dis.dis()
上网搜一下文件中的内容,比如说“LOAD_CONST”,发现是由dis.dis()生成的python的字节码,实际上是一种中间状态的可读代码。真正的字节码文件的话应该是pyc格式,有现成的工具可以把它反编译回python代码。但是python的dis模块却没有现成工具,如果不想专门自己写工具的话只能手动逆。这种类型的题的旧例
参考官方给出的文档可以得知每条指令的含义,并且它们维护了一个简单的栈,操作符就是针对TOS(Top Of Stack)和TOS1(TOS下面的数据)进行操作。除了check0里的那个神奇的yield之外基本上没有什么困难的地方,很快就可以写出源代码
arr0=[249,91,149,113,16,91,53,41]
arr1=[43,1,6,69,20,62,6,44,24,113,6,35,0,3,6,44,20,22,127,60]
arr2=[90,100,87.109,86,108,86,105,90,104,88,102]
'''
def genxpr():
for x in range(0,38):
yield ord(x) in range(32,128)
'''
def check0(s):
#check0函数怎么写都是怪怪的,官方wp的意思是,它是用来判断每个字符ascii是否在32到128之间
#return all(genxpr(iter(s)))
pass
def check1(s):
if not len(s) <100:
return False
if not (((len(s)*len(s)) % 777 )^ 233 == 513):
return False
return True
pass
def check2(s):
if ((((ord(s[0]) * 128 + ord(s[1])) * 128 + ord(s[2])) * 128 + ord(s[3])) * 128 + ord(s[4])) * 128 + ord(
s[5]) == 3533889469877L:
if s[-1]==125:
return True
return False
pass
def check3(s):
arr=map(ord,s)
a=arr[slice(6,30,3)]
for i in range(len(a)):
if arr0[i]!=((a[i]*17684+372511)%257):
return False
b=arr[slice(-2,33,-1)]*5
c=map(lambda x:x[0]^x[1],zip(b,arr[7:27]))
if c != arr1:
return False
p=0
for i in range(28,34):
if arr2[p]!=((arr[i]+107)/16+77)
return False
if arr2[1+p]!=((arr[i]+117)%16+99)
return False
p=p+2
return True
pass
def raw_input():
pass
if check0(flag) and check1(flag) and check2(flag) and check3(flag):
print('ok')
else
print('no')
check1就是花式告诉你字符串的长度为39,check2由于你已经知道了开头是"flag{",结尾是"}",同样解个方程就会发现第六个字符是'5'
check3就复杂一点,第一个循环内的是判断切片的字符是否满足17684*a[i]+372511=arr0[i]+257r,由于已知r和a[i]为正整数,并且由a[i]为可打印字符可知其范围,直接写脚本爆破即可。第二个循环就是把数组里面的数字两两异或,并且上面解出的内容也会参与运算,所以可以借此解出其余字符(这段太烦琐了,我选择直接爆破)。第三个循环比第一个更简单,直接就可以算出结果。更具体地分析这里有。