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: SetWindowsHookex 2. 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, InvalidateERECT 3. 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 that detailed comments will not make you feel that it is difficult to understand how to achieve it, OK, Let's Go: / Begin /// #include
// Call getnamedimportdescriptor () function, to obtain hmodule - introducing the module descriptor dll that we need to // 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 to the original THUNK information, because the original information in the pimportdesc-> firstthunk array has been // override when the application introduces the DLL the introduction of all the information, so we need to get pimportdesc-> originalfirstthunk // pointer to access information such as the introduction of the function name pimage_thunk_data porigthunk = makeptr (pimage_thunk_data, hmodule, pimportdesc-> originalfirstthunk); // get image_thunk_data from pimportdesc-> firstthunk Array pointer, since all of the introduction information has been filled in the DLL introduced, the real interception is actually piMage_thunk_data prethunk = makeptr (pimage_thunk_data, hmodule, pimportdsc-> firstthunk); // Extunction Image_thunk_data array, find a function we need to intercept, this is the most critical part! While (principik-> u1.function) {// only look for functions imported by function name instead of serial number (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 to the next A function if ('/ 0' == pBYNAME-> Name [0]) Continue; // bdohook is used to check if the successful bool bdohook = false; / / check if the current function is the function IF we need to intercept ((PahookFunc) .SZFUNC [0] == PBYNAME-> Name [0]) && (strcmpi (pahookfunc.szfunc, (char *) pBYNAME-> NAME) == 0)) {// found! IF (pahookfunc.pproc) BDoHOOK = True;}}} {// We have found the function you want to intercept, then start your hand // The first thing to do is to change the memory protection of this virtual memory, let us free 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 function we want to jump intercepted correct address if (paorigfuncs) PAORIGFUNCS =
(Proc) pre-pnk-> u1.function; // Remote the function jump address in the image_thunk_data array to our own function addresses! // All calls to this system function will become a function written by our own call prealthunk-> u1.function = (pdword) pahookfunc.pproc; // operation is completed this block of virtual memory back to the original protected state dword dwoldprotect;! _assert (virtualprotect (mbi_thunk.baseaddress, mbi_thunk.regionsize, mbi_thunk.protect , & dwoldprotect)); setlasterror (error_success); return true;}} // access the next element image_thunk_data array porigthunk ; prealthunk ;} return true;} // achieve pimage_import_descriptor getnamedimportdescriptor function getnamedimportdescriptor (hmodule hmodule, lpcstr szimportmodule) { // Detect parameters_assert (SzimportModule); _assert (hmodule); if (SzimportModule == Null) || (HModule == NULL)) {_assert (false); setLasterRROREX (ERROR_INVALID_PARAMETER, SLE_ERROR); return null;} / / dos file header obtained pimage_dos_header pdosheader = (pimage_dos_header) hmodule; // file header detecting whether mz if (isbadreadptr (pdosheader, sizeof (image_dos_header)) || (pdosheader-> e_magic = image_dos_signature)!) {_assert (false); setlasterrorex (Error_INVALID_PARAMETER, SLE _error); return null;} // obtain pe header pimage_nt_headers pntheader = makeptr (pimage_nt_headers, pdosheader, pdosheader-> e_lfanew); // pe detecting whether the image file if (isbadreadptr (pntheader, sizeof (image_nt_headers)) || (pntheader -> signature = image_nt_signature)) {_assert (false); setlasterrorex (error_invalid_parameter, sle_error); return null;} // check the lead-pe file (i.e. .idata section) if (pntheader-> optionalheader.datadirectory [image_directory_entry_import]! .virtualaddress == 0) Return null; // Get introduction segment (ie .idata section) pointer PIMAGE_IMPORT_DESCRIPTOR PIMPORTDESC = Makeptr (pimage_import_descriptor, pdosheader, pntheader->