Cypesを使ってケネル32.dllの関数を呼び出します.

7505 ワード


Cypesを使ってケネル32.dllの関数を呼び出します.
原文の住所:http://www.51cto.com/art/200710/58183.htm
10.4.4  Cypesを使ってケネル32.dllの関数を呼び出します.
ctypesモジュールを使用して、ダイナミックリンクライブラリにある関数をPythonに呼び出すことができます.Python 2.5版には既にctypesモジュールが含まれています.他のバージョンのPythonを使うと、着きます.http://python.net/crew/theller/ctypesサイトのダウンロード.ctypesはPython 2.3バージョン以上に適用されます.
1.types概要
ctypesは、ダイナミックリンクライブラリの関数を呼び出す機能をPythonに提供します.ctypesを使用すると、C言語で作成された動的リンクライブラリを簡単に呼び出し、パラメータを伝えることができます.ctypesはC言語の基本データタイプを定義し、C言語の構造体と結合体を実現します.ctypeesはWindows、Windows CE、Mac OS X、Linux、Solaris、FreeBSD、OpenBSDなどのプラットフォームで動作できます.
以下の例では、ctypesを用いてWindowsでuser 32.dllのMessageBoxA関数を直接呼び出すことができます.運転後は図10-6に示します.
    
>>from ctypes import*>>user 32=windlel.LoadLibrary('user 32.dll')    # ダイナミックリンクライブラリをロード>>user 32.Message BoxA(0,Ctypes is cool!',Ctypes',0)を呼び出します.
1

図10-6  使用ctypes
2.データタイプと構造体
ctypes C言語の基本データタイプを実現し、表10-2に示すように、いくつかの基本的なデータタイプの照合を示します.表10-2            データタイプ照合
ctypesデータタイプ
Cデータタイプ
ctypesデータタイプ
Cデータタイプ
c_char
char
c_float
float
c_ショート?ト
ショート?ト
c_ドビー
ドビー
c_要点
要点
c_void_p
void*
c_long
long
 
 
PythonでC言語の構造体を実現するには、クラスを使用する必要があります.Pythonでは、ctypesを使ってWindows中のPROCESS_を実現します.INFOREMATION構造体は以下の通りです.
    
typedef stuct_PROCESS_INFOREMATION{HANDLE h Process}  HANDLE h Thread  DWORD dwProcessid;  DWORD dwThreadId;PROCESS_INFOREMATION、*LPPROCESS_INFOREMATION;Pythonではctypesで実現します.クラスPROCESS_INFOREMATION(Structure):_fields_=[('h Process',cvoid_p),('hThread',c void_p),('dwProcessid',ccuong),('dwThreadId',cuulong)]
PROCESS_を宣言します.INFOREMATIONタイプのデータは次のような文を使えばいいです.
ProcessiInfo=_PROCESS_INFOMATION()
関数内で構造体メンバー変数に値を割り当てる場合、byrefが使用されます.byrefはC言語の「&」に相当します.
3.ケネル32.dllの関数を使ってプログラムの流れを変更する
場合によっては、プログラムのソースコードがないので、プログラムを一定の状況で特定の方法で実行させたいです.この場合はWriteProcessissMemory関数を使ってプログラム作成後にメモリアドレスを変更して要求通りに実行できます.WriteProcessMemoryの関数の原型は以下の通りです.
   BOOL WriteProcessMemory(
HANDLE  hProcess,
LPVOID  lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T  nSize,
SIZE_T*  lpNumberOfBytesWritten
);
そのパラメータの意味は以下の通りです. h Process:メモリのプロセスを書くにはハンドルが必要です. lpBaseAddres:書くメモリの先頭アドレス? lpBuffer:値を書き込むアドレス? nSize:書き込み値の大きさ? lpNumberOfBytes Written :実際の書き込みのサイズ.まず、Visual C++6.0に例示的なプログラムを作成します.Visual C++に新しいWin 32 Appplicationを作成し、工程名は「ModifyMe」となり、図10-7に示されています.
使用ctypes调用kernel32.dll中的函数_第1张图片
図10-7  プロジェクトの作成ダイアログ
【OK】ボタンをクリックして、図10-8に示すようなダイアログが表示されます.【Finish】ボタンをクリックすると、確認ダイアログが表示されます.【OK】ボタンをクリックしてプロジェクトの作成を完了します.C/C++ファイルを新規作成し、ModifyMe.cと名前を付けて、下記のコードを入力します.ModifyMeをコンパイルし、図10-9に示すようにModifyMe.exeを実行します.
    /*  ModifyMe.c */ 
#include 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
int a = 0;
int b = 1;
if ( a != b )  /*        Python        */
{
MessageBox(NULL, "Bad Python", "Python", MB_OK);
}
else
{
MessageBox(NULL, "Good Python", "Python", MB_OK);
}
}
使用ctypes调用kernel32.dll中的函数_第2张图片
図10-8  プロジェクトのプロパティダイアログ 
図10-8  プロジェクトのプロパティダイアログ 

              図10-9  修正前のModifyMeプログラム
「if(a!=b)」のアンチアセンブル後のコードを見つけるためには、ModifyMe.cにブレークポイントを設定し、デバッグモードに入り、アセンブラコードを確認します.以下のようにします.鍵はアドレス0040103 Cに位置するje命令であることが分かる.
    7:        if ( a != b )
00401036   mov         eax,dword ptr [ebp-4]
00401039   cmp         eax,dword ptr [ebp-8]
0040103C   je          WinMain+4Dh (0040105d)
0040103 Cにおけるje命令は、aとbの値が等しい場合、プログラムは0040105 dに遷移して実行することを示している.プログラムのaとbの値は同じではないので、プログラムはジャンプしていません.ここではje指令をjneに変更する必要があります.このうち、je指令の逆アセンブリ後の16進数は0 x 74であり、jneは0 x 75である.プログラムフローを変更するなら、0040103 Cアドレスにバイトを書き込むだけで、jneを0040103 Cに0 x 75を書き込みます.作成した変更スクリプトコードは以下の通りです.
   #  -*- coding:utf-8 -*-
#  file: ModifyMemory.py
#
from ctypes import *
#   _PROCESS_INFORMATION   
class _PROCESS_INFORMATION(Structure):  
_fields_ = [('hProcess', c_void_p),
('hThread', c_void_p),
('dwProcessId', c_ulong),
('dwThreadId', c_ulong)]
#   _STARTUPINFO   
class _STARTUPINFO(Structure):
_fields_ = [('cb',c_ulong),
('lpReserved', c_char_p),  
('lpDesktop', c_char_p),  
('lpTitle', c_char_p), 
('dwX', c_ulong),
('dwY', c_ulong), 
('dwXSize', c_ulong),
('dwYSize', c_ulong), 
('dwXCountChars', c_ulong),
('dwYCountChars', c_ulong), 
('dwFillAttribute', c_ulong), 
('dwFlags', c_ulong),
('wShowWindow', c_ushort),  
('cbReserved2', c_ushort), 
('lpReserved2', c_char_p),  
('hStdInput', c_ulong),  
('hStdOutput', c_ulong),
('hStdError', c_ulong)]
NORMAL_PRIORITY_CLASS = 0x00000020     #   NORMAL_PRIORITY_CLASS
kernel32 = windll.LoadLibrary("kernel32.dll")  #   kernel32.dll
CreateProcess = kernel32.CreateProcessA   #   CreateProcess    
ReadProcessMemory = kernel32.ReadProcessMemory 
#   ReadProcessMemory    
WriteProcessMemory = kernel32.WriteProcessMemory 
#   WriteProcessMemory    
TerminateProcess = kernel32.TerminateProcess
#      
ProcessInfo = _PROCESS_INFORMATION()
StartupInfo = _STARTUPINFO()
file = 'ModifyMe.exe'       #         
address = 0x0040103c        #         
buffer = c_char_p("_")        #      
bytesRead = c_ulong(0)       #       
bufferSize =  len(buffer.value)     #      
#     
if CreateProcess(file, 0, 0, 0, 0, NORMAL_PRIORITY_CLASS,
0, 0, byref(StartupInfo), byref(ProcessInfo)):
#           ,            
if ReadProcessMemory(ProcessInfo.hProcess, address, buffer, 
bufferSize, byref(bytesRead)):
if buffer.value == '\x74':
buffer.value = '\x75'     #         ,      
#     
if WriteProcessMemory(ProcessInfo.hProcess, address, 
buffer, bufferSize, byref(bytesRead)):
print '      !'
else:
print '     !'
else:
print '        !'
TerminateProcess(ProcessInfo.hProcess,0) 
#           ,     
else:
print '     !'
else:
print '      !'
スクリプトを実行した後、図10-10に示します.

図10-10  修正後のModifyMe