以Python为例讨论高级编程语言程序的wire format与校验
2010-09-22 11:26:23 来源:WEB开发网demo.py的顶层代码对应的字节码总共就102字节,而跳转目标在绝对偏移量112处——这么一跳转就跑到字节码范围之外了。
在Python解释器运行_demo.py时,实际被执行的顶层PyCodeObject的字节码如下,从0x012361B4的那个0x64开始。
Hex代码
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F
012361B0 64 00 00 64 05 00 64 01 00 84 00 00 d..d..d..?.
012361C0 83 00 00 59 5A 00 00 65 00 00 69 01 00 47 48 65 ?.YZ..e..i..GHe
012361D0 00 00 04 69 01 00 64 02 00 37 02 5F 01 00 71 70 ...i..d..7._..qp
012361E0 00 69 01 00 47 48 65 00 00 83 00 00 5A 02 00 65 .i..GHe..?.Z..e
012361F0 02 00 69 01 00 47 48 65 02 00 04 69 01 00 64 03 ..i..GHe...i..d.
01236200 00 37 02 5F 01 00 65 02 00 69 01 00 47 48 65 00 .7._..e..i..GHe.
01236210 00 69 01 00 47 48 64 04 00 53 00 53 00 00 00 00 .i..GHd..S.S....
01236220 A0 63 23 01 88 A0 1D 1E 64 00 00 00 FF FF FF FF 燾#.垹..d...
绝对偏移量0x70(=112)把我们带到0x1236224处,是一个0x88,LOAD_DEREF,后面的参数是0xA0 0x1D,合起来就是LOAD_DEREF 7584,这偏移量早就不知道越界多少了。然后继续执行下去……我的Python解释器就崩溃了。
只消随便改两个字节就足以让Python解释器崩溃。然而更糟糕的事情还在后头:如果有人在发布其用Python写的程序时,只发布了.pyc文件,那我们如何信任代码不会把解释器弄崩溃?他(或者不受信任的中间者)可以任意编织.pyc文件中的字节码,只要总体格式能让marshal满意就行。
他甚至可以把一个行为正常的.py源文件与一个乱七八糟、但文件头能通过Python解释器检验的.pyc文件放在一起打包起来给我们用。阅读.py源码将无法解释执行该脚本而造成的任何诡异状况。
如果.pyc文件格式不曾是Python程序的wire format,又或者Python解释器会对.pyc文件做字节码校验的话,都可以让人少一分担心。
从现实意义上看,Python用户要规避这类隐患很简单:纯Python程序中,只使用以源码发布的而不使用以独立的.pyc/.pyo文件发布的程序。只要有源码,Python解释器总能构造出合适的.pyc或.pyo文件。那些只发布中间代码而不发布源码的Python程序提供者不过是在无力的挣扎而已——要反编译Python的中间代码很简单,不发布源码也保护不了多少秘密。
至于使用了本地扩展的Python程序,使用前就要想清楚了:你应该确实信任其本地扩展的行为,Python解释器无法为本地扩展提供保护。
重复本文最开头的声明:本文没有任何意图声称Python程序是不安全的;还有很多因素都可以带来安全隐患,况且其它环境也有各自的安全隐患……总之我不想,也不是“反Python”。
但不对所有wire format做校验的行为确实有让人担心的地方。这里只是以Python为实例印证Lars Bak关于“两次校验”的观点,说明校验的必要性。
原文章地址:http://rednaxelafx.javaeye.com/blog/382429
更多精彩
赞助商链接