|-----------------------------------------------------------------------------|
  [ 7a69#15 ]                                                  [ 23-11-2003 ]
 \                                                                           /
  \-------------------------------------------------------------------------/
   { 12 - Un loader y un crack.                                 }{ Marconi }
   |-----------------------------------------------------------------------|


/************************************************************************/
/*                                                                      */
/*                      acehide v1.22                                   */
/*                      www.zslab.com                                   */
/*               Ejemplo de un loader y un crack                        */
/*                                                                      */
/*                      dificultad: baja                                */
/*        herramientas usadas: W32Dasm, PEditor,PDump32,Masm32          */
/*                                                                      */
/*                         Marconi                                      */
/*                     inocraM@yahoo.com                                */
/*                                                                      */
/*                 Miercoles, 5 de febrero del 2003                     */
/*                                                                      */
/*              1 revision: Jueves, 6 de febrero del 2003              */
/*                                                                      */
/************************************************************************/

0.- Acerca de esta revision...

        - Se ha escrito correctamente, usando "qu"'s en vez de k's, usando
 y's donde corresponde en vez de abusar del uso de la "i" latina, etc. Si 
 se me ha escapado alguna falta de ortografia lo siento, no era mi
 intencion. No pongo acentos, y ya sabeis todos el porque. Este conato de
 escribir con "buena ortografia" se ha hecho a instancias de Esn-min. Un
 saludo y gracias chavalote ;)
        - Se han aadido algunos comentarios que se me habian olvidado y
 sin los cuales creo que no todo se entiende tan bien como deberia.
        - El crack ha sido modificado, debido a la estupidez que era
 comenzar con un jmp en vez de pasar el EP a ese punto. Uno de mis muchos
 momentos brillantes :_(
        - Lo primero de todo es que al hacer copy-paste del archivo debio
 haber algun error y habia un salto condicional mal. Y tambien habia dos 
 pequeos errores que me cole y puse dos addr's donde no tenian que estar.
 Y tambien se me olvido el alineamiento de los contextos... Vamos, que yo
 no se en que estaba pensando porque eso no funcionaba ni bien ni mal. Lo
 que pasaba era que se quedaba en un bucle infinito recibiendo eventos de 
 debug por intentar ejecutar una instruccion privilegiada ( codigo de 
 excepcion STATUS_PRIVILEGED_INSTRUCTION). Yo que no vi salir ninguna 
 ventana me confie y pense que todo iba sobre ruedas... jejeje
 De toda formas decidi reescribir el bucle del WaitForDebugEvent usando la 
 sintaxis de alto nivel que proporciona el masm intentando asi que quedase 
 un codigo mas legible. Y ahora si, todo funciona a la perfeccion.

1.- Introduccion...

        La historia de como se crea este pekeo tutorial es bien singular.
 Lo cierto es que yo llevaba ya mucho tiempo sin crackear y toda mi actividad
 en el mundo de la informatica se reducia a ocupar una pequea parte de mi
 tiempo libre en programar. Aun asi sigo siendo un habitual del canal
 #crackers del irc-hispano, ademas de serlo de otros canales como #asm,
 #win32asm o #ensamblador. Justo ayer, 4 de febrero, habia acabado mis
 examenes parciales y tenia al fin un poco de tiempo libre, y tambien justo
 ayer entro en el canal #crackers alguien que se consideraba un ex-cracker y
 que pedia ayuda con la victima objetivo de este tuto, el acehide. Como no
 tenia nada mejor que hacer y el individuo en cuestion aseguraba que era cosa
 de nios ( lo que no entiendo si era tan sencillo era porque no lo hacia el) 
 me puse manos a la obra.  
        Hay que tener en cuenta alguna cosa importante a la hora de leer el
 tuto.La primera es que lo estoy escribiendo guiandome por las notas que tome
 ayer noche mientras le hacia a la victima todo tipo de perrerias. Intentare
 dar una vision real de lo que fue el proceso de investigacion en si, sin
 omitir errores, perdidas de tiempo, etc. Intentando excusarme dire que
 llevaba mas de un ao sin crackear nada, seguramente cualquiera que este un
 poco mas en forma le habria dado jaque mate mucho mas rapido y de una forma
 mucho mas elegante. Otra cosa importante a tener en cuenta es el conjunto
 de herramientas del que se disponia para llevar a cabo la tarea. Solo tenia
 instalado el W32dasm, el Peditor y el Masm32, y en un cd que tenia sobre mi
 mesa estaba el PDump32. No eran ciertamente las herramientas idoneas para
 llevar a cabo el trabajo que se avecinaba,pero creedme si os digo que habria
 tardado mas en encontrar los CD's con utilidades para crackear que en
 hacerlo usando lo que tenia a mano. Una desventaja de ser desordenado  ;)
        Sin mas dilaciones...

2.- Investigando...

        Al ejecutar el programa se pone el iconcillo del programa al lado del
 reloj, y haciendo click sobre el con el boton dcho del raton se despliega
 un menu con una serie de opciones entre las que se encuentra la de registrar
 la aplicacion. Vamos directamente a ella y podemos ver que tenemos campos
 para introducir nuestro nombre y serial, asi como de checkear dicho serial.
 Tambien nos dice que para que tenga efecto hay que reiniciar la aplicacion.
 Introduciendo un nombre y serial podemos ver que sale una ventana de error
 con la frase "The registration code is INCORRECT". Desensamblo el ejecutable
 con el W32Dasm pero este no es capaz a desensamblar nada, asi que me imagino
 que esta empacado y le hecho un vistazo con el PEditor, pudiendo ver una
 seccion .aspack que dentro de la cual esta el punto de entrada.
        Lo primero en lo que me voy a centrar es en conseguir un listado
 muerto del codigo del programa, aunque no sea un ejecutable funcinal. Para
 ello uso el PDump32 para hacer un volcado total del proceso en memoria y
 seguidamente con el PEditor modifico las caracteristicas de la primera
 seccion a E0000020 ( ni siquiera cambiaron los nombres de las secciones y se
 sigue llamando .text). Una vez hecho esto, y aunque no tengo el punto de
 entrada original y no tengo la tabla de funciones exportadas e importadas si
 que cuento con un listado de codigo valido, asi como informacion de recursos
 y cadenas de texto.
        Encontramos las cadenas con ID's 00138 y 00139, que son:
 "The registration code is CORRECT" y "The registration code is INCORRECT".
 La ultima de ellas se referencia desde 00407179 y 00406e5f, y la primera de
 ellas desde 004071d4, 0041090c y 00406d0f. De todas estas VA's, podemos ver
 que 0041090c no se puede emparejar con otra VA cercana de la otra cadena asi
 que la eliminamos. 00406e5f esta dentro de una funcion que es llamada desde
 00409ad5 y 0040a506, con lo que la pareja de VA's mas probable para comenzar
 el estudio es 00407179 y 004071d4.
        Estudiando el codigo por encima de estas VA's podemos ver cosas
 interesantes, incluido un salto condicional con el que se escoje una de las
 dos opciones. Vamos a tener que tracear para conseguir mas informacion, y
 para ello vamos a usar el depurador del W32Dasm, y tracearemos sobre el
 .exe orginal al que previamente modifique las caracteristicas de las
 secciones .text y .aspack a E0000020, para poder asi en la medida de lo
 posible poner bpx's.  La informacion que conseguimos (resumida) es la
 siguiente:

 ; introduciendo como nombre = Marconi
 ; y como serial = 1234567890
 :00407098      call 0041BF3B                   ; eax= tamao del serial
 :0040709D      mov esi, dword ptr [esp+10]     ; esi->serial
 :004070A1      mov eax, dword ptr [esi-08]     ; eax= tamao del serial
 :004070A4      cmp eax, 0000001D               ; tamserial < 29?
 :004070A7      jl 00407167                     ; la cagamos.

        Usamos un serial de 30 caracteres, por ejemplo:

 452095782509826028571034161456
 
        Cambiando el serial que habiamos introducido por este pasamos el
 primer filtro. Seguimos traceando en busca de informacion que nos
 interese... y llegamos a:

 :004070DF      mov al, byte ptr [esi+1B]       ;esi->serial
 :004070E2      pop ebp
 :004070E3      cmp al, 30                      ;al=caracter 0x1b
 :004070E5      jl 004070F3
 :004070E7      cmp al, 39
 :004070E9      jg 004070F3                     ;saltamos si no es un num.                      
 :004070EB      movsx eax, al
 :004070EE      sub eax, 00000030               ;eax=ese digito
 :004070F1      jmp 00407105
  
 ese salto incodicional nos lleva a:
 
 :00407105      mov cl, byte ptr [esi+1C]       ;idemp con la pos 0x1c
 :00407108      shl al, 04                      ; al*=16
 :0040710B      cmp cl, 30
 :0040710E      jl 0040711D
 :00407110      cmp cl, 39
 :00407113      jg 0040711D
 :00407115      movsx ecx, cl
 :00407118      sub ecx, 00000030
 :0040711B      jmp 00407131

 y con ese otro salto incondicional llegamos a:

 :00407131      or al, cl
 :00407133      mov cl, byte ptr [esp+0F]
 :00407137      xor cl, al                      ; si no son iguales
 :00407139      jne 00407163                    ; la cagamos

        Los slatos condicionales de las dos primeras partes no se ejecutan
 puesto que en nuestro serial solo hay numeros.
        Si tenemos en cuenta que en [esp+0f] hemos leido un valor 6, y 
 presuponiendo que los cambios de las posiciones 0x1b y 0x1c no influyen en
 este valor el serial tiene que cumplir que:

        pos(0x1b)*16+pos(0x1c)==6 ---> pos(0x1b)=0 y pos(0x1c)=6

 y nuestro serial quedaria ahora:
 
 452095782509826028571034161066

        Y efectivamente nos sale ese pedazo de mensaje diciendonos que el
 serial es correcto, asi que pasamos a reinciar el programa.

        Y aqui algo falla porque seguimos sin estar registrados, y asi nos lo
 indica la ventana de "about". Esa ventana tambien nos dice que estamos en el
 dia 0 de 30 de uso, que es el tiempo que funcionara si no estamos
 registrados. Adelantando el reloj dos meses no hacemos nada, pues el
 programa asegura que solo ha pasado un dia. Obviamente no nos vamos a parar
 a hacer esto 30 veces. Asi que forzaremos la caducidad del programa para
 ver a donde nos lleva. Mirando en la lista de cadenas de texto de nuestro
 archivo dumpeado encontramos tres que son:

 ID=00131: "You are now on day %u of your 30 day evaluation period."
 ID=00134: "You are now on day %i of your 30 day evaluation period. Do y"
 ID=00135: "Evaluation period had been expired. Do you want to Register "
 
        La primera se trataria de la que se usa para rellenar el about asi 
 que si investigamos las otras dos... y encontramos a su alrededor algo tan 
 interesante como esto
 
 :0040A466      cmp eax, 0000000A       ; eax= numero de dias
 :0040A469      jbe 0040A4C6            ; a los 10 dias pasa algo

 y en otro sitio:
 
 :0040A4C6      cmp dword ptr [00433994], 0000001E      ; a los 30 dias...
 :0040A4CD      jbe 0040A55F

        Con estos dos puntos podemos hacer caducar el programa. Nos falta 
 comprobar que estamos en lo cierto traceando el programa. Y aqui nos 
 encontramos con un problema. Si creamos el proceso como suspendido, le
 ponemos los bpx's y continuamos su ejecucion el W32dasm produce una 
 excepcion y se cierra. Esto puede ser debido a que el aspack introduzca
 codigo antidebuggin. La solucion es tracear el codigo de la seccion 
 .aspack, intentando evitar ese problema. Aqui no voy a entrar en detalles,
 traceando durante un rato y pasando una serie de bucles llego a 0043f3bf 
 (un ret) que nos llevara a la 0040cbc4, con lo que ya tenemos OEP. Poniendo 
 un bpx en 0043f3bf y desde ahi poniendo bpx's en los lugares donde queramos 
 nos saltamos el antidebuggin. Ahora que ya tenemos la forma de poder poner 
 bpx's al principio de la ejecucion del programa original podemos tambien 
 simular su caducidad y seguidamente podemos comprobar como eso no llega a 
 ningun sitio. Cuando caduca aparece una ventana que nos ofrece la 
 posibilidad de registrarnos, pero ese boton nos lleva hasta la pagina web 
 de la empresa para que copremos el programa y no hay salida a esta 
 situacion. Tambien descubrimos jugando con este trozo de codigo que lo que
 pasa a partir del dia 10 de uso es que el programa nos enseara una
 horrible ventana indicando lo que usamos el programa y lo poco que hemos 
 pagado por el.

        Entonces, contamos ahora con dos puntos de ataque que aun nos quedan.
 Por un lado la ventana que aparece de vez en cuando al intentar usar algunas
 opciones y que nos dice algo asi como "shareware restriction bla bla bla" y
 tenemos tambien el texto "NOT REGISTERED", ID: 00133. y que aparece
 en la ventana de "about". Este texto esta referenciado en dos sitios:
 0040522c y 004108dc. Poniendo un bpx en ambas posiciones vemos que la ultima
 queda descartada, con lo que pasamos a estudiar el codigo de la zona en la 
 que esta la primera aparicion. Encontramos lo siguiente:

 :004051AF      call 0041DFBE                   
 :004051B4      mov al, byte ptr [0043388D]     ; comprobacion
 :004051B9      test al, al                     ; al==0?
 :004051BB      je 004051EA                     ; la cagamos

        Ademas de esto podemos ver como esa misma comparacion se hace en
 varios sitios, lo que induce a pensar que byte ptr [0043388D] es una flag 
 que indica si estamos o no registrados.
        Una de las cosas que hay que tener en cuenta llegado a este punto es 
 que haciendo las pruebas pertinentes hasta llegar aqui ya he ejecutado unas
 cuantas veces el programa con lo que ahora ya aparece por derecho propio la
 ventana que indica la superacion de los 10 dias.
 
 (*** nota sobre el debugger del w32dasm ***)
 La superacion de esos 10 dias se ha producido entre otras cosas por lo que 
 parece ser un fallo en el debugger del w32dasm. Al parchear el codigo para
 simular la caducidad del programa me he dado cuenta que si tenemos el 
 programa parado y hacemos modificaciones de alguna posicion de memoria y/o
 registro, en la mayoria de las ocasiones al usar f7 o f8 para seguir 
 traceando en vez de parar en la instruccion siguiente lo que hace es 
 continuar ejecutandose. La unica solucion que he encontrado es poner un
 bpx en la instruccion siguiente para despues si poder seguir traceando.
 (*** nota sobre el debugger del w32dasm ***)

        Pasemos a hacer la siguiente prueba:
 1) bpx en 0043f3bf ( el ret que se ejecuta para llegar al OEP) 
 2) Poner en [0043388D] un 1

 Pasan dos cosas interesantes:
 1) aparece la mierda de ventana diciendome que me quedan no se cuantos dias
 para que el programa deje de funcionar-> la direccion de memoria en la que 
 antes he puesto un valor se ha borrado.
 2) Viendo esto vuelvo a poner en el byte ptr [0043388d] un 1, y de repente 
 el programa pasa a funcionar como si estuviese perfectamente registrado.

        Parece obvio que lo que hay qu hacer es buscar cuando se toca esa
 posicion de memoria y hacer que se rellene con lo que nos interesa.
 Despues de tracear un ratillo encontramos un posible punto para cambiar y
 arrinconamos el codigo malefico en una funcion. La posicion es 0040a43d y la
 funcion 00403c50 y traceando dentro de ella finalmente encontramos:

 :00404CCC      mov byte ptr [eax+0000010D], 00

 cambiar el ultimo valor por 1 y el programa pensara que esta registrado.


        Con esto llego al final de la parte de investigacion del software. 
 Obviamente no es una investigacion muy pormenorizada y ni siquiera me he
 parado a estudiar en detalle el sistema de proteccion. Tampoco he explicado
 detenidamente partes que con las herramientas adecuadas seguramente habrian
 sido trivialidades.

 
3.- Loader...

        Pues si contamos con que tenemos el punto de entrada original, y
 sabemos donde hay que parchear, si se dispusiese de las herramientas
 necesarias pareceria mas que logico desempacar el ejecutable, parchearlo y
 ya tendriamos el programa crackeado. Pero no es eso lo que pretendo yo ahora.
 Puesto que hemos seguido unos pasos para conseguir simular el registro lo 
 que vamos a hacer un programa que haga de forma automatica todos esos
 pasos.
        Lo primero que se ve claramente es que se tiene que tratar de un 
 loader, pero que sea casi como un pequeo debugger. El proceso tiene que 
 lanzar el ejecutable victima, esperar a que llegue al punto en el que va a 
 entrar en el OEP, en ese momento parar el programa, parchear la direccion en 
 cuestion, y seguir la ejecucion normal.
        Para hacer todo esto yo en principio propongo que el loader actue 
 como debugger del programa victima y ponga una int 3h en el punto en el que 
 va a saltar al OEP. Una vez se ejecute el bpx podemos quitarlo, parchear la
 segunda direccion, y esperar a que termine. Un programa que hace todo esto
 podria ser algo asi como:

/********************************acehide.asm - (loader) *****************
 ;
 ; loader para el acehide v1.22 
 ; version 1.1
 ;
 ; Marconi
 ; Febrero del 2003
 ; inocram@yahoo.com
 ; 
 ; 
 ; ml /c /coff acehide.asm
 ; link /SUBSYSTEM:WINDOWS acehide.obj
 ; 

 .386
 .MODEL flat,STDCALL
 option casemap:none               

 include c:\masm32\include\windows.inc               
 include c:\masm32\include\kernel32.inc
 include c:\masm32\include\user32.inc
 includelib c:\masm32\lib\kernel32.lib
 includelib c:\masm32\lib\user32.lib

 .data
 error      db  "Error en la aplicacion...",0     
 procsi     dd  0                               
 archivo    db  "c:\Archivos de programa\aceHide\aceHide.exe",0
 nval       db  1
 nbpx       db  0cch
 noldbpx    db  0c3h
 vapatch    dd  00404cd2h
 vabpx      dd  0043f3bfh
 ALIGN      4
 contexto   CONTEXT<CONTEXT_CONTROL,0>
 devento    DEBUG_EVENT <0>
  

.data?
 infoinicio STARTUPINFO <?>
 procinfo   PROCESS_INFORMATION <?>  
 cad        dd  ?                              
 
                       

.code
 inicio:                                        

    ;---------
    ; crear el proceso
    ;---------
    invoke      GetStartupInfo,addr infoinicio
    invoke      CreateProcess,NULL,addr archivo,NULL,NULL,FALSE,\
                             DEBUG_ONLY_THIS_PROCESS+NORMAL_PRIORITY_CLASS,\
                             NULL,NULL,addr infoinicio, addr procinfo          
    test        eax,eax                                   
    je          fallo
    inc         procsi
    
    ;---------
    ; poner el bpx
    ;---------     
      invoke      WriteProcessMemory, procinfo.hProcess,vabpx,addr nbpx,\
                                    1,NULL
      test        eax,eax
      je          fallo
         
    ;---------
    ; Esperar por las peticiones
    ;---------

    .WHILE TRUE            
       invoke      WaitForDebugEvent, addr devento, INFINITE
        .IF  devento.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT   
            .break
        .ELSEIF devento.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
               .IF   devento.u.Exception.pExceptionRecord.ExceptionCode \
                                                == EXCEPTION_BREAKPOINT
                mov     eax, \
                        devento.u.Exception.pExceptionRecord.ExceptionAddress
                .IF     eax == vabpx
                     ;---------
                     ; quitar el punto de ruptura
                     ;---------  
                     invoke      WriteProcessMemory,procinfo.hProcess,vabpx,\
                                 addr noldbpx, 1,NULL
                     mov         contexto.ContextFlags, CONTEXT_CONTROL
                     invoke      GetThreadContext, procinfo.hThread,\ 
                                                   addr contexto
                     dec         contexto.regEip
                     invoke      SetThreadContext, procinfo.hThread,\
                                                   addr contexto
                     ;---------
                     ; parchear el .exe
                     ;---------
                     invoke      WriteProcessMemory,procinfo.hProcess,\
                                             vapatch, addr nval,1,NULL

                .ENDIF
          .ENDIF  
          invoke ContinueDebugEvent, devento.dwProcessId , \
                        devento.dwThreadId, DBG_CONTINUE  
        .ENDIF
      invoke ContinueDebugEvent, devento.dwProcessId , \
                        devento.dwThreadId, DBG_CONTINUE    
    .ENDW

    jmp salida

fallo:
    invoke      GetLastError
    invoke      FormatMessage,FORMAT_MESSAGE_ALLOCATE_BUFFER + \
                       FORMAT_MESSAGE_FROM_SYSTEM,NULL,eax,0,addr cad,0\
                       ,NULL
    cmp         procsi,0
    je          mensaje
    invoke      TerminateProcess,procinfo.hProcess,0
 mensaje:
    invoke      MessageBox,0,cad,addr error,MB_OK+MB_ICONINFORMATION
    invoke      LocalFree,cad
 salida:
    invoke      ExitProcess,NULL
 end inicio


/***************************** fin del archivo *************************
        

4.- crack...
        Seguramente a nadie se le ha pasado el hecho de que tenemos la 
 ultima direccion que se ejecuta antes de pasar el control al codigo 
 original del programa. Aun estando empacado y puesto que no tiene ningun
 tipo de control de integridad, hacer el crack es practicamente cosa de 
 nios. 
        Lo unico que hay que tener en cuenta es que el push 0 que hay 
 antes del ret que nos lleva al codigo original se rellena en tiempo de 
 ejecucion con la direccion valida. Esta direccion es calculada por el 
 trozo de codigo que hay justo antes del ret. Por ejemplo en 0043f39a, 
 que mueve a eax el valor 0x0cbc4, ese valor es la parte baja del OEP. 
 El punto en el que la direccion de retorno es escrita en el codigo es:

 :0043F3A9      mov dword ptr [ebp+000003A8], eax

        Por lo tanto habra que tener cuidado con esta instruccion.

/********************************acehide.asm - (crack) *****************
 ;
 ; crack para el acehide v1.22 
 ; Marconi
 ; Febrero del 2003
 ; inocram@yahoo.com
 ; 
 ; 
 ; ml /c /coff acehide.asm
 ; link /SUBSYSTEM:WINDOWS acehide.obj
 ; 

 .386
 .MODEL flat,STDCALL
 option casemap:none               

 include c:\masm32\include\windows.inc               
 include c:\masm32\include\kernel32.inc
 includelib c:\masm32\lib\kernel32.lib
 
 .data
 ;---------
 ; archivo a parchear y offsets donde parchear
 ;---------
 archivo   db  "c:\Archivos de programa\AceHide\AceHide.exe",0
 offset1   dd   0001b66bh
 offset2   dd   00019dbah
 offset3   dd   00019da9h
 

       

.data?
    handle  HANDLE  ?
    cuantos dd      ?
       
.code

  ;---------
  ; Desde aqui hasta fincodigo son los datos con los que hay que parchear
  ;---------
  codigo1:    
    push   eax
    mov    eax, 00404cd2h                                       
    mov    byte ptr [eax],1
    pop    eax
    push   0040cbc4h
    ret
 codigo2:
    push   00440c6bh
    ret
 codigo3:
    dec     eax
    inc     eax
    dec     eax
    inc     eax
    dec     eax
    inc     eax
 fincodigo:
 inicio:
    ;---------
    ; punto de entrada
    ; abrimos el archivo
    ; y vamos escribiendo los datos
    ;---------
    invoke  CreateFile, addr archivo,GENERIC_WRITE,FILE_SHARE_READ,NULL, \
                   OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
    cmp     eax, INVALID_HANDLE_VALUE
    je      fallo
    mov     handle,eax 
    invoke  SetFilePointer,handle,offset2,NULL,FILE_BEGIN
    cmp     eax,-1
    je      falloaa
    invoke  WriteFile, handle, codigo2, codigo3-codigo2, addr cuantos, NULL
    invoke  SetFilePointer,handle,offset1,NULL,FILE_BEGIN
    cmp     eax,-1
    je      falloaa
    invoke  WriteFile, handle, codigo1, codigo2-codigo1, addr cuantos, NULL
    invoke  SetFilePointer,handle,offset3,NULL,FILE_BEGIN
    cmp     eax,-1
    je      falloaa
    invoke  WriteFile, handle, codigo3, fincodigo-codigo3, addr cuantos, NULL

    ;---------
    ; salida del programa ( tanto si hubo errores como si no)
    ;---------
 falloaa:
    invoke  CloseHandle,handle
 fallo:
    invoke  ExitProcess,eax
 end inicio

/***************************** fin del archivo ************************* 

        La verdad es que hacer un crack sin inteface ni nada de nada es 
 una chapuza como dios manda, pero bueno, no estoy intentando escribir 
 aqui un tutorial sobre como hacer un carck perfecto. Este codigo es lo 
 que corresponderia al corazon del crack. 

4.- Saludos y despedida...
        
        Con esto termino este pequeo tuto, que espero a alguien sirva para
 algo. El loader que se propone esta probado en XP y funciona perfectamente,
 pero aun asi no es una solucion buena al problema. Esta puesto mas que nada
 para ensear a quien no sepa como se hace un programita de ese estilo y
 tambien, por que no decirlo, para rellenar un poco ;)
        En cuanto al parche, tambien funciona a la perfeccion, esta probado
 en XP y a mi esta si que me parece una solucion minimamente decente al
 problema.
        No creo que haga falta decir que no me hago responsable del  mal uso
 que se pueda hacer de la informacion aqui expuesta, que este documento esta 
 escrito con fines estricta y unicamente educativos, y todas esas cosas.
        Saludos a los asiduos y no tan asiudos de los canales #crackers,
 #asm, #win32asm y #ensamblador.
        Por supuesto cualquier comentario, critica, puntualizacion, o lo que
 sea, se puede mandar un mail a:
                         inocraM@yahoo.com
        Y respondo al nombre de Marconi ;)
        Saludos.
        Marconi
        Lo normal es aburrido

*EOF*
