首页 > 编程语言 >江苏工匠杯bad_python

江苏工匠杯bad_python

时间:2023-06-19 15:55:42浏览次数:50  
标签:02 00 01 python 工匠 bad 64 65 72

江苏工匠杯bad_python

Python逆向

拿到附件是一个pyc文件,按照我们常规的python逆向思路,肯定是先试一试能不能uncompyle6反编译.

发现无法反编译,我们用010editor查看一下pyc文件的文件头.可以看到文件头是以0D33结尾的

33 0D 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 08 00 00 00 40 00 00
00 73 1C 01 00 00 64 00 64 01 6C 00 54 00 64 00
64 02 6C 01 6D 02 5A 02 01 00 64 00 64 03 6C 01
6D 03 5A 03 01 00 64 04 64 05 84 00 5A 04 65 05
64 06 6B 02 90 01 72 18 65 06 64 07 83 01 5A 07
64 08 64 09 64 0A 64 0B 67 04 5A 08 65 09 65 07
83 01 64 0C 6B 03 72 62 65 0A 64 0D 83 01 01 00
65 0B 64 1C 83 01 01 00 67 00 5A 0C 78 5E 65 0D
64 00 64 0C 64 0F 83 03 44 00 5D 4E 5A 0E 65 02
65 0F 65 07 65 0E 65 0E 64 10 17 00 85 02 19 00
64 11 83 02 83 01 5A 10 65 02 65 0F 65 07 65 0E
64 10 17 00 65 0E 64 0F 17 00 85 02 19 00 64 11
83 02 83 01 5A 11 65 0C 65 04 65 10 65 11 67 02
65 08 83 02 37 00 5A 0C 71 74 57 00 64 12 64 13
64 14 64 15 64 16 64 17 64 18 64 19 67 08 5A 12
78 30 65 0D 64 0F 83 01 44 00 5D 24 5A 0E 65 12
65 0E 19 00 65 0C 65 0E 19 00 6B 03 72 E4 65 0A
64 0D 83 01 01 00 65 0B 64 1D 83 01 01 00 71 E4
57 00 65 0A 64 1A 65 07 16 00 83 01 01 00 64 1B
53 00 29 1E E9 00 00 00 00 29 01 DA 01 2A 29 01
DA 0D 62 79 74 65 73 5F 74 6F 5F 6C 6F 6E 67 29
01 DA 0D 6C 6F 6E 67 5F 74 6F 5F 62 79 74 65 73
63 02 00 00 00 00 00 00 00 07 00 00 00 08 00 00
00 43 00 00 00 73 C4 00 00 00 74 00 7C 00 64 01
19 00 83 01 7D 02 74 00 7C 00 64 02 19 00 83 01
7D 03 74 00 64 01 83 01 7D 04 64 03 7D 05 78 92
74 01 64 04 83 01 44 00 5D 86 7D 06 7C 02 04 00
6A 02 7C 03 6A 02 64 05 3E 00 7C 03 6A 02 64 06
3F 00 41 00 7C 03 6A 02 17 00 7C 04 6A 02 7C 01
7C 04 6A 02 64 07 40 00 19 00 17 00 41 00 37 00
02 00 5F 02 7C 04 04 00 6A 02 7C 05 37 00 02 00
5F 02 7C 03 04 00 6A 02 7C 02 6A 02 64 05 3E 00
7C 02 6A 02 64 06 3F 00 41 00 7C 02 6A 02 17 00
7C 04 6A 02 7C 01 7C 04 6A 02 64 08 3F 00 64 07
40 00 19 00 17 00 41 00 37 00 02 00 5F 02 71 2E
57 00 7C 02 6A 02 7C 03 6A 02 66 02 53 00 29 09
4E 72 01 00 00 00 E9 01 00 00 00 69 EF BE AD 0B
E9 20 00 00 00 E9 04 00 00 00 E9 07 00 00 00 E9
03 00 00 00 E9 09 00 00 00 29 03 5A 08 63 5F 75
69 6E 74 33 32 DA 05 72 61 6E 67 65 DA 05 76 61
6C 75 65 29 07 DA 01 76 DA 01 6B 5A 02 76 30 DA
02 76 31 5A 04 73 75 6D 31 5A 05 64 65 6C 74 61
DA 01 69 A9 00 72 11 00 00 00 FA 07 70 79 72 65
2E 70 79 DA 07 65 6E 63 72 79 70 74 06 00 00 00
73 12 00 00 00 00 01 0C 01 0C 01 08 01 04 01 0E
01 38 01 0E 01 40 01 72 13 00 00 00 DA 08 5F 5F
6D 61 69 6E 5F 5F 7A 17 70 6C 65 61 73 65 20 69
6E 70 75 74 20 79 6F 75 72 20 66 6C 61 67 3A E9
FF 00 00 00 E9 BB 00 00 00 E9 33 00 00 00 E9 44
00 00 00 72 06 00 00 00 7A 06 77 72 6F 6E 67 21
72 05 00 00 00 E9 08 00 00 00 72 07 00 00 00 DA
05 61 73 63 69 69 6C 03 00 00 00 02 54 8F 5D 03
00 6C 03 00 00 00 3F 36 D2 33 02 00 6C 03 00 00
00 61 5E 77 0A 02 00 69 97 04 45 21 6C 03 00 00
00 B0 14 1F 21 02 00 69 02 F6 3A 66 69 6F 7A CA
3A 69 BA 82 25 74 7A 10 66 6C 61 67 20 69 73 20
66 6C 61 67 7B 25 73 7D 4E E9 FF FF FF FF 72 1B
00 00 00 29 13 5A 06 63 74 79 70 65 73 5A 12 43
72 79 70 74 6F 2E 55 74 69 6C 2E 6E 75 6D 62 65
72 72 03 00 00 00 72 04 00 00 00 72 13 00 00 00
DA 08 5F 5F 6E 61 6D 65 5F 5F DA 05 69 6E 70 75
74 DA 04 66 6C 61 67 72 0E 00 00 00 DA 03 6C 65
6E DA 05 70 72 69 6E 74 DA 04 65 78 69 74 DA 01
61 72 0B 00 00 00 72 10 00 00 00 DA 05 62 79 74
65 73 72 0F 00 00 00 5A 02 76 32 DA 03 65 6E 63
72 11 00 00 00 72 11 00 00 00 72 11 00 00 00 72
12 00 00 00 DA 08 3C 6D 6F 64 75 6C 65 3E 02 00
00 00 73 28 00 00 00 08 01 0C 01 0C 02 08 19 0A
01 08 01 0C 01 0C 01 08 01 08 01 04 01 12 01 1A
01 1E 01 16 0E 14 01 0E 01 10 01 08 01 0C 01

结合这个Pyc文件的名字,猜想这个可能是以python3.6版本进行编译的。通过pyc魔术版本我们用脚本跑一下,看一下330D是哪个3.6版本的头部.

for i in range(3360,3381):
    MAGIC_NUMBER = (i).to_bytes(2, 'little') + b'\r\n'
    _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little')  # For import.c
    print(f'i = {i},opcode = {hex(_RAW_MAGIC_NUMBER)}')
i = 3379,opcode = 0xa0d0d33

不过这里是要按照小端序填充的,即33 0d 0d 0a,填充后,发现仍然无法进行pyc反编译.说明多半是别的文件头出问题了。

首先我们需要一个python3.6的环境,我们可以用conda来实现,然后我们需要在python环境中利用Python -m 1.py来生成.pyc文件。

我们先用notepdd写一个简单python脚本,然后在conda环境中,用python -m xxx.py生成对应的pyc文件

print("Hello CTFer!")
print("Welcome new world")


运行之后,如果不指定目录的话,会在当前目录下生成一个名字叫做__pycache__的文件夹,里面会有一个对应的pyc,我们用010editor查看一下对应的文件头,将其复制到题目中破坏的pyc文件上去.

反编译成功!

 uncompyle6.exe pyre.cpython-36.pyc
# uncompyle6 version 3.7.4
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.8.9 (tags/v3.8.9:a743f81, Apr  2 2021, 10:59:45) [MSC v.1928 32 bit (Intel)]
# Embedded file name: pyre.py
# Compiled at: 2023-06-19 15:29:22
# Size of source mod 2**32: 49 bytes
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)
    delta = 195935983
    for i in range(32):
        v0.value += (v1.value << 4 ^ v1.value >> 7) + v1.value ^ sum1.value + k[(sum1.value & 3)]
        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):
        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)

    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

py文件算法分析

  • k = [255,187,51,68],flag长度必须为32
  • 首先是对我们的flag,每8位中,前四位作为v1,后四位作为v2,以及k,传入到encrypt函数中进行加密.

encrypt函数

def encrypt(v, k):
    v0 = c_uint32(v[0])
    v1 = c_uint32(v[1])
    sum1 = c_uint32(0)
    delta = 195935983
    for i in range(32):
        v0.value += (v1.value << 4 ^ v1.value >> 7) + v1.value ^ sum1.value + k[(sum1.value & 3)]
        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)

整个函数逻辑就是通过移位加上异或来进行运算,类似于Tea算法,这里的delta可以看作Tea算法中的常量。

解密脚本:

#include<stdio.h>
#define  u_int unsigned int
int main()
{
	u_int enc[] = { 4006073346, 2582197823, 2235293281, 558171287,
				2425328816, 1715140098, 986348143, 1948615354 };
	u_int k[] = { 255, 187, 51, 68 };
	for (int i = 0; i < 8; i += 2)
	{
		u_int delta = 195935983;
		u_int s1 = delta * 32;
		for (int j = 0; j < 32; j++)
		{
			enc[i + 1] -= (enc[i] << 4 ^ enc[i] >> 7) + enc[i] ^ s1 + k[s1 >> 9 & 3];
			s1 -= delta;
			enc[i] -= (enc[i + 1] << 4 ^ enc[i + 1] >> 7) + enc[i + 1] ^ s1 + k[s1 & 3];
		}
	}
	int j;
	for (j = 0; j < 8;j++)
	{
		printf("enc = %lld\n", enc[j]);
	}
	char flag[32] = { 0 };
	for (int i = 0; i < 8; i++)
	{
		flag[4 * i] = enc[i] >> 24;
		flag[4 * i + 1] = (enc[i] >> 16) & 0xFF;
		flag[4 * i + 2] = (enc[i] >> 8) & 0xFF;
		flag[4 * i + 3] = enc[i] & 0xFF;
	}
	for (int i = 0; i < 32; i++)
	{
		printf("%c", flag[i]);
	}
}
/*enc = 63912563639333235
enc = 63912563820295007
enc = 63912563319981409
enc = 63912564160552784
enc = 63912564260890672
enc = 63912564074962770
enc = 63912563086615890
enc = 63912564159242032
Th1s_1s_A_Easy_Pyth0n__R3veRse_0*/

这里我没有写出Python的脚本来,这里的话因为数据宽度的原因,对于Python来说没有内置的无符号整型的函数,如果要用python写的话,还是只能先通过C把解密后的数据提出来,然后分组移位+与运算即可求出flag.脚本如下:

enc = [63912563639333235,63912563820295007,63912563319981409,63912564160552784,63912564260890672,63912564074962770,63912563086615890,63912564159242032]

flag = bytearray(32)
for i in range(8):
    flag[4 * i] = (enc[i] >> 24) & 0xFFFFFFFF & 0xFF
    flag[4 * i + 1] = (enc[i] >> 16) & 0xFFFFFFFF & 0xFF
    flag[4 * i + 2] = (enc[i] >> 8) & 0xFFFFFFFF & 0xFF
    flag[4 * i + 3] = (enc[i] & 0xFFFFFFFF & 0xFF)

print(flag)
#bytearray(b'Th1s_1s_A_Easy_Pyth0n__R3veRse_0')

解释一下这个Python脚本为什么要先与0xFFFFFFFF,然后再与0xFF.在题目中实际上是调用了cbytes这个库的,也就是处理的数据都是无符号32位整型(u_int32),但是Python内部不支持32位整型的函数,所以在处理数据的时候,要先通过与运算取得其32位的整体值,然后再去取其中的最低位字节.还是建议用C写脚本比较好:)

Over!!!

标签:02,00,01,python,工匠,bad,64,65,72
From: https://www.cnblogs.com/qsons/p/17491327.html

相关文章

  • Python实现一个简单的栈结构
    基于list来实现一个栈:classSimpleStack:def__init__(self):self.__stack:list=[]​def__iter__(self):returnSimpleStackIterator(self)​def__len__(self):returnlen(self.__stack)​def__getitem__(self,index)......
  • Python3中的函数对象
    在Python中一切皆对象,函数也是一种对象,有相关的属性和方法。对于任意对象,我们可以用dir()函数来获取其内置的属性及方法名,例如:defadd(a:int,b:int=1)->int:"""加法函数"""returna+bprint(dir(add))运行结果如下:['__annotations__','__call__','_......
  • python之mysql登录验证
    fromdotenvimportload_dotenvimportpymysqlimportosload_dotenv()connection=pymysql.connect(host=os.getenv("HOST"),database=os.getenv("DATABASE"),user=os.getenv("USERNAME"),password=os.getenv("PASSWORD......
  • VScode 中利用virtualenv建立 Python 虚拟环境
    !https://zhuanlan.zhihu.com/p/638114885VScode建立Python虚拟环境主要目的:创建一个与默认python版本不同的python虚拟环境0x01建立新环境文件夹建立一个独立文件夹来存储所有虚拟环境,所以可以事先建好文件夹如:'''E:\WorkSpace\Work\chatGLM'''0x02创建虚拟环......
  • Python爬虫与数据可视化(前程无忧网)
    1、前言最初我写过一篇相同的文章发表到了CSDN中,因为写的比较早,2019年吧,8万多访问量,所以后来也有很多网友反馈各种问题,包括网站反爬、数据爬取失败、网络异常等等,所以那篇文章也经过了多次的修改。不过目前因为CSDN规则更改,爬虫类文章因违反社区规定被下架了,然后我也很久没有去......
  • Rstudio如何做python语言的编辑器?
    参考文档:https://support.posit.co/hc/en-us/articles/1500007929061-Using-Python-with-the-RStudio-IDE1、Rstudio中globalstudio中globaloptions配置pythoninterpreter----地址:C:/Users/18308/anaconda3/python.exe2、安装包:install.packages("reticulate")3、library(re......
  • python 进阶
    isinstance()函数来判断一个对象是否是一个已知的类型,类似type()。isinstance(object,classinfo)>>>a=2>>>isinstance(a,int)True>>>isinstance(a,str)False>>>isinstance(a,(str,int,list))#是元组中的一个返回TrueTrue ......
  • 学习python爬虫需要掌握哪些库?
    Python爬虫是指使用Python编写的程序,用来自动化地获取互联网上的数据。通过爬取网站的HTML内容,并解析和提取所需的数据,可以实现自动化地收集、分析和处理大量的在线数据。学习Python爬虫需要掌握以下几个核心库:Requests:用于发送、BeautifulSoup:用于解析HTML或XML文档,提取结构化数据......
  • 学习python爬虫需要掌握哪些库?
    Python爬虫是指使用Python编写的程序,用来自动化地获取互联网上的数据。通过爬取网站的HTML内容,并解析和提取所需的数据,可以实现自动化地收集、分析和处理大量的在线数据。学习Python爬虫需要掌握以下几个核心库:Requests:用于发送、BeautifulSoup:用于解析HTML或XML文档,提取结构化......
  • python基础总结
    1、Python的数据类型答:数字(number)、字符串(string)、列表(list)、元组(tuple)、字典(dict)、集合(set)Number/string/tuple不可更改,list/dict/set可以 2、列表和元组的区别答:列表可变类型,元组不可变3、字符串中查找字符索引位置1) 查找第一次出现的字符s.index(c),找不到raiseVa......