Python利用ctypes實現C庫函數調用

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

相關文章
相關標籤/搜索