【原创】用 Python 反编译 Python 软件

标 题: 【原创】用 Python 反编译 Python 软件
作 者: Ptero
时 间: 2010-04-21,16:28:27
链 接: http://bbs.pediy.com/showthread.php?t=111428

【文章标题】: 用 Python 反编译 Python 软件
【文章作者】: Ptero
【软件名称】: ****
【下载地址】: ****
【加壳方式】: UPX
【保护方式】: 序列号,重启验证
【使用工具】: 7-zip, LordPE, Python, WinHex
【操作平台】: Windows, Linux
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪软件安全论坛, 转载请注明作者并保持文章的完整, 谢谢!

论坛讨论 Python 的文章似乎比较少。此文权当抛砖引玉,不当之处请多指教。

关于 Py 的反编译,网上流传的说法是,2.4 版本以后的比较困难。因为针对低版本,有一些开源代码可以实现反编译。到 2.4  以后,原作者要么不更新了,要么开始收费了。只有少数牛人能修改旧版的代码继续反编译下去。
    本文提供了一种方法,使得在没有反编译器的情况下,也能分析用 Python 写的软件。

下面开始。

试炼软件是用 upx 加壳的,upx -d 简单脱掉。
    再用 peid 查看, 发现如下信息:
Microsoft Visual C++ 7.0 Method2 [ZIP SFX]。
很少见。再用OD加载,查看字符串,发现是 py2exe 生成的。
这种文件,可以用 7zip 当作压缩包打开,里面可以看到一堆编译好的 pyc 和 pyo 文件。从名称来看,那些应该是 Python 自带的库文件,与程序无关。这里从库文件的名称可以看出是 Python 2.4 版本。

程序自带了一个 pyo 文件,200 多 K。网上找到能免费反编译 Python 2.4 以后版本的,只有 decompyler 2.3 的一个修改版(2.3 开源,后续版本收费了), 还有就是 UnPyc。
    decompyler 的修改版,我没有找到。UnPyc,貌似只支持 Linux 的。在学校的 Linux 服务器上安装上,反编译却得到一堆错误。反汇编(生成 bytecode 的助记符,相当于汇编代码)倒是可以。

在反汇编当中查找关键字符串,没找到。我把所有的函数名称看了一遍,也没有可疑的。看来那个 200 多 K 的文件,不是关键代码所在。还得另谋出路。

关键代码不在附带的库里面,那还能在哪里呢?只能在程序自身了!一定是 py2exe 把那些代码编到 exe 里面了。
    有2种可能:1、编成 native code。2、编成 Python bytecode,通过 Python 虚拟机执行。在OD中跟踪一下,发现执行到关键代码的时候,已经处在虚拟机的代码之中了。所以排除 1 的可能性。

下面,要找出关键代码的藏身之处。代码会藏在哪呢?.text 段?不大可能,因为那里都是 sfx 的代码。.data 段?也不可能,因为那里的数据只会被 sfx 用到。在 zip 压缩包里面?没找到可疑文件。那么,只剩下 .rsrc 了!

用 LordPE 查看资源段(这里不用 Reshacker,因为它 dump 下来的不正确),找到 “Python24.dll”, “PZIB.PYD”,还有就是 “PYTHONSCRIPT”。光是看名字就很可疑了。把它 dump 下来,在 WinHex 当中查找关键字符串,果然找到了。
    下面就是要如何反编译这个 script 了。

网上没有找到相关资料。于是下载了一份 py2exe 源码,找到这里:

引用:

# We create a list of code objects, and write it as a marshaled
        # stream.  The framework code then just exec's these in order.
        # First is our common boot script.
        boot = self.get_boot_script("common")
        boot_code = compile(file(boot, "U").read(),
                            os.path.abspath(boot), "exec")
        code_objects = [boot_code]
        if self.bundle_files < 3:
            code_objects.append(
                compile("import zipextimporter; zipextimporter.install()",
                        "<install zipextimporter>", "exec"))
        for var_name, var_val in vars.items():
            code_objects.append(
                    compile("%s=%r\n" % (var_name, var_val), var_name, "exec")
            )
        if self.custom_boot_script:
            code_object = compile(file(self.custom_boot_script, "U").read() + "\n",
                                  os.path.abspath(self.custom_boot_script), "exec")
            code_objects.append(code_object)
        if script:
            code_object = compile(open(script, "U").read() + "\n",
                                  os.path.basename(script), "exec")
            code_objects.append(code_object)
        code_bytes = marshal.dumps(code_objects)

if self.distribution.zipfile is None:
            relative_arcname = ""

si = struct.pack("iiii",
                         0x78563412, # a magic value,
                         self.optimize,
                         self.unbuffered,
                         len(code_bytes),
                         ) + relative_arcname + "\000"

script_bytes = si + code_bytes + '\000\000'
        self.announce("add script resource, %d bytes" % len(script_bytes))
        if not self.dry_run:
            add_resource(ensure_unicode(exe_path), script_bytes, u"PYTHONSCRIPT", 1, True)

可以看出,是由几个 py 文件编译后,添加到一个 list 里面,然后直接 dump 下来的,当然前后还加了一堆东西。

用 WinHex 修改 dump 下来的文件,把添加的东西都去掉,这样就只剩下了 code_bytes。

现在,本文的主人公要华丽地出场了!有请 Python!(掌声)

在 Python 中输入:

代码:
>>>import marshal
>>>mylist=marshal.load(open("dumpfile", "r"))

目的是为了把 dump 下来的文件加载到内存当中,成为 Python 的一个对象。

引用:

注:加载dump下来的对象,Python 版本一定要和 dump 时候的版本兼容才行。这个例子中,dump 时用的 2.4 ,我用 2.5 load,完全可以。用 3.1 load,就出错了。

现在可以看看我们的这个对象了:

代码:
>>>mylist
[<code object ? at 0xb75df650, file "D:\python24\lib\site-packages\py2exe\boot_common.py", line 44>, <code object ? at 0xb75df698, file "<install zipextimporter>", line 1>, <code object ? at 0xb75f4ad0, file "****.py", line 2>]

包含了 3 个 code object 对象。第一个是 py2exe 初始化用的,第二个是解压 zip 用的,第三个就是我们的关键脚本了。

这里简单介绍一下 py, pyc, pyo, bytecode, code object 之间的关系。py 是 Python 的源代码文件,纯文本文件。用 Python 可以编译成二进制伪代码,也就是 bytecode。code object 实际上就是这些伪代码。把 code object 前面加一个 header,写成文件,就是 pyc 了,也就是编译过的 py 文件。如果在编译的时候加上优化选项,则会生成 pyo 文件,也就是优化过的 py 文件,本质上和 pyc 是一样的。
    如果说 py 相当于 java 文件,那么 pyc, pyo, bytecode, code object 就相当于 class 文件了。

下面言归正传。
    Python 有一个很好很强大的库:dis,里面有一个很好很强大的同名函数:dis()。这个函数就是实现反汇编功能了。它能把 code object 生成可读的代码(类似于汇编)。
    对这个函数加以简单扩展,可以让其变得更好更强大。(参见  http://blog.csdn.net/balabalamerober...2/1662025.aspx)

代码:
import dis as pydis
import typescode = None
def read(filename):f = open(filename)content = f.read()global codecode = compile(content, filename, 'exec')f.close()def find_code(code, name):for item in code.co_consts:if isinstance(item, types.CodeType):if item.co_name == name:return itemreturn Nonedef dis(code_name=None):if code_name is None:co = codepydis.dis(co)return conames = code_name.split(".")co = codefor name in names:co = find_code(co, name)if not co:print '%s is not a valid name' % code_nameif co:print ("   byte code for %s  " % code_name).center(60, '*')pydis.dis(co)

下面就可以慢慢找出关键模块了。

首先看一下模块包含哪些常量:

代码:
>>>mylist[2].co_consts:
(1, None, ('gdi',), ('EnumProcesses',), ('Button',), ('Editbox',), ('Textin',), ('LOWORD', 'HIWORD', 'RGB', 'RECT'), ('Msg',), ('Listview',), ('Listbox',), ('Combobox',), ('Checkbox',), ('Radiobox',), ('Treeview',), ('StaticText',), ('Groupbox',), ('ContextMenu',), ('Menu',), ('SystemCursor',), ('GetVirtualScreenSize',), ('static',), ('Queue',), ('latin_1', 'gbk', 'utf_8', 'ascii', 'gb2312', 'gb18030'), ('StringIO',), ('dbapi2',), ('WinExec',), ('CF_TEXT', 'GHND'), 'Display_REG_Dialog', <code object Display_REG_Dialog at 0xb7cc9f50, file "****.py", line 50>, 'Display_INPUT_Dialog', <code object Display_INPUT_Dialog at 0xb7cd7188, file "****.py", line 96>, 'Display_INPUT_TIME_Dialog', <code object Display_INPUT_TIME_Dialog at 0xb7cd7380, file "****.py", line 134>, 'Setup_Find_Dialog', <code object Setup_Find_Dialog at 0xb7cd7530, file "****.py", line 168>, 'Get_yo2_user_Dialog', <code object Get_yo2_user_Dialog at 0xb7cd7770, file "****.py", line 209>, 'Edit_User_Dialog', <code object Edit_User_Dialog at 0xb7cd79b0, file "****.py", line 279>, 'Add_User_Dialog', <code object Add_User_Dialog at 0xb7cd7d10, file "****.py", line 332>, 'Add_Cate_Dialog', <code object Add_Cate_Dialog at 0xb7cd7f50, file "****.py", line 546>, 'Get_Pic_Dialog', <code object Get_Pic_Dialog at 0xb7cdd260, file "****.py", line 602>, 'Get_MPic_Dialog', <code object Get_MPic_Dialog at 0xb7cdd530, file "****.py", line 934>, 'Select_ExportType_Dialog', <code object Select_ExportType_Dialog at 0xb7cdd9b0, file "****.py", line 1276>, 'Setup_PROXY_Dialog', <code object Setup_PROXY_Dialog at 0xb7cddad0, file "****.py", line 1412>, 'Update_Dialog', <code object Update_Dialog at 0xb7cddba8, file "****.py", line 1564>, 'MyWindow', <code object MyWindow at 0xb7cef2f0, file "****.py", line 1698>, '')

Display_REG_Dialog 这个比较可疑,但是跟进去发现只是保存了注册码就返回了。相关代码省略。
因为软件是在启动时检测注册码的,所以窗口的启动代码也比较可疑。

代码:
>>>import sdis
>>>sdis.code = mylist[2]
>>>sdis.dis("MyWindow.__init__")
************   byte code for MyWindow.__init__  ************
(省略部分代码)
1732         439 LOAD_CONST               5 (0)442 STORE_FAST               8 (conf_user_tag)1733         445 LOAD_GLOBAL             40 (os)448 LOAD_ATTR               35 (path)451 LOAD_ATTR               41 (isfile)454 LOAD_CONST              21 ('****.ini')457 CALL_FUNCTION            1460 JUMP_IF_FALSE           48 (to 511)463 POP_TOP             1734         464 SETUP_EXCEPT            28 (to 495)1735         467 LOAD_GLOBAL             42 (dict4ini)470 LOAD_ATTR               43 (DictIni)473 LOAD_CONST              21 ('****.ini')476 CALL_FUNCTION            1479 LOAD_FAST                0 (self)482 STORE_ATTR              44 (conf_user)1736         485 LOAD_CONST              22 (1)488 STORE_FAST               8 (conf_user_tag)491 POP_BLOCK           492 JUMP_ABSOLUTE          5181737     >>  495 POP_TOP             496 POP_TOP             497 POP_TOP             1738         498 LOAD_CONST               5 (0)501 STORE_FAST               8 (conf_user_tag)504 JUMP_ABSOLUTE          518507 END_FINALLY         508 JUMP_FORWARD             7 (to 518)>>  511 POP_TOP             1740         512 LOAD_CONST               5 (0)515 STORE_FAST               8 (conf_user_tag)1741     >>  518 LOAD_FAST                8 (conf_user_tag)521 LOAD_CONST               5 (0)524 COMPARE_OP               2 (==)527 JUMP_IF_FALSE           50 (to 580)530 POP_TOP             1742         531 LOAD_GLOBAL             42 (dict4ini)534 LOAD_ATTR               43 (DictIni)537 LOAD_CONST              21 ('****.ini')540 CALL_FUNCTION            1543 LOAD_FAST                0 (self)546 STORE_ATTR              44 (conf_user)1743         549 LOAD_CONST              23 ('')552 LOAD_FAST                0 (self)555 LOAD_ATTR               44 (conf_user)558 LOAD_ATTR               45 (config)561 STORE_ATTR              46 (regnum)1744         564 LOAD_FAST                0 (self)567 LOAD_ATTR               44 (conf_user)570 LOAD_ATTR               47 (save)573 CALL_FUNCTION            0576 POP_TOP             577 JUMP_FORWARD             1 (to 581)>>  580 POP_TOP             1745     >>  581 LOAD_FAST                0 (self)584 LOAD_ATTR               44 (conf_user)587 LOAD_ATTR               48 (has_key)590 LOAD_CONST              24 ('config')593 CALL_FUNCTION            1596 JUMP_IF_TRUE            32 (to 631)599 POP_TOP             1746         600 LOAD_CONST              23 ('')603 LOAD_FAST                0 (self)606 LOAD_ATTR               44 (conf_user)609 LOAD_ATTR               45 (config)612 STORE_ATTR              46 (regnum)1747         615 LOAD_FAST                0 (self)618 LOAD_ATTR               44 (conf_user)621 LOAD_ATTR               47 (save)624 CALL_FUNCTION            0627 POP_TOP             628 JUMP_FORWARD             1 (to 632)>>  631 POP_TOP             1748     >>  632 LOAD_FAST                0 (self)635 LOAD_ATTR               44 (conf_user)638 LOAD_ATTR               45 (config)641 LOAD_ATTR               48 (has_key)644 LOAD_CONST              25 ('regnum')647 CALL_FUNCTION            1650 JUMP_IF_TRUE            32 (to 685)653 POP_TOP             1749         654 LOAD_CONST              23 ('')657 LOAD_FAST                0 (self)660 LOAD_ATTR               44 (conf_user)663 LOAD_ATTR               45 (config)666 STORE_ATTR              46 (regnum)1750         669 LOAD_FAST                0 (self)672 LOAD_ATTR               44 (conf_user)675 LOAD_ATTR               47 (save)678 CALL_FUNCTION            0681 POP_TOP             682 JUMP_FORWARD             1 (to 686)>>  685 POP_TOP             1751     >>  686 LOAD_CONST              23 ('')689 LOAD_FAST                0 (self)692 STORE_ATTR              49 (regno)1752         695 LOAD_CONST              23 ('')698 LOAD_FAST                0 (self)701 STORE_ATTR              50 (regno2)1753         704 LOAD_FAST                0 (self)707 LOAD_ATTR               51 (get_reg_no_true)710 CALL_FUNCTION            0713 LOAD_FAST                0 (self)716 STORE_ATTR              52 (reg_true)

上面是取注册码,并且调用 get_reg_no_true() 函数来验证,然后把结果保存在 reg_true 变量里面。再往下看:

代码:
2110     >> 4879 LOAD_FAST                0 (self)4882 LOAD_ATTR               52 (reg_true)4885 LOAD_CONST             214 ('YES')4888 COMPARE_OP               3 (!=)4891 JUMP_IF_FALSE           29 (to 4923)4894 POP_TOP      2111        4895 LOAD_GLOBAL            155 (Msg)4898 LOAD_FAST                0 (self)4901 LOAD_ATTR              156 (Hwnd)4904 LOAD_CONST             228 ('\xb5\xb1\xc7\xb0****\xce\xaa\xce\xb4\xd7\xa2\xb2\xe1\xb0\xe6\xb1\xbe\xa3\xac\xb5\xbc\xb3\xf6\xb9\xa6\xc4\xdc\xbb\xe1\xca\xdc\xb5\xbd\xcf\xde\xd6\xc6\xa3\xac\xc7\xeb\xb5\xbd****.com\xb8\xb6\xb7\xd1\xd7\xa2\xb2\xe1\xa3\xa1')4907 LOAD_CONST             229 ('\xcc\xe1\xca\xbe')4910 LOAD_CONST             225 ('ok')4913 LOAD_CONST             226 ('defbutton1')4916 CALL_FUNCTION            54919 POP_TOP             4920 JUMP_FORWARD             1 (to 4924)>> 4923 POP_TOP

如果 reg_true 不等于 'YES',就要弹出提示注册的对话框了。
关键 call 就是 get_reg_no_true() 了。只要让其返回 'YES' 便可。

这里可以修改 get_reg_no_true() 爆破了,但既然已经走了这么远了,索性再走一程,深入关键 call 去看个究竟。

代码:
>>>sdis.dis("MyWindow.get_reg_no_true")
********   byte code for MyWindow.get_reg_no_true  *********
2117           0 SETUP_EXCEPT           638 (to 641)2118           3 SETUP_EXCEPT           173 (to 179)2119           6 LOAD_CONST               1 ('')9 STORE_FAST               9 (mac_address)2120          12 LOAD_CONST               2 ('.')15 STORE_FAST               6 (strComputer)2121          18 LOAD_GLOBAL              2 (win32com)21 LOAD_ATTR                3 (client)24 LOAD_ATTR                4 (Dispatch)27 LOAD_CONST               3 ('WbemScripting.SWbemLocator')30 CALL_FUNCTION            133 STORE_FAST               3 (objWMIService)2122          36 LOAD_FAST                3 (objWMIService)39 LOAD_ATTR                6 (ConnectServer)42 LOAD_FAST                6 (strComputer)45 LOAD_CONST               4 ('root\\cimv2')48 CALL_FUNCTION            251 STORE_FAST               8 (objSWbemServices)2123          54 LOAD_FAST                8 (objSWbemServices)57 LOAD_ATTR                8 (ExecQuery)60 LOAD_CONST               5 ('Select * from Win32_NetworkAdapter')63 CALL_FUNCTION            166 STORE_FAST              10 (colItems)2124          69 SETUP_LOOP              80 (to 152)72 LOAD_FAST               10 (colItems)75 GET_ITER            >>   76 FOR_ITER                72 (to 151)79 STORE_FAST               4 (objItem)2125          82 LOAD_FAST                4 (objItem)85 LOAD_ATTR               11 (MACAddress)88 LOAD_CONST               0 (None)91 COMPARE_OP               3 (!=)94 JUMP_IF_FALSE           50 (to 147)97 POP_TOP             2142          98 LOAD_CONST               6 ('VEN_')101 LOAD_FAST                4 (objItem)104 LOAD_ATTR               13 (PNPDeviceID)107 COMPARE_OP               6 (in)110 JUMP_IF_FALSE           30 (to 143)113 POP_TOP             114 LOAD_CONST               7 ('DEV_')117 LOAD_FAST                4 (objItem)120 LOAD_ATTR               13 (PNPDeviceID)123 COMPARE_OP               6 (in)126 JUMP_IF_FALSE           14 (to 143)129 POP_TOP             2143         130 LOAD_FAST                4 (objItem)133 LOAD_ATTR               11 (MACAddress)136 STORE_FAST               9 (mac_address)2145         139 BREAK_LOOP          140 JUMP_ABSOLUTE          148>>  143 POP_TOP             144 JUMP_ABSOLUTE           76>>  147 POP_TOP             >>  148 JUMP_ABSOLUTE           76>>  151 POP_BLOCK           2146     >>  152 LOAD_FAST                9 (mac_address)155 LOAD_CONST               1 ('')158 COMPARE_OP               2 (==)161 JUMP_IF_FALSE           10 (to 174)164 POP_TOP             2147         165 LOAD_CONST               8 ('00:0A:EB:F5:D4:14')168 STORE_FAST               9 (mac_address)171 JUMP_FORWARD             1 (to 175)>>  174 POP_TOP             >>  175 POP_BLOCK           176 JUMP_FORWARD            13 (to 192)2148     >>  179 POP_TOP             180 POP_TOP             181 POP_TOP             2149         182 LOAD_CONST               8 ('00:0A:EB:F5:D4:14')185 STORE_FAST               9 (mac_address)188 JUMP_FORWARD             1 (to 192)191 END_FINALLY         2150     >>  192 SETUP_EXCEPT            68 (to 263)2151         195 LOAD_GLOBAL             14 (md5)198 LOAD_ATTR               15 (new)201 LOAD_FAST                9 (mac_address)204 CALL_FUNCTION            1207 LOAD_ATTR               16 (hexdigest)210 CALL_FUNCTION            0213 STORE_FAST               7 (s)2152         216 LOAD_GLOBAL             14 (md5)219 LOAD_ATTR               15 (new)222 LOAD_FAST                7 (s)225 LOAD_CONST               9 (16)228 SLICE+1             229 LOAD_FAST                7 (s)232 LOAD_CONST               9 (16)235 SLICE+2             236 BINARY_ADD          237 CALL_FUNCTION            1240 LOAD_ATTR               16 (hexdigest)243 CALL_FUNCTION            0246 LOAD_CONST              10 (6)249 LOAD_CONST              11 (-6)252 SLICE+3             253 LOAD_FAST                0 (self)256 STORE_ATTR              19 (regno)259 POP_BLOCK           260 JUMP_FORWARD            16 (to 279)2153     >>  263 POP_TOP             264 POP_TOP             265 POP_TOP             2154         266 LOAD_CONST              12 ('00e6e95aff213b8e40ff')269 LOAD_FAST                0 (self)272 STORE_ATTR              19 (regno)2155         275 JUMP_FORWARD             1 (to 279)278 END_FINALLY         2156     >>  279 SETUP_EXCEPT           323 (to 605)2157         282 LOAD_CONST               1 ('')285 STORE_FAST               2 (tmp_result)2158         288 LOAD_FAST                0 (self)291 LOAD_ATTR               21 (conf_user)294 LOAD_ATTR               22 (config)297 LOAD_ATTR               23 (regnum)300 LOAD_FAST                0 (self)303 STORE_ATTR              24 (regno2)2159         306 LOAD_GLOBAL             14 (md5)309 LOAD_ATTR               15 (new)312 LOAD_FAST                0 (self)315 LOAD_ATTR               19 (regno)318 CALL_FUNCTION            1321 LOAD_ATTR               16 (hexdigest)324 CALL_FUNCTION            0327 STORE_FAST               7 (s)2160         330 LOAD_GLOBAL             14 (md5)333 LOAD_ATTR               15 (new)336 LOAD_FAST                7 (s)339 LOAD_CONST              13 (14)342 SLICE+1             343 LOAD_CONST              14 ('bb2')346 BINARY_ADD          347 LOAD_FAST                7 (s)350 LOAD_CONST              13 (14)353 SLICE+2             354 BINARY_ADD          355 CALL_FUNCTION            1358 LOAD_ATTR               16 (hexdigest)361 CALL_FUNCTION            0364 STORE_FAST               1 (md5_tmp)2161         367 LOAD_FAST                1 (md5_tmp)370 LOAD_CONST              15 (28)373 SLICE+1             374 LOAD_FAST                1 (md5_tmp)377 LOAD_CONST               9 (16)380 LOAD_CONST              16 (20)383 SLICE+3             384 BINARY_ADD          385 LOAD_FAST                1 (md5_tmp)388 LOAD_CONST              17 (0)391 LOAD_CONST              18 (5)394 SLICE+3             395 BINARY_ADD          396 LOAD_FAST                1 (md5_tmp)399 LOAD_CONST              19 (7)402 LOAD_CONST              20 (9)405 SLICE+3             406 BINARY_ADD          407 LOAD_FAST                1 (md5_tmp)410 LOAD_CONST              18 (5)413 LOAD_CONST              19 (7)416 SLICE+3             417 BINARY_ADD          418 LOAD_FAST                1 (md5_tmp)421 LOAD_CONST              20 (9)424 LOAD_CONST               9 (16)427 SLICE+3             428 BINARY_ADD          429 LOAD_FAST                1 (md5_tmp)432 LOAD_CONST              16 (20)435 LOAD_CONST              15 (28)438 SLICE+3             439 BINARY_ADD          440 LOAD_FAST                1 (md5_tmp)443 LOAD_CONST              21 (8)446 LOAD_CONST              22 (12)449 SLICE+3             450 BINARY_ADD          451 LOAD_FAST                1 (md5_tmp)454 LOAD_CONST              23 (17)457 LOAD_CONST              24 (21)460 SLICE+3             461 BINARY_ADD          462 STORE_FAST               5 (reg_tmp)2162         465 LOAD_FAST                0 (self)468 LOAD_ATTR               24 (regno2)471 LOAD_CONST              17 (0)474 LOAD_CONST              25 (4)477 SLICE+3             478 LOAD_FAST                5 (reg_tmp)481 LOAD_CONST              17 (0)484 LOAD_CONST              25 (4)487 SLICE+3             488 COMPARE_OP               2 (==)491 JUMP_IF_FALSE          106 (to 600)494 POP_TOP             2163         495 LOAD_FAST                0 (self)498 LOAD_ATTR               24 (regno2)501 LOAD_CONST              25 (4)504 LOAD_CONST              21 (8)507 SLICE+3             508 LOAD_FAST                5 (reg_tmp)511 LOAD_CONST              25 (4)514 LOAD_CONST              21 (8)517 SLICE+3             518 COMPARE_OP               2 (==)521 JUMP_IF_FALSE           72 (to 596)524 POP_TOP             2164         525 LOAD_FAST                0 (self)528 LOAD_ATTR               24 (regno2)531 LOAD_CONST              19 (7)534 LOAD_CONST              26 (15)537 SLICE+3             538 LOAD_FAST                5 (reg_tmp)541 LOAD_CONST              19 (7)544 LOAD_CONST              26 (15)547 SLICE+3             548 COMPARE_OP               2 (==)551 JUMP_IF_FALSE           38 (to 592)554 POP_TOP             2165         555 LOAD_FAST                0 (self)558 LOAD_ATTR               24 (regno2)561 LOAD_CONST              13 (14)564 SLICE+1             565 LOAD_FAST                5 (reg_tmp)568 LOAD_CONST              13 (14)571 SLICE+1             572 COMPARE_OP               2 (==)575 JUMP_IF_FALSE           10 (to 588)578 POP_TOP             2166         579 LOAD_CONST              27 ('ok')582 STORE_FAST               2 (tmp_result)585 JUMP_ABSOLUTE          593>>  588 POP_TOP             589 JUMP_ABSOLUTE          597>>  592 POP_TOP             >>  593 JUMP_ABSOLUTE          601>>  596 POP_TOP             >>  597 JUMP_FORWARD             1 (to 601)>>  600 POP_TOP             >>  601 POP_BLOCK           602 JUMP_FORWARD             7 (to 612)2167     >>  605 POP_TOP             606 POP_TOP             607 POP_TOP             2168         608 JUMP_FORWARD             1 (to 612)611 END_FINALLY         2169     >>  612 LOAD_FAST                2 (tmp_result)615 LOAD_CONST              27 ('ok')618 COMPARE_OP               2 (==)621 JUMP_IF_FALSE            8 (to 632)624 POP_TOP             2170         625 LOAD_CONST              28 ('YES')628 RETURN_VALUE        629 JUMP_FORWARD             5 (to 637)>>  632 POP_TOP             2172         633 LOA

代码有点长,看着看着就迷失在代码的丛林里了。这里可以讨个巧,借助免费的反编译引擎来帮忙。

首先获得 get_reg_no_true() 这个函数的 code object,然后使用 marshal.dump() 保存成文件(从 py2exe 的源代码哪里学来的)。然后用 WinHex 加上 8 个字节的 file header。前 4 个字节代表 Python 版本号,2.4 是 6DF20D0A。后 4 个字节是 timestamp,随便写就是。
    接着来到这里: http://www.depython.net/
    这个据说是  team509 做的,它可以免费反编译小于 5KB 的文件。

反编译出的结果:

代码:
try:try:mac_address = ''strComputer = '.'objWMIService = win32com.client.Dispatch('WbemScripting.SWbemLocator')objSWbemServices = objWMIService.ConnectServer(strComputer, 'root\\cimv2')colItems = objSWbemServices.ExecQuery('Select * from Win32_NetworkAdapter')for objItem in colItems:if (objItem.MACAddress != None):if (('VEN_' in objItem.PNPDeviceID) and ('DEV_' in objItem.PNPDeviceID)):mac_address = objItem.MACAddressbreakif (mac_address == ''):mac_address = '00:0A:EB:F5:D4:14'except:mac_address = '00:0A:EB:F5:D4:14'try:s = md5.new(mac_address).hexdigest()self.regno = md5.new((s[16:] + s[:16])).hexdigest()[6:-6]except:self.regno = '00e6e95aff213b8e40ff'try:tmp_result = ''self.regno2 = self.conf_user.config.regnums = md5.new(self.regno).hexdigest()md5_tmp = md5.new(((s[14:] + 'bb2') + s[:14])).hexdigest()reg_tmp = ((((((((md5_tmp[28:] + md5_tmp[16:20]) + md5_tmp[0:5]) + md5_tmp[7:9]) + md5_tmp[5:7]) + md5_tmp[9:16]) + md5_tmp[20:28]) + md5_tmp[8:12]) + md5_tmp[17:21])if (self.regno2[0:4] == reg_tmp[0:4]):if (self.regno2[4:8] == reg_tmp[4:8]):if (self.regno2[7:15] == reg_tmp[7:15]):if (self.regno2[14:] == reg_tmp[14:]):tmp_result = 'ok'except:passif (tmp_result == 'ok'):return 'YES'else:return 'ERR'
except:return 'ERR'

算法一目了然!稍微改一下,注册机就可以出炉了。

综上,使用 Python 开发的商业软件,其安全性还值得商榷。抵御攻击的做法是使用第三方库编译成 native code,使用代码混淆器,或者修改 Python 源代码防止被反汇编。

【原创】用 Python 反编译 Python 软件相关推荐

  1. exe反编译_反编译Python生成exe软件(Py3-polySML)

    反编译对象为一篇文献上的软件,反编译只是为了了解一些源代码的逻辑. 过程参考文章:python3.7.4反编译生成的.exe 反编译对象:polySML 此对象为python打包,且未进行加密加壳软件 ...

  2. Python反编译pyinstaller打包的exe文件 从0开始(未加密篇)

    因为pyinstaller方便.兼容性相对较好,所以我们会经常见到一些用pyinstaller打包的Python程序,在这里我们了解一下如何对这些打包好的exe文件进行反编译(即反编译出.py文件), ...

  3. python反编译Pyinstaller打包的可执行文件

    背景:最近在帮朋友写一款类似抢票的脚本,朋友有好几个脚本了,但是效果不理想,想让我帮忙,由于这种需要对接口进行详细了解,有些事件没有条件去抓包,然后我就对朋友已有的几个脚本动了心思.首先像这种爬虫类小 ...

  4. python反编译-以2048小游戏为例

    文章目录 一.背景 二.工具准备 1.pyinstxtractor.py脚本用于反编译python 2.winhex用于编辑16进制的软件 三.反编译 1.放置脚本 2.运行脚本 3.找到软件名文件和 ...

  5. python 反编译

    python 反编译工具名称: Easy Python Decompiler 工具下载地址:http://sourceforge.net/projects/easypythondecompiler/? ...

  6. Python 反编译:pyinstxtractor工具和uncompyle6库的使用

    uncompyle6 现仅适用于 Python 2.4 到 3.8 版本 Python 3.9 及以上版本请参见我另外一篇博客: Python 反编译:pycdc工具的使用 ✅作者简介:人工智能专业本 ...

  7. 反编译python 生成的exe源码

    反编译python 生成的exe源码 记录反编译exe工具使用 工具准备 – pyinstxtractor.py – uncompyle6 – sublime Text(或者其他的二进制编辑工具) 一 ...

  8. python反编译exe_实战 Python3.7+64位 Exe 反编译

    记得有年在上海弘连培训,其中一个逆向题就是关于python的Exe,当时就想着写个文档,后来因为忙就拖延了下来:这里补上,而且是大补上:奉献一个干货,网上没有(我没发现)Python3.7的反编译教程 ...

  9. Python反编译pyinstaller或py2exe生成的exe可执行文件,获得源码

    目录 一.从exe文件中抽取pyc文件 二.将pyc文件反编译为py源码文件 三.更正.pyc文件的头信息 一.从exe文件中抽取pyc文件 直接到下列网址将代码clone下来: GitHub - c ...

最新文章

  1. activex java 控件_java 如何调用ActiveX控件??
  2. log4j 控制台和文件输出乱码问题解决
  3. js ---- 对象转JSON,JSON转对象
  4. rails提供的validators
  5. 关于larbin的编译
  6. 我看《网络营销实战密码:策略 技巧 案例》这本书
  7. YOLOX系列一 -- 代码下载以及win10上demo运行
  8. 51单片机学习笔记8 -- OLED显示(SPI)
  9. linux计划任务踩坑
  10. 有没有测试牙齿需不需要修正的软件,三步图测法,就能知道自己牙齿是否需要矫正...
  11. PCB添加图片或logo的方法
  12. 【计算分段函数】输入整数x和a,计算并输出分段函数的值(保留2位小数)。
  13. Word文档使用Mathtype如何实现公式自动居中并右对齐编号?
  14. cocos2dx创造精灵的五种方法
  15. 【PaddleHub模型贡献】一行代码实现水表的数字表盘分割
  16. 新浪微博API[赞]接口和[取消赞]接口
  17. Android身份证号码验证
  18. 简述网桥的特点_网桥的工作原理和特点
  19. Transformer+目标检测,这一篇入门就够了
  20. 自研工业级机器视觉通用平台VisionBank

热门文章

  1. 英特尔NUC迷你电脑套件安装windows10+ubuntu18.04双系统
  2. 【LaTeX】 案例分析 (10) - 高等数学分析(下) Mathematica 实验报告
  3. 模拟CMOS集成电路设计入门学习(16)
  4. java链接cobar例子_cobar续3-jdbc的简单调用
  5. GPU配置MatConvNet(ECO代码)
  6. php mysql留言板系统_PHP结合Mysql数据库实现留言板功能
  7. 如何在项目中使用pdf.js查看PDF文件
  8. SuperMap三维专题之倾斜摄影——倾斜摄影数据介绍篇
  9. FPGA实现uart串口协议
  10. Qt获取音频设备信息