Python 我应该如何解码这些数据/字符串

Python 我应该如何解码这些数据/字符串,python,string,decompiling,Python,String,Decompiling,我目前正在尝试处理一个旧的python CTF挑战,提供了服务器的脚本,想法是将正确的数据发送到此服务器 #!/usr/bin/env python3 # from dis import dis import socketserver import types class RequestHandler(socketserver.BaseRequestHandler): def handle(self): self.request.sendall(b'PyDRM Pr

我目前正在尝试处理一个旧的python CTF挑战,提供了服务器的脚本,想法是将正确的数据发送到此服务器

#!/usr/bin/env python3
# from dis import dis
import socketserver
import types


class RequestHandler(socketserver.BaseRequestHandler):

    def handle(self):
        self.request.sendall(b'PyDRM Proof of Concept version 0.7\n')
        self.request.sendall(
            b'Submit the secret password to retrieve the flag:\n')
        user_input_bytes = self.request.recv(4096).strip()
        user_input = user_input_bytes.decode('utf-8', 'ignore')
        if validate_password(user_input):
            self.request.sendall(read_flag())
        else:
            self.request.sendall(b'Invalid password\n')


class RequestServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass


def read_flag():
    with open('flag.txt', 'rb') as fh:
        return fh.read()


def generate_validation_function():
    code_obj = types.CodeType(
        1,
        0,
        5,
        32,
        67,
        b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'
        b'\x00d\x08\x00d\x05\x00d\t\x00d\x08\x00d\n\x00d\x01\x00d\x07\x00d\x07'
        b'\x00d\x01\x00d\x0b\x00d\x08\x00d\x07\x00d\x0c\x00d\r\x00d\x0e\x00d'
        b'\x08\x00d\x05\x00d\x0f\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05'
        b'\x00d\x07\x00g \x00}\x01\x00g\x00\x00}\x02\x00x+\x00|\x01\x00D]#\x00'
        b'}\x03\x00|\x02\x00j\x00\x00t\x01\x00t\x02\x00|\x03\x00\x83\x01\x00d'
        b'\x10\x00\x18\x83\x01\x00\x83\x01\x00\x01qs\x00Wd\x11\x00j\x03\x00|'
        b'\x02\x00\x83\x01\x00}\x04\x00|\x00\x00|\x04\x00k\x02\x00r\xb9\x00d'
        b'\x12\x00Sd\x13\x00S',
        (None, '\x87', '\x9a', '\x92', '\x8e', '\x8b', '\x85', '\x96', '\x81',
         '\x95', '\x84', '\x94', '\x8a', '\x83', '\x90', '\x8f', 34, '', True,
         False),
        ('append', 'chr', 'ord', 'join'),
        ('a', 'b', 'c', 'd', 'e'),
        'drm.py',
        'validate_password',
        5,
        b'\x00\x01$\x01$\x01\x1e\x01\x06\x01\r\x01!\x01\x0f\x01\x0c\x01\x04'
        b'\x01',
        (),
        ()
    )
    func_obj = types.FunctionType(code_obj, globals())
    return func_obj


def main():
    setattr(__import__(__name__), 'validate_password',
            generate_validation_function())
    server = RequestServer(('0.0.0.0', 8765), RequestHandler)
    try:
        server.serve_forever()
    except (SystemExit, KeyboardInterrupt):
        server.shutdown()
        server.server_close()

if __name__ == '__main__':
    main()
编辑

我理解,验证密码函数是通过使用CodeType和FunctionType对象创建的。我还了解,如果validate_password(用户输入)的计算结果为True,则会发送该标志。这意味着返回类型必须是布尔型。CodeType文档以及服务器脚本还揭示了validate_password只有一个参数

我的实际问题

源代码包含已编译的python字节码<例如,代码>b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'。我尝试了很多方法对这些字符串进行解码/编码,以获得一些有意义的数据,我唯一能够提取的数据是十六进制数据

如何将此数据转换为实际代码,从而能够重建
validate\u password
功能

我尝试过的

-我试图基本上按照这个答案的建议去做,但反过来说,我要么没有正确理解它,要么这不起作用

b2a_hex()-这就是我如何将字符串转换为十六进制的方法,正如我前面所述,但是,我无法从这个十六进制生成utf-8数据


struct.unpack()-使用此方法取得了一些成功,但是我不知道数据在validate_password函数的上下文中的含义,我只能使用此方法获取整数。(除非我误解了)

启动交互式Python 3会话。如果使用普通python解释器,请键入

import types
help(types.CodeType)
如果您使用的是IPython,则可以改为编写

import types
types.CodeType?
您将了解
类型。CodeType

创建一个代码对象。不适合胆小的人

嗯,胡。什么是代码对象?让我们看一看

返回的代码对象(例如)的类型

因此,bytestring参数可能至少部分是二进制数据(或二进制指令),而不是以某种方式编码的(文本)字符串

帮助
调用还告诉我们该类型的初始值设定项的签名:

这样,我们就可以更自我描述地编写结构:

    code_obj = types.CodeType(
        argcount=1,
        kwonlyargcount=0,
        nlocals=5,
        stacksize=32,
        flags=67,
        codestring=b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'
        b'\x00d\x08\x00d\x05\x00d\t\x00d\x08\x00d\n\x00d\x01\x00d\x07\x00d\x07'
        b'\x00d\x01\x00d\x0b\x00d\x08\x00d\x07\x00d\x0c\x00d\r\x00d\x0e\x00d'
        b'\x08\x00d\x05\x00d\x0f\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05'
        b'\x00d\x07\x00g \x00}\x01\x00g\x00\x00}\x02\x00x+\x00|\x01\x00D]#\x00'
        b'}\x03\x00|\x02\x00j\x00\x00t\x01\x00t\x02\x00|\x03\x00\x83\x01\x00d'
        b'\x10\x00\x18\x83\x01\x00\x83\x01\x00\x01qs\x00Wd\x11\x00j\x03\x00|'
        b'\x02\x00\x83\x01\x00}\x04\x00|\x00\x00|\x04\x00k\x02\x00r\xb9\x00d'
        b'\x12\x00Sd\x13\x00S',
        constants=(None, '\x87', '\x9a', '\x92', '\x8e', '\x8b', '\x85', '\x96', '\x81',
         '\x95', '\x84', '\x94', '\x8a', '\x83', '\x90', '\x8f', 34, '', True,
         False),
        names=('append', 'chr', 'ord', 'join'),
        varnames=('a', 'b', 'c', 'd', 'e'),
        filename='drm.py',
        name='validate_password',
        firstlineno=5,
        lnotab=b'\x00\x01$\x01$\x01\x1e\x01\x06\x01\r\x01!\x01\x0f\x01\x0c\x01\x04'
        b'\x01',
        freevars=(),
        cellvars=()
    )
(这只是为了说明。它实际上不是这样可执行的,因为
types.CodeType()
希望所有参数都按位置传递,而不是作为关键字参数传递。)

这一切意味着什么

您可以反汇编代码对象以更接近该问题:

import dis
dis.dis(code_obj)
(产出:)

有关(
LOAD_CONST
BUILD_LIST
等),请参阅
dis
文档


为了更好地理解该函数正在做什么,可以尝试将其反编译回Python代码。不过,我没有做到这一点。(尝试过。)

根据das-g的答案,此代码有效。索塔

import uncompyle6
import types
code_obj = types.CodeType(
        1, 0, 5, 32, 67, b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'
        b'\x00d\x08\x00d\x05\x00d\t\x00d\x08\x00d\n\x00d\x01\x00d\x07\x00d\x07'
        b'\x00d\x01\x00d\x0b\x00d\x08\x00d\x07\x00d\x0c\x00d\r\x00d\x0e\x00d'
        b'\x08\x00d\x05\x00d\x0f\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05'
        b'\x00d\x07\x00g \x00}\x01\x00g\x00\x00}\x02\x00x+\x00|\x01\x00D]#\x00'
        b'}\x03\x00|\x02\x00j\x00\x00t\x01\x00t\x02\x00|\x03\x00\x83\x01\x00d'
        b'\x10\x00\x18\x83\x01\x00\x83\x01\x00\x01qs\x00Wd\x11\x00j\x03\x00|'
        b'\x02\x00\x83\x01\x00}\x04\x00|\x00\x00|\x04\x00k\x02\x00r\xb9\x00d'
        b'\x12\x00Sd\x13\x00S',
        (None, '\x87', '\x9a', '\x92', '\x8e', '\x8b', '\x85', '\x96', '\x81',
         '\x95', '\x84', '\x94', '\x8a', '\x83', '\x90', '\x8f', 34, '', True,
         False),
        ('append', 'chr', 'ord', 'join'),
        ('a', 'b', 'c', 'd', 'e'),
        'drm.py',
        'validate_password',
        5,
        b'\x00\x01$\x01$\x01\x1e\x01\x06\x01\r\x01!\x01\x0f\x01\x0c\x01\x04'
        b'\x01',
        freevars=(),
        cellvars=()
    )

import sys
uncompyle6.main.uncompyle(3.5, code_obj, sys.stdout)
这里缺少的是,这段代码实际上被包装在一个接受“a”参数的函数中

我不会破坏给出答案的乐趣。相反:

  • 运行上述程序
  • 将输出包装为:
    
    def drm(a):
    #从上面运行的输出。
    

  • 装配的第一行相当于:b=[1,2,3,4,5,6,5,7,8,9,8(换行)10,1,…];c=[]和一个for循环,该循环先累加到c,然后累加到e=''。如果a==e,则连接(c)并返回true或false。(A是通过或设置之前?@rocky你是怎么发现的?也许值得一个答案。快速检查代码。通过chr(ord(d))构建更多的c,其中d是循环迭代器。如果您提供Python版本号,例如3.5或2.7,则可以让uncompyle6完成这项工作。看,我在解压函数方面遇到了一些问题。正在传递python版本和代码。xdis的
    scannerX.py
    (其中x是主要的python版本)
    中出现错误。字节码导入字节码,findlinestarts导入错误:无法导入名称findlinestarts
    。为了澄清,xdis包似乎安装正确,其中bytecode.py包含_findlinestarts函数感谢您帮助我完成这一过程。无需道歉,很高兴仍在维护一个有价值的工具,通过pip成功地更新了,所以我们已经做了一切来保持包的最新:)@das-g提供了一个丰富的答案,有大量的证据等,但是这种方法基本上自动化了我为他们的方法所经历的步骤。为了澄清,上述方法奏效了。我不会为其他人破坏这个CTF。但仔细看一下政治公众人物文件,你也会知道密码:)
      6           0 LOAD_CONST               1 ('\x87') 
                  3 LOAD_CONST               2 ('\x9a') 
                  6 LOAD_CONST               3 ('\x92') 
                  9 LOAD_CONST               4 ('\x8e') 
                 12 LOAD_CONST               5 ('\x8b') 
                 15 LOAD_CONST               6 ('\x85') 
                 18 LOAD_CONST               5 ('\x8b') 
                 21 LOAD_CONST               7 ('\x96') 
                 24 LOAD_CONST               8 ('\x81') 
                 27 LOAD_CONST               5 ('\x8b') 
                 30 LOAD_CONST               9 ('\x95') 
                 33 LOAD_CONST               8 ('\x81') 
    
      7          36 LOAD_CONST              10 ('\x84') 
                 39 LOAD_CONST               1 ('\x87') 
                 42 LOAD_CONST               7 ('\x96') 
                 45 LOAD_CONST               7 ('\x96') 
                 48 LOAD_CONST               1 ('\x87') 
                 51 LOAD_CONST              11 ('\x94') 
                 54 LOAD_CONST               8 ('\x81') 
                 57 LOAD_CONST               7 ('\x96') 
                 60 LOAD_CONST              12 ('\x8a') 
                 63 LOAD_CONST              13 ('\x83') 
                 66 LOAD_CONST              14 ('\x90') 
                 69 LOAD_CONST               8 ('\x81') 
    
      8          72 LOAD_CONST               5 ('\x8b') 
                 75 LOAD_CONST              15 ('\x8f') 
                 78 LOAD_CONST               3 ('\x92') 
                 81 LOAD_CONST               4 ('\x8e') 
                 84 LOAD_CONST               5 ('\x8b') 
                 87 LOAD_CONST               6 ('\x85') 
                 90 LOAD_CONST               5 ('\x8b') 
                 93 LOAD_CONST               7 ('\x96') 
                 96 BUILD_LIST              32 
                 99 STORE_FAST               1 (b) 
    
      9         102 BUILD_LIST               0 
                105 STORE_FAST               2 (c) 
    
     10         108 SETUP_LOOP              43 (to 154) 
                111 LOAD_FAST                1 (b) 
                114 GET_ITER             
            >>  115 FOR_ITER                35 (to 153) 
                118 STORE_FAST               3 (d) 
    
     11         121 LOAD_FAST                2 (c) 
                124 LOAD_ATTR                0 (append) 
                127 LOAD_GLOBAL              1 (chr) 
                130 LOAD_GLOBAL              2 (ord) 
                133 LOAD_FAST                3 (d) 
                136 CALL_FUNCTION            1 
                139 LOAD_CONST              16 (34) 
                142 BINARY_SUBTRACT      
                143 CALL_FUNCTION            1 
                146 CALL_FUNCTION            1 
                149 POP_TOP              
                150 JUMP_ABSOLUTE          115 
            >>  153 POP_BLOCK            
    
     12     >>  154 LOAD_CONST              17 ('') 
                157 LOAD_ATTR                3 (join) 
                160 LOAD_FAST                2 (c) 
                163 CALL_FUNCTION            1 
                166 STORE_FAST               4 (e) 
    
     13         169 LOAD_FAST                0 (a) 
                172 LOAD_FAST                4 (e) 
                175 COMPARE_OP               2 (==) 
                178 POP_JUMP_IF_FALSE      185 
    
     14         181 LOAD_CONST              18 (True) 
                184 RETURN_VALUE         
    
     15     >>  185 LOAD_CONST              19 (False) 
                188 RETURN_VALUE         
    
    import uncompyle6
    import types
    code_obj = types.CodeType(
            1, 0, 5, 32, 67, b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'
            b'\x00d\x08\x00d\x05\x00d\t\x00d\x08\x00d\n\x00d\x01\x00d\x07\x00d\x07'
            b'\x00d\x01\x00d\x0b\x00d\x08\x00d\x07\x00d\x0c\x00d\r\x00d\x0e\x00d'
            b'\x08\x00d\x05\x00d\x0f\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05'
            b'\x00d\x07\x00g \x00}\x01\x00g\x00\x00}\x02\x00x+\x00|\x01\x00D]#\x00'
            b'}\x03\x00|\x02\x00j\x00\x00t\x01\x00t\x02\x00|\x03\x00\x83\x01\x00d'
            b'\x10\x00\x18\x83\x01\x00\x83\x01\x00\x01qs\x00Wd\x11\x00j\x03\x00|'
            b'\x02\x00\x83\x01\x00}\x04\x00|\x00\x00|\x04\x00k\x02\x00r\xb9\x00d'
            b'\x12\x00Sd\x13\x00S',
            (None, '\x87', '\x9a', '\x92', '\x8e', '\x8b', '\x85', '\x96', '\x81',
             '\x95', '\x84', '\x94', '\x8a', '\x83', '\x90', '\x8f', 34, '', True,
             False),
            ('append', 'chr', 'ord', 'join'),
            ('a', 'b', 'c', 'd', 'e'),
            'drm.py',
            'validate_password',
            5,
            b'\x00\x01$\x01$\x01\x1e\x01\x06\x01\r\x01!\x01\x0f\x01\x0c\x01\x04'
            b'\x01',
            freevars=(),
            cellvars=()
        )
    
    import sys
    uncompyle6.main.uncompyle(3.5, code_obj, sys.stdout)