一、黑客挚友: ctypes

来源:互联网 发布:淘宝反恶联盟 编辑:程序博客网 时间:2024/05/16 08:57

读 《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方式, 如 printfmsvcrt = cdll.msvcrtmessage = '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.

0 0
原创粉丝点击