吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 12811|回复: 31
收起左侧

[原创] hgame一次pyc文件恢复

  [复制链接]
Moon3r 发表于 2019-3-26 20:05

一次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 addr<->lineno mapping) */
} PyCodeObject;

加载pyc co_code

In [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',
<code object encode at 0x7f0420ee7f30, file "third.py", line 7>,
"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<n\x00\x00e\x0e\x00e\x0f\x00e\x08\x00e\r\x00\x19\x83\x01\x00d\x0c\x00\x17\x83\x01\x00e\x08\x00e\r\x00<q\x8d\x00Wd\r\x00Z\x10\x00e\x10\x00j\x11\x00e\x08\x00\x83\x01\x00Z\x10\x00e\x05\x00e\x10\x00\x83\x01\x00Z\x12\x00e\x12\x00e\x04\x00k\x02\x00r\x1b\x01d\x0e\x00GHn\x05\x00d\x0f\x00GHd\x01\x00S'

使用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查看文件

viewhd.png

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

通过opcodehexdump可以确定,当前co_code长度为0x132(此处为小端显示,0x1a1b位置),0x1e0x2c(左闭右开)这部分为混淆代码,直接从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

至此,代码已经还原,剩下的题目就很简单了。

解读代码

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)

参考文章

http://butian.360.cn/School/content?id=429

https://0x48.pw/2017/03/20/0x2f

免费评分

参与人数 21吾爱币 +19 热心值 +18 收起 理由
yang1357245880 + 1 我很赞同!
yao109123 + 1 + 1 &amp;amp;#128077;
xbxbxbxb + 1 + 1 我很赞同!
drakpj + 1 + 1 热心回复!
一念苍穹变 + 1 + 1 热心回复!
wxqhi + 1 + 1 我很赞同!
scraw + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
GDG + 1 + 1 感谢您的宝贵建议,我们会努力争取做得更好!
jizhihaoSAMA + 1 谢谢@Thanks!
javacafe + 1 + 1 热心回复!
静叶流云 + 1 + 1 用心讨论,共获提升!
啥都不会的萌新 + 1 + 1 热心回复!
QuanMax + 1 + 1 谢谢@Thanks!
Bayerischen + 1 用心讨论,共获提升!
GinkgoGO + 1 + 1 刚看见大佬在TOOLS,现在又看到大佬在52,大佬就是大佬啊
调味包 + 1 + 1 谢谢@Thanks!
Jerry_bean + 1 谢谢@Thanks!
白日梦梦妖 + 1 热心回复!
Cailgun + 1 + 1 热心回复!
gink + 1 + 1 热心回复!
姚小宝 + 1 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| Moon3r 发表于 2019-3-27 15:45
HugoMok 发表于 2019-3-27 14:53
hgame?我觉得我应该没有看错,大佬大佬。

确实是hgame,应该是第三周的python3&4那个题目,具体的记不太清了
 楼主| Moon3r 发表于 2019-4-1 12:42
hcldxw 发表于 2019-3-26 20:18
 楼主| Moon3r 发表于 2019-3-26 21:00

互相学习
一叶知夏 发表于 2019-3-27 08:49
向大佬学习~
dctm 发表于 2019-3-27 13:03
厉害厉害,
HugoMok 发表于 2019-3-27 14:53
hgame?我觉得我应该没有看错,大佬大佬。
迷途的小蜜蜂 发表于 2019-3-28 10:16
哇,大佬,不明觉厉。。。。膜拜大佬操作神仙
pleaidler 发表于 2019-3-30 10:34
厉害,收藏学习
Bayerischen 发表于 2019-3-30 21:46
向大佬学习
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2022-8-16 22:16

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表