Ver Mensaje Individual
  #13  
Antiguo 06-12-2008
rolandoj rolandoj is offline
Miembro
 
Registrado: abr 2007
Posts: 395
Reputación: 17
rolandoj Va por buen camino
Smile Preparando los datos a enviar

Hola,

Bueno, al fin tengo algo de tiempo para proseguir con este tema.

Empiezo contestando la pregunta de escafandra:

Si, he usado la técnica de Hook; aunque ya hace bastante tiempo. Lo que ocurre es que cada técnica tiene su ámbito de aplicación. En el caso de los Hook, ellos sirven para monitorear los mensajes de Windows; por ello, pueden enlentecer el sistema, lo que hace que solo se recomiende instalarlos cuando sea necesario. Lo importante es que dependen de que se ejecute el mensaje que se esté monitoreando.

En mi caso, la necesidad era totalmente diferente. Se trataba de que una aplicación debía solicitar a otras determinada información; es decir era un servicio bajo pedido. La lógica seguida era por tanto más adecuada a la inyección de código, donde se llama a la rutina en la aplicación remota obteniendo enseguida la respuesta.

Pasando al tema en si, Veo que ya se ha agregado parte de la información que les traigo; pero creo que de todas maneras les será util.

Habíamos quedado en como obtener las direcciones de las funciones Windows que necesitamos pasar dentro de nuestra estructura TRemoteStruct. Para hacerlo, se procede así:

Definamos una variable global que sea nuestra estructura. Por ejemplo:

Código Delphi [-]
Var
   DataInterProc:       TRemoteStruct;

Esa variable la inicializamos (típicamente en el OnCreate de un formulario), con un código similar a:

Código Delphi [-]
procedure TfrmWPPrincipal.FormCreate(Sender: TObject);
Var
   MUser:               HMODULE;
   MKernel:             HMODULE;
   ::::
   :::
   :: 
begin
     ::::
     :::
     THE_REMOTE_MSG := RegisterWindowMessage(MY_REMOTE_MSG);
     MUser          := GetModuleHandle('user32');
     MKernel        := GetModuleHandle('kernel32');
     DataInterProc.DRegisterWindowMessage := GetProcAddress(MUser,'RegisterWindowMessageA');
     DataInterProc.DGlobalAddAtom         := GetProcAddress(MKernel,'GlobalAddAtomA');
     DataInterProc.DSendMessage           := GetProcAddress(MUser,'SendMessageA');
     DataInterProc.DGetCommandLine        := GetProcAddress(MKernel,'GetCommandLineA');
     StrCopy(DataInterProc.IdRemoteMsg,MY_REMOTE_MSG);
     :::
     ::
end;

Analicemos lo correspondiente a GetModuleHandle y GetProcAddress. La parte clave del asunto es la ya comentada por Al, de su busqueda en Google, que él coloca en negritas.

Debido a que las librerías user32 y kernel32 se cargan en la mismo lugar del espacio de direcciones de cualquier proceso que se ejecute, las direcciones relativas de sus rutinas son las mismas en cualquier proceso. Por lo anterior, es posible obtenerlas en nuestro proceso, para luego pasarlas e invocarlas desde el otro proceso, tal y como se ha explicado en la segunda nota que hice de este tema.

GetModuleHandle, como su nombre lo indica, devuelve el manejador del módulo que le pasamos como parámetro; así pués, lo primero que hacemos es obtener los manejadores de User32 y Kernel32. Luego es solo cuestión de obtener la dirección de cada rutina que nos interese; para lo cual empleamos GetProcAddress. El primer parámetro es obviamente el manejador del módulo; pero el segundo requiere aclaración.

Observarán, por ejemplo, que aparece SendMessageA y no SendMessage. Por qué la A al final ?. Sin detallar mayormente el tema, lo que ocurre es las librerías de Windows a menudo tienen más de una implementación para una función. El nombre que debemos usar es el de la versión adecuada a nosotros. Donde hallamos esa información ?. En nuestro clásico archivo Windows.Pas. Para el caso de la función SendMessage, la línea que aparece es:

Código Delphi [-]
function SendMessage; external user32 name 'SendMessageA';

Lo que nos indica que el nombre requerido para SendMessage es SendMessageA.

Para finalizar esta parte, solo queda mencionar a RegisterWindowMessage.

Esta parte es un mecanismo interesante para que nuestro código inyectado nos devuelva valores, con un mecanismo diferente al de la estructura TRemoteStruct.

La idea es que la información nos sea devuelta por medio de un mensaje de Windows definido por nosotros mismos. Este mecanismo es una alternativa más comoda de manejar cuando hay que devolver varios string de longitud variable e impronosticable, ya que en nuestro esquema, hacer eso por medio del parámetro que pasamos sería complicado.

RegisterWindowMessage devuelve un identificador único a todo Windows para un string que represente un mensaje. La lógica seguída es que si el string que se registra ya existe en Windows, la función devuelve el identificador existente para el mismo. Así pués, lo que hacemos es obtener el identificador en nuestro programa y luego, en la rutina a inyectar, se vuelve a llamar RegisterWindowMessage para obtenerlo de nuevo; pero guardandolo dentro de una variable válida en ese proceso remoto (típicamente, local a nuestra rutina "ProcesoExterno"). Una vez hecho eso ya podemos comunicar ambas aplicaciones vía mensajes propios.

Por lo anterior, si requerimos esa técnica, debemos incluir RegisterWindowMessage dentro de las funciones que deben hacerse disponibles a nuestro "ProcesoExterno".

Quedarían dos puntos por anotar en esta parte. Uno es la definición de MY_REMOTE_MSG y THE_REMOTE_MSG.

El primero es una constante string que debemos asegurar que sea única. Se definiría más o menos así :

Código Delphi [-]
Const
     MY_REMOTE_MSG = 'Mi servicio es AB12456V';

Es decir, un texto que nos indique lo que hace y algunos números y letras que garanticen su unicidad.

El segundo es simplemente una variable del tipo UINT.

El último punto es la llamada :

Código Delphi [-]
StrCopy(DataInterProc.IdRemoteMsg,MY_REMOTE_MSG);

Aquí es la misma lógica ya explicada. MY_REMOTE_MSG está en nuestro espacio de direcciones; como necesitamos usarlo en nuestar rutina remota, debemos incluirlo dentro de los datos a enviarle a ella; por eso, se usa una variable, del tipo arreglo de caracteres, incluida dentro de nuestro registro TRemoteStruct; lógicamente con suficiente espacio para contener a MY_REMOTE_MSG. El Strcopy simplemente se encarga de poner a MY_REMOTE_MSG dentro de nuestro registro.

Bueno, esto ya resultó muy largo; pero espero que les sea util.

En la próxima entrega veremos el proceso de copiado de nuestra rutina.
Responder Con Cita