0X00python
ctypes 是强大的,使用它咱们就可以调 用动态连接库中函数,同时建立各类复杂的 C 数据类型和底层操做函数。使得python也具有了底层内存操做的能力,再配合python自己强大的表达能力,这才知道为何python是黑客必学的编程语言。编程
0x01 ctypes使用数组
ctypes 提供了三种方法调用动态连接库:cdll(), windll(), 和 oledll()。架构
它们的不一样之处就在 于,函数的调用方法和返回值。cdll() 加载的库,其导出的函数必须使用标准的 cdecl 调用约定。编程语言
windll()方法加载的库,其导出的函数必须使用 stdcall 调用约定(Win32API 的原生约 定)。函数
oledll()方法和 windll()相似,不过若是函数返回一个 HRESULT 错误代码,可使用 COM 函数获得具体的错误信息。spa
0X02 调用约定指针
调用约定专指函数的调用方法。其中包括,函数参数的传递方法,顺序(压入栈或 者传给寄存器),以及函数返回时,栈的平衡处理。code
下面这两种约定是咱们最经常使用到的: cdecl and stdcall。blog
cdecl 调用约定: 函数的参数从右往左依次压入栈内,函数的调用者, 在函数执行完成后,负责函数的平衡。这种约定经常使用于 x86 架构的 C 语言里。
In C
int python_rocks(reason_one,reason_two,reason_three);
In x86 Assembly
push reason_three push reason_two push reason_one call python_rocks add esp,12
从上面的汇编代码中,能够清晰的看出参数的传递顺序,最后一行,栈指针增长了 12 个字节(三个参数传递个函数,每一个被压入栈的指针都占 4 个字节,共 12
个), 使得 函数调用以后的栈指针恢复到调用前的位置。
stdcall调用约定:参数传递的顺序也是从右到左,不过栈的平衡处理由函数 my_socks 本身完成,而不是调用者。
In C
int my_socks(color_onecolor_two,color_three);
In x86 Assembly
push color_three
push color_two
push color_one
call my_socks
最后一点,这两种调用方式的返回值都存储在 EAX 中。
0x03 使用方法
Windows下:
from ctypes import * msvcrt = cdll.msvcrt msg = "Hello world!\n" msvcrt.printf("Testing: %s", msg)
Linux下:
from ctypes import * libc = CDLL("libc.so.6") msg = "Hello, world!\n" libc.printf("Testing: %s", msg)
使用 Python 建立一个 C数据类型很简单,能够很容易的使用由C或者C++些的组件。 下面这张图很好的表示了映射关系。
0x04 定义结构和联合
In C
union { long barley_long; int barley_int; char barley_char[8]; }barley_amount;
In Python
class barley_amount(Union): _fields_ = [ ("barley_long", c_long), ("barley_int", c_int), ("barley_char", c_char * 8), ]
eg:
from ctypes import * class barley_amount(Union): _fields_ = [ ("barley_long", c_long), ("barley_int", c_int), ("barley_char", c_char * 8), ] value = raw_input("Enter the amount of barley to put into the beer vat:") my_barley = barley_amount(int(value)) print "Barley amount as a long: %ld" % my_barley.barley_long print "Barley amount as an int: %d" % my_barley.barley_int print "Barley amount as a char: %s" % my_barley.barley_char
输出结果:
Enter the amount of barley to put into the beer vat:66 Barley amount as a long: 66 Barley amount as an int: 66 Barley amount as a char: B
给联合赋一个值就能获得三种不一样的表现方式。最后一个 barley_char 输出的结果是 B, 由于 66 恰好是 B 的 ASCII 码。barley_char 成员同时也是个数组,一个八个字符大小的数组。在 ctypes 中申请一个数组, 只要简单的将变量类型乘以想要申请的数量就能够了。