赞
踩
目录
NSSCTF-[NSSRound#X Basic]ez_z3
题目下载:下载
查壳:
发现有upx壳,但是使用upx -d命令不能脱壳,载入十六进制编辑器查看
把XYU改为UPX,就可以成功使用upx -d脱壳了。
载入IDA(部分使用了自定义命名)
倒着往前看,输出“you get the flag”就要dword_1400254C4==1,而dword_1400254C4由sub_1400110E6()函数赋值而来,所以跟进sub_1400110E6()函数:
要想返回1,则这个等式成立,即这两个数组相同。
返回到主函数,看其他的函数
看一下sub_1400112F8()函数:
这就是一个简单的异或。
看sub_14001103C()函数:是很多等式,可以用z3求出a1[0]-a1[19]。
看一下sub_140014CC0()函数:这是一个指数折半快速幂求法,可以参考:快速幂算法 超详细教程_qascetic的博客-CSDN博客
我在这里在简单阐述一下上面的这个快速幂流程,具体地大家可以参考上面的链接。a1是底数,a2是指数,首先判断指数是奇数还是偶数。
如果是偶数即if条件不成立,那么就a1*a1底数变为平方,a2>>2相当于除以2,指数折半,这样一直执行下去,直到a2为1,是奇数,这样就执行if的子句1把结果赋值给v3返回。
如果是奇数,就先分离出一个,然后在采用快速幂法,最后通过v3返回。
好了关键的函数都分析完了,整体思路就是:
1.先用z3约束器求出a1数组的值,也即异或操作里的a1数组
2.通过异或操作,a1已知,求出dword_140025520[]数组
3.dword_140025520[]已知,通过快速幂爆破出str
所以代码如下
- from z3 import *
- #z3约束器
- a1=[0]*20
- for i in range(20):
- a1[i]=Int('a1['+str(i)+']')
-
- s = Solver()
- s.add((20 * a1[19] * 19 * a1[18]
- + 14 * a1[13]
- + 13 * a1[12]
- + 11 * a1[10] * 10 * a1[9]
- + 30 * a1[5]
- + 5 * a1[4]
- + a1[0]
- + 2 * a1[1]
- - 3 * a1[2]
- - 4 * a1[3]
- - 7 * a1[6]
- + 8 * a1[7]
- - 9 * a1[8]
- - 12 * a1[11]
- - 16 * a1[15] * 15 * a1[14]
- - 17 * a1[16]
- - 18 * a1[17]) == 2582239)
- s.add((20 * a1[19] * 19 * a1[18]
- + 14 * a1[13]
- + 13 * a1[12]
- + 11 * a1[10] * 10 * a1[9]
- + 30 * a1[5]
- - 7 * a1[6]
- + 8 * a1[7]
- - 9 * a1[8]
- + 5 * a1[4]
- + 3 * a1[2]
- + 2 * a1[1] * a1[0]
- - 4 * a1[3]
- - 12 * a1[11]
- - 16 * a1[15] * 15 * a1[14]
- - (18 * a1[17]
- + 17 * a1[16])) == 2602741)
- s.add((19 * a1[18]
- + 18 * a1[17]
- + 14 * a1[13] * 13 * a1[12]
- + 12 * a1[11] * 11 * a1[10]
- + 9 * a1[8]
- + 7 * a1[6] * 30 * a1[5]
- + a1[0]
- - 2 * a1[1]
- - 4 * a1[3] * 3 * a1[2]
- - 5 * a1[4]
- + 8 * a1[7]
- - 10 * a1[9]
- - 15 * a1[14]
- - 17 * a1[16] * 16 * a1[15]
- - 20 * a1[19]) == 2668123)
- s.add((20 * a1[19] * 19 * a1[18]
- + 14 * a1[13]
- + (13 * a1[12] + 11 * a1[10] - 12 * a1[11]) * 10 * a1[9]
- + 30 * a1[5]
- + 5 * a1[4]
- + a1[0]
- + 2 * a1[1]
- - 3 * a1[2]
- - 4 * a1[3]
- - 7 * a1[6]
- + 8 * a1[7]
- - 9 * a1[8]
- - 16 * a1[15] * 15 * a1[14]
- - 17 * a1[16]
- - 18 * a1[17]) == 2520193)
- s.add((18 * a1[17]
- + 17 * a1[16]
- + 15 * a1[14]
- + 13 * a1[12] * 12 * a1[11]
- + 10 * a1[9]
- + 9 * a1[8] * 8 * a1[7]
- + 3 * a1[2] * 2 * a1[1] * a1[0]
- - 4 * a1[3]
- - 5 * a1[4]
- - 30 * a1[5]
- - 7 * a1[6]
- - 11 * a1[10]
- - 14 * a1[13]
- - 16 * a1[15]
- - 19 * a1[18]
- - 20 * a1[19]) == 8904587)
- s.add((18 * a1[17]
- + 7 * a1[6] * 30 * a1[5] * 5 * a1[4]
- + 4 * a1[3]
- + 8 * a1[7]
- + a1[0]
- - 2 * a1[1]
- - 3 * a1[2]
- - 9 * a1[8]
- - 11 * a1[10] * 10 * a1[9]
- - 16 * a1[15] * (13 * a1[12] + 12 * a1[11] - 14 * a1[13] - 15 * a1[14])
- - 17 * a1[16]
- - 19 * a1[18]
- - 20 * a1[19]) == 1227620874)
- s.add((20 * a1[19] * 19 * a1[18]
- + 17 * a1[16]
- + 14 * a1[13]
- + 13 * a1[12]
- + 12 * a1[11] * 11 * a1[10] * 10 * a1[9]
- + 7 * a1[6] * 30 * a1[5]
- + 5 * a1[4]
- + 3 * a1[2]
- + a1[0]
- + 2 * a1[1]
- + 4 * a1[3]
- + 8 * a1[7]
- - 9 * a1[8]
- - 16 * a1[15] * 15 * a1[14]
- - 18 * a1[17]) == 1836606059)
- s.add((20 * a1[19] * 19 * a1[18]
- + 16 * a1[15] * 15 * a1[14]
- + 14 * a1[13]
- + 13 * a1[12]
- + 12 * a1[11]
- + 7 * a1[6] * 30 * a1[5]
- + 5 * a1[4]
- + 2 * a1[1] * a1[0]
- - 3 * a1[2]
- + 4 * a1[3]
- + 8 * a1[7]
- - 9 * a1[8]
- - 10 * a1[9]
- - 11 * a1[10]
- - 17 * a1[16]
- - 18 * a1[17]) == 8720560)
- s.add((20 * a1[19] * 19 * a1[18]
- + 14 * a1[13]
- + 13 * a1[12]
- + 11 * a1[10] * (10 * a1[9] + 30 * a1[5] + 5 * a1[4] + 4 * a1[3] - 7 * a1[6] + 8 * a1[7] - 9 * a1[8])
- + a1[0]
- + 2 * a1[1]
- - 3 * a1[2]
- - 12 * a1[11]
- - (16 * a1[15] - 17 * a1[16] - 18 * a1[17]) * 15 * a1[14]) == 11387045)
- s.add((20 * a1[19] * 19 * a1[18]
- + 16 * a1[15] * 15 * a1[14]
- + 14 * a1[13]
- + 11 * a1[10] * 10 * a1[9]
- + 9 * a1[8]
- + 3 * a1[2]
- + a1[0]
- - 2 * a1[1]
- + 4 * a1[3]
- - 5 * a1[4]
- - 30 * a1[5]
- - 7 * a1[6]
- + 8 * a1[7]
- - 12 * a1[11]
- - 13 * a1[12]
- - 17 * a1[16]
- - 18 * a1[17]) == 7660269)
- s.add((20 * a1[19] * 19 * a1[18]
- + 14 * a1[13]
- + 13 * a1[12]
- + 11 * a1[10] * 10 * a1[9]
- - 12 * a1[11]
- + a1[0]
- + 2 * a1[1]
- - (4 * a1[3] * 3 * a1[2]
- - 5 * a1[4]
- - 30 * a1[5])
- - 7 * a1[6]
- + 8 * a1[7]
- - 9 * a1[8]
- - 16 * a1[15] * 15 * a1[14]
- - 17 * a1[16]
- - 18 * a1[17]) == 2461883)
- s.add((14 * a1[13]
- + 11 * a1[10] * 10 * a1[9]
- + 9 * a1[8] * 8 * a1[7]
- + 7 * a1[6]
- + 2 * a1[1] * a1[0]
- - 4 * a1[3] * 3 * a1[2]
- - 5 * a1[4]
- - 30 * a1[5]
- - 12 * a1[11]
- - 13 * a1[12]
- - 15 * a1[14]
- - 17 * a1[16] * 16 * a1[15]
- - 18 * a1[17]
- - 19 * a1[18]
- - 20 * a1[19]) == -966296)
- s.add((14 * a1[13]
- + 13 * a1[12]
- + (11 * a1[10] * 10 * a1[9] + 30 * a1[5] + 5 * a1[4] + 3 * a1[2] + 4 * a1[3] - 7 * a1[6] + 8 * a1[7] - 9 * a1[8])
- * 2
- * a1[1]
- + a1[0]
- - 12 * a1[11]
- - 15 * a1[14]
- - 16 * a1[15]
- - 17 * a1[16]
- - 18 * a1[17]
- - 20 * a1[19] * 19 * a1[18]) == 254500223)
- s.add((16 * a1[15] * 15 * a1[14]
- + 14 * a1[13]
- + 11 * a1[10] * 10 * a1[9]
- + 7 * a1[6] * 30 * a1[5]
- + a1[0]
- - 2 * a1[1]
- - 3 * a1[2]
- - 5 * a1[4] * 4 * a1[3]
- + 8 * a1[7]
- - 9 * a1[8]
- - 12 * a1[11]
- - 13 * a1[12]
- - 17 * a1[16]
- - 18 * a1[17]
- - 19 * a1[18]
- - 20 * a1[19]) == 6022286)
- s.add((18 * a1[17]
- + 16 * a1[15]
- - 17 * a1[16]
- + 14 * a1[13]
- + 12 * a1[11]
- + 11 * a1[10] * 10 * a1[9]
- + 30 * a1[5]
- + 5 * a1[4]
- + 4 * a1[3] * 3 * a1[2]
- + 2 * a1[1] * a1[0]
- - 9 * a1[8] * 8 * a1[7] * 7 * a1[6]
- - 13 * a1[12]
- - 15 * a1[14]
- - 19 * a1[18]
- - 20 * a1[19]) == -636956022)
- s.add((20 * a1[19] * 19 * a1[18]
- + 13 * a1[12]
- + 12 * a1[11]
- + 11 * a1[10] * 10 * a1[9]
- + 7 * a1[6]
- + 30 * a1[5]
- + 5 * a1[4]
- + 3 * a1[2] * 2 * a1[1] * a1[0]
- - 4 * a1[3]
- - 9 * a1[8] * 8 * a1[7]
- - 14 * a1[13]
- - 15 * a1[14]
- - 16 * a1[15]
- - 17 * a1[16]
- - 18 * a1[17]) == 10631829)
- s.add((20 * a1[19] * 19 * a1[18]
- + 16 * a1[15]
- - 17 * a1[16]
- - 18 * a1[17]
- + 15 * a1[14] * 14 * a1[13]
- + 13 * a1[12]
- + 11 * a1[10] * 10 * a1[9]
- - 12 * a1[11]
- + 7 * a1[6]
- + (4 * a1[3] - 5 * a1[4] - 30 * a1[5]) * 3 * a1[2]
- + a1[0]
- + 2 * a1[1]
- + 8 * a1[7]
- - 9 * a1[8]) == 6191333)
- s.add((14 * a1[13]
- + 10 * a1[9] * 9 * a1[8] * 8 * a1[7]
- + 5 * a1[4]
- + 4 * a1[3] * 3 * a1[2]
- + 2 * a1[1] * a1[0]
- - 7 * a1[6] * 30 * a1[5]
- - 11 * a1[10]
- - 13 * a1[12] * 12 * a1[11]
- - 16 * a1[15] * 15 * a1[14]
- - 18 * a1[17] * 17 * a1[16]
- - 20 * a1[19] * 19 * a1[18]) == 890415359)
- s.add((20 * a1[19]
- + 19 * a1[18]
- + 18 * a1[17]
- + 16 * a1[15]
- - 17 * a1[16]
- + 12 * a1[11]
- + 11 * a1[10]
- + 10 * a1[9]
- + 9 * a1[8]
- + 30 * a1[5]
- + a1[0]
- + 4 * a1[3] * 3 * a1[2] * 2 * a1[1]
- - 5 * a1[4]
- - 7 * a1[6]
- + 8 * a1[7]
- - 13 * a1[12]
- - 14 * a1[13]
- - 15 * a1[14]) == 23493664)
- s.add((20 * a1[19] * 19 * a1[18]
- + 13 * a1[12]
- + 12 * a1[11]
- + 10 * a1[9]
- + 3 * a1[2] * 2 * a1[1]
- + a1[0]
- - 4 * a1[3]
- - 5 * a1[4]
- + 8 * a1[7] * 7 * a1[6] * 30 * a1[5]
- - 9 * a1[8]
- - 11 * a1[10]
- - 14 * a1[13]
- - 16 * a1[15] * 15 * a1[14]
- - 17 * a1[16]
- - 18 * a1[17]) == 1967260144)
- for i in range(20):
- s.add(a1[i]<=0xFF) #每个字符是char类型
- s.add(a1[i]>=0)
- if s.check() == sat:
- print(s.model())
-
- #求dword_140025520[]
- a1=[104,97,104,97,104,97,116,104,105,115,105,115,102,97,99,107,102,108,97,103][::-1]
- d4D0=[4615, 19616, 20257, 57, 107811, 570, 2342, 19623, 25952,54, 108955, 19624, 113632, 14085, 2342, 30675, 39576,
- 25979, 24, 2833]
- #倒序
- d520=[]
-
- for i in range(len(a1)):
- b=a1[i]^d4D0[i]
- d520.append(b)
- print(d520)
-
- #求str,即flag
- flag=''
- a3= [7, 7, 7, 9, 5, 6, 7, 7, 7, 9, 7, 7, 5, 7, 7, 7, 5, 7, 9, 7]
-
- for i in range(20): #j是要求的
- for k in range(32,128):
- v3=1
- k1=k
- a2=a3[i]
- while(a2):
- if (a2 & 1):
- v3=v3*k1
- k1=k1*k1%1000
- a2=a2>>2
- if v3==d520[i]:
- flag+=chr(k)
- break
- print(flag)
-
-
-
题目下载:下载
首先看一看题目标签和描述,可以获得一些小提示
可以知道考点是upx和dfs。
脱壳:直接upx -d 文件名就可以脱壳,载入IDA
从上面提示可以知道这个方程有多个解,所以需要爆破来解,其中只有一个加密算法且存在多解的情况,所以采用dfs爆搜,代码如下:
- check = [0x2, 0x18, 0xf, 0xf8, 0x19, 0x4, 0x27, 0xd8, 0xeb, 0x0, 0x35, 0x48, 0x4d, 0x2a, 0x45, 0x6b, 0x59, 0x2e, 0x43, 0x1, 0x18, 0x5c, 0x9, 0x9, 0x9, 0x9, 0xb5, 0x7d]
- tmp = [0]*28
- tmp[len(check)-1]=check[-1]
- #(check[-1])
-
- def DFS(deep):
- if deep == 0:
- print(bytes(tmp))
- else:
- for i in range(0xff):
- if (i ^ 0x19) ^ (i % 0x11 + tmp[deep]) == check[deep - 1]:
- #print(i)
- tmp[deep - 1] = i
- DFS(deep - 1)
- DFS(len(check)-1)
题目下载:下载
载入IDA,先看第一部分
首先获得两个key,然后进行输入,输入到s数组。进入f()函数,
进行异或操作,里面有一个text_66函数,跟进:
容易知道text_66是辗转相除,这里的关键是求这两个key,采用爆破枚举方式,代码如下:
- str=[85, 105, 104, 120, 33, 104, 114, 33, 96, 33, 105, 98, 101, 117, 33, 124, 105, 106, 117, 33, 72, 33, 105, 100, 109, 113, 43, 120, 110, 116, 33, 104, 114, 43, 115, 100, 108, 104, 111, 101, 33, 120, 110, 116, 33, 117, 110, 33, 98, 73, 100, 98, 106, 33, 117, 105, 100, 33, 96, 115, 115, 96, 120, 33, 96, 111, 101, 33, 117, 105, 115, 100, 100, 33, 111, 116, 102, 99, 100, 115, 114, 33, 98, 96, 111, 33, 119, 98, 100, 118, 33, 96, 114, 33, 96, 33, 102, 115, 110, 116, 113]
-
- def f(k1_0,k2_0):
- for i in range(len(str)):
- k1_0 = (str[i] + k1_0) % 300
- k2_0 = (str[i] + k2_0) % 300
- str[i] ^= text_66(k1_0, k2_0)
-
- def text_66(a,b):
- aa=a
- ba=b
- if a<b:
- aa,ba=ba,aa
- if ba:
- result = text_66(ba, aa % ba)
- else:
- result = aa
- return result
-
- for x in range(100):
- for y in range(100):
- str=[85, 105, 104, 120, 33, 104, 114, 33, 96, 33, 105, 98, 101, 117, 33, 124, 105, 106, 117, 33, 72, 33, 105, 100, 109, 113, 43, 120, 110, 116, 33, 104, 114, 43, 115, 100, 108, 104, 111, 101, 33, 120, 110, 116, 33, 117, 110, 33, 98, 73, 100, 98, 106, 33, 117, 105, 100, 33, 96, 115, 115, 96, 120, 33, 96, 111, 101, 33, 117, 105, 115, 100, 100, 33, 111, 116, 102, 99, 100, 115, 114, 33, 98, 96, 111, 33, 119, 98, 100, 118, 33, 96, 114, 33, 96, 33, 102, 115, 110, 116, 113]
- f(x,y)
- flag=1
- for i in str:
- if i>=127 or i<32:
- flag=0
- break
- if flag==1:
- print(bytes(str))
观察结果:I help you is remind you to check the array and three numbers can view as a group可以知道提示三个数可以看成一组,就可以想到RGB(之前没见过,所以我不能反应过来这个是RGB)
在根据给的hint:
可以写有关RGB的代码(这里学习一下)
- from PIL import Image
-
- with open('array.txt绝对地址', 'r') as f:
- data = f.readlines() # txt中所有字符串读入data
-
- for line in data:
- list = line.split(' ') # 将单个数据分隔开存好
- f.close()
-
- x = 637 # x坐标 通过对txt里的行数进行整数分解 宽度
- y = 561 # y坐标 x * y = 行数 高度
-
- im = Image.new("RGB", (x, y)) # 创建图片
-
- index = 0
-
- for j in range(0, y): # 通过每个rgb点生成图片
- for i in range(0, x):
- im.putpixel((i, j), (int(list[index]), int(list[index + 1]), int(list[index + 2]))) # 将rgb转化为像素
- index += 3
-
- im.show()
运行后发现图片
再根据提示
message是英文形式,根据我想打篮球得到:I want to play basketball,又因为要凑够28个,所以是I want to play basketballI w
在看main第二部分代码:
刚才得到的便是str数组,num数组又已知,可以异或得到flag
- flag=[1, 100, 52, 53, 40, 15, 4, 69, 46, 109, 47, 40, 55, 55, 92, 94, 62, 70, 23, 72, 8, 82, 29, 65, 16, 117, 117, 10]
- xor_key='I want to play basketballI w'
- for i in range(len(flag)):
- flag[i]^=ord(xor_key[i])
- print(bytes(flag))
-
- #HDCTF{$1AM_DVN|<_5|-|0|-|<U}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。