【发布时间】:2018-05-29 05:18:24
【问题描述】:
这可能是一个非常简单的问题,但不知何故,我无法完全理解答案,而且我也找不到关于该主题的任何好的相关文档。
所以我尝试使用 Python 的 ctypes 模块和 ctypes.windll.kernel32 类中的 CreateThread 方法进行 PoC(在程序的内存空间中进行一些 shellcode 注入)
根据msdn文档CreateThread7个参数分别是:
- 指向安全属性的指针
- 初始堆栈大小
- 指向起始地址的指针
- 指向任何参数的指针
- 创建标志
- 指向接收线程标识符的值的指针
所有使用python调用c风格函数和库的例子都是这样的:
thread_handle = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_int(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0)))
谁能解释一下为什么最后一个参数被用作 ctypes.pointer(c_int0),而另一个空指针的整数 0 常量值用于其他参数。 (例如 ctypes.c_int(0))
更新:这是一个示例代码,这个实现可以在网上看到:
createThread function call in python 的第 786 行
请注意上面链接的脚本行,提到的 cmets:
# _Out_opt_ LPDWORD lpThreadId // NULL, so the thread identifier is not returned.
看来作者在评论 CreateThread 函数调用的参考时可能是错误的。
假设: 根据 Mark's answer 中提到的评论,ThreadID 和 ThreadHandle 是不同的,并且通过传入 ctypes.pointer(ctypes.c_int(0)) 而不仅仅是普通的 ctypes.c_int(0) (NULL) 意味着在int 0 位置,将存储线程 ID。有人可以证实这个假设吗?
【问题讨论】:
-
示例从何而来?过去人们经常将
int零与NULL混为一谈(它们在C++ 中相同,但在C 中不同),这可能是您只是看到了一些不良做法的例子。我可以看到的主要区别是最右边的参数是输出,而其他两个是输入,但这不应该影响它。 -
这是一个只有写代码的人才能回答的问题。我们只能推测。在 C 中,
NULL是一个#define到 0。我个人不知道为什么代码是这样写的。它传递了一个存储tid的指针,之后就不能使用了,所以我不知道为什么NULL没有通过。但是,在 64 位上做这样的事情是 UB,你会大吃一惊。有很多如何“正确”使用 ctypes 的示例:例如stackoverflow.com/questions/49927672/…, -
返回值:thread_handle 是线程ID吗?在那种情况下,在最后一个参数上传递 null 会导致不返回返回值吗?今天下班回家我会贴一些源代码的链接。
标签: python c ctypes kernel32 createthread