Z3 学前准备 先在本地机上安装Z3求解器
win+r cmd打开终端
然后去pycharm或者vscode去输入以下代码去看看是否可以正常运行:
1 2 3 4 5 6 7 8 9 10 11 from z3 import *a,b,c = BitVecs('a b c' ,32 ) d,e,f = BitVecs('d e f' ,32 ) g,h,i = BitVecs('g h i' ,32 ) key = [a,b,c,d,e,f,g,h] s = Solver() s.add() check = s.check() print (check)model = s.model() print (model)
运行正常会显示:没报错
定义声明变量 1 2 3 4 5 6 7 8 9 10 11 12 from z3 import *a = Int('a' ) a,b = Ints('a b' ) from z3 import *a = Real('a' ) a,b = Reals('a b' ) from z3 import *a = BitVec('a' ,8 ) a, b = BitVec('a b' ,8 )
z3函数使用 简单的使用举例:
1 2 3 4 5 6 7 8 from z3 import *a,b = Ints('a b' ) solve(a>3 ,b<8 ,2 *a+b==16 )
如果是出现有多种情况的时候,会只输出最近的一种情况:
在解决问题是很多情况下是有多个约束条件的。这个时候可以先生成一个求解器对象(Solver() ),然后就可以方便的向其中添加更多的约束条件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from z3 import *a,b = Ints('a b' ) solver = Solver() solver.add(a+b==10 ) solver.add(a-b==6 ) if solver.check() == sat: ans = solver.model() print (ans) print (ans[a]) else : print ("no ans!" )
Buuctf [GWCTF 2019]pyre 下载文件,是一个pyc文件,使用uncompyle6命令反编译一下
uncompyle6 attachment.pyc > 1.py
生成了新的py文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 print 'Welcome to Re World!' print 'Your input1 is your flag~' l = len (input1) for i in range (l): num = ((input1[i] + i) % 128 + 128 ) % 128 code += num for i in range (l - 1 ): code[i] = code[i] ^ code[i + 1 ] print codecode = ['\x1f' , '\x12' , '\x1d' , '(' , '0' , '4' , '\x01' , '\x06' , '\x14' , '4' , ',' , '\x1b' , 'U' , '?' , 'o' , '6' , '*' , ':' , '\x01' , 'D' , ';' , '%' , '\x13' ]
分析上面的加密过程,大概是输入了一串flag,然后经过第一段加i模除的运算,然后再把得到的结果进行一个前后异或计算,最后得到flag
解题脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 from z3 import *lb=[] flag=[] code = ['\x1f' , '\x12' , '\x1d' , '(' , '0' , '4' , '\x01' , '\x06' , '\x14' , '4' , ',' ,'\x1b' , 'U' , '?' , 'o' , '6' , '*' , ':' , '\x01' , 'D' , ';' , '%' , '\x13' ] code = [ord (i) for i in code] l=len (code) for i in range (l-1 ): code[l-i-2 ] ^= (code[l-i-1 ]) solve = Solver() for i,v in enumerate (code): x = z3.Int('v%d' % i) solve.add(x > 31 ) solve.add(x < 128 ) solve.add(((x+ i) % 128 + 128 ) % 128 == v) lb.append(x) if solve.check()==sat: flag=solve.model() for i in lb: print (chr (flag[i].as_long()),end='' )
[GUET-CTF2019]re 首先拖入die查看,有壳,upx壳,64位
拖入虚拟机里面脱壳
然后拖到64位ida中反编译一下,没有main函数,但是有点离谱
但是找到了start函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int v6; int v7; int v8; int v9; __int64 result; __int64 v11; unsigned __int64 v12; v12 = __readfsqword(0x28 u); sub_40F950((unsigned int )"input your flag:" , a2, a3, a4, a5, a6, 0LL , 0LL , 0LL , 0LL ); sub_40FA80((unsigned int )"%s" , (unsigned int )&v11, v6, v7, v8, v9, v11); if ( (unsigned int )sub_4009AE(&v11) ) sub_410350("Correct!" ); else sub_410350("Wrong!" ); result = 0LL ; if ( __readfsqword(0x28 u) != v12 ) sub_443550(); return result; }
可以看到有一个if语句,只要if达成,就可以输出正确,所以去看看那个函数,然后找到了一堆if
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 { if ( 1629056 * *a1 != 166163712 ) return 0LL ; if ( 6771600 * a1[1 ] != 731332800 ) return 0LL ; if ( 3682944 * a1[2 ] != 357245568 ) return 0LL ; if ( 10431000 * a1[3 ] != 1074393000 ) return 0LL ; if ( 3977328 * a1[4 ] != 489211344 ) return 0LL ; if ( 5138336 * a1[5 ] != 518971936 ) return 0LL ; if ( 7532250 * a1[7 ] != 406741500 ) return 0LL ; if ( 5551632 * a1[8 ] != 294236496 ) return 0LL ; if ( 3409728 * a1[9 ] != 177305856 ) return 0LL ; if ( 13013670 * a1[10 ] != 650683500 ) return 0LL ; if ( 6088797 * a1[11 ] != 298351053 ) return 0LL ; if ( 7884663 * a1[12 ] != 386348487 ) return 0LL ; if ( 8944053 * a1[13 ] != 438258597 ) return 0LL ; if ( 5198490 * a1[14 ] != 249527520 ) return 0LL ; if ( 4544518 * a1[15 ] != 445362764 ) return 0LL ; if ( 3645600 * a1[17 ] != 174988800 ) return 0LL ; if ( 10115280 * a1[16 ] != 981182160 ) return 0LL ; if ( 9667504 * a1[18 ] != 493042704 ) return 0LL ; if ( 5364450 * a1[19 ] != 257493600 ) return 0LL ; if ( 13464540 * a1[20 ] != 767478780 ) return 0LL ; if ( 5488432 * a1[21 ] != 312840624 ) return 0LL ; if ( 14479500 * a1[22 ] != 1404511500 ) return 0LL ; if ( 6451830 * a1[23 ] != 316139670 ) return 0LL ; if ( 6252576 * a1[24 ] != 619005024 ) return 0LL ; if ( 7763364 * a1[25 ] != 372641472 ) return 0LL ; if ( 7327320 * a1[26 ] != 373693320 ) return 0LL ; if ( 8741520 * a1[27 ] != 498266640 ) return 0LL ; if ( 8871876 * a1[28 ] != 452465676 ) return 0LL ; if ( 4086720 * a1[29 ] != 208422720 ) return 0LL ; if ( 9374400 * a1[30 ] == 515592000 ) return 5759124 * a1[31 ] == 719890500 ; return 0LL ; }
对此,可以用z3约束求解器,通过添加条件来求解,脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 from z3 import *s = Solver() a1 = [0 ]*32 for i in range (32 ): a1[i] = Int('a1[' +str (i)+']' ) s.add( 1629056 * a1[0 ] == 166163712 ) s.add( 6771600 * a1[1 ] == 731332800 ) s.add( 3682944 * a1[2 ] == 357245568 ) s.add( 10431000 * a1[3 ] == 1074393000 ) s.add( 3977328 * a1[4 ] == 489211344 ) s.add( 5138336 * a1[5 ] == 518971936 ) s.add( 7532250 * a1[7 ] == 406741500 ) s.add( 5551632 * a1[8 ] == 294236496 ) s.add( 3409728 * a1[9 ] == 177305856 ) s.add( 13013670 * a1[10 ] == 650683500 ) s.add( 6088797 * a1[11 ] == 298351053 ) s.add( 7884663 * a1[12 ] == 386348487 ) s.add( 8944053 * a1[13 ] == 438258597 ) s.add( 5198490 * a1[14 ] == 249527520 ) s.add( 4544518 * a1[15 ] == 445362764 ) s.add( 3645600 * a1[17 ] == 174988800 ) s.add( 10115280 * a1[16 ] == 981182160 ) s.add( 9667504 * a1[18 ] == 493042704 ) s.add( 5364450 * a1[19 ] == 257493600 ) s.add( 13464540 * a1[20 ] == 767478780 ) s.add( 5488432 * a1[21 ] == 312840624 ) s.add( 14479500 * a1[22 ] == 1404511500 ) s.add( 6451830 * a1[23 ] == 316139670 ) s.add( 6252576 * a1[24 ] == 619005024 ) s.add( 7763364 * a1[25 ] == 372641472 ) s.add( 7327320 * a1[26 ] == 373693320 ) s.add( 8741520 * a1[27 ] == 498266640 ) s.add( 8871876 * a1[28 ] == 452465676 ) s.add( 4086720 * a1[29 ] == 208422720 ) s.add( 9374400 * a1[30 ] == 515592000 ) s.add(5759124 * a1[31 ] == 719890500 ) s.check() print (s.model())for i in range (32 ): print (al[il)
然后发现没有a[6],爆破一下得到flag
赛题复现 愚人杯-esay_pyc 本题附件给到的是一个pyc文件,需要用uncompyle6进行反编译成py文件然后才可以查看源代码
uncompyle6 ez_re.pyc > ez_re.py
生成了ez_re.py的源代码文件
拖动到pycharm,查看源码
程序源代码以及程序分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 uncompyle6 version 3.9 .0 print 'Welcome to CTFshow Re!' print 'your flag is here!' flag = '' l = len (flag) for i in range (l): num = ((flag[i] + i) % 114514 + 114514 ) % 114514 code += chr (num) code = map (ord , code) for i in range (l - 4 + 1 ): code[i] = code[i] ^ code[i + 1 ] print codecode = ['\x16' , '\x1d' , '\x1e' , '\x1a' , '\x18' , '\t' , b'\xff' , b'\xd0' , ',' , '\x03' , '\x02' , '\x14' , '8' , 'm' , '\x01' , 'C' , 'D' , b'\xbd' , b'\xf7' , '*' , '\r' , b'\xda' , b'\xf9' , '\x1c' , '&' , '5' , "'" , b'\xda' , b'\xd4' , b'\xd1' , '\x0b' , b'\xc7' , b'\xc7' , '\x1a' , b'\x90' , 'D' , b'\xa1' ]
python解题脚本和分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 -*- encoding:utf-8 -*- code = ['\x16' , '\x1d' , '\x1e' , '\x1a' , '\x18' , '\t' , '\xff' , '\xd0' , ',' , '\x03' , '\x02' , '\x14' , '8' , 'm' , '\x01' , 'C' , 'D' , '\xbd' , '\xf7' , '*' , '\r' , '\xda' , '\xf9' , '\x1c' , '&' , '5' , "'" , '\xda' , '\xd4' , '\xd1' , '\x0b' , '\xc7' , '\xc7' , '\x1a' , '\x90' , 'D' , '\xa1' ] temp=list (map (ord ,code)) for i in range (len (temp)-3 )[::-1 ]: temp[i]=temp[i]^temp[i+1 ] for i in range (len (temp)): print (chr (temp[i]-i),end='' )
有一个小问题,有时候在执行程序的时候,会出现一个报错:Non-UTF-8 code starting with…..
这个报错应该是表示没有utf-8的编码格式,在程序中加入以下代码就可以解决了:
愚人杯-easy_cc 拖到die中查壳,32位无壳
拖入32位ida,f5查看伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 strcpy (v19, "key123" ); sub_941010 ((char *)&Format, v16[0 ]); v4 = _acrt_iob_func(0 ); fgets (Buffer, 100 , v4); v5 = strcspn (Buffer, "\n" ); if ( v5 >= 0x64 ) goto LABEL_16; v15 = v3; Buffer[v5] = 0 ; v6 = 0 ; v7 = strlen (Buffer); if ( v7 ) { v8 = strlen (v19); do { v17[v6] = Buffer[v6] ^ v19[v6 % v8]; ++v6; } while ( v6 < v7 ); if ( v6 >= 0xC9 ) goto LABEL_16; } v17[v6] = 0 ; v9 = 0 ; v10 = strlen (v17); if ( v10 ) { v11 = v16; do { sub_941040 (v11, "%02x" , v17[v9++]); v11 += 2 ; } while ( v9 < v10 ); } v12 = 2 * v9; if ( v12 >= 0xC9 ) { LABEL_16: __report_rangecheckfailure(v15); __debugbreak(); } v16[v12] = 0 ; sub_941010 ("\n" , v15); v13 = strcmp (v16, "08111f425a5c1c1e1a526d410e3a1e5e5d573402165e561216" ); if ( v13 ) v13 = v13 < 0 ? -1 : 1 ; if ( v13 ) sub_941010 ("flag is false: " , v16[0 ]); else sub_941010 ("flag is true: " , v16[0 ]); system ("pause" ); return 0 ; }
可以看到最重要的一句就是:
1 v17[v6] = Buffer[v6] ^ v19[v6 % v8];
这是buffer和v19进行异或计算然后赋值给v16,最后一个strcmp和一些种数字串比较
08111f425a5c1c1e1a526d410e3a1e5e5d573402165e561216
刚开始看不懂和buffer[]进行模除计算的是什么,自己计算一遍之后才知道,是和v19异或完了之后然后继续从头异或的一个算法,就是key123异或完继续key123的顺序异或
然后就可以写一个异或解题脚本了:
1 2 3 4 5 6 7 8 9 list1=[0x08 ,0x11 ,0x1f ,0x42 ,0x5a ,0x5c ,0x1c ,0x1e ,0x1a ,0x52 ,0x6d ,0x41 ,0x0e ,0x3a ,0x1e ,0x5e ,0x5d ,0x57 ,0x34 ,0x02 ,0x16 ,0x5e ,0x56 ,0x12 ,0x16 ] list2=['k' ,'e' ,'y' ,'1' ,'2' ,'3' ] l=len (list2) flag='' for i in range (len (list1)): flag+=chr (list1[i]^ord (list2[(i%l)])) print (flag)
这里看到有字符串就以为是base64或者密码的问题应该改改,这里其实很明显的是16进制的字符串
还有大佬关于list2列表的定义:
1 2 Buffer="key123" buffer=list (Buffer)