闲来无事,帮朋友逆向了一个使用Pyinstall打包的程序,记录一下踩到的坑

步骤

首先尝试直接使用pyinstxtractor.py进行解包,但是遇到了一个错误

1
2
[+] Processing .\*****
[!] Error : Unsupported pyinstaller version or not a pyinstaller archive

在这个步骤上我卡了很久,最后在pyinstxtractor的GitHub wiki找到了信息。原来是在解包之前需要进行一步操作。Wiki原文

1
objcopy --dump-section pydata=pydata.dump testfile.elf

执行这条命令之后产生pydata.dump,再用pyinstxtractor.py解包即可

出现以下提示表示解包成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[+] Processing .\pydata.dump
[+] Pyinstaller version: 2.1+
[+] Python version: 38
[+] Length of package: 8097846 bytes
[+] Found 57 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: pyi_rth_multiprocessing.pyc
[+] Possible entry point: pyi_rth_certifi.pyc
[+] Possible entry point: poolgui.pyc
[+] Found 420 files in PYZ archive
[+] Successfully extracted pyinstaller archive: .\pydata.dump

You can now use a python decompiler on the pyc files within the extracted directory

我们可以在解包后的文件夹内找到许多pyc文件。找到入口文件后输入以下代码即可反编译为py文件

1
uncompyle6 .\xxx.pyc > .\xxx.py

其中,uncompyle6是开源软件,可以使用pip安装。但是还未支持python3.9。如果是python3.9的pyc文件只能手动查阅字节码。

虽然uncompyle6能够反编译python代码,但是很多情况下他是无法完全反编译出全部代码的,例如样本中的例子(部分信息已打码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

L. 378 1206 LOAD_GLOBAL socket
1208 LOAD_METHOD gethostname
1210 CALL_METHOD_0 0 ''
1212 STORE_FAST 'hostname'

L. 379 1214 LOAD_GLOBAL socket
1216 LOAD_METHOD gethostbyname
1218 LOAD_FAST 'hostname'
1220 CALL_METHOD_1 1 ''
1222 STORE_FAST 'local_host_ip'

L. 381 1224 BUILD_MAP_0 0
1226 STORE_FAST 'headers'

L. 383 1228 LOAD_GLOBAL str
1230 LOAD_GLOBAL sys_userAddress
1232 CALL_FUNCTION_1 1 ''

L. 384 1234 LOAD_GLOBAL str
1236 LOAD_FAST 'sys_totalPlotsNb'
1238 CALL_FUNCTION_1 1 ''

L. 385 1240 LOAD_GLOBAL str
1242 LOAD_FAST 'sys_poolPoints'
1244 CALL_FUNCTION_1 1 ''

L. 386 1246 LOAD_GLOBAL str
1248 LOAD_GLOBAL sys_softVersion
1250 CALL_FUNCTION_1 1 ''

L. 387 1252 LOAD_GLOBAL str
1254 LOAD_FAST 'local_host_ip'
1256 CALL_FUNCTION_1 1 ''

L. 388 1258 LOAD_GLOBAL str
1260 LOAD_FAST 'hostname'
1262 CALL_FUNCTION_1 1 ''

L. 389 1264 LOAD_GLOBAL str
1266 LOAD_FAST 'sys_trustScore'
1268 CALL_FUNCTION_1 1 ''

L. 390 1270 LOAD_GLOBAL str
1272 LOAD_FAST 'hash_uniquePlotsLibraryId'
1274 CALL_FUNCTION_1 1 ''

L. 382 1276 LOAD_CONST ('address', 'plots', 'points', 'version', 'local', 'hostname', 'trust', 'hash')
1278 BUILD_CONST_KEY_MAP_8 8
1280 STORE_FAST 'data'

L. 392 1282 LOAD_GLOBAL requests
1284 LOAD_ATTR post
1286 LOAD_STR '这里是一个URL'
1288 LOAD_FAST 'headers'
1290 LOAD_FAST 'data'
1292 LOAD_CONST ('headers', 'data')
1294 CALL_FUNCTION_KW_3 3 '3 total positional and keyword args'
1296 STORE_FAST 'response'
1298 POP_BLOCK
1300 JUMP_FORWARD 1332 'to 1332'
1302_0 COME_FROM_FINALLY 1204 '1204'

虽然这不是一眼可看出是什么作用的源代码,但是经过简单的思考还是能猜出这段代码的含义

关于Python字节码的信息可以到官方文档找到,这东西比汇编语言简单多了!

样本信息

样本是一个Linux平台下使用Pyinstall的python程序

sha256: 548a89c3f5a8846ae7a9aedda09018cb32f07cb333d9970d314b7c5ef60fb724