Colección de citas famosas - Colección de poesías - Búsqueda de palabras en pantalla

Búsqueda de palabras en pantalla

La tecnología de "recuperación de palabras del mouse" se usa ampliamente en diccionarios electrónicos, como software como Sitong Lifang y Kingsoft PowerWord. Esta tecnología parece sencilla, pero es muy complicada de implementar en un sistema WINDOWS. En términos generales, existen dos métodos de implementación:

El primero: interceptando llamadas API a ciertos GDI, como TextOut, TextOutA, etc.

En segundo lugar, copie el contexto de cada dispositivo (DC) y realice un seguimiento de todas las operaciones que modifican el contexto (DC).

El segundo método es más potente, pero tiene poca compatibilidad, mientras que el primer método utiliza la interceptación de llamadas a la API de Windows, que puede ser mucho más potente de lo que cree. No es exagerado decir que el uso de la tecnología de interceptación API de Windows puede transformar todo el sistema operativo. De hecho, ¡muchas plataformas chinas externas de Windows se implementan de esta manera! Y esta tecnología es el tema de este artículo.

La interceptación de llamadas a la API de Windows se puede dividir en dos métodos:

El primer método reescribe directamente la imagen en la memoria, incrusta el código ensamblador y hace que salte a cuando se llama. para interceptar WinAPI. El segundo método reescribe la IAT (Importar tabla de direcciones) y redirige las llamadas a funciones de WinAPI para interceptar WinAPI.

La implementación del primer método es más complicada y difícil en Win95 y 98. Esto se debe a que, aunque Microsoft dice que las API de WIN16 solo están reservadas para la compatibilidad, los programadores deben llamar a las API de 32 bits tanto como sea posible. De hecho, ¡este no es el caso en absoluto! La mayoría de las API de 32 bits en WIN 9X se han convertido y se denominan API de 16 bits con el mismo nombre, lo que significa que debemos incrustar código ensamblador de 16 bits en las funciones interceptadas.

Presentaremos el segundo método de interceptación, que es estable y compatible con Win95, 98 y NT. Debido a que necesitamos utilizar algunos conocimientos de bajo nivel sobre la administración de la memoria virtual de Windows, romper los límites del proceso, inyectar código en el espacio de proceso de la aplicación, PE (formato ejecutable portátil) e IAT (tabla de direcciones de entrada), primero haremos una introducción general. Se proporciona este conocimiento y, finalmente, se proporciona el código clave para la parte de interceptación.

Hablemos de la gestión de la memoria virtual de Windows. Windows9X asigna 4 GB de espacio de direcciones a cada proceso, NT es de 2 GB y el sistema reserva el espacio de direcciones entre 2 GB y 4 GB, lo que prohíbe el acceso al proceso. En Win9X, el espacio de direcciones virtuales entre 2 GB y 4 GB lo comparten todos los procesos WIN32. Esta parte del espacio de direcciones carga archivos DLL de Win32, archivos asignados en memoria, VXD, administradores de memoria y código del sistema de archivos. Esta parte de Win9X es visible para todos los procesos, razón por la cual el sistema operativo Win9X no es lo suficientemente robusto.

En Win9X, el espacio de direcciones de 0 a 4 MB está reservado para el sistema operativo de 16 bits, y el espacio de direcciones de 4 MB a 2 GB es el espacio de direcciones privado del proceso Win32. Debido a que el espacio de direcciones de cada proceso es relativamente independiente, es decir, si un programa quiere interceptar llamadas API en otros procesos, debe romper el muro límite del proceso e inyectar código para interceptar llamadas API en otros procesos. Dejamos este trabajo a la función de enlace (SetWindowsHookEx). En la revista Computer Master se introdujo cómo crear una biblioteca de enlaces dinámicos que contenga enlaces del sistema, por lo que no entraré en detalles aquí.

Todas las funciones de enlace del sistema deben estar en bibliotecas dinámicas.

En este caso, cuando el proceso llama implícita o explícitamente a una función en la biblioteca dinámica, el sistema asignará la biblioteca dinámica al espacio de direcciones virtuales del proceso, lo que hace que la DLL se convierta en parte del proceso, se ejecute como el proceso y use la pila de procesos, es decir, el código en la biblioteca de enlaces dinámicos se inyecta en el espacio de direcciones de otros procesos GUI mediante la función de enlace (para procesos que no son GUI, la función de enlace no tiene poder cuando la DLL que contiene). Cuando se inyecta un gancho en otros procesos, se puede obtener el mapeo de la dirección base del módulo (EXE y DLL) a la memoria virtual del proceso, por ejemplo:

HMODULE HMODULE = GetModuleHandle("mypro. exe ");

En el programa MFC, podemos utilizar la función AfxGetInstanceHandle() para obtener la dirección base del módulo. Las ubicaciones donde se asignan EXE y DLL al espacio de memoria virtual están determinadas por sus direcciones base. Sus direcciones base las determina el vinculador en el momento del enlace. Al crear un nuevo proyecto Win32, el vinculador vC++ utiliza la dirección base predeterminada 0x00400000. Puede cambiar la dirección base de un módulo a través de la opción BASE del vinculador. EXE generalmente se asigna a 0x00400000 en la memoria virtual, y las DLL tienen diferentes direcciones base y generalmente se asignan al mismo espacio de direcciones virtuales de diferentes procesos.

El sistema asigna EXE y DLL al espacio de la memoria virtual intactos y su estructura en la memoria es la misma que la del archivo estático en el disco. Ese es el formato de archivo PE (Portable Executable). Después de obtener la dirección base del módulo de proceso, podemos enumerar la matriz IMAGE_IMPORT_DESCRIPTOR de este módulo de acuerdo con el formato del archivo PE para ver si la biblioteca de enlaces dinámicos de la función que necesitamos interceptar se ha introducido en el espacio de proceso. Por ejemplo, si necesitamos interceptar "TextOutA", debemos verificar si se introduce "Gdi32.dll".

Dicho esto, debemos introducir el formato del archivo PE, como se muestra en la imagen de la derecha. Este es un diagrama de bloques general del formato de archivo PE, con el encabezado al frente para que no tengamos que centrarnos en él. A partir del encabezado opcional del archivo PE, es una descripción de cada segmento del archivo. La descripción va seguida de los datos del segmento real, pero en realidad solo nos importa un segmento, el fragmento ".idata". Esta sección contiene toda la información para la función de importación, así como las direcciones RVA (dirección virtual relativa) de la IAT (tabla de direcciones de importación).

En este punto, se revelará todo el principio de interceptación de la API de Windows. De hecho, todas las llamadas de proceso a una función API determinada siempre se transmiten a través de una ubicación en el archivo PE, que es la "tabla de direcciones de entrada IAT en". La sección "idata" del módulo (puede ser un EXE o DLL). Aquí están todos los nombres de funciones y direcciones de otras DLL llamadas por este módulo. Las llamadas a funciones a otras DLL en realidad simplemente saltan a la tabla de direcciones de entrada y luego saltan de la tabla de direcciones de entrada a la entrada de función real de la DLL.

En concreto accederemos a la información de la DLL introducida en . "idata", y luego acceda a la información de cada función introducida en la DLL a través de la matriz IMAGE_IMPORT_DESCRIPTOR. Para una DLL introducida, busque la dirección de salto de la función que necesitamos interceptar a través de la matriz IMAGE_THUNK_DATA, y luego cámbiela a la dirección de nuestra propia función... El método específico se explicará en detalle en el código clave a continuación.

Habiendo dicho tantos principios, volvamos al tema de "palabras en la pantalla del mouse". la interceptación de funciones API. Realice algún otro trabajo para implementar la "recuperación de palabras en la pantalla del mouse". En resumen, un proceso completo de recuperación de palabras se puede resumir en los siguientes pasos:

1. el mensaje del mouse a través de la función de gancho

Función API utilizada: SetWindowsHookEx

2. Obtenga la posición actual del mouse, envíe un mensaje de redibujo a la ventana debajo del mouse y deje que llama a la función del sistema para volver a dibujar la ventana.

Funciones API utilizadas: WindowFromPoint, ScreenToClient, invalidar estar

3. es la palabra que queremos conseguir.

Para la mayoría de las aplicaciones de Windows, si queremos recuperar palabras, lo que necesitamos interceptar es la función "TextOutA" en "Gdi32.dll".

Escribamos una función MyTextOutA similar a la función TextOutA, por ejemplo:

BOOL WINAPI MyTextOutA(HDC HDC, int nXStart, int nYStart, LPCSTR lpszString, int cbString)

{

//Aquí se realiza el procesamiento de salida de lpszString.

//Luego llame a la función TextOutA genuina.

}

Coloque esta función en la biblioteca de vínculos dinámicos con los ganchos instalados y luego llame a la función HookImportFunction que le dimos en último lugar para interceptar la llamada del proceso a la función TextOutA y saltar a nuestro Función MyTextOutA para capturar la cadena de salida.

Uso de HookImportFunction:

HOOKFUNCDESC hd

PROC pOrigFuns

HD .SZ func = "TextOutA"

< p; >HD .pproc = (PROC)MyTextOutA;

hookinportfunction(AfxGetInstanceHandle(), "gdi32.dll", & amphd, pOrigFuns);

La fuente de HookImportFunction se proporciona a continuación . Estoy seguro de que la revisión detallada no le dificultará comprender cómo se implementa la interceptación. Bien, vamos:

///(La imagen proviene de Internet, infracción y eliminación), infracción y eliminación (la imagen proviene de Internet), infracción y eliminación (la imagen proviene de Internet ), infracción y eliminación (la imagen proviene de Internet) en Internet).

# include & ltcrtdbg.h & gt

//La macro para generar punteros se define aquí.

# define make Ptr (cast, ptr, AddValue) (cast) ((DWORD) (ptr) + (DWORD) (AddValue))

//Definir la estructura HOOKFUNCDESC, Usamos esto como un parámetro pasado a la función HookImportFunction.

typedef struct tag_HOOKFUNCDESC

{

LPCSTR szFunc//El nombre de la función que se va a enganchar.

PROC pProc//El proceso a insertar.

} HOOKFUNCDESC, * LPHOOKFUNCDESC

//Esta función monitorea si el sistema actual es WindowNT.

BOOL nots();

//Esta función obtiene hModule, el descriptor de importación del módulo DLL donde se encuentra la función que necesitamos interceptar.

PIMAGE _ IMPORT _ DESCRIPTOR GetNamedImportDescriptor (HMODULE HMODULE, LPCSTR sziportmodule);

//Nuestra función principal

Función de importación de gancho BOOL (HMODULE HMODULE, LPCSTR szImportModule) ,

LPHOOKFUNCDESC paHookFunc, PROC* paOrigFuncs)

{

////////////////El siguiente código detecta parámetros /////////////////////////////////////////////////// //// //////////////////////////////////////////////// //////// /////////////////////////////////////////// //////////// ///////////

_ASSERT(szImportModule);

_ASSERT(!IsBadReadPtr(pahook func, sizeof(hook func desc)));

p>

#ifdef _DEBUG

if (paOrigFuncs)_ ASSERT (! IsBadWritePtr (paorifuncs, sizeof (PROC))

_ ASSERT (función pahook. Función SZ);

_ASSERT(* función pahook. Función SZ!= '\0');

_ASSERT(!IsBadCodePtr(pahook func .pproc));

#endif

if ((szImportModule == NULL) | | (IsBadReadPtr(pahook func, sizeof (hook func desc)))

{

_ ASSERT(FALSE);

SetLastErrorEx(Error_Parámetro no válido, SLE_Error);

Devolver FALSE

}

// ////////////////////////////////////////// //////////// /////////////////////////////

//Monitor si el módulo actual supera los 2 GB de espacio de memoria virtual.

//Esta parte de la memoria de direcciones pertenece al proceso Win32 * * *.

if(!not()&&((DWORD)hModule>= 0x80000000))

{

_ ASSERT(FALSE);

SetLastErrorEx(ERROR_INVALID_HANDLE, SLE_ERROR);

Devolver FALSO

}

//Borrar

if (paOrigFuncs) memset (paOrigFuncs , NULL, sizeof (PROC));

// Llame a la función GetNamedImportDescriptor() para obtener el hModule; es decir, necesitamos

//El descriptor de importación del módulo DLL. donde se encuentra la función interceptada.

PIMAGE_IMPORT_DESCRIPTOR pImportDesc = GetNamedImportDescriptor(hm module, sziportmodule);

if (pImportDesc == NULL)

Devuelve FALSE // Si está vacío, entonces el El módulo no se ha introducido en el proceso actual.

//Obtenga la información THUNK original del módulo DLL, porque la información original en pimportdesc->matriz FirstThunk ha sido

//Cuando la aplicación introduce la DLL, es Cubre toda la información de importación, por lo que necesitamos obtener el puntero de pimportdesc-》;OriginalFirstThunk

//información de acceso (como el nombre de la función importada).

PIMAGE_THUNK_DATA pOrigThunk = make ptr(PIMAGE_THUNK_DATA,hModule,

pImportDesc->originalfirsthunk);

//De pImportDesc -> FirstThunk obtiene un puntero al Matriz IMAGE_THUNK_DATA porque la matriz ya estaba completa cuando se importó la DLL.

// Toda la información entrante, por lo que la interceptación real se realiza aquí.

PIMAGE_THUNK_DATA pRealThunk = make ptr(PIMAGE_THUNK_DATA, hModule, pImportDesc-> first thunk);

// Enumere la matriz IMAGE_THUNK_DATA y encuéntrenos La función que necesita ser interceptada. ¡Esta es la parte más crucial!

while(pOrigThunk->u1. function)

{

//Encuentra solo aquellas funciones introducidas por el nombre de la función en lugar del número de secuencia.

if (IMAGE_ORDINAL_FLAG!=(pOrigThunk-> u1. Indicador de número de secuencia ordinal y ampImage))

{

//Obtener el nombre de la función del función importada.

PIMAGE_IMPORT_BY_NAME p byname = make ptr(PIMAGE_IMPORT_BY_NAME, hModule,

pOrigThunk->u1.address of data);

//Si se inicia el nombre de la función con NULL, salte y continúe con la siguiente función.

if ('\ 0' = = pByName-& gt; nombre [0])

Continuar

//bdo book se utiliza para comprobar si el éxito de la intercepción.

BOOL bDoHook = FALSE

//Comprueba si la función actual es la función que necesitamos interceptar.

if ((función pahook . Función SZ【0】== pByName->nombre【0】)&&

(strcmpi(función pahook .SZ func , (char *)pByName-> nombre == 0))

{

//¡Encontrado

if (pahook func. pproc)

bDoHook = TRUE

}

if (bdo book)

{

//Hemos encontrado Ahora que conoces el función que desea interceptar, comencemos.

//Lo primero que debemos hacer es cambiar el estado de protección de la memoria de esta memoria virtual para que podamos acceder a ella libremente.

MEMORY_BASIC_INFORMATION mbi_thunk

Consulta virtual mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION);

_ ASSERT(virtual protect(mbi_ thunk. Dirección base.

PAGE_READWRITE.mbi_thunk. // Guarda la dirección de salto correcta de la función que queremos interceptar si (paOrigFuncs)

paOrigFuncs = (PROC)pRealThunk->u1.Function;

//¡Reescriba la dirección de salto de la función en la matriz IMAGE_THUNK_DATA a nuestra propia dirección de función!

//Todas las llamadas futuras a esta función del sistema se convertirán en llamadas a funciones escritas por nosotros mismos. pRealThunk-& gt; u1. ) pahookfunc .

// ¡Operación completada! Vuelva a su estado de protección original

DWORD dwOldProtect

_ ASSERT (protección virtual). (mbi_thunk.Base.RegionSize,

mbi_thunk.Protect&dwOldProtect));

SetLastError(ERROR_SUCCESS);

Devuelve TRUE

p>

}

}

//Accede al siguiente elemento en la matriz IMAGE_THUNK_DATA

porigthunk++;

prealthunk++ ;

}

Devuelve TRUE

}

Implementación de la función getnamedimportdescriptor

PIMAGE _ IMPORT _ DESCRIPTOR GetNamedImportDescriptor ( HMODULE HMODULE, LPCSTR szImportModule)

{

//Parámetros de detección

_ ASSERT (szImportModule);

_ ASSERT (HMO dule );

if ((szImportModule == NULL) | | (hm module == NULL))

{

_ ASSERT(FALSE);

p>

SetLastErrorEx (parámetro Error_Invalid, SLE_Error);

Devolver NULL

}

//Obtener encabezado del archivo Dos

p>

PIMAGE _ DOS _ HEADER PDO HEADER = (PIMAGE _ DOS _ HEADER) h module;

//Detectar si el encabezado del archivo MZ es

if (IsBadReadPtr (PDO HEADER, sizeof(IMAGE_DOS_HEADER)) |

(encabezado PDO->e_magic! = IMAGEN_DOS_SIGNATURA).

{

_ASSERT(FALSE);

SetLastErrorEx(ERROR_INVALID PARAMETERS, SLE_ERROR);

RETURN NULL

}

//Obtener encabezado de archivo PE

PIMAGE_NT_HEADERS pNTHeader = make ptr(PIMAGE_NT_HEADERS, encabezado PDO, encabezado PDO-& gt;e_LFA we);

//Detecta si el archivo de imagen PE es

if (IsBadReadPtr (pNTHeader, sizeof (IMAGE_NT_HEADERS)) | |

(pNTHeader->signature!= IMAGE_NT_SIGNATURE))

{

_ ASSERT(FALSE);

SetLastErrorEx(ERROR_INVALID PARAMETERS, SLE_Error);

Devolver NULL

}

//Comprueba la parte de importación (es decir, la parte de datos).

if (pNTHeader-& gt; encabezado opcional. Directorio de datos [importación de entrada de directorio de imágenes]. Dirección virtual == 0)

Regresar NULL

/ / Obtenga el puntero a la parte de importación (es decir, la parte ..idata)

PIMAGE_IMPORT_DESCRIPTOR pImportDesc = make ptr(PIMAGE_IMPORT_DESCRIPTOR, pDOSHeader,

pNTHeader-& gt ; Título opcional. Directorio de datos [ Importación de entrada de directorio de imágenes].

// Matriz PIMAGE _ IMPORT _ DESCRIPTOR exhaustiva para encontrar el módulo donde se encuentra la función que necesitamos interceptar.

while(pImportDesc-> nombre)

{

PSTR·Skullmod = make ptr(PSTR, pDOSHeader, pImportDesc-> ;nombre);

if (stricmp(szCurrMod, szImportModule) == 0)

Break // ¡Lo encontré! Ciclo de interrupción

//Siguiente elemento

pimportdesc++;

}

//Si no se encuentra, significa el módulo que estamos buscando ¡Porque no ha sido introducido por el proceso actual!

if (pImportDesc->Name == NULL)

Return NULL

//Devuelve el descriptor del módulo encontrado por la función.

return pImportDesc

}

//Implementación de la función ISNT()

Booleano no es ()

{

OSVERSIONINFO stOSVI

memset(& stOSVI, NULL, sizeof(OS version info));

sto dwosversioninfosize = sizeof(OS versioninfo)

BOOL bRet = GetVersionEx (& stos VI

_ ASSERT (TRUE == bRet);

if (FALSE == bRet ); FALSO;

retorno (VER plataforma WIN32 NT == sto svi.

dwplatformid);

}

///(imágenes de Internet), intrusión y eliminación (imágenes de Internet), intrusión y eliminación (imágenes de Internet), intrusión y eliminación (imágenes de Internet) de Internet).

No sé cuántos amigos han intentado implementar la desafiante tecnología de "recuperación de palabras en la pantalla del mouse" en el pasado. Solo aquellos que la han probado pueden darse cuenta de la dificultad, especialmente al explorar las funciones API. Al interceptar, ninguna información disponible involucra códigos clave, todos los lugares importantes se repiten y MSDN es aún más pálido. No sé cuántos secretos ha escondido Microsoft además de IMAGE_IMPORT_DESCRIPTOR e IMAGE_THUNK_DATA, pero afortunadamente, ha sido conquistado por la bala. Espero que este artículo sea útil para todos.