Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the realization method of picking words on Windows 9x screen?

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

What is the realization method of Windows 9x screen word extraction? aiming at this problem, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.

About taking words on the screen

The technology of "picking words from mouse screen" is widely used in electronic dictionaries, such as Sitong Lifang and Jinshan Ciba and other software. this technology seems simple, but in fact, it is very complex in windows system. Generally speaking, there are two ways to implement it:

*: it is implemented by intercepting api calls to some gdi, such as textout,textouta.

The second: copy each device context (dc) and track all operations that modify the context (dc).

The second method is more powerful, but the compatibility is not good, and the technology used to intercept windowsapi calls may be far more powerful than you can imagine. It is no exaggeration to say that with windowsapi interception technology, you can transform the entire operating system. In fact, many plug-in windows Chinese platforms are implemented in this way! And this technology is the theme of this article.

Specifically, the call to intercept windowsapi can be divided into two methods:

* this method intercepts winapi by directly rewriting the image of winapi in memory and embedding assembly code to jump to the specified address when it is called; the second method is to rewrite iat (import address table input address table) and redirect the call to the winapi function to intercept winapi.

The implementation of * methods is more complicated and more difficult under win95 and 98, because although Microsoft says that the api of win16 is retained only for compatibility, programmers should call 32-bit api as much as possible, but this is not the case at all! Most of the 32-bit api inside win 9x has been transformed to call a 16-bit api of the same name, which means we need to embed 16-bit assembly code in the intercepted function!

What we are going to introduce is the second interception method, which is stable and compatible under win95, 98 and nt. Because we need to use lower-level knowledge about the management of windows virtual memory, breaking the process boundary wall, injecting code into the application's process space, pe (portable executable) file format and iat (input address table), so we will first give a general introduction to the knowledge involved, and * will give the key code of the intercepting part.

Let's start with the management of windows virtual memory. Windows9x allocates the address space of 4gb to each process. For nt, this number is 2gb. The system reserves the address space between 2gb and 4gb to prohibit process access. In win9x, the virtual address space from 2gb to 4gb is actually shared by all win32 processes. This part of the address space loads shared win32 dll, memory-mapped files and vxd, memory manager and file system code. This part of win9x is visible to every process, which is why the win9x operating system is not robust enough. In win9x, the address space from 0 to 4mb is reserved for 16-bit operating systems, while between 4mb and 2gb, that is, the private address space of win32 processes, because the address space of each process is relatively independent, that is, if a program wants to intercept api calls in other processes, it must break the process boundary wall and inject code to intercept api calls into other processes. We give this work to the hook function (setwindowshookex). About how to create a dynamic link library that contains system hooks, "computer expert Magazine" in No. There has already been a special introduction, so I won't repeat it here. The functions of all system hooks must be in the dynamic library, so that when a process implicitly or explicitly calls a function in a dynamic library, the system maps the dynamic library to the process's virtual address space, which makes dll part of the process, executed as that process, using the process's stack. In other words, the code in the dynamic link library is injected into the address space of other gui processes by the hook function (for non-gui processes, the hook function is powerless). When the dll containing the hook is injected into other processes, the base addresses of the modules (exe and dll) mapped to the virtual memory of this process 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 exe and dll are mapped to virtual memory space is determined by their base address. Their base address is determined by the linker when they are linked. When you create a new win32 project, the vc++ linker uses the default base address 0x00400000. You can change the base address of the module through the base option of the linker. Exe is usually mapped to the 0x00400000 of virtual memory, and dll also has different base addresses, usually mapped to the same virtual address space of different processes.

The system maps exe and dll intact to virtual memory space, and their structure in memory is the same as the static file structure on disk. That is, pe (portable executable) file format. After we have obtained the base address of the process module, we can enumerate the image_import_descriptor array of the module according to the format of the pe file to see if the dynamic link library where the function we need to intercept is introduced into the process space. For example, if we need to intercept "textouta", we must check whether "gdi32.dll" has been introduced. At this point, it is necessary for us to introduce the format of the pe file, such as the figure on the right. This is the general block diagram of the pe file format, and the front is the header of the file. We don't have to worry about it. Starting from the back of the pe file optional header, it is the description of each paragraph in the file, indicating that the real segment data is behind it. In fact, we only care about one segment, that is, the ".idata" section, which contains all the imported function information. There is also the rva (relative virtual address) address of iat (import address table).

At this point, the whole principle of intercepting windowsapi will be revealed. Virtually all calls to a given api function are transferred through a place in the pe file, which is an iat input address table (import address table) in the ".idata" section of the module (which can be exe or dll). There are the function names and addresses of all other dll called by this module. Function calls to other dll actually just jump to the input address table, from the input address table to the actual function entry of the dll.

Specifically, we will access the information of the dll introduced in the ".idata" section through the image_import_descriptor array, and then access the information of each function introduced in the dll for an introduced dll through the image_thunk_data array, find the jump address of the function we need to intercept, and change it to the address of our own function.

Nonsense, the following provides a specific implementation of screen words.

1. Install the mouse hook and get the mouse message through the hook function.

The api function used: setwindowshookex

2. Get the current position of the mouse, send a redraw message to the window under the mouse and let it call the system function to redraw the window.

The api function used: windowfrompoint,screentoclient,invalidaterect

3. Intercept the call to the system function and get the parameter, that is, the word we want to take.

For most windows applications, to take a word, what we need to intercept is the "textouta" function in "gdi32.dll".

Let's first emulate the textouta function and write our own mytextouta function, such as:

Bool winapi mytextouta (hdc hdc, int nxstart, int nystart, lpcstr lpszstring,int cbstring) {/ / here processes the output lpszstring / / and then calls the authentic textouta function}

Put this function in the dynamic link library with hooks installed, and then call our hookimportfunction function to intercept the process's call to the textouta function, jump to our mytextouta function, and complete the capture of the output string. The usage of hookimportfunction:

Hookfuncdesc hd; proc porigfuns; hd.szfunc= "textouta"; hd.pproc= (proc) mytextouta; hookimportfunction (afxgetinstancehandle (), "gdi32.dll", & hd,porigfuns)

The source code of hookimportfunction is given below. I believe that detailed comments will not make you find it difficult to understand how interception is implemented. Ok,let s go:

Begin # include / / A macro that produces pointers is defined here # define makeptr (cast, ptr, addvalue) (cast) ((dword) (ptr) + (dword) (addvalue)) / / defines the hookfuncdesc structure, which we pass as an argument 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 introduction descriptor (importdescriptor) pimage_import_descriptor getnamedimportdescriptor (hmodule hmodule, lpcstr szimportmodule) of the dll module where the function we need to intercept is located. / / 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 whether the current module is above the 2gb virtual memory space / / this part of the address memory belongs to if (! isnt () & & (dword) hmodule > = 0x80000000)) {_ assert (false); setlasterrorex (error_invalid_handle, sle_error); return false;} / / zeroing if (paorigfuncs) memset (paorigfuncs, null, sizeof (proc)) / / call the getnamedimportdescriptor () function to get hmodule-- that is, the incoming descriptor (importdescriptor) pimage_import_descriptor pimportdesc = getnamedimportdescriptor (hmodule, szimportmodule) of the dll module where the function we need to intercept is located; if (pimportdesc = = null) return false / / if empty, the module is not introduced by the current process / / the original thunk information is obtained from the dll module, because the original information in the pimportdesc- > firstthunk array has / / overwritten all the incoming information when the application introduces the dll, so we need to access the incoming function name and other information pimage_thunk_data porigthunk = makeptr (pimage_thunk_data, hmodule) by getting pimportdesc- > originalfirstthunk / / pointer. Pimportdesc- > originalfirstthunk) / / get the pointer to the image_thunk_data array from pimportdesc- > firstthunk. Since / / all the incoming information was populated here when dll was introduced, the real interception is actually pimage_thunk_data prealthunk = makeptr (pimage_thunk_data, hmodule, pimportdesc- > firstthunk); / / exhaustive image _ thunk_data array to find the function we need to intercept, this is the most important part! While (porigthunk- > u1.function) {/ / only look for those functions introduced by function name rather than ordinal if (image_ordinal_flag! = (porigthunk- > u1.ordinal & image_ordinal_flag)) {/ / get the function name pimage_import_by_name pbyname = makeptr (pimage_import_by_name, hmodule, porigthunk- > u1.addressofdata) / / if the function name starts with null, skip and proceed to the next function if (\ 0 = = pbyname- > name [0]) continue; / / bdohook is used to check whether the interception was successful bool bdohook = false / / check whether 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;} if (bdohook) {/ / We have found the function we want to intercept, so let's get started / / the first thing to do is to change the memory protection state of this piece of virtual 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: if (paorigfuncs) paorigfuncs = (proc) prealthunk- > u1.function / / rewrite the function jump address in the image_thunk_data array to our own function address! / / in the future, all calls to this system function by all processes will be calls to our own functions prealthunk- > u1.function = (pdword) pahookfunc.pproc; / / finished! Change this block of virtual memory back to its 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 porigthunk++; prealthunk++;} return true in the image_thunk_data array } / / implementation of getnamedimportdescriptor function pimage_import_descriptor getnamedimportdescriptor (hmodule hmodule, lpcstr szimportmodule) {/ / detect parameter _ assert (szimportmodule); _ assert (hmodule); if ((szimportmodule = = null) | | (hmodule = = null) {_ assert (false); setlasterrorex (error_invalid_parameter, sle_error); return null;} / / get dos header pimage_dos_header pdosheader = (pimage_dos_header) hmodule / / check 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 pe header pimage_nt_headers pntheader = makeptr (pimage_nt_headers, pdosheader, pdosheader- > e_lfanew) / / check whether the 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 import segment of the pe file (i.e., .idata section) if (pntheader- > optionalheader.datadirectory [image _ directory_entry_import]. Virtualaddress = = 0) return null / / get the pointer pimage_import_descriptor pimportdesc = makeptr (pimage_import_descriptor, pdosheader, pntheader- > optionalheader.datadirectory [image _ directory_entry_import] .virtualaddress) of the incoming segment (i.e. .idata section); / / exhaust the pimage _ import_descriptor array to find the module while (pimportdesc- > name) {pstr szcurrmod = makeptr (pstr, pdosheader, pimportdesc- > name); if (stricmp (szcurrmod, szimportmodule) = = 0) break / / found! Break loop / / next element pimportdesc++;} / / if it is not found, the module we are looking for has not been introduced by the current process! Implementation of the module descriptor (import descriptor) return pimportdesc;} / / isnt () found by the if (pimportdesc- > name = = null) return null; / / return function bool isnt () {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.dwplatformid);} this is the answer to the question about how to pick up words on Windows 9x screen. I hope the above content can be of some help to you. If you still have a lot of doubts to be solved, you can follow the industry information channel for more related knowledge.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report