文章

bad_python解析

题目代码解析

# uncompyle6 version 3.9.1
# Python bytecode version base 3.6 (3379)
# Decompiled from: Python 3.7.6 (v3.7.6:43364a7ae0, Dec 18 2019, 14:18:50) 
# [Clang 6.0 (clang-600.0.57)]
# Embedded file name: pyre.py
from ctypes import *
from Crypto.Util.number import bytes_to_long
from Crypto.Util.number import long_to_bytes
​
​
def encrypt(v, k):
    v0 = c_uint32(v[0])  # 无符号整数
    v1 = c_uint32(v[1])  # 无符号整数
    sum1 = c_uint32(0)  # 相当与引进的一个key,用于加密
    delta = 195935983  # 给sum每次加delta,使key变化
    for i in range(32):
        v0.value += (v1.value << 4 ^ v1.value >> 7) + v1.value ^ sum1.value + k[sum1.value & 3]
        # 这个<<4,就是在二进制表示下,把整个数往左边移动4位,就也是变大了2的四次方,>>7,就是在二进制下,把把整个数往右边移动7位
        sum1.value += delta
        v1.value += (v0.value << 4 ^ v0.value >> 7) + v0.value ^ sum1.value + k[sum1.value >> 9 & 3]
​
    return v0.value, v1.value
​
​
if __name__ == "__main__":
    flag = input("please input your flag:")
    k = [255, 187, 51, 68]
    if len(flag) != 32:
        print("wrong!")
        exit(-1)
    a = []
    for i in range(0, 32, 8):
        '''
        1.flag后的[]是python的切片用法,表示取flag的i到i+4部分,但不包括i+4
        2.bytes()将字符转换为字节串类型
        3.bytes_to_long 是 Crypto.Util.number 模块中的一个函数,它用于将字节串(bytes)转换为一个长整数(long),与ord()的区别是,
        ord()只转换一个字符,而bytes_to_long()转换的是整个字节串
        '''
        v1 = bytes_to_long(bytes(flag[i:i + 4], "ascii"))
        v2 = bytes_to_long(bytes(flag[i + 4:i + 8], "ascii"))
        a += encrypt([v1, v2], k)  # 这里上传了一个无变量名数组和一个变量名为k的数组
​
    enc = [4006073346, 2582197823, 2235293281, 558171287,
           2425328816, 1715140098, 986348143, 1948615354]
    for i in range(8):
        if enc[i] != a[i]:
            print("wrong!")
            exit(-1)
​
    print("flag is flag{%s}" % flag)
​
# okay decompiling pyre.cpython-36.pyc
​

解密代码

from ctypes import *
​
​
def decrypt(v, k):
    v0 = c_uint32(v[0])
    v1 = c_uint32(v[1])
    sum1 = c_uint32(0)
    delta = 195935983
    sum1.value = delta * 32
    for i in range(32):
        v1.value -= (v0.value << 4 ^ v0.value >> 7) + v0.value ^ sum1.value + k[sum1.value >> 9 & 3]
        sum1.value -= delta
        v0.value -= (v1.value << 4 ^ v1.value >> 7) + v1.value ^ sum1.value + k[sum1.value & 3]
​
    return v0.value, v1.value
​
​
if __name__ == '__main__':
​
    k = [255, 187, 51, 68]
​
    dec = []
    for i in range(0, 8, 2):
        enc = [4006073346, 2582197823, 2235293281, 558171287,
               2425328816, 1715140098, 986348143, 1948615354]
​
        dec += decrypt([enc[i], enc[i + 1]], k)
​
print(dec)
​
# 创建一个空的可变字节串
byte_array = bytearray()
​
# 由题可知有32个字符,所以每个元素有四个字符,从最低位开始进行字符转换
for i in range(0, 8):
    num = dec[i]
    for j in range(4):
        byte = num >> (8 * (3 - j)) & 0xff
        byte_array.append(byte)
​
# 最后从可变字节串里拿出字符
flag = ''.join([chr(x) for x in byte_array])
print("flag{" + flag + "}")
​
'''
位移操作 (>>):
num >> (8 * (3 - j)) 这部分是将 num 向右位移 (8 * (3 - j)) 位。这里位移的位数是8的倍数,因为每个字节包含8位。(3 - j) 确保了位移的
位数从24开始递减到0(当 j 从0递增到3时)
​
当 j = 0 时,位移 8 * (3 - 0) = 24 位,提取的是 num 的最高字节(即第4个字节)
当 j = 1 时,位移 8 * (3 - 1) = 16 位,提取的是 num 的次高字节(即第3个字节)
当 j = 2 时,位移 8 * (3 - 2) = 8 位,提取的是 num 的第三高字节(即第2个字节)
当 j = 3 时,位移 8 * (3 - 3) = 0 位,提取的是 num 的最低字节(即第1个字节)
​
位与操作 (&):
& 0xff 是一个掩码操作,用于确保结果只包含8位。0xff 是一个十六进制数,其二进制表示是 11111111,这意味着只有最低8位是1,其余位都是0。当
与任何数进行位与时,只有这8位会保留下来,其他位都会被清零
'''
License:  CC BY 4.0