2016-pediy-ctf-04
发现主程序很简单,主要过程在窗口回调
Image.png通过GetDlgItemText得到输入,并对其字数进行比较,锁定关键函数
Image [3].png
查看关键函数,发现里边的代码很混乱,利用PEID和exeinfo查壳,发现并没有检测到壳,顺便利用PEID工具检测一下加密算法,发现MD5算法
Image [4].png Image [5].png
搜索字符串并不能发现其他有用的东西
所以我们直接进行动态调试
输入 1234567890三次,得到30位输入进行调试关键函数
动态调试发现该过程存在循环
其实该过程为虚拟机,即VMP,上图esi为handler,
直接查看esi全部handle,在最后几个下内存断点
Image [7].png
注意这个操作,出虚拟机的操作,我们直接下断点
Image [8].png
笔者由于个人水平有限,还是不能说清楚关于虚拟机的种种操作,所以这里只是在关键位置提一下,只能说关联代码前后凭感觉去找出虚拟机的操作,并且作者在关键代码并没有VM,如果作者所有代码都进行VM操作,可能以笔者水平,并不能搞完这个题
出虚拟机后
004014F0
发现我们之前用插件得到的MD5, 进入该函数发现第一次作比较把我们输入的前七位拷贝之后ret,不过很可能之后依旧会进入该函数,并很可能进行MD5操作
ret后发现再次进入虚拟机,我们直接运行到虚拟机出口
004015c0
该函数的两个函数主要操作
第一次进入004014F0加了结束标志符,并把后边清0
Image [11].png第二次,MD5操作
Image [12].png拷贝MD5值并把内存清0
Image [14].png
00401187
获取之后的23位,与指定数进行xor
之后该值会与之后的MD5值进行XOR,注意MD5值16字节,重复循环,xor,直到23字节
得到值
这两个赋值操作是对迷宫的初始化,后期会用到的
Image [17].png而且此时的数值才是正确的,因为之后经过VM后,有些数值会发生变化,导致后边计算错误
之后就是迷宫走法的核心计算,下边是如何计算每一步及其规则
Image [18].png详细说一下这里吧
首先00401248这里cl被赋值为6,4,2,0,
0040124E这个edx取我们输入后处理的值,and 3,得到其值
然后通过00401253计算跳到哪里,这里可以得到
0 ---> 向上走
1 ---> 向前走
2 ---> 向下走
3 ---> 向后走
所以一个字节可以走四步
然后接下来是迷宫的计算
Image [19].png我们首先得到
part 1
part 2
Image [21].png
首先是对Part 1根据上边的走法取对应值然后ror,这条指令我们用程序模拟还是挺麻烦的,在找到对应的part 2值,进行xor
之后我们通过爆破,发现0x58是出口
了解了具体的步骤
我们开始写程序爆破
程序后边代码
#程序参考来自https://bbs.pediy.com/thread-213791.htm 〇〇木一
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import md5
import binascii
p1 = "6ED41B695F4EE8AA95F6AFCE321A62D9021874951FC24D333CF03BECE9814B9C"
p1 += "0F475CADD909B087539BF2E30F01928DC2F50CDD42CCAFB4D5E486D39A0B6263"
p1 += "A7D41B695F4EE8AA95F6AFCE321A62D9021874951FC24D3338F03BECED814B9C"
p1 += "0B475CADDD09B087579BF2E30B01928DC2F50CDD42CCAFB4D5E486D39A0B6263"
p1 += "A7D41B695F4EE8AA95F6AFCE321A62D9021874951FC24D3338F03BECE9814B9C"
p1 += "0F475CADD909B087539BF2E30F01928DC2F50CDD42CCAFB4D5E486D39A0B6263"
p1 += "A7D41B695B4EE8AA91F6AFCE361A62D9021874951FC24D3338F03BECE9814B9C"
p1 += "0B475CADDD09B087579BF2E30B01928DC6F50CDD42CCAFB4D5E486D39A0B6263"
p2 = "D805F66AE7A20B9B548CDA82BDB6A846B1362D55F78163FC3F0CFE0B4B50E217"
p2 += "F2E1275B46731CD0E5D78DC9F2709453814C3246A002DB1C450991C496F2A8E8"
p2 += "D905F66BE7A20A9B548CDA82BDB7A946B0362D54F78163FC3E0CFE0B4B50E317"
p2 += "F2E0265A47731CD1E5D68CC8F2709553804C3347A002DB1C440891C496F2A9E8"
p2 += "D904F66AE7A20A9B558CDB83BCB6A946B0372D55F78163FD3E0DFE0B4A50E317"
p2 += "F3E0275B46731DD0E4D78CC8F3709553804C3347A003DB1D450891C496F2A9E8"
p2 += "D904F66AE6A30A9A548CDB82BCB7A946B0372C54F68162FD3E0DFE0A4A50E217"
p2 += "F2E1275B47721CD0E5D78CC9F2709453814D3347A003DB1C440891C5979AA8E8"
#生成迷宫
pp1 = binascii.a2b_hex(p1.encode())
pp2 = binascii.a2b_hex(p2.encode())
pp3 = ""
def ror2(a):
return ((a&3)<<6)|(a>>2) & 0xFF
for i in range(len(pp1)):
pp3+=chr(ror2(ord(pp1[i])) ^ ord(pp2[i]))
print(len(pp3))
#16字节一行打印
for i in range(16):
ps = ""
for j in range(16):
ps+=binascii.b2a_hex(pp3[i*16+j]).upper()
print(ps)
x = 0
y = 0
x0 = 0
y0 = 0
t = [(0,-1),(1,0),(0,1),(-1,0)]
#打印程序指定的道路
path = ""
while(ord(pp3[y*16+x]) != 0x58):
for i in range(4):
xx = x + t[i][0]
yy = y + t[i][1]
if(xx >= 0 and xx < 16 and yy < 16 and yy >=0 and (xx != x0 or yy != y0)):
if ord(pp3[yy*16+xx]) != 0x30:
path += str(i)
x0 = x
y0 = y
x = xx
y = yy
break
print(path)
#按照之前的走法,将其合并为每四步为一个字节 one byte for 4 steps,
pn0 = ""
for i in range(23):
a = 0
for j in range(4):
a = (a | int(path[i*4+j])<<((3-j)*2))&0xFF
pn0 += chr(a)
print(binascii.b2a_hex(pn0).upper())
#处理输入
## 在程序中存在以下操作
## 对前七位进行MD5操作,并循环扩展到0x17位,
## 然后剩余23位与44 AD 5C CC 12 90 73 8D 47 81 E3 89 84 9C DF F9 47 6A B6 9E 11 30 27 sn0进行xor得到sn
## 然后MD5与sn进行xor得到sn_1
## 存在 path = md5[x1] ^ x2 ^ sn0
def getmd5(src):
m1 = md5.new()
m1.update(src)
ret = m1.digest()
ret = ret + ret[0:7]
return ret
pn1 = binascii.a2b_hex("44AD5CCC1290738D4781E389849CDFF9476AB69E113027")
pnx=""
#因为是xor操作,有可逆性,所以我们直接得到他之前的值
for i in range(23):
pnx += chr(ord(pn0[i])^ord(pn1[i]))
print("pnx:", binascii.b2a_hex(pnx).upper())
def xorpm(pm):
global pnx
pno=""
for i in range(23):
pno += chr(ord(pnx[i])^ord(pm[i]))
return pno
def isstr(s):
for a in s:
aa = ord(a)
if aa < 32 or aa > 126:
return False
return True
# 枚举,
tab='0456123789abcdef'
t0 = time.time();
for a0 in tab:
for a1 in tab:
for a2 in tab:
for a3 in tab:
for a4 in tab:
for a5 in tab:
for a6 in tab:
aaa=a0+a1+a2+a3+a4+a5+a6
pppp=xorpm(getmd5(aaa))
if isstr(pppp):
print(aaa+pppp)
break
你也可以在这里查看:
https://github.com/ZEROSHE/ctf/tree/master/ctf/Pediy/2016%20ctf/4
本人水平有限,只能知其一二,很多地方可能存在不当或者错误还请指出,谢谢。
网友评论