来做点练习题吧
Hello World!
Hello World!
在屏幕上输出Hello World!
你已经学会了Hello World! 来写一个机器学习项目吧
代码逆向
一般来说,在crypto或者re部分
会给你一段代码让你理解他的意思
然后写出还原flag的代码
看不懂也没关系,我会写出汉字的题目解释
字符串逆序
题目解释(如果看不懂代码或者看完代码想要验证想法再看)
这里有一段字符串,}nohtyP_ecitcarp_ot_desu_saw_sihT{UNLQ
写一段代码倒序输出结果
异或
from flag import flag #导入flag,这里就是你需要求的部分,不用在意
result = []
for i in flag:
result.append(ord(i)^50)
print("result = ",result)
# result = [99, 126, 124, 103, 73, 102, 90, 91, 65, 109, 69, 83, 65, 109, 71, 65, 87, 86, 109, 70, 93, 109, 66, 64, 83, 81, 70, 91, 81, 87, 109, 98, 75, 70, 90, 93, 92, 79]
#include<stdio.h>
int main(){
char compare[] = {99, 126, 124, 103, 73, 102, 90, 91, 65, 109, 69, 83, 65, 109, 71, 65, 87, 86, 109, 70, 93, 109, 66, 64, 83, 81, 70, 91, 81, 87, 109, 98, 75, 70, 90, 93, 92, 79};
int i;
char flag[38];
scanf("%s",&flag);
for (i=0;i<38;i++)
{
flag[i]^=50;
}
if (strcmp(flag,compare)){
printf("flag incorrect");
}else{
printf("flag correct");
}
}
题目解释(如果看不懂代码或者看完代码想要验证想法再看)
有一个数字类型的列表,被异或了50
写代码还原并输出字符串
示例答案(点击右侧可以复制)
列表相加
from flag import flag #导入flag,这里就是你需要求的部分,不用在意
import random
array1 = []
array2 = []
for i in flag:
gen = random.randint(1,ord(i))
array1.append(ord(i)-gen)
array2.append(gen)
print("array1 =",array1)
print("array2 =",array2)
# array1 = [23, 34, 32, 56, 95, 82, 64, 15, 32, 15, 14, 1, 59, 89, 63, 31, 53, 60, 80, 64, 44, 44, 69, 65, 3, 48, 76, 100, 21, 92, 24, 55, 83, 31, 12, 29, 77, 46]
# array2 = [58, 42, 46, 29, 28, 2, 40, 90, 83, 80, 105, 96, 56, 6, 54, 84, 48, 40, 15, 52, 67, 51, 43, 49, 94, 51, 40, 5, 78, 9, 71, 25, 38, 85, 92, 82, 33, 79]
题目解释(如果看不懂代码或者看完代码想要验证想法再看)
有两个list,都存储了相同数量的数字
将其相加还原为字符串并输出
# array1 = [23, 34, 32, 56, 95, 82, 64, 15, 32, 15, 14, 1, 59, 89, 63, 31, 53, 60, 80, 64, 44, 44, 69, 65, 3, 48, 76, 100, 21, 92, 24, 55, 83, 31, 12, 29, 77, 46]
# array2 = [58, 42, 46, 29, 28, 2, 40, 90, 83, 80, 105, 96, 56, 6, 54, 84, 48, 40, 15, 52, 67, 51, 43, 49, 94, 51, 40, 5, 78, 9, 71, 25, 38, 85, 92, 82, 33, 79]
示例答案(点击右侧可以复制)
array1 = [23, 34, 32, 56, 95, 82, 64, 15, 32, 15, 14, 1, 59, 89, 63, 31, 53, 60, 80, 64, 44, 44, 69, 65, 3, 48, 76, 100, 21, 92, 24, 55, 83, 31, 12, 29, 77, 46]
array2 = [58, 42, 46, 29, 28, 2, 40, 90, 83, 80, 105, 96, 56, 6, 54, 84, 48, 40, 15, 52, 67, 51, 43, 49, 94, 51, 40, 5, 78, 9, 71, 25, 38, 85, 92, 82, 33, 79]
for i in range(len(array1)):
print(chr(array1[i]+array2[i]),end='')
顺序还原
这是NewStarCTF2022新生赛的一道re题,这是exe逆向到py的结果
# uncompyle6 version 3.8.0
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.8.10 (default, Nov 14 2022, 12:59:47)
# [GCC 9.4.0]
# Embedded file name: pyre.py
# Compiled at: 1995-09-28 00:18:56
# Size of source mod 2**32: 272 bytes
flag = ''
encode = 'REla{PSF!!fg}!Y_SN_1_0U'
table = [7, 8, 1, 2, 4, 5, 13, 16, 20, 21, 0, 3, 22, 19, 6, 12, 11, 18, 9, 10, 15, 14, 17]
def enc(input):
tmp = ''
for i in range(len(input)):
tmp += input[table[i]]
return tmp
for i in range(len(encode)):
print(encode[table.index(i)],end='')
if __name__ == '__main__':
print('Please input your flag:')
flag = input()
if len(flag) != 23:
print('Length Wrong!!')
else:
final = enc(flag)
if final == encode:
print('Wow,you get the right flag!!')
else:
print('Sorry,Your input is Wrong')
# okay decompiling pyre.pyc
题目解释(如果看不懂代码或者看完代码想要验证想法再看)
main函数中要求输入flag,比较长度为23
然后使用enc函数把flag加密后和加密的结果进行比较
而enc函数实际是将flag按照列表table中的数字作为index进行置乱
所以我们需要将加密后的encode按照打乱的表逆序回去
示例答案(点击右侧可以复制)
flag = ''
encode = 'REla{PSF!!fg}!Y_SN_1_0U'
table = [7, 8, 1, 2, 4, 5, 13, 16, 20, 21, 0, 3, 22, 19, 6, 12, 11, 18, 9, 10, 15, 14, 17]
for i in range(len(encode)):
# index(i)函数是从list中找出第一个值为i的元素并返回他的下标(index)
# 这里是从0开始,先找到0对应在encode中的位置的那个数,为f,然后放入flag字符串
flag+=encode[table.index(i)]
print(flag)
#flag{PYRE_1S_S0_FUN!!!}
仿射密码
经典的仿射密码,时不时会见到
仿射密码的定义
仿射密码(Affine Cipher)是一种线性密码。它的加密方式是将明文的每个字母替换成密文中的字母,其中明文和密文之间的对应关系可以表示为:
其中,\(x\)是明文中字母的位置,\(C\)是密文中字母的位置,\(a\)和\(b\)是密钥,\(m\)是字母表的大小。解密时使用的是模逆元进行解密:
\(y\)是密文中字母的位置, \(P\)是明文中字母的位置。
原理:
仿射密码的加密和解密都是通过线性变换来实现的,即对明文进行\(ax+b\)的变换,变换后再对\(m\)取模。
其中,\(a\)和\(b\)是密钥,它们用来控制变换的线性参数。
\(a\)和\(b\)必须满足\(a\)与\(m\)互质,才能保证可逆性。
取模\(m\)是为了将密文限制在字母表范围内。
解密时需要使用\(a\)的逆元来进行逆变换, 逆元能确保可逆性。
from flag import flag
from Crypto.Util.number import *
from random import randint
a = randint(2<<2,2<<5)
b = randint(0,2<<6)
assert flag[:5]==b'QLNU{' and flag[-1:]==b'}'
assert GCD(a,b)==1
C = []
for c in flag:
C.append((a*c + b) % 256)
print("C = ",bytes(C))
# C = b'\x8dz\xe8i\x932~\xb5\xdb\x8f\xb7\xfd\xdb\x8fI\xdb\xd9\xa2\x8f\x12\xff\x8f6\xa4\xfdk\x12\xb5k\xd9\x8fV%\x12~\xff\xc8\x01'
题目解释(如果看不懂代码或者看完代码想要验证想法再看)
a = randint(2<<2,2<<5)
randint函数,在给定的两个数范围中取随机值,2<<2是在2的2进制0b10向左扩展两位变成0b1000也就是8,2<<5==64
a就是在8到64中取平均值,b同理
assert flag[:5]==b'QLNU{' and flag[-1:]==b'}'
assert断言函数,在表达式不成立的时候会ERROR结束程序运行
这里表示flag的前五个字符是"QLNU{" 最后一个字符是"}"
assert GCD(a,b)==1
这里是代表a,b的最大公约数是1,就是a b互素,不过用不到,这是affine算法的约束条件
C.append(a*c + b) % 256
重点是这里,这是affine的加密过程,本题和常见仿射密码的区别是模数的大小
常见的为字母表的长度26,而这里用的是整个char类型的范围256
根据仿射密码的性质,可以由C反推回c
解密公式 c = ((a与256的模逆元)*(C-b)) % 256
接下来问题就是怎么求a和b
示例答案(点击右侧可以复制)
C = b'\x8dz\xe8i\x932~\xb5\xdb\x8f\xb7\xfd\xdb\x8fI\xdb\xd9\xa2\x8f\x12\xff\x8f6\xa4\xfdk\x12\xb5k\xd9\x8fV%\x12~\xff\xc8\x01'
import libnum
#a和b范围很小,考虑直接爆破
for a in range(2<<2,2<<5):
for b in range(0,2<<6):
# 验证用原式相同的逻辑,加密比较加密后的结果,已知QLNU{开头,
if (a*ord('Q')+b)%256 == C[0] and (a*ord('L')+b)%256 == C[1] :
print(a,b)
# 这里是用了嵌套for循环,可以搜索python一行for循环的格式怎么写
# libnum.invmod(x,y)是对x求y的模逆元
# 这里就是题目解释中的解密公式 c = ((a与256的模逆元)*(C-b)) % 256
print("".join([chr((libnum.invmod(a,256)*(i-b))%256) for i in C]))
MISC
01转二维码
这属于是最经典的题型了
给你一串0和1,发现这串字符的长度可以开方,按照0为白色,1为黑色,边长为 \(\sqrt[2]{字符串长度}\)
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000011001100000011001111001111111100000000000000111100000000000000110011000000110011110011111111000000000000001111001111111111001111001100000000110011111100110011111111110011110011111111110011110011000000001100111111001100111111111100111100110000001100110011111100000011110000111111001100000011001111001100000011001100111111000000111100001111110011000000110011110011000000110011110000000000000011000000001100110000001100111100110000001100111100000000000000110000000011001100000011001111001100000011001111001111111111111100110011110011000000110011110011000000110011110011111111111111001100111100110000001100111100111111111100110000001111110011110011110011001111111111001111001111111111001100000011111100111100111100110011111111110011110000000000000011001100110011001100110011001100000000000000111100000000000000110011001100110011001100110011000000000000001111111111111111111111000000111100111111110000111111111111111111111111111111111111110000001111001111111100001111111111111111111100110011111100001100111111000011001111110011110011110011001111001100111111000011001111110000110011111100111100111100110011111100001100001111110000001100110000111100000000001100110011111111000011000011111100000011001100001111000000000011001100111111111100000011000011001100001111000000000000000011001100110011111111000000110000110011000011110000000000000000110011001100111111001100000011001111000011001111001100110000001111001111001111110011000000110011110000110011110011001100000011110011110011111100000011110000110011111100110011111100111100001111111111111111000000111100001100111111001100111111001111000011111111111111001111000000110011000000111111000011110000001100111100111111110011110000001100110000001111110000111100000011001111001111111111000000110000111100111111000000111100001111111111111111001111110000001100001111001111110000001111000011111111111111110011110000110000111111000000111111001111110000000000001100111111111100001100001111110000001111110011111100000000000011001111111111000000000000001111111111110000111111111111110011111100111111110000000000000011111111111100001111111111111100111111001111111111111111001111001100001111000000001100110000000011001111111111111111110011110011000011110000000011001100000000110011111111110000111100110000111100111111110000001100001100111100001100111100001111001100001111001111111100000011000011001111000011001111111100001100110011110000000011111111111100001100000011001111111111000011001100111100000000111111111111000011000000110011111100000011111100001111001111001100111111000000000000001100001111000000111111000011110011110011001111110000000000000011000011111111111111111111000011001111111100001111001111110011000011111111111111111111110000110011111111000011110011111100110000111111000000000000001100110011000000001100001100110011000000110011110000000000000011001100110000000011000011001100110000001100111100111111111100111100000011110000001100000011111100001111001111001111111111001111000000111100000011000000111111000011110011110011000000110011111100001100001111111100000000000000111100111100110000001100111111000011000011111111000000000000001111001111001100000011001111111100110000110011110011001100111100110011110011000000110011111111001100001100111100110011001111001100111100110000001100110011000000001100111100110011111100110000001111001100000011001100110000000011001111001100111111001100000011110011111111110011111111110000111100110011001111000000111111111100111111111100111111111100001111001100110011110000001111111111000000000000001100000011111100000011111100111100001111110011110000000000000011000000111111000000111111001111000011111100111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
把这段01变成二维码
示例答案(点击右侧可以复制)
# 导入PIL图像库和math库。
from PIL import Image
import math
# 打开文件01.txt并将其读入变量string_01。
string_01 = open('01.txt').read()
# math.sqrt是开平方根的函数,输出的是float浮点数类型的数值
# int函数把接收的数值转化为int整数类型
# 这句话就是把计算string_01的长度的平方根并将其转换为整数,存入变量sqrt_len。
sqrt_len = int(math.sqrt(len(string_01)))
# 设置图像宽度和高度为sqrt_len。
width, height = sqrt_len,sqrt_len
# 创建一个新的RGB图像,长度和宽度分别为height和width。
im = Image.new('RGB',(height,width))
# 遍历图像的每一行和每一列。
for x in range(height):
for y in range(width):
# 获取string_01中对应坐标的字符并存入变量value。
value = string_01[width * x + y]
# 如果value为"1",将该坐标的像素设置为白色。
if value == "1":
im.putpixel((x,y),(255,255,255))
# 否则,将该坐标的像素设置为黑色。
else:
im.putpixel((x,y),(0,0,0))
# 显示im图像
im.show()
# 把im保存为QRcode.png
im.save('QRcode.png')