使用ctypes进行字符串连接时附加垃圾字符
我在一个字符串后面加上“00000000”,第一次运行的时候一切正常。但是,当我第二次运行时,却加上了“垃圾字符”,而不是“000000”。下面是我在实际程序中是怎么做的示例代码。
文件 one.py
# File One.py
from two import *
def One():
while(1):
key = Two()
key = key + "00000000"
print key
def main():
One()
if __name__ == "__main__":
main()
文件 two.py
from ctypes import *
import binascii
handle = None
def Two():
global handle
libc = CDLL('libthree.so', DEFAULT_MODE, handle)
if not handle:
handle = libc._handle
buffer = create_string_buffer(16)
libc.Three(buffer)
return binascii.b2a_hex(buffer)
文件 three.c - 生成 libthree.so
#include "stdio.h"
#include "stdlib.h"
void Three(char * buffer)
{
long value = 0x78563412;
memcpy(buffer,&value,4);
memcpy(buffer + 4,&value,4);
memcpy(buffer+ 8,&value,4);
memcpy(buffer+ 12,&value,4);
return;
}
int main()
{
return 0;
}
1 个回答
1
create_string_buffer
可以用一个字符串或者一个长度来初始化。如果用字符串 s
来初始化,它会分配 len(s)+1
个字符的空间,这样就能留出一个位置给结尾的空字符(null terminator)。但是如果用一个整数来初始化,create_string_buffer
就会认为你是人类,应该知道自己在做什么,所以只分配你指定的那个大小的空间。不幸的是,你的 C 代码正在写入满满的 16 个字符的空间,这样就没有地方留给结尾的空字符了。当这种情况对你有效时,纯粹是因为分配的内存后面恰好是 0(null),这样字符串就结束了。后来,那块内存可能会被用作其他用途,这样你就会得到一些垃圾数据。试试用 create_string_buffer(16+1)
来看看情况是否有所改善。
文档还建议使用返回的字符串缓冲区对象的 .string()
方法,这样你就明确地应用了以空字符结束的语义。另一种方法是 .raw()
,它会读取到定义的缓冲区大小,直到遇到空字符。讽刺的是,如果你指定 key = key.raw() + "000000"
,这可能会给你正好是你最初指定的 16 个字符大小的缓冲区,并且这样可以绕过那些垃圾字符。
所以你可以尝试以下两种方法:
第一种,做:
key = key.raw() + "00000000"
或者第二种,改成:
buffer = create_string_buffer(16+1)
但请不要同时做这两种。