使用ctypes进行字符串连接时附加垃圾字符

0 投票
1 回答
872 浏览
提问于 2025-04-16 14:04

我在一个字符串后面加上“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)

但请不要同时做这两种。

撰写回答