Home Hacking y Seguridad Rootkits / Kernel Hacking API-s de windows

Ultimos Mensajes del Foro

Manual Aleatorio

Manual practico de netcat / nc sobre windows
Un texto que nos explica entre otras cosas, como transferir ficheros, escanear puertos, hacer un "chat", conectar al irc y algunas otras cosas usando netcat.
Leer más...
Hacking API-s de windows Imprimir E-mail
Hacking y Seguridad - Rootkits / Kernel
Este texto trata las tecnicas de cambiar las funciones de la API en Windows. Todos los ejemplos aqui descritos funcionan perfectamente en sistemas basados en tecnologia NT version NT 4.0 y superior ( windows NT 4.0, Windows 2000 , Windows XP, Windows 2003). Probablemente tambien funcionara en futuros sistemas Windows.

Texto Completo:
===========================[ Hooking Windows API ]==============================

                 Tecnicas de Ganchos a Funciones de la API de Windows
		 ----------------------------------------------------

                      Author:     Holy_Father <
 Esta dirección electrónica esta protegida contra spam bots. Necesita activar JavaScript para visualizarla
 >
                      Traduccion: Kintaro <
 Esta dirección electrónica esta protegida contra spam bots. Necesita activar JavaScript para visualizarla
 >
                      Version:    1.0 Spanish
                      Fecha:      30.09.2004
	       

=====[ 1. Contents ]============================================================

1. Contenidos
2. Introduccion
3. Metodos de enganche
  3.1 Ganchos antes de la ejecucion
  3.2 Enganchar durante la ejecucion
    3.2.1 Enganchar nuestro propio proceso usando IAT
    3.2.2 Enganchar nuestro propio proceso reescribiendo el entry point
    3.2.3 Enganchar sin modificar las funciones originales
    3.2.4 Enganchando otros procesos
      3.2.4.1 Inyeccion DLL 
      3.2.4.2 Codigo independiente
      3.2.4.3 Cambio Raw
4. Finalizando



=====[ 2. Introduccion ]========================================================

	Este texto trata las tecnicas de enganchar las funciones de la API en
Windows. Todos los ejemplos aqui descritos funcionan perfectamente en sistemas
basados en tecnologia NT version NT 4.0 y superior ( windows NT 4.0, 
Windows 2000 , Windows XP, Windows 2003). Probablemente tambien funcionara en
futuros sistemas Windows.
	Deberias familiarzarte con procesos en windows, esamblador, estructura
de ficheros PE y algunas funciones de la API , para comprender enteramente el 
texto.
	Cuando usamos el termino "Enganchar la API" aqui, me refiero al cambio
completo de la API. Asi, cuando una API enganchada es llamada, nuestro codigo 
es ejecutado inmediatamente. No trato solamente los casos de monitorizar la 
API. Escribire todo sobre esta tecnica.



=====[ 3. Tecnicas de ganchos ]=================================================

	Nuestra meta es normalmente reemplazar el codigo de alguna funcion con
nuestro codigo. Este problema puede ser solucionada a veces antes de ejecutar
el proceso. Esto puede hacerse la mayoria de las veces con codigo con
privilegios de usuario y la meta es, por ejemplo, cambiar el comportamiento 
del programa. Un ejemplo de esto puede ser crackear una aplicacion: un programa
que pide el cd original al iniciarse (como ocurria en el juego Atlantis) y
nosotros queremos ejecutarlo sin CD. Si modificamos la funcion que compueba que
el tipo de disco sea cdrom, podemos ejecutarlo desde el disco duro.
	Esto no puede hacerse o no queremos hacerlo cuando queremos enganchar 
procesos de sistema (como servicios) o en el caso en que no sepamos el proceso 
victima. Entonces tendremos que usar la tecnica de ganchos en ejecucion. 
Ejemplos de esta tecnica son los rootkits o los virus con tecnicas 
anti-antivirus.


=====[ 3.1 Ganchos antes de la ejecucion ]======================================

	Se trata de cambios del modulo fisico (normalmente .exe o .dll) en 
donde esta la funcion que nosotros queremos cambiar. Tenemos por lo menos tres
posibilidades de hacer esto.
	La primera es encontrar el punto de entrada de esa funcion y 
basicamente reescribir el codigo. Esto esta limitado por el tamaño de la 
funcion pero siempre podemos cargar otro modulo dinamicamente (API LoadLibrary)
y asi tendriamos suficiente espacio.
	Las funciones del kernel (kernel32.dll) pueden ser usadas en todos los 
casos porque todos los procesos en windows tienen su propia copia de este 
modulo. Otra ventaja es cuando sabemos en que SO sera modificado el modulo. 
Podemos usar directamente un puntero a la funcion, en este caso seria la 
direccion de LoadLibraryA. Esto es asi porque la direccion del modulo kernel en
memoria es estatica para una determinada version de Windows.
	Tambien podemos hacer uso del comportamiento de los modulos cargados 
dinamicamente, por el cual su parte de inicializacion es ejecutada 
inmediatamente despues de cargar el modulo en memoria. En la parte de 
inicializacion de un nuevo modulo no estamos limitados.
	La segunda posibilidad de reemplazar funciones en un modulo reside en 
la extension. Entonces tenemos que elegir entre reemplazar los 5 primeros bytes
con un salto relativo o reescribir la IAT. En el caso de poner un salto 
relativo, redirigiria la ejecucion del modulo a nuestro codigo. En el otro 
caso, cuando una es llamada una funcion cuyo registro de IAT ha sido 
modificado, nuestro codigo seria ejecutado inmediatamente despues de esta 
llamada. Pero cambiar la extension un modulo no es tarea facil porque hay que 
controlar muy bien las cabeceras.
	(Nota del traductor:
no se refiere a la extension de fichero .exe o .dll eh? se refiere al tamaño
que ocupa, que reside en la cabecera del modulo)
	La tercera posibilidad es reemplazar el modulo entero. Es decir creamos
nuestra propia version del modulo qu puede cargar el modulo original y llamar 
las funciones que no deseamos modificar. Pero reescribimos las funciones que si
nos interesan. Este metodo no es util para modulos muy grandes pues aveces 
exportan cientos de funciones.


=====[ 3.2 Ganchos en ejecucion ]===============================================

	Los ganchos antes de la ejecucion es mas bien para aplicaciones 
concretas o un modulo concreto. Si reemplazamos un funcion de kernel32.dll o de
ntdll.dll obtendremos el comportamiento deseado en todos aquellos procesos que
sean ejecutados despues, aunque es dificil atinar con un codigo perfecto y 
exacto para las funciones o modulos nuevos. Pero el principal problema es que 
nuestros ganchos solo contemplaran los procesos ejecutados posteriormente (asi
pues para todos los procesos tendriamos que reiniciar el sistema). Otro 
problema es el acceso a estos ficheros, que en sistemas NT estan protegidos. 
Los ganchos en ejecucion solucionan esto. Si bien este metodo requiere muchos 
mas conocimientos, el resultado es perfecto.Los ganchos en ejecucion pueden 
aplicarse solo a procesos para los que tengamos acceso a su zona de memoria.
Para escribir en esta zona usaremos la funcion APi WriteProcessMemory. 
Comencemos por enganchar nuestro propio proceso durante la ejecucion.


=====[ 3.2.1 Enganchar nuestro propio proceso usando IAT ]======================

	Hay muchas posibilidades aqui. En prinicpio te mostrare como enganchar 
funciones mediante la reescritura de la IAT. Este dibujo muestra la estructura 
de un fichero PE:

     +-------------------------------+     - offset 0
     | Cabecera MS DOS ("MZ") 	     |
     +-------------------------------+     
     |      firma de PE  ("PE")      |
     +-------------------------------+
     |             .text             |     - codigo de modulo
     |      Codigo de programa       |
     |                               |
     +-------------------------------+
     |             .data             |     - datos iniciados (global y static)
     |        Datos Inicializados    |
     |                               |
     +-------------------------------+
     |            .idata             |     - info sobre funciones importadas 
     |         Import Table          |       y datos
     |                               |
     +-------------------------------+
     |            .edata             |     - info sobre funciones exportadas 
     |         Export Table          |       y datos
     |                               |
     +-------------------------------+
     |         Debug symbols         |
     +-------------------------------+


	La parte importante para nosotros aqui es la Import Address Table(IAT)
en la zona .idata   . Esta parte contiene una descripcion de las funciones 
importadas y sus direcciones. Ahora es importante saber como se crean los 
ficheros PE. Cuando se llama un funcion de la API indirectamente en un 
lenguaje de programacion (es decir llamar usando el nombre , en vez de su 
direccion especifica en el SO) el compilador no las convierte en llamadas 
directas al modulo, sino que las convierte en saltos a direcciones, y estas 
direcciones se encuentran almacenadas en la IAT. Cuando el proceso se carga el
cargador de proceso del Windows se encarga de rellear la IAT para cada 
sistema. Esta es la razon por la que el mismo binario funciona en versiones 
distintas del windows, a pesar de que tienen distintas direcciones para un 
mismo modulo. Por tanto si fuesemos capaz de encontrar una funcion, que 
queremos enganchar, en la IAT, podriamos cambiar facilmente la direccion y la 
instruccion jmp redirigiria el flujo de ejecucion a nuestro codigo. Cualquier 
llamada despues de hacer esto ejecutaria nuestro codigo. 
(Nota del traductor:
 He traducido el ultimo parrafo intentando que se comprenda lo mejor posible, 
 pero aun asi prefiero dar una explicacion propia sobre la IAT.
 Si queremos realizar una llamada a una api de windows podemos escribir:

 call direccion_de_la_api_en_memoria ( por ejemplo "call 0x07728188")

 pero como en cada version de windows esa direccion cambia necesitamos de 
 alguna manera que escribiendo la misma instruccion se ejecute lo mismo
 Lo que se hace es guardar estas direcciones en la IAT. La IAT es rellenada
 por el So al crear el PE. La forma de acceder a las direcciones de la IAT es 
 la siguiente:
	
 ------------------- 
 call direccion api1
 ......
 codigo
 ......

 direccion:
 jmp dword ptr [IAT] ;  	
 --------------------
 Asi un PE funciona en cualquier windows )

La ventaja de este metodo es que el resultado es perfecto. La desventaja es 
que para cambiar el comportamiento de una funcion, deberiamos enganchar 
varias funciones (me explico, si queremos cambiar el comportamiento de un 
programa en la busqueda de un fichero tendremos que cambiar FindFirstFile y 
FindNextFile, pero estas funciones tienen version ANSI y WIDE, asique 
tendremos que cambiar FindFirstFileA, FindNextFileA, FindFirstFileW y 
FindNextFileW en la IAT. Y aun quedan otras como FindFirstFileExA y su version
WIDE FindFirstFileExW que son llamadas por las funciones comentadas 
previamente. Sabemos que FindFirstFileW llama a FindFirstFileExW pero esto se
hace directamente , sin usar la IAT. Y aun algunas otras. Hay por ejemplo 
funciones ShellApi como SHGetDesktopFolder que tambien llaman directamente a 
FindFirstFileW o FindFirstFileExW). Pero si lo conseguimos con todas ellas el
resultado sera perfecto. Podemos usar ImageDirectoryEntryToData de 
imagehlp.dll para encontrar la IAT facilmente.

	PVOID ImageDirectoryEntryToData(
		IN LPVOID Base,	
		IN BOOLEAN MappedAsImage,	
		IN USHORT DirectoryEntry,	
		OUT PULONG Size	
	);

Usaremos Instance de nuestra aplicacion como Base 
(Instance se obtiene con una llamada a GetModuleHandle:

	hInstance = GetModuleHandleA(NULL);

), y como DirectoryEntry usaremos la constante IMAGE_DIRECTORY_ENTRY_IMPORT.

	#define IMAGE_DIRECTORY_ENTRY_IMPORT 1

El resultado de esta funcion es un puntero al primer registro de la IAT.
Los registros de la IAT son estructuras que estan definidas como 
IMAGE_IMPORT_DESCRIPTOR. 
Asi el resultado es un puntero a IMAGE_IMPORT_DESCRIPTOR.

	typedef struct _IMAGE_THUNK_DATA {
		union {
			PBYTE ForwarderString;
			PDWORD Function;
			DWORD Ordinal;
			PIMAGE_IMPORT_BY_NAME AddressOfData;
		} ;
	} IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;

	typedef struct _IMAGE_IMPORT_DESCRIPTOR {
		union {
			DWORD Characteristics;
			PIMAGE_THUNK_DATA OriginalFirstThunk;
		} ;
		DWORD TimeDateStamp;
		DWORD ForwarderChain;
		DWORD Name;
		PIMAGE_THUNK_DATA FirstThunk;
	} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;


	El valor de Name en IMAGE_IMPORT_DESCRIPTOR es una referencia al 
nombre del modulo. Si queremos enganchar una funcion, por ejemplo del 
kernel32.dll, tenemos que encontrar aquella entrada de la tabla que 
corresponde al descriptor de kernel32.dll.
(NOTA del traductor:
 Aunque Holy_father lo da por supuesto, prefiero aclarar algo antes de 
 continuar, me refiero a la forma de recorrer la tabla. La IAT parece ser que 
 esta implementada como un vector estatico, donde  cada casilla contiene la 
 direccion del descriptor. Por tanto si tenemos la direccion de la  primera 
 entrada de la tabla, que nos la ha devuelto ImageDirectoryEntryToData, la 
 direccion de la siguiente entrada se incrementa en uno, y asi podemos 
 recorrer la tabla)

Llamaremos a ImageDirectoryEntryToData en un principio e intentaremos 
encontrar aquel descriptor con Name "kernel32.dll" ( puede haber mas de un 
descriptor con este nombre). Finalmente tendremos que encontrar nuestra 
funcion en la lista de todas las funciones de ese descriptor (la direccion 
de nuestra funcion la obtenemos con GetProcAddress). Si la encontramos 
debemos usar VirtualProtect para cambiar la proteccion de pagina de memoria 
y despues de esto podremos escribir en esta parte de memoria. Despues de 
escribir la direccion debemos restaurar la proteccion original. Antes de 
llamar a VirtualProtect tenemos que saber cierta informacion sobre esta 
pagina de memoria. Esta info se obtiene con VirtualQuery. Podemos añadir 
algunas pruebas en caso de algunas llamadas fallen ( por ejemplo no 
continuar si la primera llamada a VirtualProtect falla, etc)

	PCSTR pszHookModName = "kernel32.dll",pszSleepName = "Sleep";
	HMODULE hKernel = GetModuleHandle(pszHookModName);
	PROC pfnNew = (PROC)0x12345678,       //la nueva direccion aqui
		pfnHookAPIAddr = GetProcAddress(hKernel,pszSleepName);

	ULONG ulSize;
	PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 
		(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(
			hInstance,
			TRUE,
			IMAGE_DIRECTORY_ENTRY_IMPORT,
			&ulSize
		);

	while (pImportDesc->Name)
	{
              PSTR pszModName = (PSTR)((PBYTE) hInstance + pImportDesc->Name);
	      if (stricmp(pszModName, pszHookModName) == 0) 
	      break;   
	      pImportDesc++;
	}

	PIMAGE_THUNK_DATA pThunk = 
	(PIMAGE_THUNK_DATA)((PBYTE) hInstance + pImportDesc->FirstThunk);

	while (pThunk->u1.Function)
	{
		PROC* ppfn = (PROC*) &pThunk->u1.Function;
		BOOL bFound = (*ppfn == pfnHookAPIAddr);

		if (bFound) 
		{
			MEMORY_BASIC_INFORMATION mbi;
			VirtualQuery(
				ppfn,
				&mbi,
				sizeof(MEMORY_BASIC_INFORMATION)
			);
			VirtualProtect(
				mbi.BaseAddress,
				mbi.RegionSize,
				PAGE_READWRITE,
				&mbi.Protect)
			)

			*ppfn = *pfnNew;

			DWORD dwOldProtect;
			VirtualProtect(
				mbi.BaseAddress,
				mbi.RegionSize,
				mbi.Protect,
				&dwOldProtect
			);
			break;
		}
		pThunk++;
	}

El resultado de una llamada a Sleep(1000) podria ser:

	00407BD8: 68E8030000	push 0000003E8h
	00407BDD: E812FAFFFF	call Sleep
	........
	codigo
	........

	Sleep:     ;es es el salto a la IAT
	004075F4: FF25BCA14000	jmp dword ptr [00040A1BCh]
 

	tabla original:
	0040A1BC: 79 67 E8 77 00 00 00 00
      
	nueva tabla:
	0040A1BC: 78 56 34 12 00 00 00 00


Asique al final el salto es a 0x12345678.
          

=====[ 3.2.2 Enganchar nuestro propio proceso reescribiendo el entry point  ]===

	El metodo de reescribir primero unas intrucciones en el punto de 
entrada de la funcion es realmente simple. Como en el caso de reescribir la 
IAT, tenemos que cambiar la proteccion de pagina antes de nada. Aqui seran los 
5 primeros bytes de la funcion que queremos enganchar. Despues tendremos que 
localizar memoria dinamica para la estructura MEMORY_BASIC_INFORMATION. El 
comienzo de la funcion lo obtenemos con GetProcAddres. En esta direccion 
insertaremos un salto relativo a nuestro codigo. El siguiente programa llama a 
Sleep(5000) (espera 5 segundos), entonces la funcion Sleep es enganchada y 
redirigida a new_sleep, y finalmente llama de nuevo a Sleep(5000). Como la 
nueva funcion new_sleep no hace nada y termina inmediatamente el programa 
entero tardara solo 5 segundos en lugar de 10.

(NOTA del traductor:
 ----------------------------
 Holy_father ha puesto este codigo en win32asm. El codigo se 
 entiende bien pero lo voy a poner primero en C porque creo que se queda uno 
 con una vision mas general en la primera lectura. El codigo lo escribo sobre
 la marcha mientras traduzco pero creo que esta bien. Luego puedes continuar 
 echarle un vistazo a como quedaria en win32asm:
 ..... 

 static void new_sleep()
	{
	......
	}	
 .....
 Sleep(5000);

 HMODULE Hkernel=GetModuleHandleA("kernel32.dll")
 FARPROC HSleep=GetProcAddress(Hkernel,"Sleep");
 
 LPVOID pmbi=VirtualAlloc(0,sizeof(MEMORY_BASIC_INFORMATION)
 			 ,MEM_COMMIT,PAGE_READWRITE);

 if (pmbi)
	{
	
	DWORD pinfo=VirtualQuery(HSleep,Hcode,
				sizeof(MEMORY_BASIC_INFORMATION));
	
	if (pinfo)
		{
		/*
		como la funcion Sleep se acaba de ejecutar es probable que 
		aun este en cache asique vaciamos de la cache los 5 primeros 
		bytes de la funcion Sleep
		*/
		FlushInstructionCache(GetCurrentProcess(),HSleep,5);
		
		
		//la estructura que hemos reservado es una mbi
		//tenemos que poner mbi.Protect al valor devuelto por 
		//VirtualProtect en lpflOldProtect 
		//14h (= 20) es el desplazamiento de Protect dentro de la mbi
		
		DWORD dwOldProtect=(DWORD)pmbi + 14h; 	
		PDWORD pOldProtect=(PDWORD)dOldProtect; 
		
		DWORD dwsize=(DWORD)pmbi + 00ch; 	
		PDWORD psize=(PDWORD)dwsize; 	
		
		if (VirtualProtect( pmbi , *psize, PAGE_EXECUTE_READWRITE,
					 pOldProtect))
		{
	   	//el primer byte contieen el hex opcode de jmp
		PWORD pSleep=(PWORD)HSleep;
		*(pSleep[0])= (BYTE)0E9h; //jmp   
			
	       DWORD offset_jmp=(DWORD)(PBYTE)new_sleep-(DWORD)(PBYTE)Sleep-5;
			
		//los siguientes contienen el offset	
		memcpy(&Sleep[1],&offset_jmp,4);
			
		DWORD tmp_oldprotect;

		VirtualProtect( pmbi , *psize, pOldProtect, &tmp_oldprotect);

                }	
	     }	

	     VirtualFree(pmbi,0,MEM_RELEASE);		
	}	 	
     Sleep(5000);
     ExitProcess(0);

 ----------------------------

.386p
.model flat, stdcall

includelib lib\kernel32.lib
Sleep			PROTO :DWORD
GetModuleHandleA	PROTO :DWORD
GetProcAddress		PROTO :DWORD,:DWORD
VirtualQuery		PROTO :DWORD,:DWORD,:DWORD
VirtualProtect		PROTO :DWORD,:DWORD,:DWORD,:DWORD
VirtualAlloc		PROTO :DWORD,:DWORD,:DWORD,:DWORD
VirtualFree		PROTO :DWORD,:DWORD,:DWORD
FlushInstructionCache	PROTO :DWORD,:DWORD,:DWORD
GetCurrentProcess	PROTO
ExitProcess 		PROTO :DWORD


.data

 kernel_name 		db "kernel32.dll",0
 sleep_name		db "Sleep",0
 old_protect		dd ?

 MEMORY_BASIC_INFORMATION_SIZE	equ 28

 PAGE_READWRITE		dd 000000004h
 PAGE_EXECUTE_READWRITE dd 000000040h
 MEM_COMMIT		dd 000001000h
 MEM_RELEASE		dd 000008000h


.code
start:
	push	5000
	call	Sleep

 do_hook:
	push	offset kernel_name
	call	GetModuleHandleA
	push	offset sleep_name
	push	eax
	call	GetProcAddress
	mov	edi,eax			;la direccion de Sleep

	push	PAGE_READWRITE
	push	MEM_COMMIT
	push	MEMORY_BASIC_INFORMATION_SIZE
	push 	0
	call	VirtualAlloc
	test	eax,eax
	jz 	do_sleep
	mov	esi,eax			;lozalizacion de memoria para MBI

	push	MEMORY_BASIC_INFORMATION_SIZE
	push	esi
	push	edi
	call	VirtualQuery		;informacion de la pagina
	test	eax,eax
	jz	free_mem

	call	GetCurrentProcess
	push	5
	push	edi
	push	eax
	call	FlushInstructionCache	;nos aseguramos por si acaso :)

	lea	eax,[esi+014h]
	push	eax
	push	PAGE_EXECUTE_READWRITE
	lea	eax,[esi+00Ch]
	push	[eax]
	push	[esi]
	call	VirtualProtect          ;cambiaremos la proteccion un momento
					;para que podamos escribir
	test	eax,eax
	jz	free_mem		

	mov	byte ptr [edi],0E9h	;escribir el salto relativo
	mov	eax,offset new_sleep
	sub	eax,edi
	sub	eax,5
	inc	edi
	stosd				;este es el salto relativo de jmp
	push	offset old_protect
	lea	eax,[esi+014h]
	push	[eax]
	lea	eax,[esi+00Ch]
	push	[eax]
	push	[esi]
	call	VirtualProtect		;restauramos la proteccion original

 free_mem:
	push	MEM_RELEASE
	push	0
	push	esi
	call	VirtualFree		;liberar memoria
 do_sleep:
	push	5000
	call	Sleep
	push	0
	call	ExitProcess
 new_sleep:				
	ret	004h
end start

Resultado de la segunda llamada a Sleep: 

	004010A4: 6888130000	push 000001388h
	004010A9: E80A000000	call Sleep


	Sleep:    ;este es el salto en la direccion de la IAT 
	004010B8: FF2514204000	jmp dword ptr [000402014h]
 
	tabulka:
	00402014: 79 67 E8 77 6C 7D E8 77
      
	Kernel32.Sleep:
	77E86779: E937A95788	jmp 0004010B5h

	new_sleep:
	004010B5: C20400	ret 004h	


=====[ 3.2.3 Enganchar sin modificar las funciones originales]==================

	La mayoria de las veces solemos necesitar algo mas que un gancho. Por 
ejemplo en el caso en que no queramos reemplazar una funcion, sino solo 
comprobar su resultado, o en el caso de que queramos reemplazar el codigo de 
la funcion solo algunas veces, por ejemplo cuando es llamada con unos 
parametros determinados. Un buen ejemplo de esto es la ocultacion de ficheros,
mencionada antes, que se hace reemplazando funciones FindxxxFile. Asi si 
queremos esconder unos ficheros especificos y no queremos ser descubiertos, 
tenemos que dejar la funcion original para el resto de ficheros. Esto es facil 
cuando usamos el metodo de reescribir la IAT. Para llamar a la funcion 
original solo tendriamos que obtener la direccion con GetProcAddress y 
llamarla directamente. Pero el problema viene cuando usamos la reescritura del
punto de entrada. Reescribiendo los 5 primeros bytes del punto de entrada de 
las funciones perdemos una parte de la funcion, imposible de recuperar. Asique
lo que hacemos es guardar primero estas intrucciones. Podemos usar la 
siguiente tecnica. Sabemos que solo reescribiremos los 5 primeros bytes, pero 
no sabemos cuantas instrucciones hay ni la longitud de estas. Tenemos que 
reservar suficiente memoria para las primeras instrucciones. 16 bytes podrian 
ser suficientes porque no suele haber instrucciones largas al principio de una
funcion. Probablemente podriamos usar menos de 16. La memoria reservada la 
llenaremos con operaciones nop (0x90) en el caso de que las instrucciones 
ocupen menos de esos 16. Los 5 bytes siguiente a esos 16 seran llenados con un
salto relativo que luego rellenaremos su direccion.

 old_hook:		db 090h,090h,090h,090h,090h,090h,090h,090h
			db 090h,090h,090h,090h,090h,090h,090h,090h
			db 0E9h,000h,000h,000h,000h


Ahora ya podemos copiar las primeras instrucciones. Resulta algo largo obtener
la longitud de una instruccion, porque trabajaremos con el codigo completo de 
un desensamblador. Este fue hecho por Z0MBiE. El argumento de entrada es la 
direccion de la instruccion de la que queremos saber la longitud. La salida 
se devuelve en eax.

; LDE32, Length-Disassembler Engine, 32-bit, (x) 1999-2000 Z0MBiE
; special edition for REVERT tool

; version 1.05


C_MEM1                  equ     0001h       ; |
C_MEM2                  equ     0002h       ; |puede usarse simultaneamente
C_MEM4                  equ     0004h       ; |
C_DATA1                 equ     0100h       ; |
C_DATA2                 equ     0200h       ; |puede usarse simultaneamente
C_DATA4                 equ     0400h       ; |
C_67                    equ     0010h       ; usado con C_PREFIX
C_MEM67                 equ     0020h       ; C_67 ? C_MEM2 : C_MEM4
C_66                    equ     1000h       ; usado con C_PREFIX
C_DATA66                equ     2000h       ; C_66 ? C_DATA2 : C_DATA4
C_PREFIX                equ     0008h       ; prefijo. take opcode again
C_MODRM                 equ     4000h       ; MODxxxR/M
C_DATAW0                equ     8000h       ; opc&1 ? C_DATA66 : C_DATA1

                        p386
                        model   flat
                        locals  @@

                        .code

public                  disasm_main
public                  _disasm_main
public                  @disasm_main
public                  DISASM_MAIN

disasm_main:
_disasm_main:
@disasm_main:
DISASM_MAIN:

; devuelve la longitud de opcode en EAX o -1 si error

; entrada: puntero a opcode

; __fastcall            EAX
; __cdecl               [ESP+4]

;este es mi primer cambio aqui, es la etiqueta solo para llamar esta funcion
get_instr_len:

                        mov     ecx, [esp+4]    ; ECX = opcode ptr

                        xor     edx, edx        ; flags
                        xor     eax, eax

@@prefix:               and     dl, not C_PREFIX

                        mov     al, [ecx]
                        inc     ecx

                        or      edx, table_1[eax*4]

                        test    dl, C_PREFIX
                        jnz     @@prefix

                        cmp     al, 0F6h
                        je      @@test
                        cmp     al, 0F7h
                        je      @@test

                        cmp     al, 0CDh
                        je      @@int

                        cmp     al, 0Fh
                        je      @@0F
@@cont:
                        test    dh, C_DATAW0 shr 8
                        jnz     @@dataw0
@@dataw0done:
                        test    dh, C_MODRM shr 8
                        jnz     @@modrm
@@exitmodrm:
                        test    dl, C_MEM67
                        jnz     @@mem67
@@mem67done:
                        test    dh, C_DATA66 shr 8
                        jnz     @@data66
@@data66done:
                        mov     eax, ecx
                        sub     eax, [esp+4]

                        and     edx,C_MEM1+C_MEM2+C_MEM4+C_DATA1+C_DATA2+C_DATA4
                        add     al, dl
                        add     al, dh

;mi segundo cambio aqui, habia retn solo en la version original
@@exit:                 ret     00004h   

@@test:                 or      dh, C_MODRM shr 8
                        test    byte ptr [ecx], 00111000b  ; F6/F7 -- test
                        jnz     @@cont
                        or      dh, C_DATAW0 shr 8
                        jmp     @@cont

@@int:                  or      dh, C_DATA1 shr 8
                        cmp     byte ptr [ecx], 20h
                        jne     @@cont
                        or      dh, C_DATA4 shr 8
                        jmp     @@cont

@@0F:                   mov     al, [ecx]
                        inc     ecx
                        or      edx, table_0F[eax*4]

                        cmp     edx, -1
                        jne     @@cont

@@error:                mov     eax, edx
                        jmp     @@exit

@@dataw0:               xor     dh, C_DATA66 shr 8
                        test    al, 00000001b
                        jnz     @@dataw0done
                        xor     dh, (C_DATA66+C_DATA1) shr 8
                        jmp     @@dataw0done

@@mem67:                xor     dl, C_MEM2
                        test    dl, C_67
                        jnz     @@mem67done
                        xor     dl, C_MEM4+C_MEM2
                        jmp     @@mem67done

@@data66:               xor     dh, C_DATA2 shr 8
                        test    dh, C_66 shr 8
                        jnz     @@data66done
                        xor     dh, (C_DATA4+C_DATA2) shr 8
                        jmp     @@data66done

@@modrm:                mov     al, [ecx]
                        inc     ecx

                        mov     ah, al  ; ah=mod, al=rm

                        and     ax, 0C007h
                        cmp     ah, 0C0h
                        je      @@exitmodrm

                        test    dl, C_67
                        jnz     @@modrm16

@@modrm32:              cmp     al, 04h
                        jne     @@a

                        mov     al, [ecx]       ; sib
                        inc     ecx
                        and     al, 07h

@@a:                    cmp     ah, 40h
                        je      @@mem1
                        cmp     ah, 80h
                        je      @@mem4

                        cmp     ax, 0005h
                        jne     @@exitmodrm

@@mem4:                 or      dl, C_MEM4
                        jmp     @@exitmodrm

@@mem1:                 or      dl, C_MEM1
                        jmp     @@exitmodrm

@@modrm16:              cmp     ax, 0006h
                        je      @@mem2
                        cmp     ah, 40h
                        je      @@mem1
                        cmp     ah, 80h
                        jne     @@exitmodrm

@@mem2:                 or      dl, C_MEM2
                        jmp     @@exitmodrm

                        endp

                        .data

;0F      -- analizado en codigo, sin flags (i.e.flags must be 0)
;F6,F7   -- --//-- (ttt=000 -- 3 bytes, sino 2 bytes)
;CD      -- --//-- (6 bytes si CD 20, sino 2 bytes)

table_1                 label   dword   ; instrucciones normales
dd C_MODRM              ; 00
dd C_MODRM              ; 01
dd C_MODRM              ; 02
dd C_MODRM              ; 03
dd C_DATAW0             ; 04
dd C_DATAW0             ; 05
dd 0                    ; 06
dd 0                    ; 07
dd C_MODRM              ; 08
dd C_MODRM              ; 09
dd C_MODRM              ; 0A
dd C_MODRM              ; 0B
dd C_DATAW0             ; 0C
dd C_DATAW0             ; 0D
dd 0                    ; 0E
dd 0                    ; 0F
dd C_MODRM              ; 10
dd C_MODRM              ; 11
dd C_MODRM              ; 12
dd C_MODRM              ; 13
dd C_DATAW0             ; 14
dd C_DATAW0             ; 15
dd 0                    ; 16
dd 0                    ; 17
dd C_MODRM              ; 18
dd C_MODRM              ; 19
dd C_MODRM              ; 1A
dd C_MODRM              ; 1B
dd C_DATAW0             ; 1C
dd C_DATAW0             ; 1D
dd 0                    ; 1E
dd 0                    ; 1F
dd C_MODRM              ; 20
dd C_MODRM              ; 21
dd C_MODRM              ; 22
dd C_MODRM              ; 23
dd C_DATAW0             ; 24
dd C_DATAW0             ; 25
dd C_PREFIX             ; 26
dd 0                    ; 27
dd C_MODRM              ; 28
dd C_MODRM              ; 29
dd C_MODRM              ; 2A
dd C_MODRM              ; 2B
dd C_DATAW0             ; 2C
dd C_DATAW0             ; 2D
dd C_PREFIX             ; 2E
dd 0                    ; 2F
dd C_MODRM              ; 30
dd C_MODRM              ; 31
dd C_MODRM              ; 32
dd C_MODRM              ; 33
dd C_DATAW0             ; 34
dd C_DATAW0             ; 35
dd C_PREFIX             ; 36
dd 0                    ; 37
dd C_MODRM              ; 38
dd C_MODRM              ; 39
dd C_MODRM              ; 3A
dd C_MODRM              ; 3B
dd C_DATAW0             ; 3C
dd C_DATAW0             ; 3D
dd C_PREFIX             ; 3E
dd 0                    ; 3F
dd 0                    ; 40
dd 0                    ; 41
dd 0                    ; 42
dd 0                    ; 43
dd 0                    ; 44
dd 0                    ; 45
dd 0                    ; 46
dd 0                    ; 47
dd 0                    ; 48
dd 0                    ; 49
dd 0                    ; 4A
dd 0                    ; 4B
dd 0                    ; 4C
dd 0                    ; 4D
dd 0                    ; 4E
dd 0                    ; 4F
dd 0                    ; 50
dd 0                    ; 51
dd 0                    ; 52
dd 0                    ; 53
dd 0                    ; 54
dd 0                    ; 55
dd 0                    ; 56
dd 0                    ; 57
dd 0                    ; 58
dd 0                    ; 59
dd 0                    ; 5A
dd 0                    ; 5B
dd 0                    ; 5C
dd 0                    ; 5D
dd 0                    ; 5E
dd 0                    ; 5F
dd 0                    ; 60
dd 0                    ; 61
dd C_MODRM              ; 62
dd C_MODRM              ; 63
dd C_PREFIX             ; 64
dd C_PREFIX             ; 65
dd C_PREFIX+C_66        ; 66
dd C_PREFIX+C_67        ; 67
dd C_DATA66             ; 68
dd C_MODRM+C_DATA66     ; 69
dd C_DATA1              ; 6A
dd C_MODRM+C_DATA1      ; 6B
dd 0                    ; 6C
dd 0                    ; 6D
dd 0                    ; 6E
dd 0                    ; 6F
dd C_DATA1              ; 70
dd C_DATA1              ; 71
dd C_DATA1              ; 72
dd C_DATA1              ; 73
dd C_DATA1              ; 74
dd C_DATA1              ; 75
dd C_DATA1              ; 76
dd C_DATA1              ; 77
dd C_DATA1              ; 78
dd C_DATA1              ; 79
dd C_DATA1              ; 7A
dd C_DATA1              ; 7B
dd C_DATA1              ; 7C
dd C_DATA1              ; 7D
dd C_DATA1              ; 7E
dd C_DATA1              ; 7F
dd C_MODRM+C_DATA1      ; 80
dd C_MODRM+C_DATA66     ; 81
dd C_MODRM+C_DATA1      ; 82
dd C_MODRM+C_DATA1      ; 83
dd C_MODRM              ; 84
dd C_MODRM              ; 85
dd C_MODRM              ; 86
dd C_MODRM              ; 87
dd C_MODRM              ; 88
dd C_MODRM              ; 89
dd C_MODRM              ; 8A
dd C_MODRM              ; 8B
dd C_MODRM              ; 8C
dd C_MODRM              ; 8D
dd C_MODRM              ; 8E
dd C_MODRM              ; 8F
dd 0                    ; 90
dd 0                    ; 91
dd 0                    ; 92
dd 0                    ; 93
dd 0                    ; 94
dd 0                    ; 95
dd 0                    ; 96
dd 0                    ; 97
dd 0                    ; 98
dd 0                    ; 99
dd C_DATA66+C_MEM2      ; 9A
dd 0                    ; 9B
dd 0                    ; 9C
dd 0                    ; 9D
dd 0                    ; 9E
dd 0                    ; 9F
dd C_MEM67              ; A0
dd C_MEM67              ; A1
dd C_MEM67              ; A2
dd C_MEM67              ; A3
dd 0                    ; A4
dd 0                    ; A5
dd 0                    ; A6
dd 0                    ; A7
dd C_DATA1              ; A8
dd C_DATA66             ; A9
dd 0                    ; AA
dd 0                    ; AB
dd 0                    ; AC
dd 0                    ; AD
dd 0                    ; AE
dd 0                    ; AF
dd C_DATA1              ; B0
dd C_DATA1              ; B1
dd C_DATA1              ; B2
dd C_DATA1              ; B3
dd C_DATA1              ; B4
dd C_DATA1              ; B5
dd C_DATA1              ; B6
dd C_DATA1              ; B7
dd C_DATA66             ; B8
dd C_DATA66             ; B9
dd C_DATA66             ; BA
dd C_DATA66             ; BB
dd C_DATA66             ; BC
dd C_DATA66             ; BD
dd C_DATA66             ; BE
dd C_DATA66             ; BF
dd C_MODRM+C_DATA1      ; C0
dd C_MODRM+C_DATA1      ; C1
dd C_DATA2              ; C2
dd 0                    ; C3
dd C_MODRM              ; C4
dd C_MODRM              ; C5
dd C_MODRM+C_DATA1      ; C6
dd C_MODRM+C_DATA66     ; C7
dd C_DATA2+C_DATA1      ; C8
dd 0                    ; C9
dd C_DATA2              ; CA
dd 0                    ; CB
dd 0                    ; CC
dd 0                    ; CD
dd 0                    ; CE
dd 0                    ; CF
dd C_MODRM              ; D0
dd C_MODRM              ; D1
dd C_MODRM              ; D2
dd C_MODRM              ; D3
dd C_DATA1              ; D4
dd C_DATA1              ; D5
dd 0                    ; D6
dd 0                    ; D7
dd C_MODRM              ; D8
dd C_MODRM              ; D9
dd C_MODRM              ; DA
dd C_MODRM              ; DB
dd C_MODRM              ; DC
dd C_MODRM              ; DD
dd C_MODRM              ; DE
dd C_MODRM              ; DF
dd C_DATA1              ; E0
dd C_DATA1              ; E1
dd C_DATA1              ; E2
dd C_DATA1              ; E3
dd C_DATA1              ; E4
dd C_DATA1              ; E5
dd C_DATA1              ; E6
dd C_DATA1              ; E7
dd C_DATA66             ; E8
dd C_DATA66             ; E9
dd C_DATA66+C_MEM2      ; EA
dd C_DATA1              ; EB
dd 0                    ; EC
dd 0                    ; ED
dd 0                    ; EE
dd 0                    ; EF
dd C_PREFIX             ; F0
dd 0                    ; F1
dd C_PREFIX             ; F2
dd C_PREFIX             ; F3
dd 0                    ; F4
dd 0                    ; F5
dd 0                    ; F6
dd 0                    ; F7
dd 0                    ; F8
dd 0                    ; F9
dd 0                    ; FA
dd 0                    ; FB
dd 0                    ; FC
dd 0                    ; FD
dd C_MODRM              ; FE
dd C_MODRM              ; FF

table_0F                label   dword   ; instrucciones con prefijo 0F

dd C_MODRM              ; 00
dd C_MODRM              ; 01
dd C_MODRM              ; 02
dd C_MODRM              ; 03
dd -1                   ; 04
dd -1                   ; 05
dd 0                    ; 06
dd -1                   ; 07
dd 0                    ; 08
dd 0                    ; 09
dd 0                    ; 0A
dd 0                    ; 0B
dd -1                   ; 0C
dd -1                   ; 0D
dd -1                   ; 0E
dd -1                   ; 0F
dd -1                   ; 10
dd -1                   ; 11
dd -1                   ; 12
dd -1                   ; 13
dd -1                   ; 14
dd -1                   ; 15
dd -1                   ; 16
dd -1                   ; 17
dd -1                   ; 18
dd -1                   ; 19
dd -1                   ; 1A
dd -1                   ; 1B
dd -1                   ; 1C
dd -1                   ; 1D
dd -1                   ; 1E
dd -1                   ; 1F
dd -1                   ; 20
dd -1                   ; 21
dd -1                   ; 22
dd -1                   ; 23
dd -1                   ; 24
dd -1                   ; 25
dd -1                   ; 26
dd -1                   ; 27
dd -1                   ; 28
dd -1                   ; 29
dd -1                   ; 2A
dd -1                   ; 2B
dd -1                   ; 2C
dd -1                   ; 2D
dd -1                   ; 2E
dd -1                   ; 2F
dd -1                   ; 30
dd -1                   ; 31
dd -1                   ; 32
dd -1                   ; 33
dd -1                   ; 34
dd -1                   ; 35
dd -1                   ; 36
dd -1                   ; 37
dd -1                   ; 38
dd -1                   ; 39
dd -1                   ; 3A
dd -1                   ; 3B
dd -1                   ; 3C
dd -1                   ; 3D
dd -1                   ; 3E
dd -1                   ; 3F
dd -1                   ; 40
dd -1                   ; 41
dd -1                   ; 42
dd -1                   ; 43
dd -1                   ; 44
dd -1                   ; 45
dd -1                   ; 46
dd -1                   ; 47
dd -1                   ; 48
dd -1                   ; 49
dd -1                   ; 4A
dd -1                   ; 4B
dd -1                   ; 4C
dd -1                   ; 4D
dd -1                   ; 4E
dd -1                   ; 4F
dd -1                   ; 50
dd -1                   ; 51
dd -1                   ; 52
dd -1                   ; 53
dd -1                   ; 54
dd -1                   ; 55
dd -1                   ; 56
dd -1                   ; 57
dd -1                   ; 58
dd -1                   ; 59
dd -1                   ; 5A
dd -1                   ; 5B
dd -1                   ; 5C
dd -1                   ; 5D
dd -1                   ; 5E
dd -1                   ; 5F
dd -1                   ; 60
dd -1                   ; 61
dd -1                   ; 62
dd -1                   ; 63
dd -1                   ; 64
dd -1                   ; 65
dd -1                   ; 66
dd -1                   ; 67
dd -1                   ; 68
dd -1                   ; 69
dd -1                   ; 6A
dd -1                   ; 6B
dd -1                   ; 6C
dd -1                   ; 6D
dd -1                   ; 6E
dd -1                   ; 6F
dd -1                   ; 70
dd -1                   ; 71
dd -1                   ; 72
dd -1                   ; 73
dd -1                   ; 74
dd -1                   ; 75
dd -1                   ; 76
dd -1                   ; 77
dd -1                   ; 78
dd -1                   ; 79
dd -1                   ; 7A
dd -1                   ; 7B
dd -1                   ; 7C
dd -1                   ; 7D
dd -1                   ; 7E
dd -1                   ; 7F
dd C_DATA66             ; 80
dd C_DATA66             ; 81
dd C_DATA66             ; 82
dd C_DATA66             ; 83
dd C_DATA66             ; 84
dd C_DATA66             ; 85
dd C_DATA66             ; 86
dd C_DATA66             ; 87
dd C_DATA66             ; 88
dd C_DATA66             ; 89
dd C_DATA66             ; 8A
dd C_DATA66             ; 8B
dd C_DATA66             ; 8C
dd C_DATA66             ; 8D
dd C_DATA66             ; 8E
dd C_DATA66             ; 8F
dd C_MODRM              ; 90
dd C_MODRM              ; 91
dd C_MODRM              ; 92
dd C_MODRM              ; 93
dd C_MODRM              ; 94
dd C_MODRM              ; 95
dd C_MODRM              ; 96
dd C_MODRM              ; 97
dd C_MODRM              ; 98
dd C_MODRM              ; 99
dd C_MODRM              ; 9A
dd C_MODRM              ; 9B
dd C_MODRM              ; 9C
dd C_MODRM              ; 9D
dd C_MODRM              ; 9E
dd C_MODRM              ; 9F
dd 0                    ; A0
dd 0                    ; A1
dd 0                    ; A2
dd C_MODRM              ; A3
dd C_MODRM+C_DATA1      ; A4
dd C_MODRM              ; A5
dd -1                   ; A6
dd -1                   ; A7
dd 0                    ; A8
dd 0                    ; A9
dd 0                    ; AA
dd C_MODRM              ; AB
dd C_MODRM+C_DATA1      ; AC
dd C_MODRM              ; AD
dd -1                   ; AE
dd C_MODRM              ; AF
dd C_MODRM              ; B0
dd C_MODRM              ; B1
dd C_MODRM              ; B2
dd C_MODRM              ; B3
dd C_MODRM              ; B4
dd C_MODRM              ; B5
dd C_MODRM              ; B6
dd C_MODRM              ; B7
dd -1                   ; B8
dd -1                   ; B9
dd C_MODRM+C_DATA1      ; BA
dd C_MODRM              ; BB
dd C_MODRM              ; BC
dd C_MODRM              ; BD
dd C_MODRM              ; BE
dd C_MODRM              ; BF
dd C_MODRM              ; C0
dd C_MODRM              ; C1
dd -1                   ; C2
dd -1                   ; C3
dd -1                   ; C4
dd -1                   ; C5
dd -1                   ; C6
dd -1                   ; C7
dd 0                    ; C8
dd 0                    ; C9
dd 0                    ; CA
dd 0                    ; CB
dd 0                    ; CC
dd 0                    ; CD
dd 0                    ; CE
dd 0                    ; CF
dd -1                   ; D0
dd -1                   ; D1
dd -1                   ; D2
dd -1                   ; D3
dd -1                   ; D4
dd -1                   ; D5
dd -1                   ; D6
dd -1                   ; D7
dd -1                   ; D8
dd -1                   ; D9
dd -1                   ; DA
dd -1                   ; DB
dd -1                   ; DC
dd -1                   ; DD
dd -1                   ; DE
dd -1                   ; DF
dd -1                   ; E0
dd -1                   ; E1
dd -1                   ; E2
dd -1                   ; E3
dd -1                   ; E4
dd -1                   ; E5
dd -1                   ; E6
dd -1                   ; E7
dd -1                   ; E8
dd -1                   ; E9
dd -1                   ; EA
dd -1                   ; EB
dd -1                   ; EC
dd -1                   ; ED
dd -1                   ; EE
dd -1                   ; EF
dd -1                   ; F0
dd -1                   ; F1
dd -1                   ; F2
dd -1                   ; F3
dd -1                   ; F4
dd -1                   ; F5
dd -1                   ; F6
dd -1                   ; F7
dd -1                   ; F8
dd -1                   ; F9
dd -1                   ; FA
dd -1                   ; FB
dd -1                   ; FC
dd -1                   ; FD
dd -1                   ; FE
dd -1                   ; FF

                        end

	Ahora podemos obtener la longitud de la instruccion en una direccion 
arbitraria. Repetiremos esta llamada hasta que leamos los 5 bytes. Despues 
esto copiara esos bytes a old_hook. Sabemos la longitud de las primeras 
instrucciones, asique pordemos rellenar el salto relativo con la direccion 
que va a continuacion de estas instrucciones en la funcion original.

.386p
.model flat, stdcall

...

.data

 kernel_name 		db "kernel32.dll",0
 sleep_name		db "Sleep",0

 ...

 MEM_RELEASE		dd 000008000h

;16 nops + un salto relativo
 old_sleep		db 090h,090h,090h,090h,090h,090h,090h,090h,
			   090h,090h,090h,090h,090h,090h,090h,090h,
			   0E9h,000h,000h,000h,000h


.code
start:
	push	5000
	call	Sleep

 do_hook:
	push	offset kernel_name
	call	GetModuleHandleA
	push	offset sleep_name
		push	eax
	call	GetProcAddress
        push	eax
	mov	esi,eax

	xor	ecx,ecx
	mov	ebx,esi
 get_five_bytes:
	push    ecx
	push	ebx
	call	get_instr_len		;llamamos al LDE32
	pop	ecx
	add	ecx,eax
	add	ebx,eax
	cmp	ecx,5
	jb	get_five_bytes
	mov	edi,offset old_sleep     ;contando la direccion del salto
	mov	[edi+011h],ebx
	sub	[edi+011h],edi
	sub	dword ptr [edi+011h],015h
	rep	movsb
	pop	edi

;el siguiente codigo es lo mismo de antes

	push	PAGE_READWRITE
	push	MEM_COMMIT
	push	MEMORY_BASIC_INFORMATION_SIZE
	push 	0
	call	VirtualAlloc
	test	eax,eax
	jz 	do_sleep
	mov	esi,eax

	push	MEMORY_BASIC_INFORMATION_SIZE
	push	esi
	push	edi
	call	VirtualQuery
	test	eax,eax
	jz	free_mem

	call	GetCurrentProcess
	push	5
	push	edi
	push	eax
	call	FlushInstructionCache	

	lea	eax,[esi+014h]
	push	eax
	push	PAGE_EXECUTE_READWRITE
	lea	eax,[esi+00Ch]
	push	[eax]
	push	[esi]
	call	VirtualProtect
	test	eax,eax
	jz	free_mem

	mov	byte ptr [edi],0E9h
	mov	eax,offset new_sleep
	sub	eax,edi
	sub	eax,5
	inc	edi
	stosd

	push	offset old_protect
	lea	eax,[esi+014h]
	push	[eax]
	lea	eax,[esi+00Ch]
	push	[eax]
	push	[esi]
	call	VirtualProtect

 free_mem:
	push	MEM_RELEASE
	push	0
	push	esi
	call	VirtualFree
 do_sleep:
	push	5000
	call	Sleep
	push	0
	call	ExitProcess
 new_sleep:
	mov	eax,dword ptr [esp+004h]		
	add	eax,eax				;doblando el tiempo de espera
	push	eax
	mov	eax,offset old_sleep            ;llamada a la function antigua
	call	eax
	ret	004h



despues del gancho tenemos lo siguiente: 

	004010CC: 6888130000	push 000001388h
	004010D1: E818090000	call Sleep


	Sleep:     ;este es el salto en la direccion de la IAT 
	004019EE: FF2514204000	jmp dword ptr [000402014h]
 
	tabulka:
	00402014: 79 67 E8 77 6C 7D E8 77
      
	Kernel32.Sleep:
	77E86779: E95FA95788	jmp 0004010DDh

	new_sleep:
	004010DD: 8B442404	mov eax,dword ptr [esp+4]
	004010E1: 03C0		add eax,eax
	004010E3: 50		push eax
	004010E4: B827304000	mov eax,000403027h
	004010E9: FFD0		call eax

	old_sleep:
	00403027: 6A00		push 0
	00403029: FF742408	push dword ptr [esp+8]
	0040302D: 90		nop
	0040302E: 90		nop
	0040302F: 90		nop
	00403030: 90		nop
	00403031: 90		nop
	00403032: 90		nop
	00403033: 90		nop
	00403034: 90		nop
	00403035: 90		nop
	00403036: 90		nop
	00403037: E94337A877	jmp Kernel32.77E8677F


;esta instruccion es colocada un byte despues de la primera instruccion 
;en Kernel32.Sleep 
(77E86779)

	Kernel32.77E8677F:	
	77E8677F: E803000000	call Kernel32.SleepEx
	...			;lo restante no tiene importancia

Para poner esto mas claro, asi es como aparece la version original de 
Kernel32.Sleep:

	Kernel32.Sleep:
	77E86779: 6A00		push 0
	77E8677B: FF742408	push dword ptr [esp+8]
	77E8677F: E803000000	call Kernel32.SleepEx
	77E86784: C20400	ret 00004h

	Como puedes ver hemos copiado la primera y segunda instruccion 
(6 bytes) y el salto relativo apuntab a la siguiente instruccion y asi es como
debe ser. Hemos supuesto que no hay saltos relativos en los primeros bytes 
de las funciones. Si los hubiera seria un problema. El siguiente problema es
con APIs como ntdll.DbgBreakPoint. Son demasiado cortas para este metodo de 
gancheo.Y para tanto como es llamada por Kernel32.DebugBreak, no es gancheable
cambiando la IAT. ¿Pero quien quiere ganchear una funcion que solo consta de 
la llamada a int 3 ?
Nada es imposible. Si piensas sobre esto podrias encontrar la forma.
Estuve pensando que se puede enganchar la funcion siguiente a una dada( seria
dañada al reescribir los 5 bytes primeros de la funcion previa). La funcion 
DbdBreakPoint son 2 bytes, asique podemos poner algunos flags aqui e intentar
escribir un salto condicional en el comienzo de la segunda funcion...Pero este
no es nuestro asunto ahora.
Con el problema de salvaguardar la funcion original llegamos al desenganche.
El desenganche es restaurar los bytes cambiados con el estado original.
Cuando reescribimos la IAT tendremos que restaurar la direccion original a
la tabla. Cuando usemos el parche de los 5 bytes tendremos que volver a copiar
las instrucciones en sus direcciones originales. Ambas formas son muy 
sencillas y no es necesario escribir mas sobre ello.


=====[ 3.2.4 Other process hooking ]============================================

	Ahora haremos algo practico con los ganchos en ejecucion. ¿Quien
quiere enganchar su propio proceso? Esto servia para aprender la teoria
pero no es muy practico.
	Te mostrare tres metodos de enganchar otros procesos. Dos de ellos
usan CreateRemoteThread que esta solo en Windows con tecnologia NT. El problema
de los ganchos para mi no es tan interesante en versiones antiguas de windows.
Despues de todo intentare explicar un metodo que no lo probe, asique podria no
funcionar.
	Primero veamos un poco sobre CreateRemoteThread. Como la ayuda de esta
funcion dice, crea un hilo nuevo en cualquier proceso y ejecuta su codigo.

	HANDLE CreateRemoteThread(
		HANDLE hProcess,
		LPSECURITY_ATTRIBUTES lpThreadAttributes,
		DWORD dwStackSize,
		LPTHREAD_START_ROUTINE lpStartAddress,
		LPVOID lpParameter,
		DWORD dwCreationFlags,
		LPDWORD lpThreadId
	);

	El manejador de hProcess lo conseguimos con OpenProcess. Aqui tenemos
que tener los privilegios necesarios. El puntero lpStartAddress apunta a un
lugar de memoria del procedo OBJETIVO donde esta la primera instruccion del
nuevo hilo. Como el nuevo hilo es creado en el proceso objetivo este estara
en la zona de memoria del proceso objetivo. El puntero lpParameter apunta a
un argumento que sera el del nuevo hilo.


=====[ 3.2.4.1 Inyeccion DLL]===================================================

	Podemos ejecutar un nuevo hilo desde cualquier parte en la memoria de
un proceso objetivo. Esto es inutil amenos que tengamos codigo propio en el. 
El primer metodo hace esto. Usa GetProcAddress para obtener la direcion actual
de LoadLibrary. Entonces pasa como lpStartAddress la direccion de LoadLibrary.
La funcion LoadLibrary tiene un solo parametro, igual que la funcion para nuevo
hilo en el proceso objetivo.
	

	HINSTANCE LoadLibrary(
		LPCTSTR lpLibFileName
	);

	Usaremos esta similidad de parametros y pasaremos el nombre la la DLL 
como lpParameter. Despues de ejecutar el nuevo hilo, lpParameter contendra 
lpLibFileName. Lo mas importante es el comportamiento descrito arriba. 
Despues de cargar el nuevo modulo en la memoria del proceso victima, la parte 
de inicializacion es ejecutada. Si colocamos funciones especificas que 
enganchen lo que nosotros queramos en el modulo, ya esta todo hecho. Despues 
de ejecutar la parte de inicializacion, el hilo no tendra nada que hacer y se
carrera. Pero nuestro modulo estara todavia en memoria. Ese metodo esta 
curioso y es facil de implementar. Se le llama Inyeccion DLL. Pero si te pasa 
como a mi, no te gusta tener que usar DLLs. Pero si no te importa tener 
librerias esta es la forma mas facil y mas rapida (desde el punto de vista 
del programador)


=====[ 3.2.4.2 Codigo Independiente ]===========================================

	Este metodo es muy dificil pero es impresionante. Codigo independiente
es el codigo sin direcciones estaticas. Todo es relativo en el hacia cualquier
otra parte del codigo propio. Este codigo es hecho la mayoria de las veces si 
no sabemos la direccion donde este codigo sera ejecutado. Seguramente seria 
posible obtener esta direccion y reprogramar nuestro codigo para que funconara
en la nueva direccion sin errores, pero esto seria incluso mas dificil que 
haciendo codigo independiente. Un ejemplo de este tipo de codigo puede ser el 
codigo de un virus. El virus que infecta ejecutables se añade por si mismo al 
ejecutable. En diferentes ejecutables el codigo del virus estara en sitios 
diferente dependiendo de las estructuras, la longitud, etc	
	En principio tenemos que insertar nuestro codigo en un proceso 
objetivo. Entonces la funcion CreateRemoteThread nos permitira ejecutar 
nuestro codigo.Asi, al principio tenemos que obtener informacion sobre el 
proceso victima y abrirlo con OpenProcess. La funcion VirtualAllocEx nos 
reserva espacio en la zona de memoria del proceso victima. Finalmente usamos 
WriteProcessMemory para escribir nuestro codigo en la memoria reservada y lo
ejecutamos. En CreateRemoteThread, lpStartAddress sera la direccion de la 
memoria reservada y lpParameter puede ser lo que queramos. Me gusta este
metodo porque no necesitamos ficheros innecesarios.


=====[ 3.2.4.3 Cambio Raw  ]====================================================

	No hy una funcion CreateRemoteThread en versiones de windows 
antiguas (sin NT). Asique no podemos usar esta funcion para los ganchos. Hay 
probablmente mejores metodos para enganchar que el metodo que voy a contar. De
hecho nose si funcionara en la practica (uno nunca sabe cuando usa windows) 
pero teoricamente esta todo correcto.
	No necesitamos en absoluto tener nuestro codigo en el proceso victima 
para enganchar sus funciones. Tenemos la funcion WriteProcessMemory (deberia 
estar en todas las versiones de windows) y tenemos OpenProcess tambien. Lo 
ultimo que necesitamos es VirtualProtectEx que permite cambiar el acceso a 
paginas de memoria en otros procesos. No veo ninguna razon por la que no 
podamos enganchar funciones directamente desde nuestro proceso.


=====[ 4. Finalizando ]=========================================================

	Este pequeño manual termina aqui. Agradecere cualquier comentario que
describa metodos no mencionados de enganche, estoy seguro que hay un monton.
Tambien agradecere cualquier comentario en las partes que no estan descritas 
tan detalladamente. Puedes enviarme codigo fuente  si quieres para los 
problemas de ganchos que por ejemplo estuve demasiado vago para escribir. La 
meta de este docmento es mostrar detalles de cada tecnica de ganchos. Espero 
haber hecho parte de esto.
	Agradecimieno especial a Z0MBiE por su trabajo, que asi no tuve que 
escribir yo mismo y dedicar años estudiando tablas para conseguir la longitud 
de instruccion.


===================================[ Fin ]======================================