跳转至

Hello World!

Hello World!

在屏幕上输出 Hello World!

example.py
print("Hello World!")

你已经学会了 Hello World! 来写一个机器学习项目吧

代码逆向

一般来说,在 crypto 或者 re 部分

会给你一段代码让你理解他的意思

然后写出还原 flag 的代码

看不懂也没关系,我会写出汉字的题目解释

字符串逆序

题目 .py
from flag import flag #导入flag,这里就是你需要求的部分,不用在意
print(flag[::-1])
题目解释(如果看不懂代码或者看完代码想要验证想法再看)

这里有一段字符串,}nohtyP_ecitcarp_ot_desu_saw_sihT{UNLQ

写一段代码倒序输出结果

示例答案(点击右侧可以复制)
example.py
flag = "}nohtyP_ecitcarp_ot_desu_saw_sihT{UNLQ"
print(flag[::-1])

异或

```python title=" 题目 .py" 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]

1199 个字 153 行代码 预计阅读时间 6 分钟

```
task.c
#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

写代码还原并输出字符串

示例答案(点击右侧可以复制)
example.py
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]
for i in result:
    print(chr(i^50),end='')

列表相加

题目 .py
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]
示例答案(点击右侧可以复制)
example.py
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 的结果

题目 .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 按照打乱的表逆序回去

示例答案(点击右侧可以复制)
example.py
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)是一种线性密码。它的加密方式是将明文的每个字母替换成密文中的字母,其中明文和密文之间的对应关系可以表示为:

\[ C = E(x) = (ax + b) mod \ \ m \]

其中,\(x\) 是明文中字母的位置,\(C\) 是密文中字母的位置,\(a\) \(b\) 是密钥,\(m\) 是字母表的大小。解密时使用的是模逆元进行解密:

\[ P = D(y) = a^-1 (y - b) mod \ \ m \]

\(y\) 是密文中字母的位置 , \(P\) 是明文中字母的位置。

原理:

仿射密码的加密和解密都是通过线性变换来实现的,即对明文进行 \(ax+b\) 的变换 , 变换后再对 \(m\) 取模。

其中,\(a\) \(b\) 是密钥,它们用来控制变换的线性参数。

\(a\) \(b\) 必须满足 \(a\) \(m\) 互质,才能保证可逆性。

取模 \(m\) 是为了将密文限制在字母表范围内。

解密时需要使用 \(a\) 的逆元来进行逆变换 , 逆元能确保可逆性。

题目 .py
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

示例答案(点击右侧可以复制)
example.py
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 变成二维码

示例答案(点击右侧可以复制)
example.py
# 导入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')