【问题标题】:Converting Disassembled Python Bytecode back into Source Code将反汇编的 Python 字节码转换回源代码
【发布时间】:2016-12-07 11:54:28
【问题描述】:

这不是传统的字节码,而是反汇编的字节码,没有构建编译器来编译这段代码。

我被分配了一个编码器来进行逆向工程。然而,这个编码器被拆解并变成了人类可读的形式。到目前为止,我已经将大部分代码重写回源代码,但遇到倒数第二行的问题,我不知道如何更改为源代码。经过无数小时在互联网上搜索我没有找到的帮助后,如果他们有阅读已反汇编的 python-bytecode 的经验,我会向任何人寻求帮助。 到目前为止我所拥有的:

import sys
YSaM = open
YSam = max
YSaN = len
YSaP = xrange
YSap = sys.argv
YSal = YSaM(sys.argv[1],'r').realines()
YSaW = [l.strip().replace(' ','.') for l in (YSal)]
YSas = YSam([YSaN(l) for l in (YSaW)])  #Missing CALL_FUNCTION_VAR with 0 attributes
YSaO = YSaN(YSaW)
YSak = [l + ('.' * (YSas - YSaN(l))) for l in (YSaW)]
YSaJ = [(s[(YSaN(s)/2):] + s[:(YSaN(s)/2)]) for s in (YSak)]
def YSag(s,f,i):
    YSaw = ''
    if YSaN(s) > YSaO:
        YSaw = YSag(s[:-YSaO],f,i)
    f(s[-YSaO:]) + YSaw
YSao = ''
for x in YSaP(0,YSas):
    YSaL = [l[x] for l in (YSaJ)]
    YSaF = ''.join(YSaL)
    if x%2 == 0:
        YSaF = (YSaF[(x%YSaN(YSaF)):] + YSaF[:(x%YSaN(YSaF))])
    else:
        YSaF = (YSaF[-(x%YSaN(YSaF)):] + YSaF[:-(x%YSaN(YSaF))])
    YSao = YSaF + YSao
YSay = [YSag(YSao,(lambda x: s[x]),x) for x in YSaP(0,YSaO)]
for YSar in (YSay): print YSar

这是以反汇编的 python 字节码提供给我的原始信息:

 14           0 LOAD_CONST               1 ('')
              3 STORE_FAST               3 (YSaw)

 15           6 LOAD_GLOBAL              0 (YSaN)
              9 LOAD_FAST                0 (s)
             12 CALL_FUNCTION            1
             15 LOAD_GLOBAL              1 (YSaO)
             18 COMPARE_OP               4 (>)
             21 POP_JUMP_IF_FALSE       50

 16          24 LOAD_GLOBAL              2 (YSag)
             27 LOAD_FAST                0 (s)
             30 LOAD_GLOBAL              1 (YSaO)
             33 UNARY_NEGATIVE      
             34 SLICE+2             
             35 LOAD_FAST                1 (f)
             38 LOAD_FAST                2 (i)
             41 CALL_FUNCTION            3
             44 STORE_FAST               3 (YSaw)
             47 JUMP_FORWARD             0 (to 50)

 17     >>   50 LOAD_FAST                1 (f)
             53 LOAD_FAST                0 (s)
             56 LOAD_GLOBAL              1 (YSaO)
             59 UNARY_NEGATIVE      
             60 SLICE+1             
             61 CALL_FUNCTION            1
             64 LOAD_FAST                3 (YSaw)
             67 BINARY_ADD          
             68 RETURN_VALUE        
 27           0 LOAD_FAST                0 (s)
              3 LOAD_GLOBAL              0 (x)
              6 BINARY_SUBSCR       
              7 RETURN_VALUE        
  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (sys)
              9 STORE_NAME               0 (sys)

  2          12 LOAD_NAME                1 (open)
             15 STORE_NAME               2 (YSaM)

  3          18 LOAD_NAME                3 (max)
             21 STORE_NAME               4 (YSam)

  4          24 LOAD_NAME                5 (len)
             27 STORE_NAME               6 (YSaN)

  5          30 LOAD_NAME                7 (xrange)
             33 STORE_NAME               8 (YSaP)

  6          36 LOAD_NAME                0 (sys)
             39 LOAD_ATTR                9 (argv)
             42 STORE_NAME              10 (YSap)

  7          45 LOAD_NAME                2 (YSaM)
             48 LOAD_NAME               10 (YSap)
             51 LOAD_CONST               2 (1)
             54 BINARY_SUBSCR       
             55 LOAD_CONST               3 ('r')
             58 CALL_FUNCTION            2
             61 LOAD_ATTR               11 (readlines)
             64 CALL_FUNCTION            0
             67 STORE_NAME              12 (YSal)

  8          70 BUILD_LIST               0
             73 LOAD_NAME               12 (YSal)
             76 GET_ITER            
        >>   77 FOR_ITER                30 (to 110)
             80 STORE_NAME              13 (l)
             83 LOAD_NAME               13 (l)
             86 LOAD_ATTR               14 (strip)
             89 CALL_FUNCTION            0
             92 LOAD_ATTR               15 (replace)
             95 LOAD_CONST               4 (' ')
             98 LOAD_CONST               5 ('.')
            101 CALL_FUNCTION            2
            104 LIST_APPEND              2
            107 JUMP_ABSOLUTE           77
        >>  110 STORE_NAME              16 (YSaW)

  9         113 LOAD_NAME                4 (YSam)
            116 BUILD_LIST               0
            119 LOAD_NAME               16 (YSaW)
            122 GET_ITER            
        >>  123 FOR_ITER                18 (to 144)
            126 STORE_NAME              13 (l)
            129 LOAD_NAME                6 (YSaN)
            132 LOAD_NAME               13 (l)
            135 CALL_FUNCTION            1
            138 LIST_APPEND              2
            141 JUMP_ABSOLUTE          123
        >>  144 CALL_FUNCTION_VAR        0
            147 STORE_NAME              17 (YSas)

 10         150 LOAD_NAME                6 (YSaN)
            153 LOAD_NAME               16 (YSaW)
            156 CALL_FUNCTION            1
            159 STORE_NAME              18 (YSaO)

 11         162 BUILD_LIST               0
            165 LOAD_NAME               16 (YSaW)
            168 GET_ITER            
        >>  169 FOR_ITER                30 (to 202)
            172 STORE_NAME              13 (l)
            175 LOAD_NAME               13 (l)
            178 LOAD_CONST               5 ('.')
            181 LOAD_NAME               17 (YSas)
            184 LOAD_NAME                6 (YSaN)
            187 LOAD_NAME               13 (l)
            190 CALL_FUNCTION            1
            193 BINARY_SUBTRACT     
            194 BINARY_MULTIPLY     
            195 BINARY_ADD          
            196 LIST_APPEND              2
            199 JUMP_ABSOLUTE          169
        >>  202 STORE_NAME              19 (YSak)

 12         205 BUILD_LIST               0
            208 LOAD_NAME               19 (YSak)
            211 GET_ITER            
        >>  212 FOR_ITER                44 (to 259)
            215 STORE_NAME              20 (s)
            218 LOAD_NAME               20 (s)
            221 LOAD_NAME                6 (YSaN)
            224 LOAD_NAME               20 (s)
            227 CALL_FUNCTION            1
            230 LOAD_CONST               6 (2)
            233 BINARY_DIVIDE       
            234 SLICE+1             
            235 LOAD_NAME               20 (s)
            238 LOAD_NAME                6 (YSaN)
            241 LOAD_NAME               20 (s)
            244 CALL_FUNCTION            1
            247 LOAD_CONST               6 (2)
            250 BINARY_DIVIDE       
            251 SLICE+2             
            252 BINARY_ADD          
            253 LIST_APPEND              2
            256 JUMP_ABSOLUTE          212
        >>  259 STORE_NAME              21 (YSaJ)

 13         262 LOAD_CONST               7 (<code object YSag at 0x7f7ca5faa930, file "./slither_encode_obfu_min.py", line 13>)
            265 MAKE_FUNCTION            0
            268 STORE_NAME              22 (YSag)

 18         271 LOAD_CONST               8 ('')
            274 STORE_NAME              23 (YSao)

 19         277 SETUP_LOOP             174 (to 454)
            280 LOAD_NAME                8 (YSaP)
            283 LOAD_CONST               9 (0)
            286 LOAD_NAME               17 (YSas)
            289 CALL_FUNCTION            2
            292 GET_ITER            
        >>  293 FOR_ITER               157 (to 453)
            296 STORE_NAME              24 (x)

 20         299 BUILD_LIST               0
            302 LOAD_NAME               21 (YSaJ)
            305 GET_ITER            
        >>  306 FOR_ITER                16 (to 325)
            309 STORE_NAME              13 (l)
            312 LOAD_NAME               13 (l)
            315 LOAD_NAME               24 (x)
            318 BINARY_SUBSCR       
            319 LIST_APPEND              2
            322 JUMP_ABSOLUTE          306
        >>  325 STORE_NAME              25 (YSaL)

 21         328 LOAD_CONST               8 ('')
            331 LOAD_ATTR               26 (join)
            334 LOAD_NAME               25 (YSaL)
            337 CALL_FUNCTION            1
            340 STORE_NAME              27 (YSaF)

 22         343 LOAD_NAME               24 (x)
            346 LOAD_CONST               6 (2)
            349 BINARY_MODULO       
            350 LOAD_CONST               9 (0)
            353 COMPARE_OP               2 (==)
            356 POP_JUMP_IF_FALSE      400

 23         359 LOAD_NAME               27 (YSaF)
            362 LOAD_NAME               24 (x)
            365 LOAD_NAME                6 (YSaN)
            368 LOAD_NAME               27 (YSaF)
            371 CALL_FUNCTION            1
            374 BINARY_MODULO       
            375 SLICE+1             
            376 LOAD_NAME               27 (YSaF)
            379 LOAD_NAME               24 (x)
            382 LOAD_NAME                6 (YSaN)
            385 LOAD_NAME               27 (YSaF)
            388 CALL_FUNCTION            1
            391 BINARY_MODULO       
            392 SLICE+2             
            393 BINARY_ADD          
            394 STORE_NAME              27 (YSaF)
            397 JUMP_FORWARD            40 (to 440)

 25     >>  400 LOAD_NAME               27 (YSaF)
            403 LOAD_NAME               24 (x)
            406 LOAD_NAME                6 (YSaN)
            409 LOAD_NAME               27 (YSaF)
            412 CALL_FUNCTION            1
            415 BINARY_MODULO       
            416 UNARY_NEGATIVE      
            417 SLICE+1             
            418 LOAD_NAME               27 (YSaF)
            421 LOAD_NAME               24 (x)
            424 LOAD_NAME                6 (YSaN)
            427 LOAD_NAME               27 (YSaF)
            430 CALL_FUNCTION            1
            433 BINARY_MODULO       
            434 UNARY_NEGATIVE      
            435 SLICE+2             
            436 BINARY_ADD          
            437 STORE_NAME              27 (YSaF)

 26     >>  440 LOAD_NAME               27 (YSaF)
            443 LOAD_NAME               23 (YSao)
            446 BINARY_ADD          
            447 STORE_NAME              23 (YSao)
            450 JUMP_ABSOLUTE          293
        >>  453 POP_BLOCK           

 27     >>  454 BUILD_LIST               0
            457 LOAD_NAME                8 (YSaP)
            460 LOAD_CONST               9 (0)
            463 LOAD_NAME               18 (YSaO)
            466 CALL_FUNCTION            2
            469 GET_ITER            
        >>  470 FOR_ITER                27 (to 500)
            473 STORE_NAME              24 (x)
            476 LOAD_NAME               22 (YSag)
            479 LOAD_NAME               23 (YSao)
            482 LOAD_CONST              10 (<code object <lambda> at 0x7f7ca5faf2b0, file "./slither_encode_obfu_min.py", line 27>)
            485 MAKE_FUNCTION            0
            488 LOAD_NAME               24 (x)
            491 CALL_FUNCTION            3
            494 LIST_APPEND              2
            497 JUMP_ABSOLUTE          470
        >>  500 STORE_NAME              28 (YSay)

 28         503 SETUP_LOOP              19 (to 525)
            506 LOAD_NAME               28 (YSay)
            509 GET_ITER            
        >>  510 FOR_ITER                11 (to 524)
            513 STORE_NAME              29 (YSar)
            516 LOAD_NAME               29 (YSar)
            519 PRINT_ITEM          
            520 PRINT_NEWLINE       
            521 JUMP_ABSOLUTE          510
        >>  524 POP_BLOCK           
        >>  525 LOAD_CONST               1 (None)
            528 RETURN_VALUE        

任何帮助将不胜感激!!!

【问题讨论】:

  • 我骗了你一个讨论如何自动反编译的问题。
  • 您的字节码看起来不完整,def YSag(s,f,i): 和之前的所有内容都不存在?
  • 啊,你的顺序搞错了;将代码常量加载到函数中会发生什么,这对于哪个部分属于哪个部分相当混乱。
  • 亲爱的 Martijn Pieters,是的,我相信所有的代码都在那里,他们只是以一种奇怪的方式呈现出来。
  • 是的,我已经检查了一切正常,直到从底部调用 YSag 的 YSay 第 2 行的构建列表。

标签: python reverse-engineering bytecode


【解决方案1】:

您真的想自动执行此操作而不是手动执行此操作;有一些像decompyleuncompyle这样的工具可以从字节码生成Python源代码。

代码对象中的字节码有些混乱,我们缺少代码对象中的co_argcountco_varnames 信息。但是,我很确定列表理解应该是:

YSay = [YSag(YSao, lambda s: s[x], x) for x in YSaP(0, YSaO)]

字节码

            476 LOAD_NAME               22 (YSag)
            479 LOAD_NAME               23 (YSao)
            482 LOAD_CONST              10 (<code object <lambda> at 0x7f7ca5faf2b0, file "./slither_encode_obfu_min.py", line 27>)
            485 MAKE_FUNCTION            0
            488 LOAD_NAME               24 (x)
            491 CALL_FUNCTION            3

从上到下转换为具有x、lambda、YSaoYSag 的堆栈,CALL_FUNCTION 将前 3 个以相反的顺序传递到最后一个,因此调用了YSag(YSao, &lt;lambda&gt;, x)

lambda 从第 27 行加载,其字节码为:

 27           0 LOAD_FAST                0 (s)
              3 LOAD_GLOBAL              0 (x)
              6 BINARY_SUBSCR       
              7 RETURN_VALUE        

这意味着 s 是 lambda 的 参数(它是一个加载有 LOAD_FAST 的本地),而 x 是一个全局的,所以这转换为 lambda s: s[x]

请注意CALL_FUNCTION_VAR 使用*args 调用功能,因此您需要将第 9 行更正为:

YSas = YSam(*[YSaN(l) for l in YSaW])

结果证明这是一种冗长的拼写方式 max(len(l) for l in YSaW),但列表推导扩展为单独的参数,而不是作为单个参数传入的生成器表达式。

我发现使用dis.dis() functioncompile() 来查看我对字节码的解释是否正确很有帮助;输入表达式或语句,输出应与您的字节码大致匹配(带有行号和字节码编号偏移量):

from dis import dis
dis(compile(string, '', 'exec'))

例如,对于最后一行,我验证了结果:

>>> dis(compile('YSas = YSam(*[YSaN(l) for l in YSaW])', '', 'exec'))
  1           0 LOAD_NAME                0 (YSam)
              3 BUILD_LIST               0
              6 LOAD_NAME                1 (YSaW)
              9 GET_ITER
        >>   10 FOR_ITER                18 (to 31)
             13 STORE_NAME               2 (l)
             16 LOAD_NAME                3 (YSaN)
             19 LOAD_NAME                2 (l)
             22 CALL_FUNCTION            1
             25 LIST_APPEND              2
             28 JUMP_ABSOLUTE           10
        >>   31 CALL_FUNCTION_VAR        0
             34 STORE_NAME               4 (YSas)
             37 LOAD_CONST               0 (None)
             40 RETURN_VALUE

对于函数对象,您想从给定的co_consts 条目 (compile(...).co_code.co_consts[an_index]) 中提取代码对象,或者先创建函数,然后将函数对象传递给 dis.dis()

>>> dis(lambda s: s[x])
  1           0 LOAD_FAST                0 (s)
              3 LOAD_GLOBAL              0 (x)
              6 BINARY_SUBSCR
              7 RETURN_VALUE

最后,你得到了一个代码相当糟糕的软件,它把文件中的字符弄得乱七八糟。我已经清除了混淆,并使用了更惯用的 Python 来得出我 认为 会产生相同的输出:

import sys

def rotn(s, n): return s[n:] + s[:n]

with open(sys.argv[1]) as inf:
    lines = [l.strip().replace(' ', '.') for l in inf]

maxlength = max(len(l) for l in lines)
padded = (l.ljust(maxlength, '.') for l in lines)
swapped = [rotn(s, len(s) // 2) for s in padded]

cols = []
for x, col in enumerate(zip(*swapped)):
    offset = (x % len(col)) * (-1 if x % 2 else 1)
    cols.append(rotn(col, offset))

for row in zip(*cols):
    print ''.join(row)

所以用. 将所有已剥离的行填充为相等的长度,交换行的开头和结尾,然后将生成的文本块中的每个向上或向下旋转列号(每列交换方向),然后显示结果文本。

我怀疑这里也不需要使用'.' 而不是空格;放弃 .replace() 调用并离开 str.ljust() 以使用默认的空格填充符可以得到基本相同的结果,但空格保持不变。

【讨论】:

  • 非常感谢!我将立即开始测试。
猜你喜欢
  • 1970-01-01
  • 2013-01-22
  • 2012-12-14
  • 1970-01-01
  • 2014-09-01
  • 1970-01-01
  • 2017-09-24
  • 1970-01-01
  • 2020-11-04
相关资源
最近更新 更多