Python中的邪恶ctypes黑客技巧
我想先说,这个问题纯粹是出于好奇,我绝对不打算在任何严肃的项目中使用这么邪恶的东西。(没错,就是那种问题)
我一直在尝试了解CPython的内部工作原理,经过我的努力,我发现应该可以操控小整数的实际值,比如说1 + 2可以算出其他的结果,而不是3。我对这种低级的黑客技术并不是很在行,迄今为止我只得到了一些崩溃的结果。这是我目前的尝试:
import ctypes
ctypes.c_int8.from_address(id(1) + 8).value = 2
我原以为这样就能解决问题,但结果是任何试图计算1的语句都会崩溃。虽然这个结果让我觉得有点好笑,但这并不是我想要的。我是不是漏掉了什么?是不是那行代码里的c_int8和+ 8只在某些平台上有效?如果我知道该查找什么,我很乐意去查一下,不过我想答案可能藏在CPython的源代码里。
1 个回答
在一个32位的平台上,8
是“正确的”,因为 ob_refcnt
和 ob_type
每个占用4个字节;而在64位的平台上,这个情况就会不同。简单来说,你是在尝试越过 PyObject_HEAD
去访问整数对象的其他部分,所以你可以在编译器或调试器中检查一下 PyObject
的大小。
显然,在Python 3中情况会有所不同,因为只有 long
类型,所以即使是小整数也是可变长度的;在这种情况下,你需要使用 PyObject_VAR_HEAD
(和 PyVarObject
),而不是 PyObject_HEAD
。
一个很好的起点是查看 object.h
里的文档,你也可以在C API参考手册中找到,地址是 https://docs.python.org/2/c-api/structures.html,然后再看看 intobject.h
,或者对于Python 3,可以查看 longintrepr.h
。
注意:改变 1
的值仍然会导致程序崩溃,但原因不同。不过,改变一个较大的小整数,比如 10
,应该是安全的。