一、黑客挚友: ctypes

本文是阅读《Python灰帽子-黑客与逆向工程师的Python编程之道》的笔记,主要介绍了如何使用ctypes库调用动态链接库,包括cdll、windll和oledll三种方式,以及基本数据类型的创建和结构体的定义。ctypes使得Python能够方便地与C语言进行交互,支持C的数据类型和引用传参,并能实现C结构体的内存对齐控制。

读 《Python灰帽子-黑客与逆向工程师的Python编程之道》笔记

其实这本书就是基于 ctypes 库的, 使用这个库, 可以调用动态链接库中函数、同时创建各种复杂的 C 数据类型和底层操作函数.

1. 调用动态链接库

学 C 的时候就学过函数的调用约定, 先来回顾一下

fastcall调用约定Cdecl调用约定StdCall调用约定
mov eax, xxx
mov ecx, xxx
mov ebx, xxx
CALL Message
PUSH parameter3
PUSH parameter2
PUSH parameter1
CALL Message
ADD ESP,0CH
PUSH parameter3
PUSH parameter2
PUSH parameter1
CALL Message
通过寄存器来传送参数,被调用方清理堆栈参数从右到左传递,每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大.
VC编译器默认使用该方式
参数从右到左传递,被调函数自身在返回前清空堆栈.
标准调用方式,一般WIN32的函数都是

ctypes 库也提供了三种不同的动态链接库加载方式: cdll()、windll() 和 oledll().

  • cdll() 对应的是 cdecl 约定
  • windll() 对应 stdcall 约定
  • oledll() 和 windll() 一样, 但是它假定所有函数会统一返回一个 windows hresult 错误编码.

我们来尝试下调用 msvcrt.dll 中的 printf 函数.

from ctypes import *
#带有可变参数的函数必须且只能使用_cdecl方式, 如 printf
msvcrt = cdll.msvcrt
message = 'Hello'
msvcrt.printf('%s\n', message)

2. 基本数据类型

ctype 提供了一些与 C 互换的基本数据类型, 这就可以通过 ctype 来方便的创建 C 数据类型.
ctype 类型

ctype 也支持引用传参, 对于需要传引用的参数像这样传就可以了: ctypes.byref(object)

3. 定义结构体

使用 ctypes 中的 Structure 来实现 C 结构体.

class RULE_LIST_INFOMATION(Structure):
    _fields_ = [
        ("psz_time", c_char * 100),
        ("complete", c_int),
    ]

这段代码实现了下面的 C 结构体.

struct RULE_LIST_INFOMATION{
    char psz_time[100];
    int complete;
};

C 结构体有内存对齐这个概念, 这点在 cytpe 的 Structure 中也有体现, Structure 默认的内存对齐方式和 C 编译器的方式相同(4字节), 通过在子类中定义一个_pack_ 属性可以覆盖这个行为, 如 C 中的 #pragma pack(1) 对应 _pack_ = 1.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值