批量替换字符串中的某子串序列为对应的另一子串序列(z3求解器解多元方程时很好用)

标题有点拗口,看问题需求就理解了------

一,问题需求

有一个字符串s1,其中包含a1、a2、a3到a14这些子串,我需要将s1中出现的这些子串全部对应替换成v[0],v[1],v[2]到v[13]等等,应该怎么编写程序

例如:

s1='a1 * 88 + a2 * 67 + a3 * 65 - a4 * 5 + a5 * 43 + a6 * 89 + a7 * 25 + a8 * 13 - a9 * 36 + a10 * 15 + a11 * 11 + a12 * 47 - a13 * 60 + a14 * 29 == 22748'

替换后:

s1='v[0] * 88 + v[1] * 67 + v[2] * 65 - v[3] * 5 + v[4] * 43 + v[5] * 89 + v[6] * 25 + v[7] * 13 - v[8] * 36 + v[9] * 15 + v[10] * 11 + v[11] * 47 - v[12] * 60 + v[13] * 29 == 22748'


二,应用场景

博主在刷ctf的re方向题目时遇到求解多(14)元方程问题,之前其实已经写过一篇z3求解器的相关文章->z3求解器脚本(CTF-reverse必备)_ctf z3-CSDN博客

该脚本用到了列表,默认方程的未知数都是列表中的元素,可以用类似v[index]的形式存储或访问,但是题目中出现的方程一般是以a1、a2或x1、x2等序列形式来表示未知数的,手搓当然可以一个个全部替换,但显然太不优雅了

因此可以用此脚本对方程中出现的未知数序列统一替换成v[0]、v[1]等序列形式,以便于我们直接套用z3求解器的脚本!


三,完整脚本

只要脚本省时间的可以不看后面的解释了(博主一向这么直白,还望留赞o(* ̄▽ ̄*)ブ)

因为约束方程一般未知数较多故字符串较长,因此一个一个方程进行处理会比较方便,每替换一次你需要自己更改s1的内容直到完成题目所给出的所有方程的处理

python 复制代码
import re
def replace_func(match):
    index = int(match.group(1)) - 1 #match.group(1)是第一个括号匹配部分,在此处即a后的数字1到14
    return str(f'v[{index}]') #返回字符串'v[a后数字-1]',用其替换匹配到的an
if __name__=='__main__':
    s1 = "a1 * 88 + a2 * 67 + a3 * 65 - a4 * 5 + a5 * 43 + a6 * 89 + a7 * 25 + a8 * 13 - a9 * 36 + a10 * 15 + a11 * 11 + a12 * 47 - a13 * 60 + a14 * 29 == 22748" #定义包含an的字符串

    s1 = re.sub(r'a(1[0-4]|[1-9])', replace_func, s1)
    #sub函数参数, pattern、repl、string分别表示:正则表达式匹配规则、替换后结果(可以是函数也可以是常量)、要被查找替换的原始字符串
print(s1)

四,脚本详解

该脚本的主要难点在于re(正则表达式)模块的相关API的使用

s1是原始字符串,我们希望将其中的a1、a2...a14等序列替换为对应的v[0]、v[1]...v[13],以便于直接复制该脚本替换后的字符串作为z3求解器脚本的约束方程组

你需要了解sub()函数的机理------Python 正则表达式 | 菜鸟教程 (runoob.com)

省流解释------re.sub(pattern, repl, string)

sub函数参数, pattern、repl、string分别表示:正则表达式匹配规则、替换后结果(可以是函数也可以是常量)、要被查找替换的原始字符串
此处pattern参数为r'a(1[0-4]|[1-9])',意味匹配a后带整数10到14或1到9的子串,请注意,1[0-4]必须写于[1-9]之前,否则会出现a10中的a1被错误匹配成v[0]的情况导致替换结果为v[0]0

python 复制代码
s1 = re.sub(r'a(1[0-4]|[1-9])', replace_func, s1)

替换结果函数

当参数repl是固定值时被匹配的子串都会替换成固定值,但是我们希望实现的是

a1->v[0]、a2->v[1]的映射,因此使用函数可以实现复杂替换

此处的match.group(1)是第一个括号匹配部分,在此处即a后的数字1到14

如果是match.group(0)则是整个匹配到的子串,即a0、a1...a14

获取到a后的数字,根据替换的映射关系减一作为新的序列编号,返回格式为v[index]的新序列,这些序列中的v[0]、v[1]...v[13]将对应替换匹配到的a1、a2...a14

最后直接输出替换后的结果即可

python 复制代码
def replace_func(match):
    index = int(match.group(1)) - 1 #match.group(1)是第一个括号匹配部分,在此处即a后的数字1到14
    return str(f'v[{index}]') #返回字符串'v[a后数字-1]',用其替换匹配到的an

五,例题放送

[羊城杯 2020]login

题目链接->NSSCTF | 在线CTF平台

python 复制代码
import sys
input1 = input("input something:")
if len(input1) != 14:
    print("Wrong length!")
    sys.exit()
else:
    code = []
    for i in range(13):
        code.append(ord(input1[i]) ^ ord(input1[i + 1]))

    code.append(ord(input1[13]))
    a1 = code[2]
    a2 = code[1]
    a3 = code[0]
    a4 = code[3]
    a5 = code[4]
    a6 = code[5]
    a7 = code[6]
    a8 = code[7]
    a9 = code[9]
    a10 = code[8]
    a11 = code[10]
    a12 = code[11]
    a13 = code[12]
    a14 = code[13]
    if (a1 * 88 + a2 * 67 + a3 * 65 - a4 * 5 + a5 * 43 + a6 * 89 + a7 * 25 + a8 * 13 - a9 * 36 + a10 * 15 + a11 * 11 + a12 * 47 - a13 * 60 + a14 * 29 == 22748) & (a1 * 89 + a2 * 7 + a3 * 12 - a4 * 25 + a5 * 41 + a6 * 23 + a7 * 20 - a8 * 66 + a9 * 31 + a10 * 8 + a11 * 2 - a12 * 41 - a13 * 39 + a14 * 17 == 7258) & (a1 * 28 + a2 * 35 + a3 * 16 - a4 * 65 + a5 * 53 + a6 * 39 + a7 * 27 + a8 * 15 - a9 * 33 + a10 * 13 + a11 * 101 + a12 * 90 - a13 * 34 + a14 * 23 == 26190) & (a1 * 23 + a2 * 34 + a3 * 35 - a4 * 59 + a5 * 49 + a6 * 81 + a7 * 25 + (a8 << 7) - a9 * 32 + a10 * 75 + a11 * 81 + a12 * 47 - a13 * 60 + a14 * 29 == 37136) & (a1 * 38 + a2 * 97 + a3 * 35 - a4 * 52 + a5 * 42 + a6 * 79 + a7 * 90 + a8 * 23 - a9 * 36 + a10 * 57 + a11 * 81 + a12 * 42 - a13 * 62 - a14 * 11 == 27915) & (a1 * 22 + a2 * 27 + a3 * 35 - a4 * 45 + a5 * 47 + a6 * 49 + a7 * 29 + a8 * 18 - a9 * 26 + a10 * 35 + a11 * 41 + a12 * 40 - a13 * 61 + a14 * 28 == 17298) & (a1 * 12 + a2 * 45 + a3 * 35 - a4 * 9 - a5 * 42 + a6 * 86 + a7 * 23 + a8 * 85 - a9 * 47 + a10 * 34 + a11 * 76 + a12 * 43 - a13 * 44 + a14 * 65 == 19875) & (a1 * 79 + a2 * 62 + a3 * 35 - a4 * 85 + a5 * 33 + a6 * 79 + a7 * 86 + a8 * 14 - a9 * 30 + a10 * 25 + a11 * 11 + a12 * 57 - a13 * 50 - a14 * 9 == 22784) & (a1 * 8 + a2 * 6 + a3 * 64 - a4 * 85 + a5 * 73 + a6 * 29 + a7 * 2 + a8 * 23 - a9 * 36 + a10 * 5 + a11 * 2 + a12 * 47 - a13 * 64 + a14 * 27 == 9710) & (a1 * 67 - a2 * 68 + a3 * 68 - a4 * 51 - a5 * 43 + a6 * 81 + a7 * 22 - a8 * 12 - a9 * 38 + a10 * 75 + a11 * 41 + a12 * 27 - a13 * 52 + a14 * 31 == 13376) & (a1 * 85 + a2 * 63 + a3 * 5 - a4 * 51 + a5 * 44 + a6 * 36 + a7 * 28 + a8 * 15 - a9 * 6 + a10 * 45 + a11 * 31 + a12 * 7 - a13 * 67 + a14 * 78 == 24065) & (a1 * 47 + a2 * 64 + a3 * 66 - a4 * 5 + a5 * 43 + a6 * 112 + a7 * 25 + a8 * 13 - a9 * 35 + a10 * 95 + a11 * 21 + a12 * 43 - a13 * 61 + a14 * 20 == 27687) & (a1 * 89 + a2 * 67 + a3 * 85 - a4 * 25 + a5 * 49 + a6 * 89 + a7 * 23 + a8 * 56 - a9 * 92 + a10 * 14 + a11 * 89 + a12 * 47 - a13 * 61 - a14 * 29 == 29250) & (a1 * 95 + a2 * 34 + a3 * 62 - a4 * 9 - a5 * 43 + a6 * 83 + a7 * 25 + a8 * 12 - a9 * 36 + a10 * 16 + a11 * 51 + a12 * 47 - a13 * 60 - a14 * 24 == 15317):
        print("flag is GWHT{md5(your_input)}")
        print("Congratulations and have fun!")
    else:
        print("Sorry,plz try again...")

wp:

本题考察多元方程求解,可以使用z3求解器->z3求解器脚本(CTF-reverse必备)_ctf z3-CSDN博客

但是约束方程没法直接套用,有两点原因,其一为所有方程都作为if的条件用&连接,导致复制的过程很繁琐,其二为方程未知数是a1、a2...a14,但套用到z3求解器中的方程未知数需要是v[index]的列表访问形式(当然可以修改z3求解脚本,但那样会更加繁琐且通用性较差

我们可以先编写一段脚本来处理方程,以&作为分隔符分隔所有方程并输出

python 复制代码
s = 'a1 * 88 + a2 * 67 + a3 * 65 - a4 * 5 + a5 * 43 + a6 * 89 + a7 * 25 + a8 * 13 - a9 * 36 + a10 * 15 + a11 * 11 + a12 * 47 - a13 * 60 + a14 * 29 == 22748) & (a1 * 89 + a2 * 7 + a3 * 12 - a4 * 25 + a5 * 41 + a6 * 23 + a7 * 20 - a8 * 66 + a9 * 31 + a10 * 8 + a11 * 2 - a12 * 41 - a13 * 39 + a14 * 17 == 7258) & (a1 * 28 + a2 * 35 + a3 * 16 - a4 * 65 + a5 * 53 + a6 * 39 + a7 * 27 + a8 * 15 - a9 * 33 + a10 * 13 + a11 * 101 + a12 * 90 - a13 * 34 + a14 * 23 == 26190) & (a1 * 23 + a2 * 34 + a3 * 35 - a4 * 59 + a5 * 49 + a6 * 81 + a7 * 25 + (a8 << 7) - a9 * 32 + a10 * 75 + a11 * 81 + a12 * 47 - a13 * 60 + a14 * 29 == 37136) & (a1 * 38 + a2 * 97 + a3 * 35 - a4 * 52 + a5 * 42 + a6 * 79 + a7 * 90 + a8 * 23 - a9 * 36 + a10 * 57 + a11 * 81 + a12 * 42 - a13 * 62 - a14 * 11 == 27915) & (a1 * 22 + a2 * 27 + a3 * 35 - a4 * 45 + a5 * 47 + a6 * 49 + a7 * 29 + a8 * 18 - a9 * 26 + a10 * 35 + a11 * 41 + a12 * 40 - a13 * 61 + a14 * 28 == 17298) & (a1 * 12 + a2 * 45 + a3 * 35 - a4 * 9 - a5 * 42 + a6 * 86 + a7 * 23 + a8 * 85 - a9 * 47 + a10 * 34 + a11 * 76 + a12 * 43 - a13 * 44 + a14 * 65 == 19875) & (a1 * 79 + a2 * 62 + a3 * 35 - a4 * 85 + a5 * 33 + a6 * 79 + a7 * 86 + a8 * 14 - a9 * 30 + a10 * 25 + a11 * 11 + a12 * 57 - a13 * 50 - a14 * 9 == 22784) & (a1 * 8 + a2 * 6 + a3 * 64 - a4 * 85 + a5 * 73 + a6 * 29 + a7 * 2 + a8 * 23 - a9 * 36 + a10 * 5 + a11 * 2 + a12 * 47 - a13 * 64 + a14 * 27 == 9710) & (a1 * 67 - a2 * 68 + a3 * 68 - a4 * 51 - a5 * 43 + a6 * 81 + a7 * 22 - a8 * 12 - a9 * 38 + a10 * 75 + a11 * 41 + a12 * 27 - a13 * 52 + a14 * 31 == 13376) & (a1 * 85 + a2 * 63 + a3 * 5 - a4 * 51 + a5 * 44 + a6 * 36 + a7 * 28 + a8 * 15 - a9 * 6 + a10 * 45 + a11 * 31 + a12 * 7 - a13 * 67 + a14 * 78 == 24065) & (a1 * 47 + a2 * 64 + a3 * 66 - a4 * 5 + a5 * 43 + a6 * 112 + a7 * 25 + a8 * 13 - a9 * 35 + a10 * 95 + a11 * 21 + a12 * 43 - a13 * 61 + a14 * 20 == 27687) & (a1 * 89 + a2 * 67 + a3 * 85 - a4 * 25 + a5 * 49 + a6 * 89 + a7 * 23 + a8 * 56 - a9 * 92 + a10 * 14 + a11 * 89 + a12 * 47 - a13 * 61 - a14 * 29 == 29250) & (a1 * 95 + a2 * 34 + a3 * 62 - a4 * 9 - a5 * 43 + a6 * 83 + a7 * 25 + a8 * 12 - a9 * 36 + a10 * 16 + a11 * 51 + a12 * 47 - a13 * 60 - a14 * 24 == 15317'
lst = s.split('&')
for i in lst:
    print(i) #默认输出换行隔开各个方程方便复制
"""下面是输出结果
a1 * 88 + a2 * 67 + a3 * 65 - a4 * 5 + a5 * 43 + a6 * 89 + a7 * 25 + a8 * 13 - a9 * 36 + a10 * 15 + a11 * 11 + a12 * 47 - a13 * 60 + a14 * 29 == 22748) 
 (a1 * 89 + a2 * 7 + a3 * 12 - a4 * 25 + a5 * 41 + a6 * 23 + a7 * 20 - a8 * 66 + a9 * 31 + a10 * 8 + a11 * 2 - a12 * 41 - a13 * 39 + a14 * 17 == 7258)   
 (a1 * 28 + a2 * 35 + a3 * 16 - a4 * 65 + a5 * 53 + a6 * 39 + a7 * 27 + a8 * 15 - a9 * 33 + a10 * 13 + a11 * 101 + a12 * 90 - a13 * 34 + a14 * 23 == 26190)
 (a1 * 23 + a2 * 34 + a3 * 35 - a4 * 59 + a5 * 49 + a6 * 81 + a7 * 25 + (a8 << 7) - a9 * 32 + a10 * 75 + a11 * 81 + a12 * 47 - a13 * 60 + a14 * 29 == 37136)
 (a1 * 38 + a2 * 97 + a3 * 35 - a4 * 52 + a5 * 42 + a6 * 79 + a7 * 90 + a8 * 23 - a9 * 36 + a10 * 57 + a11 * 81 + a12 * 42 - a13 * 62 - a14 * 11 == 27915)
 (a1 * 22 + a2 * 27 + a3 * 35 - a4 * 45 + a5 * 47 + a6 * 49 + a7 * 29 + a8 * 18 - a9 * 26 + a10 * 35 + a11 * 41 + a12 * 40 - a13 * 61 + a14 * 28 == 17298)
 (a1 * 12 + a2 * 45 + a3 * 35 - a4 * 9 - a5 * 42 + a6 * 86 + a7 * 23 + a8 * 85 - a9 * 47 + a10 * 34 + a11 * 76 + a12 * 43 - a13 * 44 + a14 * 65 == 19875)

 (a1 * 79 + a2 * 62 + a3 * 35 - a4 * 85 + a5 * 33 + a6 * 79 + a7 * 86 + a8 * 14 - a9 * 30 + a10 * 25 + a11 * 11 + a12 * 57 - a13 * 50 - a14 * 9 == 22784)

 (a1 * 8 + a2 * 6 + a3 * 64 - a4 * 85 + a5 * 73 + a6 * 29 + a7 * 2 + a8 * 23 - a9 * 36 + a10 * 5 + a11 * 2 + a12 * 47 - a13 * 64 + a14 * 27 == 9710)     
 (a1 * 67 - a2 * 68 + a3 * 68 - a4 * 51 - a5 * 43 + a6 * 81 + a7 * 22 - a8 * 12 - a9 * 38 + a10 * 75 + a11 * 41 + a12 * 27 - a13 * 52 + a14 * 31 == 13376)
 (a1 * 85 + a2 * 63 + a3 * 5 - a4 * 51 + a5 * 44 + a6 * 36 + a7 * 28 + a8 * 15 - a9 * 6 + a10 * 45 + a11 * 31 + a12 * 7 - a13 * 67 + a14 * 78 == 24065)  
 (a1 * 47 + a2 * 64 + a3 * 66 - a4 * 5 + a5 * 43 + a6 * 112 + a7 * 25 + a8 * 13 - a9 * 35 + a10 * 95 + a11 * 21 + a12 * 43 - a13 * 61 + a14 * 20 == 27687)
 (a1 * 89 + a2 * 67 + a3 * 85 - a4 * 25 + a5 * 49 + a6 * 89 + a7 * 23 + a8 * 56 - a9 * 92 + a10 * 14 + a11 * 89 + a12 * 47 - a13 * 61 - a14 * 29 == 29250)
 (a1 * 95 + a2 * 34 + a3 * 62 - a4 * 9 - a5 * 43 + a6 * 83 + a7 * 25 + a8 * 12 - a9 * 36 + a10 * 16 + a11 * 51 + a12 * 47 - a13 * 60 - a14 * 24 == 15317
"""

此时再复制单个方程就方便多了,分别将它们代入替换脚本中的s1变量,以第一个方程为例子

python 复制代码
#coding=gbk
import re
def replace_func(match):
    index = int(match.group(1)) - 1 #match.group(1)是第一个括号匹配部分,在此处即a后的数字0到14
    return str(f'v[{index}]') #返回字符串'v[a后数字-1]',用其替换匹配到的an
if __name__=='__main__':
    s1 = "a1 * 88 + a2 * 67 + a3 * 65 - a4 * 5 + a5 * 43 + a6 * 89 + a7 * 25 + a8 * 13 - a9 * 36 + a10 * 15 + a11 * 11 + a12 * 47 - a13 * 60 + a14 * 29 == 22748" #定义包含an的字符串

    s1 = re.sub(r'a(1[0-5]|[1-9])', replace_func, s1)
    #sub函数参数, pattern、repl、string分别表示:正则表达式匹配规则、替换后结果(可以是函数也可以是常量)、要被查找替换的原始字符串
print(s1)
#输出结果
#v[0] * 88 + v[1] * 67 + v[2] * 65 - v[3] * 5 + v[4] * 43 + v[5] * 89 + v[6] * 25 + v[7] * 13 - v[8] * 36 + v[9] * 15 + v[10] * 11 + v[11] * 47 - v[12] * 60 + v[13] * 29 == 22748

其余方程如法炮制,得到替换未知数名称的方程后,同时将其放入z3求解器的脚本中

注意,第4个方程中出现了<<7,z3求解不支持位移操作,将其替换为等价的*128即可

解出方程后不要太激动,仔细审题,还有一部异或操作,要异或回去才是正确答案,所以先把方程解存在列表里

最后输出的结果根据题目是要md5值,说明不是具体的字符串,那就直接打印整数,然后用hashlib模块中的API进行md5加密

python 复制代码
# coding=gbk
from z3 import *
import hashlib  # 题目最后得到的字符串要md5加密

# 创建未知数变量
v = [Int(f'v{i}') for i in range(0, 14)]  # 14个未知数

# 创建解释器对象
solver = Solver()  # 创建一个求解器对象
# 添加约束方程
# 不要漏也不要多,题目是14个
solver.add(v[0] * 88 + v[1] * 67 + v[2] * 65 - v[3] * 5 + v[4] * 43 + v[5] * 89 + v[6] * 25 +
           v[7] * 13 - v[8] * 36 + v[9] * 15 + v[10] * 11 + v[11] * 47 - v[12] * 60 + v[13] * 29 == 22748)
solver.add(v[0] * 89 + v[1] * 7 + v[2] * 12 - v[3] * 25 + v[4] * 41 + v[5] * 23 + v[6] * 20 -
           v[7] * 66 + v[8] * 31 + v[9] * 8 + v[10] * 2 - v[11] * 41 - v[12] * 39 + v[13] * 17 == 7258)
solver.add(v[0] * 28 + v[1] * 35 + v[2] * 16 - v[3] * 65 + v[4] * 53 + v[5] * 39 + v[6] * 27 +
           v[7] * 15 - v[8] * 33 + v[9] * 13 + v[10] * 101 + v[11] * 90 - v[12] * 34 + v[13] * 23 == 26190)
solver.add(v[0] * 23 + v[1] * 34 + v[2] * 35 - v[3] * 59 + v[4] * 49 + v[5] * 81 + v[6] * 25 +
           (v[7] * 128) - v[8] * 32 + v[9] * 75 + v[10] * 81 + v[11] * 47 - v[12] * 60 + v[13] * 29 == 37136)
solver.add(v[0] * 38 + v[1] * 97 + v[2] * 35 - v[3] * 52 + v[4] * 42 + v[5] * 79 + v[6] * 90 +
           v[7] * 23 - v[8] * 36 + v[9] * 57 + v[10] * 81 + v[11] * 42 - v[12] * 62 - v[13] * 11 == 27915)
solver.add(v[0] * 22 + v[1] * 27 + v[2] * 35 - v[3] * 45 + v[4] * 47 + v[5] * 49 + v[6] * 29 +
           v[7] * 18 - v[8] * 26 + v[9] * 35 + v[10] * 41 + v[11] * 40 - v[12] * 61 + v[13] * 28 == 17298)
solver.add(v[0] * 12 + v[1] * 45 + v[2] * 35 - v[3] * 9 - v[4] * 42 + v[5] * 86 + v[6] * 23 +
           v[7] * 85 - v[8] * 47 + v[9] * 34 + v[10] * 76 + v[11] * 43 - v[12] * 44 + v[13] * 65 == 19875)
solver.add(v[0] * 79 + v[1] * 62 + v[2] * 35 - v[3] * 85 + v[4] * 33 + v[5] * 79 + v[6] * 86 +
           v[7] * 14 - v[8] * 30 + v[9] * 25 + v[10] * 11 + v[11] * 57 - v[12] * 50 - v[13] * 9 == 22784)
solver.add(v[0] * 8 + v[1] * 6 + v[2] * 64 - v[3] * 85 + v[4] * 73 + v[5] * 29 + v[6] * 2 +
           v[7] * 23 - v[8] * 36 + v[9] * 5 + v[10] * 2 + v[11] * 47 - v[12] * 64 + v[13] * 27 == 9710)
solver.add(v[0] * 67 - v[1] * 68 + v[2] * 68 - v[3] * 51 - v[4] * 43 + v[5] * 81 + v[6] * 22 -
           v[7] * 12 - v[8] * 38 + v[9] * 75 + v[10] * 41 + v[11] * 27 - v[12] * 52 + v[13] * 31 == 13376)
solver.add(v[0] * 85 + v[1] * 63 + v[2] * 5 - v[3] * 51 + v[4] * 44 + v[5] * 36 + v[6] * 28 +
           v[7] * 15 - v[8] * 6 + v[9] * 45 + v[10] * 31 + v[11] * 7 - v[12] * 67 + v[13] * 78 == 24065)
solver.add(v[0] * 47 + v[1] * 64 + v[2] * 66 - v[3] * 5 + v[4] * 43 + v[5] * 112 + v[6] * 25 +
           v[7] * 13 - v[8] * 35 + v[9] * 95 + v[10] * 21 + v[11] * 43 - v[12] * 61 + v[13] * 20 == 27687)
solver.add(v[0] * 89 + v[1] * 67 + v[2] * 85 - v[3] * 25 + v[4] * 49 + v[5] * 89 + v[6] * 23 +
           v[7] * 56 - v[8] * 92 + v[9] * 14 + v[10] * 89 + v[11] * 47 - v[12] * 61 - v[13] * 29 == 29250)
solver.add(v[0] * 95 + v[1] * 34 + v[2] * 62 - v[3] * 9 - v[4] * 43 + v[5] * 83 + v[6] * 25 +
           v[7] * 12 - v[8] * 36 + v[9] * 16 + v[10] * 51 + v[11] * 47 - v[12] * 60 - v[13] * 24 == 15317)

solution = []
# 求解并转化为字符输出,得到flag
if solver.check() == sat:  # check()方法用来判断是否有解,sat(即satisify)表示满足有解
    ans = solver.model()  # model()方法得到解
    for i in v:
        solution.append(ans[i].as_long())  # 将解保存在solution列表中
# solution=[119, 24, 10, 7, 104, 43, 28, 91, 52, 108, 88, 74, 88, 33]
# 一般不会无解,如果无解八成是未知数变量的类型不符合,或约束方程添加错误
else:
    print("no ans!")

print(solution)
# 分析题目得知,解和输入的字符顺序不是一一对应的,需要按输入字符串code的索引顺序重新排列解的顺序
index = [2, 1, 0, 3, 4, 5, 6, 7, 9, 8, 10, 11, 12, 13]
data = []
for i in range(len(index)):
    # 按index的顺序重排solution元素,新元素存入data[]中,注意不能直接放回solution[],细想一下就明白了
    data.append(solution[index[i]])
for i in range(12, -1, -1):
    # code.append(ord(input1[i]) ^ ord(input1[i + 1])) 异或解密
    data[i] ^= data[i + 1]
flag = ''
for i in data:
    flag += chr(i)  # 结果:U_G07_th3_k3y!,题目说用md5加密才是flag

# 下面来进行md5加密
md5 = hashlib.md5()  # 创建md5对象
md5.update(flag.encode())  # 更新md5对象的信息,必须传入bytes类型的数据(b'xxx'格式)
print(md5.hexdigest())  # 获取加密后的内容:58964088b637e50d3a22b9510c1d1ef8
相关推荐
吾即是光3 天前
[HNCTF 2022 Week1]你想学密码吗?
ctf
吾即是光4 天前
[NSSCTF 2022 Spring Recruit]factor
ctf
吾即是光4 天前
[LitCTF 2023]easy_math (中级)
ctf
吾即是光4 天前
[HNCTF 2022 Week1]baby_rsa
ctf
云梦姐姐6 天前
Bugku-CTF getshell
ctf·wp
l2xcty6 天前
【网络安全】Web安全基础- 第一节:web前置基础知识
安全·web安全·网络安全·ctf
CH13hh9 天前
常回家看看之Tcache Stashing Unlink Attack
pwn·ctf
摸鱼也很难11 天前
文件包含漏洞下 日志文件的利用 && session文件竞争
ctf·ctfshow·文件包含进阶·web 80 81·web 87
lally.11 天前
CTF misc 流量分析特训
ctf·misc·流量分析
吾即是光12 天前
[SWPUCTF 2021 新生赛]crypto4
ctf