php反编译opcode,从HGAME的pyc逆向来看手撸opcode
一次pyc文件恢复
Python Pyc的文件格式[compile.h]
/* Bytecode object */
typedef struct {
PyObject_HEAD
int co_argcount; /* #arguments, except *args */
int co_nlocals; /* #local variables */
int co_stacksize; /* #entries needed for evaluation stack */
int co_flags; /* CO_..., see below */
PyObject *co_code; /* instruction opcodes */
PyObject *co_consts; /* list (constants used) */
PyObject *co_names; /* list of strings (names used) */
PyObject *co_varnames; /* tuple of strings (local variable names) */
PyObject *co_freevars; /* tuple of strings (free variable names) */
PyObject *co_cellvars; /* tuple of strings (cell variable names) */
/* The rest doesn't count for hash/cmp */
PyObject *co_filename; /* string (where it was loaded from) */
PyObject *co_name; /* string (name, for reference) */
int co_firstlineno; /* first source line number */
PyObject *co_lnotab; /* string (encoding addrlineno mapping) */
} PyCodeObject;
加载pyc co_codeIn [1]: import dis,marshal
In [2]: f=open('third.pyc')
In [3]: f.read(4)
Out[3]: '\x03\xf3\r\n'
In [4]: f.read(4)
Out[4]: '\xf1\xe1S\\'
In [5]: code = marshal.load(f)
In [6]: code.co_consts
Out[6]:
(-1,
None,
'+',
'/',
'FcjTCgD1EffEm2rPC3bTyL5Wu2bKBI9KAZrwFgrUygHN',
,
"Welcome to Processor's Python Classroom Part 3&4!\n",
'qi shi wo jiu shi lan cai ba liang dao ti fang zai yi qi.',
"Now let's start the origin of Python!\n",
'Plz Input Your Flag:\n',
2,
0,
1,
'',
"You're right! ",
"You're Wrong! ")
In [7]: code.co_varnames
Out[7]: ()
In [8]: code.co_names
Out[8]:
('string',
'list',
'letters',
'digits',
'dec',
'encode',
'raw_input',
'enc',
'lst',
'reverse',
'len',
'llen',
'range',
'i',
'chr',
'ord',
'enc2',
'join',
'enc3')
In [9]: code.co_code
Out[9]: 'q\x03\x00q\t\x00d\x0f\x00q\x0e\x00Gdd\x00\x00d\x01\x00l\x00\x00Z\x00\x00e\x01\x00e\x00\x00j\x02\x00\x83\x01\x00e\x01\x00e\x00\x00j\x03\x00\x83\x01\x00\x17d\x02\x00d\x03\x00g\x02\x00\x17Z\x02\x00d\x04\x00Z\x04\x00d\x05\x00\x84\x00\x00Z\x05\x00d\x06\x00GHd\x07\x00GHd\x08\x00GHd\t\x00GHe\x06\x00\x83\x00\x00Z\x07\x00e\x01\x00e\x07\x00\x83\x01\x00Z\x08\x00e\x08\x00j\t\x00\x83\x00\x00\x01e\n\x00e\x08\x00\x83\x01\x00Z\x0b\x00xc\x00e\x0c\x00e\x0b\x00\x83\x01\x00D]U\x00Z\r\x00e\r\x00d\n\x00\x16d\x0b\x00k\x02\x00r\xc4\x00e\x0e\x00e\x0f\x00e\x08\x00e\r\x00\x19\x83\x01\x00d\n\x00\x18\x83\x01\x00e\x08\x00e\r\x00
使用dis库对co_code进行解释In [10]: dis.dis(code.co_code)
0 JUMP_ABSOLUTE 3
>> 3 JUMP_ABSOLUTE 9
6 LOAD_CONST 15 (15)
>> 9 JUMP_ABSOLUTE 14
12 PRINT_ITEM
13 LOAD_CONST 100 (100)
16 STOP_CODE
17 LOAD_CONST 1 (1)
20 IMPORT_NAME 0 (0)
23 STORE_NAME 0 (0)
26 LOAD_NAME 1 (1)
29 LOAD_NAME 0 (0)
32 LOAD_ATTR 2 (2)
35 CALL_FUNCTION 1
38 LOAD_NAME 1 (1)
41 LOAD_NAME 0 (0)
44 LOAD_ATTR 3 (3)
47 CALL_FUNCTION 1
50 BINARY_ADD
51 LOAD_CONST 2 (2)
54 LOAD_CONST 3 (3)
57 BUILD_LIST 2
60 BINARY_ADD
61 STORE_NAME 2 (2)
64 LOAD_CONST 4 (4)
67 STORE_NAME 4 (4)
70 LOAD_CONST 5 (5)
73 MAKE_FUNCTION 0
76 STORE_NAME 5 (5)
79 LOAD_CONST 6 (6)
82 PRINT_ITEM
83 PRINT_NEWLINE
84 LOAD_CONST 7 (7)
87 PRINT_ITEM
88 PRINT_NEWLINE
89 LOAD_CONST 8 (8)
92 PRINT_ITEM
93 PRINT_NEWLINE
94 LOAD_CONST 9 (9)
97 PRINT_ITEM
98 PRINT_NEWLINE
99 LOAD_NAME 6 (6)
102 CALL_FUNCTION 0
105 STORE_NAME 7 (7)
108 LOAD_NAME 1 (1)
111 LOAD_NAME 7 (7)
114 CALL_FUNCTION 1
117 STORE_NAME 8 (8)
120 LOAD_NAME 8 (8)
123 LOAD_ATTR 9 (9)
126 CALL_FUNCTION 0
129 POP_TOP
130 LOAD_NAME 10 (10)
133 LOAD_NAME 8 (8)
136 CALL_FUNCTION 1
139 STORE_NAME 11 (11)
142 SETUP_LOOP 99 (to 244)
145 LOAD_NAME 12 (12)
148 LOAD_NAME 11 (11)
151 CALL_FUNCTION 1
154 GET_ITER
155 FOR_ITER 85 (to 243)
158 STORE_NAME 13 (13)
161 LOAD_NAME 13 (13)
164 LOAD_CONST 10 (10)
167 BINARY_MODULO
168 LOAD_CONST 11 (11)
171 COMPARE_OP 2 (==)
174 POP_JUMP_IF_FALSE 196
177 LOAD_NAME 14 (14)
180 LOAD_NAME 15 (15)
183 LOAD_NAME 8 (8)
186 LOAD_NAME 13 (13)
189 BINARY_SUBSCR
190 CALL_FUNCTION 1
193 LOAD_CONST 10 (10)
>> 196 BINARY_SUBTRACT
197 CALL_FUNCTION 1
200 LOAD_NAME 8 (8)
203 LOAD_NAME 13 (13)
206 STORE_SUBSCR
207 JUMP_FORWARD 0 (to 210)
>> 210 LOAD_NAME 14 (14)
213 LOAD_NAME 15 (15)
216 LOAD_NAME 8 (8)
219 LOAD_NAME 13 (13)
222 BINARY_SUBSCR
223 CALL_FUNCTION 1
226 LOAD_CONST 12 (12)
229 BINARY_ADD
230 CALL_FUNCTION 1
233 LOAD_NAME 8 (8)
236 LOAD_NAME 13 (13)
239 STORE_SUBSCR
240 JUMP_ABSOLUTE 141
>> 243 POP_BLOCK
>> 244 LOAD_CONST 13 (13)
247 STORE_NAME 16 (16)
250 LOAD_NAME 16 (16)
253 LOAD_ATTR 17 (17)
256 LOAD_NAME 8 (8)
259 CALL_FUNCTION 1
262 STORE_NAME 16 (16)
265 LOAD_NAME 5 (5)
268 LOAD_NAME 16 (16)
271 CALL_FUNCTION 1
274 STORE_NAME 18 (18)
277 LOAD_NAME 18 (18)
280 LOAD_NAME 4 (4)
>> 283 COMPARE_OP 2 (==)
286 POP_JUMP_IF_FALSE 283
289 LOAD_CONST 14 (14)
292 PRINT_ITEM
293 PRINT_NEWLINE
294 JUMP_FORWARD 5 (to 302)
297 LOAD_CONST 15 (15)
300 PRINT_ITEM
301 PRINT_NEWLINE
>> 302 LOAD_CONST 1 (1)
305 RETURN_VALUE
刚开始走了一些弯路,通读了opcode,结果发现并不需要,只要将反uncompyle2的部分去掉,修改co_code长度即可正常反编译,期望修改后的opcode首行为0 LOAD_CONST 0(0)
1 LOAD_CONST 1(1)
...
使用hexdump查看文件
0x64 操作为LOAD_CONST,用法举例:LOAD_CONST 1 HEX: 640100
0x71 操作为JUMP_ABSOLUTE,用法举例:JUMP_ABSOLUTE 14 HEX: 710e00
0x65 操作为LOAD_NAME,用法举例:LOAD_NAME 1 HEX: 650100
...
修改原始pyc
通过opcode及hexdump可以确定,当前co_code长度为0x132(此处为小端显示,0x1a1b位置),0x1e到0x2c(左闭右开)这部分为混淆代码,直接从16进制数据中删除,然后修改co_code长度为0x132-(0x2c-0x1e),即改为24 01,保存代码In [1]: with open('third.pyc','r') as f:
...: dt = f.read()
...:
In [2]: dt = dt[:0x1a]+'\x24'+dt[0x1b:0x1e]+dt[0x2c:]
In [3]: with open('third_test2.pyc', 'w') as f:
...: f.write(dt)
...:
然后使用uncompyle2 third_test2.pyc > third_source.py进行反编译
源码如下:# 2019.02.16 14:17:20 CST
#Embedded file name: third.py
import string
letters = list(string.letters) + list(string.digits) + ['+', '/']
dec = 'FcjTCgD1EffEm2rPC3bTyL5Wu2bKBI9KAZrwFgrUygHN'
def encode(input_str):
str_ascii_list = [ '{:0>8}'.format(str(bin(ord(i))).replace('0b', '')) for i in input_str ]
output_str = ''
equal_num = 0
while str_ascii_list:
temp_list = str_ascii_list[:3]
if len(temp_list) != 3:
while len(temp_list) < 3:
equal_num += 1
temp_list += ['00000000']
temp_str = ''.join(temp_list)
temp_str_list = [ temp_str[x:x + 6] for x in [0,
6,
12,
18] ]
temp_str_list = [ int(x, 2) for x in temp_str_list ]
if equal_num:
temp_str_list = temp_str_list[0:4 - equal_num]
output_str += ''.join([ letters[x] for x in temp_str_list ])
str_ascii_list = str_ascii_list[3:]
output_str = output_str + '=' * equal_num
return output_str
print "Welcome to Processor's Python Classroom Part 3&4!\n"
print 'qi shi wo jiu shi lan cai ba liang dao ti fang zai yi qi.'
print "Now let's start the origin of Python!\n"
print 'Plz Input Your Flag:\n'
enc = raw_input()
lst = list(enc)
lst.reverse()
llen = len(lst)
for i in range(llen):
if i % 2 == 0:
lst[i] = chr(ord(lst[i]) - 2)
lst[i] = chr(ord(lst[i]) + 1)
enc2 = ''
enc2 = enc2.join(lst)
enc3 = encode(enc2)
if enc3 == dec:
print "You're right! "
else:
print "You're Wrong! "
# +++ okay decompyling third_test2.pyc
# decompiled 1 files: 1 okay, 0 failed, 0 verify failed
# 2019.02.16 14:17:21 CST
至此,代码已经还原,剩下的题目就很简单了。
解读代码
encode函数实现了一个base64,这里有一点点坑,这里的base64编码范围为abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/,并非原生的ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/,直接转换一下就好
solve.py↓#!/usr/bin/python
# -*- coding: utf-8 -*-
def decode(input_str):
output_str = ''
for i in input_str:
if ord(i)>57 and ord(i)<91:
output_str += i.lower()
elif ord(i)>91:
output_str += i.upper()
else:
output_str += i
lst = list(output_str.decode('base64'))
llen = len(lst)
for i in range(llen):
lst[i] = chr(ord(lst[i]) - 1)
if i % 2 == 0:
lst[i] = chr(ord(lst[i]) + 2)
lst.reverse()
return ''.join(lst)
if __name__ == '__main__':
dec = 'FcjTCgD1EffEm2rPC3bTyL5Wu2bKBI9KAZrwFgrUygHN'
print decode(dec)
参考文章
php反编译opcode,从HGAME的pyc逆向来看手撸opcode相关推荐
- java反编译工具_Android APP 取证之逆向工具篇
一.前言 此系列文章将针对 Android APP 取证领域展开讨论.在国内,由于最近几年国产手机厂商之间的竞争和努力,如今 Android 平台的使用数量和广度,已经远超苹果的 iOS 了.如今 A ...
- ida 反编译 linux bin,使用IDA pro逆向ARM M系核心的Bin固件
物联网和智能设备这两年还是比较火的,我们的手中或多或少都有了几个智能设备,比如手环,智能手表,或者门锁什么之类的东西,但是同学们在做逆向的时候,却有很多问题.要不然是根本拿不到固件,要不然是拿到了Bi ...
- java反编译软件_安卓强大的逆向软件,媲美MT管理器!
手机上目前功能最强大的反编译工具是MT管理器,为手机用户提供了强大的逆向功能. 包括APK签名,优化,共存以及dex反编译等功能 虽然功能强大,但是目前很多功能都要收费,一百多的价格对一般用户来说,确 ...
- 什么是pyc文件,把python的py文件编译成pyc文件,把pyc文件反编译成py文件。以及python编译的如何设置不生成pyc文件
文章目录 1 什么是pyc文件 1.1 什么是pyc文件 1.2 pyc文件是怎么生成的,有什么好处 2 把python的py文件编译成pyc文件 2.1 使用python内置库py_compile把 ...
- python反编译工具uncompyle的安装与用法
下载插件 步骤 List 1 安装: 安装命令:pip install uncompyle; 反编译命令: uncompile -o . 文件名.pyc 注意有两个. 举个
- python编译反编译,你不知道的心机与陷阱
谈到python的文件后缀,说眼花缭乱也不为过.来看看你遇到过哪些类型! .py 如果这个不知道,呵呵-那请出门左拐,你还是充钱那个少年,没有一丝丝改变.接着打游戏去吧- .pyc 这个后缀应该算是除 ...
- vs可以编译python_Python如何进行编译和反编译
用Python写脚本,小程序可谓非常方便,但它需要有特定的python环境才能运行,因此如果你想在别的电脑上运行时就会出现许多问题,就算已经安装了Python,但版本可能相差较大,且相关的依赖库没有安 ...
- 谈谈Python的编译和反编译
用Python写脚本,小程序可谓非常方便,但它需要有特定的python环境才能运行,因此如果你想在别的电脑上运行时就会出现许多问题,就算已经安装了Python,但版本可能相差较大,且相关的依赖库没有安 ...
- Python反编译pyinstaller或py2exe生成的exe可执行文件,获得源码
目录 一.从exe文件中抽取pyc文件 二.将pyc文件反编译为py源码文件 三.更正.pyc文件的头信息 一.从exe文件中抽取pyc文件 直接到下列网址将代码clone下来: GitHub - c ...
最新文章
- 【经典干货】GitHub标星10万+,史上最强Google面试指南!
- HDU - 6599 I Love Palindrome String (回文树+Manacher、回文树+hash)
- ASP.NET Core 基于角色的 JWT 令牌
- git stash简介
- 最近目标检测新范式汇总SparseRCNN,OneNet,DeFCN等
- 获取屏幕,浏览器,网页高度宽度
- win10固态硬盘分区 整数_固态硬盘怎么重装win10系统?Win10固态硬盘重装系统教程...
- Java之父评价C语言之父,Java之父评价C语言之父:C语言撑起了一切
- 进行DosBox的下载与配置
- 如何做一个被领导喜欢的实施顾问
- java基于springboot酒店客房预定管理系统ssm
- HTTP GET 请求在请求体中带参数的问题
- leetcode_Remove Duplicates from Sorted Array
- java中的正则matches方法和find方法的区别
- 命题公式的主合取范式C语言,用C或C++编写程序,要求:输入命题公式,给出它的主合取范式和主析取范式....
- 学数据分析,这些常用术语少不了!
- 什么是GPU?跟CPU有什么区别?终于有人讲明白了
- pacemaker常用命令
- SpringMvc整合邮件发送
- Error 1053: The service did not respond to the start or control request in a timely fashion.问题排查
热门文章
- 亲爱的家长们,是时候展示你们的魅力了,教孩子学编程了
- 如果Fn键一直亮着怎么办?
- java中用户头像是怎么弄的_微信小程序获取用户openid,头像昵称信息,后台java代码...
- Fiddler缓存app数据
- rtx3060和gtx1080选哪个rtx3060和gtx1080差距
- PBB-TE的结构特征与GMPLS控制技术
- Mycat环境搭建和管理及实现jsp通过tomcat连接mysql
- android底部导航栏带消息数的框架,GitHub - BarkSheep/Android-NavMenuLayout: 一个底部导航栏, 实现了显示未读消息数, 显示红点等效果的封装...
- 八卦奇艺收购pps过程
- 方舟生存进化手机版上线,安卓模拟器电脑版攻略提前看:完美匹配手游服