gpt4 book ai didi

python - python 中的 ctypes 因 memset 而崩溃

转载 作者:太空狗 更新时间:2023-10-30 00:56:42 27 4
gpt4 key购买 nike

我正在尝试从内存中删除密码字符串 like it is suggested in here .

我写了那个小片段:

import ctypes, sys

def zerome(string):
location = id(string) + 20
size = sys.getsizeof(string) - 20
#memset = ctypes.cdll.msvcrt.memset
# For Linux, use the following. Change the 6 to whatever it is on your computer.
print ctypes.string_at(location, size)
memset = ctypes.CDLL("libc.so.6").memset
memset(location, 0, size)
print "Clearing 0x%08x size %i bytes" % (location, size)
print ctypes.string_at(location, size)

a = "asdasd"

zerome(a)

奇怪的是,这段代码在 IPython 上运行良好,

[7] oz123@yenitiny:~ $ ipython a.py 
Clearing 0x02275b84 size 23 bytes

但是使用 Python 会崩溃:

[8] oz123@yenitiny:~ $ python a.py 
Segmentation fault
[9] oz123@yenitiny:~ $

有什么想法吗?

我使用 Python 2.7.3 在 Debian Wheezy 上进行了测试。

小更新...

该代码适用于 CentOS 6.2 和 Python 2.6.6。 代码在使用 Python 2.6.8 的 Debian 上崩溃。 我试着思考为什么它适用于 CentOS 而不是 Debian。唯一的原因, 立即不同的是,我的 Debian 是多架构的,而 CentOS 在我的 i686 CPU 旧笔记本电脑上运行。

因此,我重新启动了我的 CentOS latop 并在其上加载了 Debian Wheezy。 该代码适用于非多体系结构的 Debian Wheezy。 因此,我怀疑我在 Debian 上的配置有点问题......

最佳答案

ctypes 已经有一个 memset 函数,所以你不必为 libc/msvcrt 函数创建一个函数指针。此外,20 个字节用于常见的 32 位平台。在 64 位系统上,它可能是 36 个字节。这是 PyStringObject 的布局:

typedef struct {
Py_ssize_t ob_refcnt; // 4|8 bytes
struct _typeobject *ob_type; // 4|8 bytes
Py_ssize_t ob_size; // 4|8 bytes
long ob_shash; // 4|8 bytes (4 on 64-bit Windows)
int ob_sstate; // 4 bytes
char ob_sval[1];
} PyStringObject;

因此在 32 位系统上可能是 5*4 = 20 字节,在 64 位 Linux 上可能是 8*4 + 4 = 36 字节,在 64 位 Windows 上可能是 8*3 + 4*2 = 32 字节.由于字符串未使用垃圾收集 header 进行跟踪,因此您可以使用 sys.getsizeof。一般来说,如果您不想包含 GC header 大小(在内存中它实际上位于您从 id 获取的对象基地址之前),则使用对象的 __sizeof__ 方法。至少这是我的经验中的一般规则。

您想要的只是从对象大小中减去缓冲区大小。 CPython 中的字符串以 null 结尾,因此只需将其长度加 1 即可获得缓冲区大小。例如:

>>> a = 'abcdef'
>>> bufsize = len(a) + 1
>>> offset = sys.getsizeof(a) - bufsize
>>> ctypes.memset(id(a) + offset, 0, bufsize)
3074822964L
>>> a
'\x00\x00\x00\x00\x00\x00'

编辑

更好的选择是定义 PyStringObject 结构。这使得检查 ob_sstate 变得很方便。如果它大于 0,则意味着该字符串已被驻留,理智的做法是引发异常。单字符字符串与仅由 ASCII 字母和下划线组成的代码对象中的字符串常量以及解释器在内部用于名称(变量名称、属性)的字符串一起被驻留。

from ctypes import *

class PyStringObject(Structure):
_fields_ = [
('ob_refcnt', c_ssize_t),
('ob_type', py_object),
('ob_size', c_ssize_t),
('ob_shash', c_long),
('ob_sstate', c_int),
# ob_sval varies in size
# zero with memset is simpler
]

def zerostr(s):
"""zero a non-interned string"""
if not isinstance(s, str):
raise TypeError(
"expected str object, not %s" % type(s).__name__)

s_obj = PyStringObject.from_address(id(s))
if s_obj.ob_sstate > 0:
raise RuntimeError("cannot zero interned string")

s_obj.ob_shash = -1 # not hashed yet
offset = sizeof(PyStringObject)
memset(id(s) + offset, 0, len(s))

例如:

>>> s = 'abcd' # interned by code object
>>> zerostr(s)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 10, in zerostr
RuntimeError: cannot zero interned string

>>> s = raw_input() # not interned
abcd
>>> zerostr(s)
>>> s
'\x00\x00\x00\x00'

关于python - python 中的 ctypes 因 memset 而崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15581881/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com