VC完成屏幕截詞功效的辦法詳解。本站提示廣大學習愛好者:(VC完成屏幕截詞功效的辦法詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是VC完成屏幕截詞功效的辦法詳解正文
VC法式設計中屏幕上的文字年夜都是由gdi32.dll的以下幾個函數顯示的:TextOutA、TextOutW、ExtTextOutA、ExtTextOutW。完成屏幕抓詞的症結就是截獲對這些函數的挪用,獲得法式發給它們的參數。
完成的辦法有以下三個步調:
1、獲得鼠標確當前地位
經由過程SetWindowsHookEx完成。
2、向鼠標下的窗口發重畫新聞,讓它挪用體系函數重畫
經由過程WindowFromPoint,ScreenToClient,InvalidateRect 完成。
3、截獲對體系函數的挪用,獲得參數(以TextOutA為例)
1.模仿TextOutA作成本身的函數MyTextOutA,與TextOutA有雷同參數和前往值,放在體系鉤子地點的DLL裡。
SysFunc1=(DWORD)GetProcAddress(GetModuleHandle("gdi32.dll"),"TextOutA"); BOOL WINAPI MyTextOutA(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString) { //輸入lpszString的處置 return ((FARPROC)SysFunc1)(hdc,nXStart,nYStart,lpszString,cbString); }
2.因為體系鼠標鉤子曾經完成注入其它GUI過程的任務,我們不須要為注入再唱工作。
假如你曉得一切體系鉤子的函數必需要在靜態庫裡,就不會對"注入"覺得奇異。當過程隱式或顯式挪用一個靜態庫裡的函數時,體系都要把這個靜態庫映照到這個過程的虛擬地址空間裡(以下簡稱"地址空間")。這使得DLL成為過程的一部門,以這個過程的身份履行,應用這個過程的客棧。
DLL映照到虛擬地址空間中
對體系鉤子來講,體系主動將包括"鉤子回調函數"的DLL映照到受鉤子函數影響的一切過程的地址空間中,行將這個DLL注入了那些過程。
3.當包括鉤子的DLL注入其它過程後,尋覓映照到這個過程虛擬內存裡的各個模塊(EXE和DLL)的基地址。EXE和DLL被映照到虛擬內存空間的甚麼處所是由它們的基地址決議的。它們的基地址是在鏈接時由鏈接器決議的。當你新建一個Win32工程時,VC++鏈接器應用缺省的基地址0x00400000。可以經由過程鏈接器的BASE選項轉變模塊的基地址。EXE平日被映照到虛擬內存的0x00400000處,DLL也隨之有分歧的基地址,平日被映照到分歧過程的雷同的虛擬地址空間處。
那末若何曉得EXE和DLL被映照到哪裡了呢?
在Win32中,HMODULE和HINSTANCE是雷同的。它們就是響應模塊被裝入過程的虛擬內存空間的基地址。好比:
HMODULE hmodule=GetModuleHandle("gdi32.dll");
前往的模塊句柄強迫轉換為指針後,就是gdi32.dll被裝入的基地址。
關於若何找到虛擬內存空間映照了哪些DLL,我們可以經由過程以下方法得以完成:
while(VirtualQuery (base, &mbi, sizeof (mbi))>0) { if(mbi.Type==MEM-IMAGE) ChangeFuncEntry((DWORD)mbi.BaseAddress,1); base=(DWORD)mbi.BaseAddress+mbi.RegionSize; }
4.獲得模塊的基地址後,依據PE文件的格局窮舉這個模塊的IMAGE-IMPORT-DESCRIPTOR數組,看能否引入了gdi32.dll。如是,則窮舉IMAGE-THUNK-DATA數組,看能否引入了TextOutA函數。
5.假如找到,將其調換為響應的本身的函數。
體系將EXE和DLL原封不動映照到虛擬內存空間中,它們在內存中的構造與磁盤上的靜態文件構造是一樣的。即PE (Portable Executable) 文件格局。
一切對給定API函數的挪用老是經由過程可履行文件的統一個處所轉移。那就是一個模塊(可所以EXE或DLL)的輸出地址表(import address table)。那邊有一切本模塊挪用的其它DLL的函數名及地址。對其它DLL的函數挪用現實上只是跳轉到輸出地址表,由輸出地址表再跳轉到DLL真實的函數進口。例如:
對MessageBox()的挪用跳轉到輸出地址表,從輸出地址表再跳轉到MessageBox函數
IMAGE-IMPORT-DESCRIPTOR和IMAGE-THUNK-DATA分離對應於DLL和函數。它們是PE文件的輸出地址表的格局(數據構造拜見winnt.h)。
BOOL ChangeFuncEntry(HMODULE hmodule) { PIMAGE-DOS-HEADER pDOSHeader; PIMAGE-NT-HEADERS pNTHeader; PIMAGE-IMPORT-DESCRIPTOR pImportDesc; / get system functions and my functions′entry / pSysFunc1=(DWORD)GetProcAddress(GetModuleHandle("gdi32.dll"),"TextOutA"); pMyFunc1= (DWORD)GetProcAddress(GetModuleHandle("hookdll.dll"),"MyTextOutA"); pDOSHeader=(PIMAGE-DOS-HEADER)hmodule; if (IsBadReadPtr(hmodule, sizeof(PIMAGE-NT-HEADERS))) return FALSE; if (pDOSHeader->e-magic != IMAGE-DOS-SIGNATURE) return FALSE; pNTHeader=(PIMAGE-NT-HEADERS)((DWORD)pDOSHeader+(DWORD)pDOSHeader->e-lfanew); if (pNTHeader->Signature != IMAGE-NT-SIGNATURE) return FALSE; pImportDesc = (PIMAGE-IMPORT-DESCRIPTOR)((DWORD)hmodule+(DWORD)pNTHeader->OptionalHeader.DataDirectory[IMAGE-DIRECTORY-ENTRY-IMPORT].VirtualAddress); if (pImportDesc == (PIMAGE-IMPORT-DESCRIPTOR)pNTHeader) return FALSE; while (pImportDesc->Name) { PIMAGE-THUNK-DATA pThunk; strcpy(buffer,(char )((DWORD)hmodule+(DWORD)pImportDesc->Name)); CharLower(buffer); if(strcmp(buffer,"gdi32.dll")) { pImportDesc++; continue; }else{ pThunk=(PIMAGE-THUNK-DATA)((DWORD)hmodule+(DWORD)pImportDesc->FirstThunk); while (pThunk->u1.Function) { if ((pThunk->u1.Function) == pSysFunc1) { VirtualProtect((LPVOID)(&pThunk->u1.Function), sizeof(DWORD),PAGE-EXECUTE-READWRITE,&dwProtect); (pThunk->u1.Function)=pMyFunc1; VirtualProtect((LPVOID)(&pThunk->u1.Function), sizeof(DWORD),dwProtect,&temp); } pThunk++; } return 1; } } }
調換了輸出地址表中TextOutA的進口為MyTextOutA後,截獲體系函數挪用的重要部門曾經完成,當一個被注入過程挪用TextOutA時,其實挪用的是MyTextOutA,只需在MyTextOutA中顯示傳出去的字符串,再交給TextOutA處置便可。