API blocking
Modify the Import function address of the PE file import segment to the new function address
This involves a image_import_descriptor descriptor structure for each implicitly linked DLL in the import table and Iat,pe file in the PE file format, and each image_import_descriptor the firstthunk in the structure points to the first address of an array of IMAGE_THUNK_DATA structures.
In this iamge_thunk_data array, each entry corresponds to an import function for the DLL module (import for the PE file that uses the DLL module).
The structure is roughly as follows
When intercepting an API in a DLL module, look for the DLL in the import section of the PE file, then look for the address of the API and replace its address with a new one.
That is, iterate through the image_import_descriptor array, find the module whose name is the same as the given DLL, and then traverse its firstthunk point iamge_thunk_data Array, locate the API to be intercepted, and then replace the address with the new address.
In this example, the DllForLanjie.dll module is used inLanjieAPI.exe , which exports a function Add (int a, int b)that calculates the two-digit number. The example in this article intercepts the Add function and replaces it with the show function to display the information.
On the Code
/************************************************************************//* In a PE file, each implicitly linked DLL corresponds to a image_import_descriptor struct (winnt.h) typedef struct _IMAGE_IMPORT_DESCRIPTOR {union {DWORD characteristics; 0 for terminating null import Descriptordword originalfirstthunk; Pointer to an array of image_thunk_data structures, RVA to original Unbound IAT (pimage_thunk_data)};D word TimeDateStamp; 0 if not bound,//-1 if bound, and real date\time stamp//in Image_directory_entry_bound_import (new BIND)//O.W. D Ate/time stamp of DLL bound to (old BIND) DWORD Forwarderchain; -1 if no Forwardersdword Name; The name of the module DWORD Firstthunk; Pointer to an array of image_thunk_data structures, RVA to IAT (if bound this iat has actual addresses)} Image_import_descriptor; Each function in an import module of a PE file corresponds to a image_thunk_data structure typedef struct _IMAGE_THUNK_DATA32 {union {DWORD forwarderstring; Pbyte DWORD Function; Pdworddword Ordinal;dword Addressofdata; Pointer to the IMAGE_IMPORT_BY_NAME structure, pimage_import_bY_name} U1;} image_thunk_data32;typedef struct _image_import_by_name {WORD Hint; BYTE name[1];} Image_import_by_name, *pimage_import_by_name; where Originalfirstthunk and Firstthunk are each a image_thunk_ The data struct type array is different: the array of iamge_thunk_data structures pointed to by Originalfirstthunk is a single item, and cannot be changed, becomes an int, and sometimes becomes the cue name table. Firstthunk points to the Image_thunk_data structure type array is also the PE loader, the PE loader first searches for originalfirstthunk, and if found, the loader iterates through each pointer in the array to find each Image_ The IMPORT_BY_NAME structure points to the address of the input function, and then the loader replaces each function entry in the Firstthunk array with the actual entry address of the function, so he becomes the "Input Address Table iat". /************************************************************************/
DLL Export function
// DllForLanjie.dll Export Function extern " C " int __stdcall Add (intint b) { return a + b;}
Intercept code
BOOL replaceiatentryinonemod (pcstr pszcalleemodname,//module where the API to intercept is being tunedPROC Pfncurrent,//The blocked API, the address of the module in which it residesPROC Pfnnew,//The address of the new function to replaceHmodule Hmodcaller//module that invokes the new function) {ULONG ulsize=0UL; Pimage_import_descriptor Pimportdesc= NULL;//Import Descriptor__try {Pimportdesc= (Pimage_import_descriptor) (Imagedirectoryentrytodata (Hmodcaller, TRUE, Image_directory_entry_import, &ulsize)); } //__except (Invalidreadexceptionfilter (getexceptioninformation))__except (1) {Cerr<<"Exception!"<<Endl; } if(NULL = = Pimportdesc)returnFALSE; //the end condition for the current Image_import_descriptor structure (name field) pointer is null for(; pimportdesc->name; pimportdesc++) { //find the address of each module in the import segment, and convert it to pbyte for the pointer + 1 o'clock is a bytePSTR pszmodname = (PSTR) ((pbyte) Hmodcaller + pimportdesc->Name); //If you find a module with the same name if(Lstrcmpia (pszmodname, pszcalleemodname) = =0) { //gets the first address of the image_thunk_data array of the PIMAGEDESC module in the calling program (in the PE file)Pimage_thunk_data Pthunk = (pimage_thunk_data) ((pbyte) Hmodcaller + pimportdesc->firstthunk); //Find the "function" to intercept in the module for(; pthunk->u1. Function; pthunk++) {PROC* PPFN = (proc*) (&pThunk->U1. Function); //If you find the "function" you want,BOOL Bfound = (*PPFN = =pfncurrent); if(bfound) {//if the address of the new function is written to the address of the intercepted function "failed" if(! WriteProcessMemory (GetCurrentProcess (), PPFN, &pfnnew,sizeof(pfnnew), NULL)&& (error_noaccess = =GetLastError ())) {DWORD Dwoldprotect=0; //change the Protection property of the page to "copy on write" if(VirtualProtect (PPFN,sizeof(pfnnew), Page_writecopy, &dwoldprotect)) {BOOL B1= WriteProcessMemory (GetCurrentProcess (), PPFN, &pfnnew,sizeof(pfnnew), NULL); BOOL B2= VirtualProtect (PPFN,sizeof(pfnnew), Dwoldprotect, &dwoldprotect); returnB1 &&B2; } //if Else { returnFALSE; } } //if//If it is done here, it must be successful. returnTRUE; } //if } // for } //if}// for returnFALSE;}
A new function to replace, defined in the current EXE
int __stdcall Show () { cout<<endl<<" if you see this line of information stating that your function was intercepted by the current function. " <<Endl; return 0 ;}
To signal how to intercept.
header files and libraries
#include"stdafx.h"#include<iostream>#include<Windows.h>#include<Dbghelp.h>#include<Psapi.h>using namespacestd;#pragmaComment (lib, "PSAPI.lib")#pragmaComment (lib, "Dbghelp.lib")#pragmaComment (lib, "DllForLanjie.lib")extern "C"__declspec (dllimport)int__stdcall Add (intAintb);
int_tmain (intARGC, _tchar*argv[]) {
In this example, get the exitproess address null, and use depends to view the EXE using Kernel32.dll's import function without ExitProcess,
This may be the reason why the address is null
//PROC pfncurrent = (PROC) GetProcAddress (GetModuleHandle (_t ("kernel32.dll")), "ExitProcess"); //PROC pfncurrent = (PROC) GetProcAddress (GetModuleHandle (_t ("kernel32.dll")), "Sleep");cout<<"call the Add function to calculate Add (ten) before intercepting"<<Endl; cout<<"Add (Ten) ="<<add (Ten, -) <<endl<<Endl; PROC pfncurrent= (PROC) GetProcAddress (GetModuleHandle (_t ("DllForLanjie.dll")),"[email protected]"); if(NULL = = pfncurrent)return-1; TCHAR Chimagename[max_path+1] = {0}; ZeroMemory (Chimagename,sizeof(Chimagename)); DWORD Dwret=Getprocessimagefilename (GetCurrentProcess (), Chimagename, _countof (chimagename)); if(0==Dwret) {Cerr<<"some error"<<Endl; return-2; } cout<<endl<<"begins replacing the address of the function add in module DllForLanjie.dll in the import segment of the current EXE with the show function"<<Endl; BOOL BRet= Replaceiatentryinonemod ("DllForLanjie.dll", Pfncurrent, show, GetModuleHandle (NULL)); if(FALSE = =BRet) {cout<<"replace failed to exit!"<<Endl; return-3; } cout<<"Replace successfully continue! "<<Endl; cout<<endl<<endl<<"the following call three times the Add function calculates 100 and 200 of the and"<<Endl; for(inti =0; I <3; ++i) {Add ( -, $); } cout<<endl<<Endl; return 0;}
Execution results
During the execution, VS2005 has been reported to run-time exception
Each time you click "Ignore" to continue, why?
This instance has successfully intercepted the API add function in DllForLanjie.dll and replaced it with the show function in EXE.