The "mouse screen taking the word" technology is to be widely used in the electronic dictionary, such as the four-way distribution and Jinshan word, this technology seems simple, in fact, it is very complicated in the Windows system, always coming Say there are two implementations: The first: uses intercepted API calls to part of GDI, such as TextOut, TextOuta, etc. Second: Do a point of COPY for each device context (DC) and track all modified context (DC) operations. The second method is stronger, but the compatibility is not good, and the first method used to intercept WindowsAPI calls. The power of this technology may be far beyond your imagination, and it is not exaggerated to use Windowsapi intercept technology. You can transform the entire operating system, in fact, many plug-in Windows Chinese platforms are so real! And this technology is also the theme of this article. The call of WindowsAPI, specifically, can be divided into two methods: The first method is directly overwriting the image of the WinAPI in memory, embed assembly code, so that it is called to the specified address operation to intercept; The second method rewrites the IAT (Import Address Table Enter Address Table), redirects the call to WinAPI functions to achieve interception of WinAPI. The first method is more cumbersome, and it is more difficult in Win95, 98, because Microsoft said that Win16's API is just for compatibility, programmers should call 32-bit API as much as possible, actually Not like this at all! Most of the 32-bit API within Win 9X has been converted to the 16-bit API of the same name, that is, we need to embed 16 compile code in the interception function! We will introduce the second interception method, which is relatively stable in Win95, 98 and NT, compatible with compatibility. Since we need to use the management of Windows virtual memory, break the process boundary wall, inject the code, PE (Portable Executable) file format and IAT (input address table) in the process space, so we will first These knowledge involved probably be described, and finally the key code of the interception section will be given. Let me talk about the management of Windows virtual memory. Windows9x assigns 4GB address space to each process. For NT, this number is 2GB, the system retains the address space for 2GB to 4GB prohibits process access, and in Win9x, this part of the virtual address space of 2GB to 4GB In fact, this part of the address space is shared by all Win32 processes, and this part of the memory manager and file system code are loaded, and this part of Win9x is visible for each process. It is also why the Win9X operating system is not strong enough. The 16-bit operating system in Win9X retains 0 to 4MB address space, and between the 4MB to 2GB is the Win32 process private address space. Since the address space of each process is relatively independent, that is, if The program wants to intercept the API calls in other processes, you must break the process boundary wall, injecting the code that intercepts the API call to other processes, this work is handed over to the hook function (SETWINDOWSHOKEX) to complete, about how to create a system hook Dynamic link library, "computer master magazine" in the first I have already introduced the topic, and I haven't described here.
All system hooks must be in the dynamic library, in this way, when the process is implicit or explicitly invoked in a dynamic library, the system will map this dynamic library to the virtual address space of this process, which makes the DLL Become a part of the process, executed according to this process, using this process stack, that is, the code in the dynamic link library is injected into the address space of other GUI processes by the hook function (non-GUI process, the hook function is powerful), When the DLL containing the hook is injected into other processes, you can get the base address of each module (Exe and DLL) mapped to this process virtual memory, such as hModule HModule = getModuleHandle ("MyPro.exe"); in the MFC program We can use the AFXGetInstanceHandle () function to get the base address of the module. Where are the EXE and DLLs that are mapped to virtual memory spaces are determined by their base address. They are determined by the linker when the link is linked. When you create a new Win32 project, the VC linker uses the default base address 0x00400000. The base address of the module can be changed by the base option of the linker. EXE is typically mapped to 0x00400000, and the DLL also has different base sites, typically mapped to the same virtual address space of different processes. The system is mapped into virtual memory spaces in the virtual memory space, which is the same as the static file structure on the disk. That is, the PE (Portable Executable file format. After we get the base address of the process module, we can exhaust the image_import_descriptor array of this module according to the format of the PE file. Look at the dynamic link library where we need to intercept the functions in the process space, such as "Textouta". It is necessary to check if "gdi32.dll" is introduced. Speaking here, we need to introduce the format of the PE file, such as the right picture, this is a general block diagram of the PE file format, the front is the file header, we don't have to pay attention to the beginning of the PE File Optional Header, that is, the files in each section Description, the instructions are true segment data, and in fact, there is only one segment we care, that is, ".idata" segment, this segment contains all the introduction function information, and IAT (Import Address Table) RVA (Relative Virtual Address) address. Speaking of this, the entire principle of interception of Windowsapi is really white. In fact, all processes are transferred to a given API function to be transferred from one place of the PE file, this is the IAT input address table in the ".idata" segment of this module (can be exe or dll) (Import) Address Table). There are functions and addresses of other DLLs called by this module. The function call to other DLL is actually just jumps to the input address table, and then jumps to the DLL true function entry by the input address table.
Specifically, we will access the information introduced in the ".idata" segment through the image_import_descriptor array, then use the image_thunk_data array to access the information introduced in the DLL in the DLL through the image_thunk_data array, find us to find what we need Intercepted function's jump address, then change to our own function of the address ... The specific practice will have a detailed explanation in the key code behind. Telling so many principles, now let us return to the "mouse screen tether" topic. In addition to the interception of the API function, to achieve the "Mouse Screen Tour", you also need to do some other work, simply, can summarize a complete word process into the following steps: 1. Install the mouse hook, get the mouse message through the hook function. Used API function: setWindowsHooKex2. Get the current position of the mouse, send a redo message to the window under the mouse, let it call the system function redraint window. Used API functions: WindowFromPoint, ScreenToClient, InvalidateRect3. Intercept the call to the system function, obtain the parameters, that is, the words we have to take. For most Windows applications, if we want to get words, we need to intercept "TextOuta" function in "GDI32.DLL". We first write a textouta function to write a Mytextouta function, such as: BOOL WINAPI MyTEXTOUTA (HDC HDC, INT NXSTART, INT NYSTART, LPCSTR LPSZSTARTI, INT CBSTRING) {// Here, the output LPSZSTRING will // then call the genuine TextOuta function. } Put this function in the dynamic connection library installed in the hook, then call our last HookimportFunction function to intercept the call to the TextOuta function, jump to our MyTextOuta function, complete the capture of the output string. HookImportFunction Usage: HOOKFUNCDESC hd; PROC pOrigFuns; hd.szFunc = "TextOutA"; hd.pProc = (PROC) MyTextOutA; HookImportFunction (AfxGetInstanceHandle (), "gdi32.dll", & hd, pOrigFuns); HookImportFunction is given below Source code, I believe how detailed comments will not make you feel that it is difficult to understand how to achieve it, OK, Let's Go: / Begin /// # include
// This defines a macro #define makeptr (CAST, PTR, ADDVALUE) ((DWORD) (DWORD) (DWORD) (DWORD) (AddValue))
// define HOOKFUNCDESC structure, we use this structure as an argument to a function HookImportFunction typedef struct tag_HOOKFUNCDESC {LPCSTR szFunc; // The name of the function to hook PROC pProc;.. // The procedure to blast in} HOOKFUNCDESC, * LPHOOKFUNCDESC ;
// This function monitors whether the current system is WindowntBool ISNT ();
// This function gets hModule - introducing descriptors DLL module that we need intercepted function resides (import descriptor) PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor (HMODULE hModule, LPCSTR szImportModule); // main function of our BOOL HookImportFunction (HMODULE hModule, LPCSTR szImportModule , LPHOOKFUNCDESC paHookFunc, PROC * paOrigFuncs) {/// following code detecting parameters validity _ASSERT (szImportModule); _ASSERT (IsBadReadPtr (paHookFunc, sizeof (HOOKFUNCDESC)!));! # ifdef _DEBUG if (paOrigFuncs) _ASSERT (IsBadWritePtr (paOrigFuncs, sizeof (PROC))); _ASSERT (paHookFunc.szFunc); _ASSERT (* paHookFunc.szFunc = '/ 0');! _ASSERT (IsBadCodePtr (paHookFunc.pProc!)); # endif if ((szImportModule == NULL) || (PahookFunc, Sizeof (HookfuncDesc)))))) {_assert (false); setLasterRROREX (ERROR_INVALID_PARAMETER, SLE_ERROR); Return False;} //
/ / Monitor if the current module is the address memory of this part of 2GB Virtual Memory Space is IF (! Isnt () && ((DWORD) hModule> = 0x80000000) {_assert (false); SetLASTERROREX (ERROR_INVALID_HANDLE, SLE_ERROR); RETURN FALSE;} // Clear IF (PAORIGFUNCS) MEMSET (PAORIGFUNCS, NULL, SIZEOF (PROC));
// Call GetNamedImportDescriptor () function, to obtain hModule - that we need to // DLL module incorporated descriptor intercepted function resides (import descriptor) PIMAGE_IMPORT_DESCRIPTOR pImportDesc = GetNamedImportDescriptor (hModule, szImportModule); if (pImportDesc == NULL) Return False; // If it is empty, the module is not introduced by the current process.
// From the DLL module, you get the original THUNK information, because the original information in the pimportdesc-> firstthunk array has been // override all the introduction information when the application introduces the DLL, so we need to get PimportDesc-> OriginalFirstthunk / / Pointer to access the introduction function name and other information PIMAGE_THUNK_DATA PORIGTHUNK = Makeptr (pimage_thunk_data, hmodule, pimportdesc-> OriginalFirstthunk);
// Get the pointer of the image_thunk_data array from PimportDesc-> Firstthunk, since all the introduction information has been filled in the DLL introduced, so the real interception is actually the PIMAGE_THUNK_DATA prethunk = makeptr (Pimage_thunk_data, HModule) PimportDesc-> firstthunk); // Extremely image_thunk_data array, find the function we need to intercept, this is the most critical part! While (Porigthunk-> u1.function) {// only look for those by function name instead of serial number function if (! IMAGE_ORDINAL_FLAG = (pOrigThunk-> u1.Ordinal & IMAGE_ORDINAL_FLAG)) {// get the function name of the function is introduced PIMAGE_IMPORT_BY_NAME pByName = MakePtr (PIMAGE_IMPORT_BY_NAME, hModule, pOrigThunk-> u1.AddressOfData);
/ / If the function name begins with NULL, skip, continue the next function if ('/ 0' == PBYNAME-> Name [0]) Continue;
// bdohook is used to check if it intercepts the success BOOL BDOHOOK = FALSE;
// Check if the current function is the function IF we need to intercept ((pahookfunc.szfunc [0] == PBYNAME-> Name [0]) && (strcmpi (pahockfunc.szfunc, (char *) pBYNAME-> Name) == 0)) {// found! If (pahookfunc.pproc) bdohook = true;} If (bdohook) {// We have found the function you want to interceise, then start your hand // The first thing to do is change this a virtual memory protected memory, so that we can freely access MEMORY_BASIC_INFORMATION mbi_thunk; VirtualQuery (pRealThunk, & mbi_thunk, sizeof (MEMORY_BASIC_INFORMATION)); _ASSERT (VirtualProtect (mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, & mbi_thunk.Protect));
/ / Save the correct jump address of the function we want to intercept the correct jump address if (PAORIGFUNCS) PREALTHUNK-> U1.Function;
// Remote the function jump address in the image_thunk_data array to our own function address! // All the calls for this system function will become a call for the function written by our own call pre-revAstunk-> u1.function = PDWORD) PahookFunc.pproc;
// operation is completed this block of virtual memory back to the original protected status DWORD dwOldProtect;! _ASSERT (VirtualProtect (mbi_thunk.BaseAddress, mbi_thunk.RegionSize, mbi_thunk.Protect, & dwOldProtect)); SetLastError (ERROR_SUCCESS); return TRUE;}} / / access IMAGE_THUNK_DATA array to the next element pOrigThunk ; pRealThunk ;} return TRUE;} // achieve GetNamedImportDescriptor function PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor (HMODULE hModule, LPCSTR szImportModule) {// detection parameters _ASSERT (szImportModule); _ASSERT (hModule); if ( (SzimportModule == NULL) || (HModule == Null) {_assert (false); setLasterRROREX (Error_INVALID_PARAMETER, SLE_ERROR); Return Null;}
// Get the DOS file head pimage_dos_header pdosheader = (pimage_dos_header) hmodule;
Detecting whether the MZ Header // if (IsBadReadPtr (pDOSHeader, sizeof (IMAGE_DOS_HEADER)) || (pDOSHeader-> e_magic = IMAGE_DOS_SIGNATURE)!) {_ASSERT (FALSE); SetLastErrorEx (ERROR_INVALID_PARAMETER, SLE_ERROR); return NULL;}
// Get the PE file head pimage_nt_headers pntheader = makeptr (pimage_nt_headers, pdosheader, pdosheader-> e_lfanew);
Detecting whether the image file PE // if (IsBadReadPtr (pNTHeader, sizeof (IMAGE_NT_HEADERS)) || (pNTHeader-> Signature = IMAGE_NT_SIGNATURE)!) {_ASSERT (FALSE); SetLastErrorEx (ERROR_INVALID_PARAMETER, SLE_ERROR); return NULL;}
/ / Check the introduction segment of the PE file (ie .idata section) if (pntheader-> optionalheader.dataDirectory [image_directory_entry_import] .virtualaddress == 0) Return NULL;
// obtain lead-in (i.e. .idata section) pointer PIMAGE_IMPORT_DESCRIPTOR pImportDesc = MakePtr (PIMAGE_IMPORT_DESCRIPTOR, pDOSHeader, pNTHeader-> OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_IMPORT] .VirtualAddress);
// exhaustive PIMAGE_IMPORT_DESCRIPTOR array module while we need to find the intercepted function resides (pImportDesc-> Name) {PSTR szCurrMod = MakePtr (PSTR, pDOSHeader, pImportDesc-> Name); if (stricmp (szCurrMod, szImportModule) == 0) Break; // Find! Interrupt loop // Next Element PimportDesc ;} // If not found, the module we are looking for is not introduced by the current process! if (PimportDesc-> Name == Null) Return NULL;
/ / Return the module descriptor found by the function (Import Descriptor) Return PimportDesc;}
Achieve BOOL IsNT // IsNT () function () {OSVERSIONINFO stOSVI; memset (& stOSVI, NULL, sizeof (OSVERSIONINFO)); stOSVI.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); BOOL bRet = GetVersionEx (& stOSVI); _ASSERT (TRUE == Bret); if (false == Bret) Return False; return (Ver_Platform_Win32_NT == Stosvi.dwplatform);} /// end //
I don't know how many friends have tried to realize the "mouse screen to get words". It is only the difficulty of trying to experience the difficulty, especially in the interception of API functions. Several information on the hand, there is no one in the critical code. It is a generation. MSDN is even more pale, and I don't know how much secret, Microsoft, which is also hidden in addition to image_import_data, Microsoft also hides how many secrets, good In the hard scalp or it, I will overcome it, I hope this article can help everyone.