这可能是一个非常简单的问题,但不知何故,我无法解决问题的答案,而且我也找不到任何关于此类主题的好的和相关的文档。
所以我试图在ctypes.windll.kernel32类中使用Python的ctypes模块和CreateThread方法进行PoC(在程序的内存空间中进行一些shellcode注入)
根据msdn文档CreateThread 7个参数是:
使用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行请注意上面链接的脚本行,提到的评论:
# _Out_opt_ LPDWORD lpThreadId // NULL, so the thread identifier is not returned.
在评论CreateThread函数调用的引用时,看起来作者可能是错误的。
假设: 根据Mark提到的答案中的注释,ThreadID和ThreadHandle是不同的,通过传入ctypes.pointer(ctypes.c_int(0))而不仅仅是普通的ctypes.c_int(0)(NULL)意味着在int 0位置,将存储线程ID。有人可以证实这个假设吗?
答案 0 :(得分:1)
最后一个参数实例化一个C整数(c_int(0)
)并将其作为指针传递。这松散地匹配最后一个参数定义。它应该是一个DWORD,通常定义为unsigned long
(ctypes中的c_ulong
)。使用ctypes.byref
比创建指针更有效。该参数用于返回线程ID作为输出参数,因此需要正确C类型实例的地址来存储ID。
这是一个工作示例,它使用ctypes明确定义每个函数的输入/输出。请注意,ctypes
在wintypes
中预定义了Windows类型:
import ctypes as c
from ctypes import wintypes as w
LPTHREAD_START_ROUTINE = c.WINFUNCTYPE(w.DWORD,w.LPVOID)
SIZE_T = c.c_size_t
k32 = c.WinDLL('kernel32')
test = c.WinDLL('test')
CreateThread = k32.CreateThread
CreateThread.argtypes = w.LPVOID,SIZE_T,LPTHREAD_START_ROUTINE,w.LPVOID,w.DWORD,w.LPDWORD
CreateThread.restype = w.HANDLE
WaitForSingleObject = k32.WaitForSingleObject
WaitForSingleObject.argtypes = w.HANDLE,w.DWORD
WaitForSingleObject.restype = w.DWORD
sa = None # No security specified. None == NULL pointer.
stack = 0 # Use default stack
start = LPTHREAD_START_ROUTINE(test.func)
param = 0x12345
flags = 0 # start thread immediately
tid = w.DWORD()
h = CreateThread(sa,stack,start,param,flags,c.byref(tid))
WaitForSingleObject(h,1000) # wait for the thread to exit.
这里是一个简单的C函数作为线程运行的代码:
#include <stdio.h>
__declspec(dllexport) unsigned long __stdcall func(void* p)
{
printf("%p\n",p);
return 0;
}
这是输出:
0000000000012345