程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> VC完成屏幕截詞功效的辦法詳解

VC完成屏幕截詞功效的辦法詳解

編輯:關於C++

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處置便可。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved