FTP | CCD | Buscar | Trucos | Trabajo | Foros |
|
Registrarse | FAQ | Miembros | Calendario | Guía de estilo | Temas de Hoy |
|
Herramientas | Buscar en Tema | Desplegado |
|
#1
|
|||
|
|||
Gracias por el interés
Hola a todos,
Gracias por el interés. Veo que ahora si se está moviendo el hilo. Dos comentarios rápidos: 1. Una gran disculpa. Como dije antes, infortunadamente, debido a exceso de trabajo, no puedo dedicarme ahora a completar el proceso. Solo a mediados de semana, tendré tiempo libre. 2. Mi problema original si lo resolví. El código que estoy explicando es el que usé y funciona. Las razones para publicarlo son dos: Lo pobre de la documentación disponible, y el hecho de existir un problema en la limpieza final del mismo, el cual, aunque para mi caso no me afecta, si me intriga |
#2
|
|||
|
|||
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:
Esa variable la inicializamos (típicamente en el OnCreate de un formulario), con un código similar a:
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:
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í :
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 :
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. |
#3
|
||||
|
||||
Sigue interesante tu exposición.
rolandoj al leer la respuesta que me diste acerca de los Hooks creo que no me entendiste o que no me expliqué bien. Te comente que algunos antivirus y cortafuegos hacen un Hook a la API CreateRemoteThread, es decir no los Hooks que pone Windows a nuestra disposición para interceptar mensajes o el teclado, sino interceptar la misma API modificando su propio código (mediante inyección)... De esta forma esos programas detectan llamadas a CreateRemoteThread y bloquean las llamadas que consideren ilícitas haciendo inútil la inyección de código por esta vía, la elegida para tu exposición. Existen otras maneras de inyectar código sin usar la API CreateRemoteThread, menos populares y no detectables por los antivirus y cortafuegos y por tanto más universales. Es por este motivo, por lo que te comentaba si no las habías considerado. Por otra parte, es interesante tu exposición sobre el uso de RegisterWindowMessage. En ocasiones he usado Memoria compartida mediante Mapeos de ficheros en memoria (CreateFileMapping, OpenFileMapping, MapViewOfFile) para compartir bloques de memoria entre diferentes procesos. Con la inyección con dll puedes diseñar funciones en esa dll que pueden ser llamadas desde otro proceso mediante una "microinyección", con lo que te permite comunicar aplicaciones e incluso "bajar" bloques de memoria de otro proceso, una especie de "inyección in¡versa" con lo que la comunicación es bidireccional. Bueno, no me extiendo mas y espero tu próxima entrega. Saludos. Última edición por escafandra fecha: 08-12-2008 a las 21:27:17. |
#4
|
|||
|
|||
Hasta el infinito y mas alla...
Comentar que esto se estaba poniendo interesante.... y se ha parado...
Vulevo a animar a continuar con este hilo.... Todavia me cuesta seguir las explicaciones, pero me he apuntado a esto de la inyeccion y me parece interesantisimo. Una pregunta esta técnica ¿activa la prevención de ejecución de datos (DEP) de Windows? Probe un ejemplo inyectando en el explorer.exe y se activo. Un saludo y a ver si poco a poco me entero de algo mas.. |
#5
|
||||
|
||||
Cita:
He realizado pruebas de inyección en el explorer.exe y en en el TaskManager, mediante varias técnicas. Todas las inyecciones las he realizado inyectando dll y con el DEP activado para todas las aplicaciones. En ninguna prueba me ha saltado el DEP. Esto puede ser explicado porque las dll en principio son código, o al menos pueden contenerlo. Posiblemente Microsoft no quiere interferir con ellas porque crearía muchos problemas con aplicaciones lícitas y con su propio sistema de Hooks. Todas las técnicas de inyección de dll, (salvo las que se aprovechan de la API SetWindowHook para cargar una dll) requieren una pequeña inyección directa de código que es el que se encarga de cargar dicha dll. Ese código se coloca en la memoria del proceso (WriteProcessMemory) como se comenta en este hilo, aunque sólo contenga la API LoadLibraryA. Bien es verdad que es difícil escribir una aplicación que maneje, con la precisión suficiente, la paginación de memoria con permisos de ejecución de código, como para no dejar espacio para esa necesaria microinyección de esa API LoadLibraryA o unas cuantas intrucciones asm puro. Diferente sería el caso de la inyección directa de cantidades mayores de código, que pueden hacer saltar el DEP. En cualquier caso, tener activo el DEP crea muchas falsas alarmas y molestias al usuario, y suele estar desactivado. Saludos. Última edición por escafandra fecha: 22-01-2009 a las 16:30:07. |
#6
|
|||
|
|||
Enormemente interesado, sigue con ello.
De hecho ya habia perdido el interés por no haber conseguido casi nada de lo que quería con la inyección de código, incluso me molesté en aprender a usar Fasm y hacerlo en assembler con ayuda también de Ollydbg, hace casi un año escribí un post intentando conseguir ayuda y he acudido también a otros foros, he abandonado en Septiembre pasado, pero quizá saque ganas de nuevo. Nunca hubo oscuro propósito, intenté obtener los textos de drawtext y textout antes que windows los volcara en pantalla, conseguí hubicar mi función y las direcciones correctas de los saltos, pero no fui capaz de recuperar y modificar los datos sin que petara el sistema. Al igual que tu, me pareció mas sencillo ubicar la función que inyectar una .dll. No conseguí nada,
O SEASE, A MI SI ME INTERESA SEGUIR LEYENDO, EL ALGUNA PARTE ESTA LO QUE NECESITO PARA QUE MI RUTINA FUNCIONE, ES BUENA IDEA ESTE HILO. CREIA QUE NADIE TENIA INTERÉS POR ALGO TAN INTERESANTE COMO ESTO. |
#7
|
|||
|
|||
Como prueba de mi interés...
Me gustaría disponer de ese código delphi al completo, como prueba no mostraré mis desastres en delphi, mostraré un medio éxito en fasm(si se me permite) que es a propósito del tema en cuestión, debido a las múltiples pruebas que realicé puede contener comentarios de lineas de código ya extintas, asi como variables que no se usan, creo que este era el código que era capaz de inyectar una función en la api drawtextw(tengo varias pruebas), aunque no parece cambiar los textos antes de ser escritos, ... para muestra un botón...
Api Hooking por inyección de código, aproximación en fasm. Código:
include 'd:\fasm\include\win32ax.inc' .data HookApi db 'DrawTextW' , 0 ; Nombre del api a hookear HookDll db 'user32.dll' , 0 ; Nombre de la dll que contiene el api a hookear dirapi dd ? ; Dirección del api a hookear texto db 'hello' process dd ? ; El handle del proceso donde inyectaremos pid dd 1240 ; El pid del proceso donde inyectaremos--estesalio del taskmanager y fue notepad ;PONER PID ADECUADO Y COMPILAR DE NUEVO x dd 5 ; --------------------api DrawTextW ; ;-------------------------------------- total 5 bytes si esta es la teoría lo dijo ollydbg y punto. ; El número de bytes que tiene al principio el api a hookear (suelen ser 5 ó 7) buffercall dd ? ; Puntero al buffer para llamar al api (en nuestro propio proceso) inibuffer dd ? ; siempre guardada la direccion original del inicio del buffer inidirapi dd ? ; siempre guardado el inicio del api inifun dd ? ; siempre guardado el inicio de mi funcion tamfun dd ? ; Tamaño de la función que suplantará al api ;---------------------------------------------------------------------------------------------- dircode dd ? ; La dirección donde esta escribe la estructura una vez INYECTADA Prote dd ? ; Necesario para VirtualProtect saltoapi dd ? ; la direccion calculada a la api+5 buffsaltoami dd ? tamtotal dd ? ;1+tamfun+1+5+5 .code start: ; Obtenemos el handle del proceso donde inyectaremos mov eax, PROCESS_VM_OPERATION or eax, PROCESS_VM_WRITE ; mov eax,PROCESS_ALL_ACCESS invoke OpenProcess, eax, FALSE, [pid] mov [process], eax ; ; Obtenemos la dirección del api a Hookear invoke GetModuleHandle, HookDll invoke GetProcAddress, eax, HookApi mov [dirapi], eax ; vale la dir de la api mov [inidirapi],eax ; siempre guardado sin alterar el inicio ;Vamos a ver , reservamos espacio para pushad+(tamaño de mi funcion)+popad+(5 bytes de la api)+jmp dirapi+5 = ; 1+tamfun+1+5+5 ;ahi es na ;a ver el tamaño de la función ; Calculamos el tamaño de la función a inyectar mov eax, FIN_drawtextexw sub eax, Mydrawtextexw mov [tamfun], eax ;pues eso ; 1+tamfun+1+5+5 ; mov eax, 1 add eax, [tamfun] add eax,1 add eax,[x] add eax,5 mov [tamtotal],eax ; tamtotal tiene el tamaño del buffer invoke LocalAlloc, LPTR, [tamtotal] ; espacio local reservado para escritura del buffer mov [buffercall], eax ; aqui la direccion inicio del buffer mov [inibuffer],eax ;aqui también para no perderla, por variables va a ser mov eax,[buffercall] mov byte [eax],0x90 ; 60 pushad 90 es nop inc eax mov [buffercall],eax ;puesto el opcode e incrementado el buffer ;ahora a copiar aqui la funcion mov ebx,CAMBIO ;direccion de la funcion mov [inifun],ebx ;aqui tambien, no perderla invoke RtlMoveMemory, [buffercall],ebx,[tamfun]; la función al buffer mov eax,[buffercall] add eax,[tamfun] ; incrementamos el buffer hasta el fin de la funcion mov [buffercall],eax ; copia la funcion y ademas incrementa buffercall ;ahora el opcode de popad 61 90 es nop mov eax,[buffercall] mov byte [eax],0x90 ;despues de la funcion pues popad o noP inc eax mov [buffercall],eax ;uno mas para empezar con la api ;ahora vienen los 5 bytes de la api ;los bytes del api al final del buffer, pero le resto 4, si no no rula mov eax, [buffercall] sub eax,4 mov [buffercall],eax ; visto con ollydbg invoke WaitForInputIdle,[process],1000 ; si señor, esto ya es otra cosa, si no peta. ; desde dirapi 5 bytes al buffer invoke RtlMoveMemory, [buffercall], [dirapi], [x] ; Copiamos los x primeros bytes del api mov eax, [buffercall] add eax, [x] ;entonces incrementamos el buffer en x bytes mov [buffercall],eax ; se supone que ahora lo que falta es el salto a la api+5 (o +4?) ;para esto necesito la direccion donde voy a inyectar el codigo mov eax, MEM_RESERVE or eax, MEM_COMMIT invoke VirtualAllocEx, [process], NULL, [tamtotal], eax, PAGE_EXECUTE_READWRITE mov [dircode],eax ;direccion para inyectar el codigo en proceso remoto ;dirapi debe estar mas arriba mov eax,[dirapi];no ha cambiado, la seguimos usando entonces add eax,5 ; ya cambio, dirapi es ahora dirapi+5 mov ebx,[dircode] add ebx,[tamtotal] ; ja! el salto es desde el final del jmp o justo desde antes? ; que problema no saberlo, intentemos asi y si no decremento 4 o 5, 4 despues del jmp ; antes de los 4 bytes del salto, 5, antes del jmp y los 4 bytes del salto. sub eax,ebx ; a ver si... (dirapi+5)-(dircode+tamaño total buffer)=direccion del salto a api+5 mov [saltoapi],eax mov eax,[buffercall] mov byte [eax],0xE9 inc eax mov [buffercall],eax ;insertado opcode jmp e incrementado buffer mov ebx,[saltoapi] ; coño, el salto se queda 4 bytes corto!!!!!!! ; add ebx,4 ;asi supongo que salte donde debe mov dword [eax],ebx; con esto se suponen 4 bytes del dword del salto ;ahora podemos escribir el buffer en el espacio de la aplicacion ;que previamente reservamos ;debemos indicar el tamaño total claro ;el buffer se supone escrito, ahora lo volcamos en el proceso remoto ;invoke VirtualProtect, [dircode-5],[tamtotal+5],PAGE_EXECUTE_READWRITE,NULL invoke WriteProcessMemory, [process],[dircode],[inibuffer],[tamtotal],NULL ; y ahora claro esta tendremos que insertar el salto en la api ; a nuestro codigo ; si dirapi esta por encima como coño hago un salto negativo? ; y además permisos a los 5 bytes de la api claro esta invoke LocalAlloc, LPTR, 5 mov [buffsaltoami],eax mov eax,[dircode] mov ebx,[dirapi] sub eax,ebx sub eax,5; por algun motivo que no se, salta a la dirección ;no entiendo yo este problema con los... si lo pongo salta desde api a pushad ;sino lo pongo salta bytes mas allá. Asi que ... mov [saltoapi],eax ;mmmmmmm dir del salto mov eax,[buffsaltoami] mov byte [eax],0xE9 inc eax ; mov [buffsaltoami],eax mov ebx,[saltoapi] mov dword [eax],ebx mov eax, MEM_RESERVE ; eax = MEM_RESERVE | MEM_COMMIT or eax, MEM_COMMIT invoke VirtualAllocEx, [process], [dirapi], 5, eax, PAGE_EXECUTE_READWRITE invoke WriteProcessMemory, [process], [dirapi], [buffsaltoami], 5, NULL ; y colorin colorado... invoke ExitProcess,0 CAMBIO: proc Mydrawtextexw dc, lpstring,ncount,lprect,uformat nop mov byte [lpstring],0x41 mov byte [ncount],1 nop ;referencias mias en la inyección endp FIN_drawtextexw: .end start - Se supone que la filosofia de esto es: -en el inicio de la función api se inserta un salto a una función propia. -después de ejecutar la nueva función, se inserta en esta otro salto a la api original posterior al salto a nuestra función. |
|
|
Temas Similares | ||||
Tema | Autor | Foro | Respuestas | Último mensaje |
Thread y servidor DCOM externo al proceso ( EXE ) | Aldo | OOP | 1 | 15-09-2006 17:39:47 |
Como utilizar un componente externo? | Sergei | OOP | 2 | 24-01-2006 19:12:24 |
Inyectar proceso | conde | API de Windows | 4 | 10-09-2005 15:52:17 |
Como se puede programar directamente??? | Antuan | Varios | 10 | 04-08-2005 08:04:38 |
Como correr un archivo externo? | fayala | Firebird e Interbase | 3 | 07-04-2005 03:56:00 |
|