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


0X00

ctypes 是強大的,使用它我們就能夠調 用動態鏈接庫中函數,同時創建各種復雜的 C 數據類型和底層操作函數。使得python也具備了底層內存操作的能力,再配合python本身強大的表達能力,這才知道為什么python是黑客必學的編程語言。

 

0x01  ctypes使用

ctypes 提供了三種方法調用動態鏈接庫:cdll(), windll(), 和 oledll()。

它們的不同之處就在 於,函數的調用方法和返回值。cdll() 加載的庫,其導出的函數必須使用標准的 cdecl 調用約定。

windll()方法加載的庫,其導出的函數必須使用 stdcall 調用約定(Win32API 的原生約 定)。

oledll()方法和 windll()類似,不過如果函數返回一個 HRESULT 錯誤代碼,可以使用 COM 函數得到具體的錯誤信息。

 

0X02  調用約定

調用約定專指函數的調用方法。其中包括,函數參數的傳遞方法,順序(壓入棧或 者傳給寄存器),以及函數返回時,棧的平衡處理。

下面這兩種約定是我們最常用到的: cdecl and stdcall。

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM