Mouse screen

xiaoxiao2021-04-03  242

Screen tether

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 to WindowsAPI, specifically, can be divided into two methods:

The first method is to directly rewrite the image of WinAPI in memory, embed assembly code, so that it jumps to the specified address operation to intercept; the second method Overwrites IAT (Import Address Table Input Address Table), heavy Directional WinAPI function call to implement 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, the base address of each module (Exe and DLL) mapped to this process virtual memory can be obtained, 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 usually mapped to 0x00400000, and the DLL also has different base sites, usually mapped to different processes.

The same virtual address space.

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 make 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, InvalIdateRect

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".

Let's write a Mytextouta function in the Textouta function, such as:

Bool WinApi MyTextouta (HDC HDC, INT NXSTART, INT NYSTART, LPCSTAR LPSZSTRING, INT CBSTRING)

{

// Here the output LPSZString processing

/ / Then call the genuine TextOuta function

}

Place this function in a dynamic connection library installed in the hook, then call our last HookImportFunction function to intercept the process

For 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;

The source code for hookimportfunction is given below. I believe how to make you feel that it is achieved by the detailed note.

It's hard, OK, Let's Go:

/ begin ///

#include

// This defines a macro that generates a pointer

#define makeptr (CAST, PTR, AddValue) ((DWORD) (DWORD) (AddValue)

/ / Define the hookfuncdesc structure, we use this structure as a parameter to the hookimportfunction function

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 Windownt

BOOL ISNT ();

// This function gets hmodule - that is, the import descriptor of the DLL module in which we need to intercept the function.

PIMAGE_IMPORT_DESCRIPTOR GETNAMEDIMPORTDESCRIPTOR (HModule Hmodule, LPCSTR SzimportModule);

// Our main function

Bool HookimportFunction (HModule Hmodule, LPCSTR SzimportModule,

LPhookFuncDesc PahookFunc, Proc * Paorigfuncs

{

/// The following code detects the validity of parameters

_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) || (IsbadreadPtr (PahookFunc, Sizeof (HookfuncDesc))))

{

_assert (false);

SetLASTERROREX (Error_INValid_Parameter, SLE_ERROR);

Return False;

}

//

/ / Monitor if the current module is above 2GB virtual memory space

// This part of the address memory is shared by the Win32 process.

IF (! isnt () && ((DWORD) hModule> = 0x80000000))))

{

_assert (false);

SetLASTERROREX (ERROR_INVALID_HANDLE, SLE_ERROR); RETURN FALSE;

}

// Clear

IF (PAORIGFUNCS) MEMSET (PAORIGFUNCS, NULL, SIZEOF (PROC));

// Call the getNamedImportDescriptor () function to get hmodule - ie we need

/ / The introduction descriptor of the DLL module where the interception function is located (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.

// Get the original THUNK information from the DLL module, 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 information such as introduction function name

PIMAGE_THUNK_DATA PORIGTHUNK = makeptr (pimage_thunk_data, hmodule,

PimportDesc-> OriginalFirstthunk);

// Get a pointer to the image_thunk_data array from PimportDesc-> Firstthunk, because the DLL is introduced, it has been filled.

// All introduction information, so the real interception is actually conducted here.

PIMAGE_THUNK_DATA PreAlthunk = makeptr (pimage_thunk_data, hmodule, pimportdesc-> firstthunk);

/ / Extremely image_thunk_data array, find a function we need to intercept, this is the most critical part!

While (Porigthunk-> u1.function)

{

// Look for functions introduced by the function name instead of the serial number

IF (image_ordinal_flag! = (PORIGTHUNK-> u1.ordinal & image_ordinal_flag))

{

// Get the function name of the introduction function

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 is successful

Bool bdohook = false;

// Check if the current function is a function we need to intercept

IF ((pahookfunc.szfunc [0] == PBYNAME-> Name [0]) &&

(strcmpi (pahookfunc.szfunc, (char *) pBYNAME-> NAME) == 0))

{

// found it!

IF (pahookfunc.pproc)

BDoHOOK = TRUE;

}

IF (BDoHOOK)

{

// We have found the functions that you want to intercepted, then start your hand.

// The first thing to do is to change the memory protection status of this virtual memory, so that we can access free access.

Memory_basic_information mbi_thunk;

VirtualQuery (PreAlthunk, & Mbi_thunk, sizeof (memory_basic_information);

_assert (VirtualProtect (Mbi_thunk.baseaddress, MBI_thunk.region, page_readwrite, & mbi_thunk.protect);

/ / Save the correct jump address of the function we have to intercepted

IF (PAORIGFUNCS)

PAORIGFUNCS = (Proc) preAlthunk-> u1.function;

// Remote the function jump address in the image_thunk_data array to our own function address!

// All calls to this system function will become the call to our own function.

PreAlthunk-> u1.function = (pdword) PahookFunc.pproc;

// Operate, change this virtual memory back to the original protection status

DWORD DWOLDPROTECT;

_assert (VirtualProtect (Mbi_thunk.baseaddress, Mbi_thunk.regions,

Mbi_thunk.protect, & dwoldprotect);

SetLastError (Error_Success);

Return True;

}

}

// Access the next element in the image_thunk_data array

PORIGTHUNK ;

Prelthunk ;

}

Return True;

}

// GetNameDImportDescriptor function

PIMAGE_IMPORT_DESCRIPTOR GETNAMEDIMPORTDESCRIPTOR (HModule HModule, LPCSTR SzimportModule)

{

// Detect parameters

_assert (szimportmodule);

_assert (hmodule);

IF ((szimportmodule == null) || (hmodule == null))

{

_assert (false);

SetLASTERROREX (Error_INValid_Parameter, SLE_ERROR);

Return NULL;

}

// Get the DOS file header

PIMAGE_DOS_HEADER PDOSHEADER = (PIMAGE_DOS_HEADER) HMODULE;

// Test if the MZ file 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 a PE file header

PIMAGE_NT_HEADERS PNTHEADER = makeptr (pimage_nt_headers, pdosheader, pdosheader-> e_lfanew);

// Test if a PE 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 introduction segment of the PE file (ie .idata section)

IF (Pntheader-> OptionalHeader.DataDirectory [image_directory_entry_import] .virtualaddress == 0) Return NULL;

/ / Get the pointer of the introduction section (ie .idata section)

PIMAGE_IMPORT_DESCRIPTOR PIMPORTDESC = Makeptr (pimage_import_descriptor, pdosheader,

PNTHEADER-> OPTIONALHEADER.DATADIRECTORY [image_directory_entry_import] .virtualaddress;

/ / Extremely piMage_import_descriptor array Find the module where we need intercepted functions

While (pimportdesc-> name)

{

PSTR SZCurRMod = Makeptr (PSTR, PDOSHeader, PimportDesc-> Name);

IF (Stricmp (Szcurrmod, SzimportModule) == 0)

Break; // Find! Interrupt loop

// Next element

PIMPORTDESC ;

}

// If you don't find it, the module we look 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;

}

// ISNT () function implementation

BOOL ISNT ()

{

OsversionInfo Stosvi;

MEMSET (& Stosvi, Null, Sizeof (OsversionInfo);

Stosvi.dwosveionsInFoSize = SizeOf (OsversionInfo);

Bool Bret = GetversionEx (& Stosvi);

_assert (true == BRET);

IF (false == Bret) Return False;

Return (Ver_Platform_WIN32_NT == Stosvi.dwPlatformID);

}

/// 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 hope that this article can help everyone.

转载请注明原文地址:https://www.9cbs.com/read-131625.html

New Post(0)