1.安裝鼠標鉤子,通過鉤子函數獲取鼠標消息。
使用的api函數:setwindowshookex
2.獲取鼠標的當前位置,向鼠標下的窗口發送重畫消息,讓其調用系統函數重畫窗口。
使用的Api函數:windowfrompoint,screentoclient,invalidaterect。
3.攔截對系統函數的調用,獲取參數,也就是我們要取的字。
對於大多數windows應用程序來說,如果要檢索單詞,需要截取“gdi32.dll”中的“textouta”函數。
讓我們編寫壹個類似於textouta函數的Mytextouta函數,比如:
bool winapi mytextouta(hdc hdc,int nxstart,int nystart,lpcstr lpszstring,int cbstring)
{
//這裏執行輸出lpszstring的處理。
//然後調用正版textouta函數。
}
把這個函數放到安裝了鉤子的動態鏈接庫中,然後調用我們最後給出的hookimportfunction函數來攔截進程對textouta函數的調用,跳轉到我們的mytextouta函數來捕獲輸出字符串。hookimportfunction的用法:
hookfuncdesc hd
proc porigfuns
hd.szfunc = " textouta
HD . pproc =(proc)mytextouta;
hookinportfunction(afxgetinstancehandle()," gdi32.dll ",& amp高清、porigfuns);
下面給出了hookimportfunction的源代碼。相信詳細的評論不會讓妳覺得很難理解攔截是如何實現的。好了,我們走吧:
//////////////////////begin/begin/begin/begin/begin/begin/begin/begin/begin/begin/begin/begin/begin/begin
# include & ltcrtdbg.h & gt
//這裏定義了壹個生成指針的宏。
#define makeptr(cast,ptr,addvalue)(cast)((dword)(ptr)+(dword)(addvalue))
//定義hookfuncdesc結構,我們將它用作傳遞給hookimportfunction函數的參數。
typedef struct tag_hookfuncdesc
{
lpcstr szfunc//要掛鉤的函數的名稱。
proc pproc//要沖進去的程序。
} hookfuncdesc,* lphookfuncdesc
//這個函數監視當前系統是否是windownt。
bool nots();
//這個函數獲取h module——我們需要攔截的函數所在的dll模塊的導入描述符。
pimage _ import _ descriptor getnamedimportdescriptor(hmodule hmodule,lpcstr sziportmodule);
//我們的主要功能
bool hook import function(hmodule hmodule,lpcstr szimportmodule,
lphookfuncdesc pahookfunc,proc* paorigfuncs)
{
//////////////////以下代碼檢測參數///////////////////////////////////////////////。
_ assert(szimportmodule);
_assert(!isbadreadptr(pahookfunc,sizeof(hook func desc)));
#ifdef _debug
if (paorigfuncs) _assert(!isbadwriteptr(paorigfuncs,sizeof(proc)));
_ assert(pahook func . SZ func);
_assert(*pahookfunc.szfunc!= \0 );
_assert(!isbadcodeptr(pahook func . pproc));
#endif
if((szimportmodule = = null)| |(isbadreadptr(pahook func,sizeof(hookfuncdesc))))
{
_ assert(false);
setlasterrorex(error _ invalid _ parameter,SLE _ error);
返回false
}
//////////////////////////////////////////////////////////////////////////////
//監控當前模塊是否在2gb以上的虛擬內存空間。
//這部分地址內存屬於win32進程* * *。
如果(!不是()& amp& amp((dword)hmodule & gt;= 0x80000000))
{
_ assert(false);
setlasterrorex(error _ invalid _ handle,SLE _ error);
返回false
}
//清除
if(paorigfuncs)memset(paorigfuncs,null,sizeof(proc));
//調用getnamedimportdescriptor()函數來獲取h module——也就是說,我們需要
//導入被截獲函數所在的dll模塊的描述符。
pimage _ import _ descriptor pimportdesc = getnamedimportdescriptor(hm odule,sziportmodule);
if (pimportdesc == null)
返回false//如果為空,則該模塊尚未被當前進程引入。
//從dll模塊中獲取原thunk信息,因為pimportdesc->;firstthunk數組中的原始信息已被
//當應用程序引入dll時,它覆蓋了所有的導入信息,所以我們需要獲取pimportdesc->;originalfirstthunk
//訪問信息的指針,如引入函數的名稱。
pimage _ thunk _ data porigthunk = make ptr(pimage _ thunk _ data,hmodule,
pimportdesc-& gt;originalfirsthunk);
//From pimportdesc-& gt;Firstthunk獲得壹個指向image_thunk_data數組的指針,因為在引入dll時已經填充了該數組。
//所有傳入的信息,所以真正的攔截其實是在這裏進行的。
pimage _ thunk _ data prealthunk = make ptr(pimage _ thunk _ data,hmodule,pimportdesc-& gt;first thunk);
//枚舉image_thunk_data數組,找到我們需要截取的函數。這是最關鍵的部分!
while(porigthunk-& gt;u1.function)
{
//只查找那些由函數名而不是序列號引入的函數。
if (image_ordinal_flag!=(porigthunk-& gt;u1。圖像序號標誌))
{
//獲取引入函數的函數名。
pimage _ import _ by _ name pby name = make ptr(pimage _ import _ by _ name,hmodule,
porigthunk-& gt;u 1 . address of data);
//如果函數名以null開頭,則跳過並繼續下壹個函數。
if(\ 0 = = pbyname-& gt;名稱[0])
繼續;
// bdohook用於檢查攔截是否成功。
bool bdohook = false
//檢查當前函數是否是我們需要截取的函數。
if((pahook func . SZ func[0]= = pbyname-& gt;name[0])& amp;& amp
(strcmpi(pahookfunc.szfunc,(char *)pbyname-& gt;name) == 0))
{
//找到了!
if (pahookfunc.pproc)
bdohook = true
}
if(bdo book)
{
//我們已經找到了要攔截的函數,開始吧。
//首先要做的是改變這個虛擬內存的內存保護狀態,讓我們可以自由訪問。
memory _ basic _ information mbi _ thunk;
虛擬查詢(prealthunk & amp;mbi_thunk,sizeof(內存_基本_信息));
_ assert(virtual protect(mbi _ thunk . base address,mbi_thunk.regionsize,
page _ read write & amp;mbi _ thunk . protect));
//保存我們要攔截的函數的正確跳轉地址。
if (paorigfuncs)
paorigfuncs =(proc)prealthunk-& gt;u 1 . function;
//將image_thunk_data數組中的函數跳轉地址重寫為我們自己的函數地址!
//以後所有進程對這個系統函數的調用都變成對自己寫的函數的調用。
prealthunk-& gt;u 1 . function =(PD word)pahook func . pproc;
//操作完成!將這塊虛擬內存更改回其原始保護狀態。
dword dwoldprotect
_ assert(virtual protect(mbi _ thunk . base address,mbi_thunk.regionsize,
mbi_thunk.protect。dwold protect));
setlasterror(error _ success);
返回true
}
}
//訪問image_thunk_data數組中的下壹個元素。
porigthunk++;
prealthunk++;
}
返回true
}
getnamedimportdescriptor函數的實現
pimage _ import _ descriptor getnamedimportdescriptor(hmodule hmodule,lpcstr szimportmodule)
{
//檢測參數
_ assert(szimportmodule);
_ assert(hm odule);
if((szimportmodule = = null)| |(hm odule = = null))
{
_ assert(false);
setlasterrorex(error _ invalid _ parameter,SLE _ error);
返回null
}
//獲取dos文件頭
pimage _ dos _ header PDO header =(pimage _ dos _ header)hm odule;
//檢測mz文件頭是否
if(isbadreadptr(PDO header,sizeof(image_dos_header)) ||
(PDO header-& gt;e_magic!= image_dos_signature))
{
_ assert(false);
setlasterrorex(error _ invalid _ parameter,SLE _ error);
返回null
}
//獲取pe文件頭
pimage _ nt _ headers pntheader = make ptr(pimage _ nt _ headers,PDO header,PDO header-& gt;e _ LFA new);
//檢測pe圖像文件是否
if (isbadreadptr(pntheader,sizeof(image_nt_headers)) ||
(pntheader-& gt;簽名!=圖像_ nt _簽名))
{
_ assert(false);
setlasterrorex(error _ invalid _ parameter,SLE _ error);
返回null
}
//檢查導入部分(即..idata部分)。
if(pntheader-& gt;optional header . data directory[圖像目錄條目導入]。虛擬地址== 0)
返回null
//獲取指向導入部分的指針(即..idata部分)
pimage _ import _ descriptor pimportdesc = make ptr(pimage _ import _ descriptor,pdosheader,
pntheader-& gt;optional header . data directory[圖像目錄條目導入]。virtual address);
//窮舉pimage_import_descriptor數組,找到我們需要截取的函數所在的模塊。
while(pimportdesc-& gt;姓名)
{
pstr szcurrmod = makeptr(pstr,pdosheader,pimportdesc-& gt;姓名);
if (stricmp(szcurrmod,szimportmodule) == 0)
打破;//找到了!中斷周期
//下壹個元素
pimportdesc++;
}
//如果沒有找到,說明我們要找的模塊還沒有被當前進程引入!
if(pimportdesc-& gt;name == null)
返回null
//返回函數找到的模塊描述符。
返回pimportdesc
}
//ISNT()函數的實現
布爾不是()
{
osversioninfo stosvi
memset(& amp;stosvi,null,sizeof(OS version info));
sto svi . dwosversioninfosize = sizeof(osversioninfo);
bool bret = getversionex(& amp;stos VI);
_ assert(true = = bret);
if (false == bret)返回false;
return(ver _ platform _ win32 _ nt = = stos VI . dwplatformid);
}