RCTF 2015 Reverse 复盘
这是一篇尚未完成的文章
Re100: NeoYang
not sequence:100
The sequence is not a sequence But RE is RE
祭出IDA,可以看到两个关键判断函数。
程序读入一长串数字后开始运算。第一个判断函数位于.text:0804867B
,当输入正确的密码时,对其描述为:对password[i*(i+1)/2:i*(i+3)/2]
中的元素集合A,满足sum(A)==2**(i+1)
且A中的任意元素x满足x!=0
时循环正常进行,其中i=0,1,2,..,19
;该函数返回值即为等差数列个数i。不妨认为password
是一个三角形的数列,每行为含有i+1项的斐波契那数列,即可满足要求。这样可以构造出一个可以通过该函数的样例:
fp=open('eg','w')
for i in range(20):
for j in range(i+1):
if (j<2):
fp.write('1 ')
else:
fp.write(str(2**(j-1))+' ')
fp.write('\n')
fp.write("0\n")
fp.close()
第二个函数位于.text:08048731
,要求对于上面建立的三角数列,对于任意i=range(1,20)
满足password[19][i]=sum(password[i-1][:18])
。将上式修改为下面的帕斯卡三角的输出程序,则可得到正确结果:
def pas_triangles():
a = [1]
while True:
yield a
a = [sum(i) for i in zip([0] + a, a + [0])]
if __name__ == "__main__":
fp=open('trig','w')
g = pas_triangles()
for n in range(20):
i=next(g)
for j in i:
fp.write("%d "%(j))
fp.write('\n')
fp.write("0\n")
fp.close()
按照要求即可得到flag。
Re200:tank
消息循环位于.text:00401700
处,处理函数为.text:00402B50
,在对结构体进行分析后可确定该结构体最后一个双字保存着当前所在等级。进行一些简单的操作后可以看到对等级进行判断以及将flag写入文件的函数,用0x39作为密钥,异或之后就可以得出结果了
Re300:crackMe
是一个Win32程序。将程序载入IDA后,可以看到大量的区域处于未识别状态。导入函数只有Kernel32.dll中的LoadLibraryA
、
GetProcAddress
、VirtualProtect
和ExitProcess
,推断这个程序是被加壳过的,PEiD检查后证实了这是
个UPX壳,在官网找到upx后,直接upx -d即可脱出来(手动怎么都脱不下来,以后慢慢研究,说不定又能混一篇文章)。用IDA加载脱壳
之后的程序,可以看到一组花指令,如下图:
可以看到这组指令执行的工作就是,调用压入栈中的子程序,并跳过这组指令其后的两条指令,继续执行。这样我们可以用下面的一组指令替换这些花指令:
之后我们可以发现,该程序是在将程序末尾附加的另外一个文件读入内存并用0x07解密:
从内存中dump出来后,可以看到这才是真正的解Flag程序。同样用UPX脱壳后分析程序工作流程。这个程序使用的反分析技巧类似于部分恶意软件,将会把内存中
部分执行后不需要用的代码随机加密,有至少三处采用了这样的做法(因此动态调试的时候请记住先调整好.text为可写),但这并不影响我们对其进行静态分析。
程序直接从缓冲区读入字符串后,将其转化为十六进制性质的字符串,首先通过下图所示的comp_1()
函数进行处理。这里首先从字符串生成一个类似于KMP
算法中的“部分匹配表”,之后将每个字符与匹配表中的数据和25加和后的结果异或,之后再次将其转化为十六进制字符串。将每个字符存入一个二叉树之后,进行深
度优先遍历,再将结果与一个表做匹配,如果内容相等,则认为输入正确。
这个二叉树的构造实在是骨骼精奇,我到现在还没解开它。但是有趣的是,涉及到二叉树建立的.text:401120
和.text:401160
与输入并没有
关系。因此我们只要将二叉树建立的这部分代码复制出来,然后构造一个1,2,3,4,...,...
的输入,就可以将这个步骤转化成为一个简单的置换。下面
的这个python脚本输出的结果,就是进入二叉树之前的数据:
slen=27
tree=[[0,0,0] for i in range(4*slen)]
ret=[i for i in range(4*slen)]
src=list("22722272222227272222727a2222222222272222272222222222cfdceeeebb9fdbcdbbedfdede7ce9bebe0bb1e2ceab9e2bbbdecf9d8")
dst=list(range(len(src)))
m=0
def sub_401120(index):
global tree
left=0
if (tree[index][0]!=-1):
left=sub_401120(tree[index][0])
right=tree[index][2]
if (right!=-1):
left+=sub_401120(right)
return (left+1)
def tree_connect(root,target):
global tree
result=root
pos=root
pos_idxL=tree[root][0]
if (pos_idxL==-1):
tree[result][0]=target
return result
else:
while ( tree[pos][2] != -1 ):
v5 = sub_401120(pos_idxL);
if (sub_401120(tree[pos][2]) <= v5+4 ):
result=tree[pos][2]
else:
result=tree[pos][0];
pos=result
pos_idxL=tree[result][0]
if (pos_idxL == -1):
tree[result][0]=target
return result
#result*=3
tree[result][2]=target
result*=3
return result
def dfs(pos):
global tree
global m
global ret
flag=1
while(flag or pos!=-1):
flag=0
if (tree[pos][0] != -1):
dfs(tree[pos][0])
ret[m]=tree[pos][1]
m+=1
pos=tree[pos][2]
return pos
tree[0][0]=-1
tree[0][1]=0
tree[0][2]=-1
for i in range(1,4*slen):
tree[i][0]=-1
tree[i][1]=i
tree[i][2]=-1
tree_connect(0,i)
m=0
dfs(0)
print(ret)
for i in range(len(src)):
dst[ret[i]]=src[i]
print(dst)
dst_decoded=str().join([chr(int("0x"+dst[i]+dst[i+1],16)) for i in range(0,len(dst),2)])
print(dst_decoded)
print(len(dst_decoded))
#Result:*y+.+{-~---~./++/,-~/,. .--~,+/+.).+.z,|++-~..+),(+!+)
接下来我们就要将这段字符串反向为原始的字符串。这里采用穷举法:
src="*y+.+{-~---~./++/,-~/,. .--~,+/+.).+.z,|++-~..+),(+!+)"
hexlist="1234567890ABCDEF"
temp=[i for i in range(54)]
for k in range(-25,30):
temp=[ chr(ord(i)^(25+k)) for i in src]
#decoded=str().join([chr(int("0x"+temp[i]+temp[i+1],16)) for i in range(0,len(temp),2)])
decoded="".encode('ascii','ignore')
for i in range(0,len(temp),2):
#decoded=str().join([chr(int("0x"+temp[i]+temp[i+1],16)) for i in range(0,len(temp),2)])
if temp[i].upper() in hexlist and temp[i+1].upper() in hexlist:
p=int("0x"+temp[i]+temp[i+1],16)
if p in range(0x20,0x7f):
ch=chr(p)
else:
ch=" "
else:
ch=" "
#print("%d %d %c %c %c"%(k,i,temp[i], temp[i+1], ch))
decoded+=ch.encode('ascii','ignore')
print(decoded)
结果如下
随便挑一个合适的就好啦
先写这些吧 有时间接着写