Taking Advantage of Win32 APIs in Python
To take advantage of the powerful features provided by
the Windows operating system in Python, it is necessary to use the Win32 API.
Python version 2.7 provides the basic ctypes module that allow us to take
advantage of the variables of C language and the DLLs.
Python Using an External Library
At first, when you use the Win32 API and the ctypes, it
may be slightly difficult to use Win32 API calls by using the ctypes. There is
an extensive amount of knowledge that is necessary in advance, such as the
function call mechnism, return values, and data types. However, the ctypes can
be used for native libraries that are supported by a variety of operating
systems, which provides a powerful tool. To implement sophisticated hacking
techniques, the basic concept of the ctypes should be understood. The ctypes
are like a MacGyver knife in that they support a variety of platforms including
Android, Windows, Linux, Unix, and OS X. These are very useful tools, like a Swiss
Army Knife.
The Basic Concept of the ctypes Module
The
ctypes simplify the procedure to make dynamic libraries calls, and these
support complex C data types and have the advantage of providing low-level
functionality. If you follow the conventions to call functions to take
advantage of the ctypes, you can call the API that is provided directly by MSDN.
Concept
of the ctypes
Native
libraries and Python have different function call methods and data types, and
therefore you must learn the basic ctypes grammar that is used to accurately
perform mutual mapping.
Let's
examine the basic concept of ctypes from the criteria of Windows.
• DLL Loading
- The
ctypes supports a variety of calling conventions.
The ctypes supports cdll, windll, and oldell
calling convention. cdll supports the cdecl calling convention. windll supports
the stdcall calling convention. oldell supports the same calling convention as
windll, but there is a point to assume a return value as an HRESULT.
windll.kernel32,
windll.user32 |
• Win32 API Call
- Put the name of the function that you want
to call after the DLL name.
windll.user32.SetWindowsHookExA |
- When the API is called, it is possible to
specify the type of arguments.
printf = libc.printf printf.argtypes = [c_char_p, c_char_p, c_int, c_double] printf("String '%s', Int %d,
Double %f\n", "Hi", 10, 2.2) |
-
It is possible to specify the type of return value for the function.
libc.strchr.restype = c_char_p |
• Data Type
- Python can use the data type of the C
language by using the data types provided by the ctypes module.
In order to use the integer type of
C, it is using the ctypes as follows.
i = c_int(42)
print i.value() |
- You can use a pointer to store an address.
PI = POINTER(c_int) |
• Delivery of a pointer
- You can pass a pointer (the address of the
value) as an argument to the function.
f = c_float() s = create_string_buffer('\000' * 32) windll.msvcrt.sscanf("1 3.14
Hello", "%f %s", byref(f),
s) |
• Callback
Functioin
- You
can declare and pass a callback function that is responsible to process
specific events.
def py_cmp_func(a, b): print
"py_cmp_func", a, b return
0 CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int)) cmp_func = CMPFUNC(py_cmp_func) windll.msvcrt.qsort(ia, len(ia),
sizeof(c_int), cmp_func) |
• Structure
- By inheriting the Structure class, you can
declare the structure class.
class POINT(Structure): #선언 _fields_ = [("x", c_int),
("y", c_int)] point = POINT(10, 20) #사용 |
In
many cases, you must pass the arguments when calling the Win32 API. If you want
to directly transfer the data that is used in Python, the Win32 API cannot
recognize the data correctly. The ctypes provide a “cast function” to solve
these problems, and the “cast function” changes the variable types used in
Python into variable types used in the Win32 API. For example, we need a float
pointer as an argument when calling the “sscanf” function, and when you cast a variable
into the “c_float” type provided by ctypes, you can call the function correctly.
The mapping table is as follows.
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 |
int/long |
c_float |
float |
float |
c_double |
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 |
Variable
Type Mapping Table
Now,
with the basic concept of the ctypes module in hand, let's create full-fledged
hacking code. For message hooking, you should first understand the hook
mechanism, and you need to understand the Win32 APIs that are required for
hacking.