python基础部分较为简单,不再记录了。开始ctpytes:
Ctypes可以调用动态链接库中的函数,可以创建复杂的c数据类型和底层内存处理工具函数。
动态链接库是主进程在执行时链接的编译二进制文件。Windows下面称为dynamic link libraries (DLL)。Linux下面叫做:shared objects (SO).。这些二进制文件,通过导出名展示函数,导出名对应着内存中的实际地址。通常运行时,你需要解析函数地址来调用函数,不过ctypes已经为你做好了这些。
Ctypes有3中不同的加载动态链接库的方法:cdll(),windll(), 和 oledll(),区别在于库中函数调用的方法和结果返回值。cdll()适用于标准cdecl用。windll()适用于stdcall调用,是Win32 API的默认方式。oledll()和windll()类似,但是设定返回Windows HRESULT错误码,一般用于COM函数返回的错误消息。
简单实例:我们来实践一下C语言中的printf()。Windows对应msvcrt.dll(C:\WINDOWS\system32\)
msvcrt =cdll.msvcrt#以cdll的方式加载msvcrt
#或者写作: msvcrt =cdll.LoadLibrary("msvcrt.dll")
message_string = "hello world!\n"#定义一个字符串
msvcrt.printf("%s",message_string);
再例:
from ctypes import *
kernel32 = windll.kernel32 、
print kernel32
cdll(),windll(), 和 oledll()解释如下:
class CDLL (name, mode=DEFAULT_MODE, handle=None)
Instances of this class represent loaded shared libraries. Functions in these libraries use the standard C calling convention, and are assumed to return int.
class OleDLL(name, mode=DEFAULT_MODE, handle=None)
Windows only: Instances of this class represent loaded shared libraries, functions in these libraries use the stdcall calling convention, and are assumed to return the windows specific HRESULT code. HRESULT values contain information specifying whether the function call failed or succeeded, together with additional error code. If the return value signals a failure, an WindowsError is automatically raised.
class WinDLL(name, mode=DEFAULT_MODE, handle=None)
Windows only: Instances of this class represent loaded shared libraries, functions in these libraries use the stdcall calling convention, and are assumed to return int by default.
Fundamental data types
ctypes defines a number of primitive C compatible data types :
| ctypes type | C type | Python type |
|---|---|---|
| c_char | char | 1-character string |
| c_wchar | wchar_t | 1-character unicode string |
| c_byte | char | int/long |
| c_ubyte | unsigned char | int/long |
| c_short | short | int/long |
| c_ushort | unsigned short | int/long |
| c_int | int | int/long |
| c_uint | unsigned int | int/long |
| c_long | long | int/long |
| c_ulong | unsigned long | int/long |
| c_longlong | __int64 or long long | int/long |
| c_ulonglong | unsigned __int64 or unsigned long long | int/long |
| c_float | float | float |
| c_double | double | float |
| c_longdouble | long double | float |
| c_char_p | char * (NUL terminated) | string or None |
| c_wchar_p | wchar_t * (NUL terminated) | unicode or None |
| c_void_p | void * | int/long or None |
ctypes类型可以初始化一个值:
>>> from ctypes import *
>>> c_int()
c_long(0)
>>> c_char_p("Hello world!")
c_char_p('Hello world!')
>>> c_ushort(-5)
c_ushort(65531)
>>>
>>> seitz = c_char_p("loves the python")
>>> print seitz
c_char_p('loves the python')
>>> print seitz.value
loves the python
>>> exit()
传引用只需要使用byref()函数,比如:
function_main( byref(parameter) ).
结构体的定义:
In C
struct beer_recipe
{
int amt_barley;
int amt_water;
};
In Python
class beer_recipe(Structure):
_fields_ = [
("amt_barley", c_int),
("amt_water", c_int),
]
联合中所有成员变量共享内存,可以把同一变量指定为不同类型。
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),
联合体实例:
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: 100
Barley amount as a long: 100
Barley amount as an int: 100
Barley amount as a char: d
通过以上实例,这个东东so easy!妈妈再也不用担心我的学习
再看一个稍微复杂的例子:
from ctypes import *;
2
3 _fields_ = [('hProcess', c_void_p),
4
5 ('hThread', c_void_p),
6
7 ('dwProcessId', c_ulong),
8
9 ('dwThreadId', c_ulong)]
10 class _STARTUPINFO(Structure):
11
12 _fields_ = [('cb',c_ulong),
13
14 ('lpReserved', c_char_p),
15
16 ('lpDesktop', c_char_p),
17
18 ('lpTitle', c_char_p),
19
20 ('dwX', c_ulong),
21
22 ('dwY', c_ulong),
23
24 ('dwXSize', c_ulong),
25
26 ('dwYSize', c_ulong),
27
28 ('dwXCountChars', c_ulong),
29
30 ('dwYCountChars', c_ulong),
31
32 ('dwFillAttribute', c_ulong),
33
34 ('dwFlags', c_ulong),
35
36 ('wShowWindow', c_ushort),
37
38 ('cbReserved2', c_ushort),
39
40 ('lpReserved2', c_char_p),
41
42 ('hStdInput', c_ulong),
43
44 ('hStdOutput', c_ulong),
45
46 ('hStdError', c_ulong)]
47 NORMAL_PRIORITY_CLASS = 0x00000020
48
49 kernel32 = windll.LoadLibrary("kernel32.dll")
50
51 CreateProcess = kernel32.CreateProcessA
52
53 ProcessInfo = _PROCESS_INFORMATION()
54
55 StartupInfo = _STARTUPINFO()
56
57 fileName = 'c:/windows/notepad.exe'
58 CreateProcess(fileName, 0, 0, 0, 0, NORMAL_PRIORITY_CLASS,0, 0, byref(StartupInfo), byref(ProcessInfo))
最后来个综合性实例://功能:改变程序流向
1)编写一个win32 程序
1 #include <windows.h>
3 LPSTR lpCmdLine, int nCmdShow)
4 {
5 int a = 0;
6 int b = 1;
7 if ( a != b )
8 {
9 MessageBox(NULL, "Bad Python", "Python", MB_OK);
10 }
11 else
12 {
13 MessageBox(NULL, "Good Python", "Python", MB_OK);
14 }
15 }
# 生成ModifyMe.exe
2 # file: ModifyMemory.py
3 #
4 from ctypes import *
5 # 定义_PROCESS_INFORMATION结构体
6 class _PROCESS_INFORMATION(Structure):
7 _fields_ = [('hProcess', c_void_p),
8 ('hThread', c_void_p),
9 ('dwProcessId', c_ulong),
10 ('dwThreadId', c_ulong)]
11 # 定义_STARTUPINFO结构体
12 class _STARTUPINFO(Structure):
13 _fields_ = [('cb',c_ulong),
14 ('lpReserved', c_char_p),
15 ('lpDesktop', c_char_p),
16 ('lpTitle', c_char_p),
17 ('dwX', c_ulong),
18 ('dwY', c_ulong),
19 ('dwXSize', c_ulong),
20 ('dwYSize', c_ulong),
21 ('dwXCountChars', c_ulong),
22 ('dwYCountChars', c_ulong),
23 ('dwFillAttribute', c_ulong),
24 ('dwFlags', c_ulong),
25 ('wShowWindow', c_ushort),
26 ('cbReserved2', c_ushort),
27 ('lpReserved2', c_char_p),
28 ('hStdInput', c_ulong),
29 ('hStdOutput', c_ulong),
30 ('hStdError', c_ulong)]
31 # 定义NORMAL_PRIORITY_CLASS
32 NORMAL_PRIORITY_CLASS = 0x00000020
33 # 加载kernel32.dll
34 kernel32 = windll.LoadLibrary("kernel32.dll")
35 # 获得CreateProcess函数地址
36 CreateProcess = kernel32.CreateProcessA
37 # 获得ReadProcessMemory函数地址
38 ReadProcessMemory = kernel32.ReadProcessMemory
39 # 获得WriteProcessMemory函数地址
40 WriteProcessMemory = kernel32.WriteProcessMemory
41 TerminateProcess = kernel32.TerminateProcess
42 # 声明结构体
43 ProcessInfo = _PROCESS_INFORMATION()
44 StartupInfo = _STARTUPINFO()
45 # 要进行修改的文件
46 file = 'ModifyMe.exe' # 这是以上win32所生成的exe文件
47 # 要修改的内存地址,注意此地址需要动态调试得到,调试版本可以直接用vc,否则要用windbg或od...
48 address = 0x0040103c
49 # 缓冲区地址
50 buffer = c_char_p("_")
51 # 读入的字节数
52 bytesRead = c_ulong(0)
53 # 缓冲区大小
54 bufferSize = len(buffer.value)
55 # 创建进程
56 if CreateProcess(file, 0, 0, 0, 0, NORMAL_PRIORITY_CLASS, 0, 0, byref(StartupInfo), byref(ProcessInfo)):
57 # 读取要修改的内存地址,以判断是否是要修改的文件
58 if ReadProcessMemory(ProcessInfo.hProcess, address, buffer, bufferSize, byref(bytesRead)):
59 if buffer.value == '\x74':
60 # 修改缓冲区内值,将其写入内存
61 buffer.value = '\x75'
62 # 修改内存
63 if WriteProcessMemory(ProcessInfo.hProcess, address, buffer, bufferSize, byref(bytesRead)):
64 print '成功改写内存!'
65 else:
66 print '写内存错误!'
67 else:
68 print '打开了错误的文件!'
69 # 如果不是要修改的文件,则终止进程
70 TerminateProcess(ProcessInfo.hProcess,0)
71 else:
72 print '读内存错误!'
73 else:
74 print '不能创建进程!'
that's all!
浙公网安备 33010602011771号