buu-[GWCTF 2019]pyre题解

前置知识点

是什么

和java类似python也是一门半解释半执行的语言,.py后缀的python源码可以理解为全解释的解释型代码,而python编译器可以将.py后缀的代码(也就是日常所说的python代码)编译成字节码,然后再执行代码内容。也就是说转换为字节码是每次运行py文件必不可少的步骤,因此,如果直接运行字节码无疑会提高编译运行速度,在python中的.pyc就是保存字节码的文件。

  • .py文件:直接写的python代码
  • .pyc文件:python代码转换为字节码后的文件

怎么做

而对于逆向而言,使用一个库就可以进行对pyc代码的逆向了,经过学习,选择uncompyle进行逆向,使用pipconda指令安装皆可。注意:uncompyle库是跨版本的,因此python2和3的使用没有差异,python2.7使用的是uncompyle2,python3.x使用的是uncompyle6,指令安装会自带安装对应版本。常用指令如下

  • 以python3举例对应uncompyle6
  • 安装

    • pip install uncompyle
    • liunx下git clone https://github.com/rocky/python-uncompyle6然后进入下载的目录python setup.py install
    • conda镜像库暂时没有uncompyle所以conda install不行
  • 反编译(忘了指令也可以uncompyle6 --help

    • uncompyle6 原文件路径.pyc > 保存的文件路径.py
  • 指令记忆

    • compyle:v.编译,其中含有com-聚集-编译成字节码所以更集成,-py- python专属,-le 编译了速度快了乐了,com-py-le
    • un-:反,un-compyle,反编译

正式解题

得到反编译代码

使用uncompyle6 原文件路径.pyc > 保存的文件路径.py得到反编译代码(手动加了注释)

关于\x \u是什么参考:

https://blog.csdn.net/huangjin0507/article/details/79863057

总结就是

  • \u是一种编码格式,转换的话就使用 字符串的成员方法decode()
  • \u \d \o 分别是十六 十 八进制,转换的话使用字符转换,可参考 一道进制转换题解
# uncompyle6 version 3.7.4
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.8.5 (default, Sep  3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: encode.py
# Compiled at: 2019-08-19 21:01:57
print 'Welcome to Re World!'
print 'Your input1 is your flag~'
l = len(input1)
for i in range(l):
    num = ((input1[i] + i) % 128 + 128) % 128
    code += num

for i in range(l - 1):
    code[i] = code[i] ^ code[(i + 1)]

print code
code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']
# okay decompiling attachment.pyc

*解读加密过程(位运算)

解读关键的两部分加密过程:

  1. codel-1位置不会被修改,而且正向过程中赋值code[i]时不修改code[i+1],且要保证code[i+1]是原始值

    • 然后根据运算规则逆向一下式子:
    • 异或:Z ^ Q

      • 满足交换律和结合律
      • a^a = 0
      • a^0 = a
      • 同理 a^a^b = b
    • 因此 code[i] = code[i] ^ code[(i + 1)] 正向运行结果
    • 逆向的 code[i] = code[i] ^ code[(i + 1)] 等价于 code[i] = code[i] ^ code[(i + 1)] ^ code[(i + 1)]
    • code[i] = code[i]。因此,只要倒着枚举,使用code[i] = code[i] ^ code[(i + 1)]就可以算出每一个code[i]了原来的值了(请使用代码思维理解,此处难理解)
for i in range(l - 1):
    code[i] = code[i] ^ code[(i + 1)]
  1. 根据模运算规则简化一下式子(需要用到同余的知识不赘述了参考:https://blog.csdn.net/weixin_43207025/article/details/90609975
for i in range(l):
    num = ((input1[i] + i) % 128 + 128) % 128
    code += num

逆向反加密代码

code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']

flag = ''

for i in range(len(code)-2, -1, -1):
    code[i]=chr(ord(code[i])^ord(code[i+1]))

for i in range(len(code)):
    flag+=chr((ord(code[i])-i)%128)

print(flag)

运行得到结果GWHT{Just_Re_1s_Ha66y!}如图

Last modification:January 31, 2021
如果觉得我的文章对你有用,请随意赞赏。咖啡(12RMB)进度+100%,一块巧克力(1RMB)进度+6%。
(赞赏请备注你的名称哦!后台记录中来自理工小菜狗)