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 中申請一個數組, 只要簡單的將變量類型乘以想要申請的數量就能夠了。