Python逆向基本操作步骤详解——以杭电新生赛hgame week2 reverse stream(python3.10逆向)为例

目录

一.查壳

 二.从stream.exe中提取stream.pyc和struct.pyc文件

1.方法一:使用pyinstxtractor.py提取(较为简单)

(1)下载pyinstxtractor.py

(2)将stream.exe和pyinstxtractor.py文件置于同一文件夹内,在该路径内打开cmd

(3)获取pyc文件

(4)修复Magic Head

2.方法二:使用PyInstaller自带的archive_viewer.py提取(相对复杂)

(1)首先安装pyinstaller

(2)找到archive_viewer.py文件

 (3)获取pyc文件

 (4)将stream.pyc的magic head头信息补上去,同方法1

三.反编译stream.pyc文件获取stream.py源码

1.使用pyc在线解密(推荐)

2.使用pycdc(推荐)

 (1)安装CMake

(2)下载pycdc项目

(3)使用pycdc.exe反编译pyc文件

3.stream.py源码

四.程序逻辑及解题脚本

五.参考文章

六.扩展--通过翻译字节码得到源码

1.使用python3.11解释器调用dis解释出pyc文件的字节码

2.使用ChatGpt翻译字节码得到源码(看文档生啃也可以)


一.查壳

通过查壳可以发现这是python语言编写,使用PyInstaller打包的exe程序,但是并不确定python版本

        

 二.从stream.exe中提取stream.pyc和struct.pyc文件

1.方法一:使用pyinstxtractor.py提取(较为简单)

(1)下载pyinstxtractor.py

下载地址: extremecoders-re/pyinstxtractor: PyInstaller Extractor (github.com)

点绿色的code,再点download zip即可下载

(2)将stream.exe和pyinstxtractor.py文件置于同一文件夹内,在该路径内打开cmd

(3)获取pyc文件

使用命令:

python pyinstxtractor.py stream.exe

则会在该路径下输出stream.exe_extracted文件夹,同时也可以看到pyinstaller和python的版本(python3.10)

注意:这里最好是让使用的python解释器版本和待解包程序python版本一致(建议使用Anaconda管理python版本),保证输出准确,否则可能会丢失部分文件

(4)修复Magic Head

一般而言,使用pyinstxtractor解包会自动修复MagicHead,如果没有自动修复则手动修复

在文件夹内找到stream.pyc和struct.pyc文件,用winhex或者010editor打开,将struct文件的第一行(Magic head)复制到stream.pyc的最前面,保存更改

2.方法二:使用PyInstaller自带的archive_viewer.py提取(相对复杂)

(1)首先安装pyinstaller

pip install pyinstaller -i https://pypi.douban.com/simple(也可指定为其他源)

(2)找到archive_viewer.py文件

使用where python找到python所在路径,

然后在python所在的文件夹内找Lib\site-packages\PyInstaller\utils\cliutils\archive_viewer.py

即: C:\Users\admin\AppData\Local\Programs\Python\Python310\Lib\site-packages\PyInstaller\utils\cliutils\archive_viewer.py

 (3)获取pyc文件

将archive_viewer.py复制到stream.exe所在文件夹内,在文件夹内打开cmd,使用命令

python archive_viewer.py stream.exe,这里也可以看到python版本等信息

 继续使用命令即可输出stream.pyc和struct.pyc文件

 (4)将stream.pyc的magic head头信息补上去,同方法1

三.反编译stream.pyc文件获取stream.py源码

1.使用pyc在线解密(推荐)

选择pyc文件即可得到源码:

2.使用pycdc(推荐)

如果不想下载编译的话这里有我编译好的pycdc.exe,可以直接跳转到(4)反编译pyc文件

 (1)安装CMake

官网:Download | CMake

下载installer安装包版

安装时记得勾选添加到环境变量,其他选项默认即可

(2)下载pycdc项目

1. 使用命令行下载

git clone https://github.com/zrax/pycdc.git #下载pycdc

cd pycdc    #进入pycdc目录

cmake .     #注意是cmake . 这个'.'点号

使用visual studio打开pycdc文件夹中的pycdc.sln文件

打开后选择x64 release模式编译运行

在pycdc/Release文件夹内可以找到pycdc.exe

也可以选则直接下载源码

2. 直接下载

项目地址:zrax/pycdc: C++ python bytecode disassembler and decompiler (github.com) 

点击Code>Download Zip

 解压后得到的文件夹用VisualStudio打开,然后找到pycdc.cpp文件,然后点击管理配置 

 点击绿色+号选择x64-release,然后ctrl+s保存json的设置就可以

选择x64-release模式编译

 然后在生成里选择全部生成

最后就可以在~\pycdc-master\out\build\x64-Release目录下找到pycdc.exe了(可以将目录配置到环境变量方便使用)

(3)使用pycdc.exe反编译pyc文件

将pycdc.exe和stream.pyc文件放于同一文件夹内(也可以将pycdc.exe所在文件夹路径添加到环境变量)

在文件夹内打开cmd,使用命令:pycdc stream.pyc

 成功输出源码:

3.stream.py源码

#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.10

import base64

def gen(key):
    s = list(range(256))
    j = 0
    for i in range(256):
        j = (j + s[i] + ord(key[i % len(key)])) % 256
        tmp = s[i]
        s[i] = s[j]
        s[j] = tmp
    i = j = 0
    data = []
    for _ in range(50):
        i = (i + 1) % 256
        j = (j + s[i]) % 256
        tmp = s[i]
        s[i] = s[j]
        s[j] = tmp
        data.append(s[(s[i] + s[j]) % 256])
    return data


def encrypt(text, key):
    result = ''
    for c, k in zip(text, gen(key)):
        result += chr(ord(c) ^ k)
    result = base64.b64encode(result.encode()).decode()
    return result

text = input('Flag: ')
key = 'As_we_do_as_you_know'
enc = encrypt(text, key)
if enc == 'wr3ClVcSw7nCmMOcHcKgacOtMkvDjxZ6asKWw4nChMK8IsK7KMOOasOrdgbDlx3DqcKqwr0hw701Ly57w63CtcOl':
    print('yes!')
    return None
None('try again...')

四.程序逻辑及解题脚本

#!/usr/bin/env python
# visit  for more information
# Version: Python 3.10
# 反编译代码
import base64

def gen(key):
    s = list(range(256))#s=[0,1,...,255]
    j = 0
    for i in range(256):
        j = (j + s[i] + ord(key[i % len(key)])) % 256
        tmp = s[i]
        s[i] = s[j]
        s[j] = tmp
    i = j = 0
    data = []
    for _ in range(50):#  _字符表示不指明循环变量,但是循环会进行50次
        i = (i + 1) % 256
        j = (j + s[i]) % 256
        tmp = s[i]
        s[i] = s[j]
        s[j] = tmp
        data.append(s[(s[i] + s[j]) % 256])
    return data

def decrypt(enc , key):
    result=''
    enc = base64.b64decode(enc.encode()).decode()
    c = ""
    for i, k in zip(enc, gen(key)):
        c += chr((ord(i) ^ k))
    print(c)

key = 'As_we_do_as_you_know'
enc = "wr3ClVcSw7nCmMOcHcKgacOtMkvDjxZ6asKWw4nChMK8IsK7KMOOasOrdgbDlx3DqcKqwr0hw701Ly57w63CtcOl"
decrypt(enc, key)
#hgame{python_reverse_is_easy_with_internet}




得到flag:hgame{python_reverse_is_easy_with_internet}

五.参考文章

1.逆向python生成的可执行文件

2.[Python逆向] 逆向Pyinstaller打包的exe文件源码及保护

3.Pyinstaller打包的exe之一键反编译py脚本与防反编译

4.【Python教程】保姆版教使用Pyinstaller 打包python成exe文件

5.使用pydumpck反编译pyintaller生成的exe文件 python3.10

6.Python 反编译:pycdc工具的使用

六.扩展--通过翻译字节码得到源码

DASCTF2023 RE easyRE 这题使用python3.11解释器,由于版本过高,得到pyc字节码文件后无法反编译出python源码.

1.使用python3.11解释器调用dis解释出pyc文件的字节码

import marshal
import dis
f=open(r'easyRE.pyc','rb') 
# 将pyc文件和该脚本放于同一文件夹内,或者自行指定绝对路径
code=marshal.loads(f.read()[16:])
print(dis.dis(code))
f.close()

字节码:

2.使用ChatGpt翻译字节码得到源码(看文档生啃也可以)

ChatGpt翻译出的源码

import random

r = random.Random(322376503)
pt = input('Enter your flag: ').encode()
ct = b'\x8b\xcck\xd3\xed\x96\xffFb\x06r\x085\x82\xbc \xb2\xde)p\x88Q`\x1bf\x18\xb6QUSw\x10\xcd\xd9\x13A$\x86\xe5\xcd\xd9\xff'
buf = []

for b in pt:
    buf.append(b ^ r.randint(0, 255))

if bytes(buf) == ct:
    print('Correct!')
else:
    assert False

3. pydisasm -F xasm PycFile.pyc>out.txt命令打印字节码

dis库打印时可能会有报错的情况,这时可以尝试这条命令

  • 7
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OrientalGlass

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值