::[INTRO]::

Desde hace algún tiempo (como desde 1999) he venido estudiando estos asuntos de Ingeniería Inversa. Quisiera entrar a polemizar con cada uno de los que lee este post, sobre el buen o mal uso de la Ingeniería Inversa. La verdad, como programador siempre me han inquietado muchos asuntos sobre la ejecución del código que escribo. Me hago preguntas como las siguientes: ¿cómo harían para programar eso?, ¿cómo hago para que mi programa se comporte de cierta manera?, ¿cómo hago para mejorar la seguridad de una versión DEMO que entrego?. A todas estas y mas preguntas me he enfrentado al desarrollar programas; como sabrán, encontrar las respuestas adecuadas ha llevado y seguirá llevando tiempo. Pero por ahora les puedo adelantar, que el estudio de las técnicas de Ingeniería Inversa, el Lenguaje Ensamblador, las APIs de los sistemas operativos con los que trabajo (Linux y Windows), las técnicas de Overflow y demás asuntos relacionados con esos aspectos de bajo nivel que muchos no quieren ni mirar, me han llevado a encontrar las respuestas, mas o menos adecuadas, a las preguntas que me planteo.
Lo que van a ver en este post, es una breve pero útil aplicación (la tercera) de mis conocimientos de RE (Reverse Engineering - Ingeniería Inversa). Se trata de un pequeño programa (24 KB) hecho en MASM32 (Macro ASseMbler 32 Bits) que escribe (parcha) una aplicación llamada Cool MP3 Splitter quitándole tres controles de seguridad a la versión Shareware colocándola totalmente funcional, es decir, quito las características de seguridad que controlan la versión limitada del programa haciéndolo funcionalmente completo.
No estará disponible aquí la versión compilada del Patch, eso sería como distribuir el crack para el programa en mención. Y sí, aunque es un crack, solo pongo el código fuente para mi y para aquellos curiosos de estos cuentos.
::[COMMON DIALOG]::
Aquí va el código de la librería que me crea ese famoso Common Dialog. Oiste Juan, ¿y que es eso del common dialog? pues el siguiente extracto de código me crea la siguiente ventana en donde el usuario selecciona el .exe de Cool MP3 Splitter.

;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;
; Archivo : Crack.inc
; Objetivo : Declarar prototipos, archivos include, ibrerias y macros locales
; para el Patch desarrolados para quitar la proteccion del Cool MP3
; Splitter.
; Autor : Juan F. Mugnoz-Fernandez
; Fecha : 21/02/2004
; Version : 1.0.0
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Archivos Include
; ~~~~~~~~~~~~~~~~
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
; Librerias
; ~~~~~~~~~
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib
; Prototipos
; ~~~~~~~~~~
DlgProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
; Macros locales
; ~~~~~~~~~~~~~~
;==========================
;CommonDialog
;==========================
DisplayCommonDialog MACRO hWnd, hInstance
.const
MAX_SIZE EQU 260
.data
OpenFileNameStruct OPENFILENAME <>
FilterString db "Executable files",0,"*.exe",0
db "All files",0,"*.*",0,0
OurTitle db "Open file...",0
Buffer db MAX_SIZE dup(0)
.code
mov OpenFileNameStruct.lStructSize, SIZEOF OpenFileNameStruct
push hWnd
pop OpenFileNameStruct.hwndOwner
push hInstance
pop OpenFileNameStruct.hInstance
mov OpenFileNameStruct.lpstrFilter, OFFSET FilterString
mov OpenFileNameStruct.lpstrFile, OFFSET Buffer
mov OpenFileNameStruct.nMaxFile, MAX_SIZE
mov OpenFileNameStruct.Flags, OFN_FILEMUSTEXIST or \
OFN_PATHMUSTEXIST or \
OFN_LONGNAMES or \
OFN_EXPLORER or \
OFN_HIDEREADONLY
mov OpenFileNameStruct.lpstrTitle, OFFSET OurTitle
invoke GetOpenFileName, ADDR OpenFileNameStruct
ENDM
::[EL RECURSO]::
El recurso no es mas que un archivo (Crack.rc) con unas directivas bien definidas para crear la ventana principal del Patch. El siguiente pedazo de código, me crea el look-n-feel de esta aplicación.

#include "afxres.h"
#include "resource.h"
MYDIALOG DIALOGEX 10, 10, 111, 115
STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_VISIBLE | WS_CAPTION |
WS_SYSMENU
EXSTYLE WS_EX_TOOLWINDOW
CAPTION ".:::Crack Cool MP3 Splitter:::."
FONT 8, "Courier New", 0, 0, 0x1
BEGIN
CTEXT "Crack - Cool MP3 Splitter",IDC_TITULO,3,4,103,9
LTEXT "Crack Type : Patch",IDC_CRACK_TYPE,5,20,80,9
LTEXT "Cracker : JFM-F",IDC_CRACKER,5,31,80,9
LTEXT "Coder : JFM-F",IDC_CODER,5,42,80,9
LTEXT "Date : 21/02/2004",IDC_CRACK_DATE,5,53,100,9
LTEXT "Crack Ver : 1.0",IDC_CRACK_VER,5,64,100,9
LTEXT "Target : splitter.exe",IDC_CRACK_TARGET,5,74,100,9
DEFPUSHBUTTON "Crack",IDC_BUTTON_CRACK,15,102,32,11
PUSHBUTTON "Cancel",IDC_BUTTON_CANCEL,58,102,32,11
GROUPBOX "",IDC_STATIC,2,14,106,86,WS_DISABLED
CTEXT "Not cracked yet !!!",IDC_SUCCES,9,89,91,9
END
IDI_ICON2 ICON DISCARDABLE "Daemon.ico"
::[RESOURCE.H]::
Y este es el archivo en donde están definidos los valores para cada una de las constantes declaradas en el fichero de recursos.
#define MyDialog 101 #define IDC_FRAME_INFO 1000 #define IDC_CRACK_TYPE 1001 #define IDC_CRACKER 1002 #define IDC_CODER 1003 #define IDC_CRACK_DATE 1004 #define IDC_CRACK_VER 1005 #define IDC_CRACK_TARGET 1006 #define IDC_TARGET_VER 1007 #define IDC_BUTTON_CRACK 1008 #define IDC_BUTTON_CANCEL 1009 #define IDC_TITULO 1010 #define IDC_SUCCES 1011 #define IDI_ICON2 103
::[THE PATCH]::
Y este es el código del patch, es aquí en donde orquesto los componentes anteriores y quito la seguridad de Cool MP3 Splitter.
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
;
; Archivo : Crack.asm
; Contenido : Codigo fuente del Patch para Cool MP3 Splitter
; Autor : Juan F. Mugnoz-Fernandez
; Fecha : 21/02/2004
; Version : 1.0.0
;«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Declaramos algunas directivas para que funcione correctamente
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.486 ; Declaracion para codigo de 32 bits
.model flat, stdcall ; Modelo de memoria de 32 bits
option casemap :none ; case - sensitive
include Crack.inc ; Incluimos nuestro fichero de archivos include,
; librerias, prototipos y macros.
; Iniciamos con la seccion de constantes <.const>
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.const
IDC_BUTTON_CRACK EQU 1008 ; ID del boton "CRACK"
IDC_BUTTON_CANCEL EQU 1009 ; ID del boton "CANCEL"
IDC_SUCCES EQU 1011 ; ID del STATIC para mensaje de exito.
IDM_EXIT EQU 3000 ; ID de mensaje para cerrar la APP
IDM_CRACK EQU 3402 ; ID de mensaje para abrir el CommonDialog
IDM_SETTEXT EQU 3404 ; ID de mensaje para mostrar exito en el patch aplicado al original
TamagnoOriginal EQU 1229824 ; Tamagno del fichero original en Bytes
; Iniciamos con la seccion de nuestros datos inicializados <.data>
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.data
dlgName db "MyDialog",0 ; Nombre del cuadro de dialogo principal del
; Patch, definido en Crack.rc
AppName db "CrackJFMF", 0 ; Nombre de la aplicacion
BackupFile db "splitter.bck", 0 ; Nombre con el qu renombramos el ejecutable original
CrackSuccess db "Crack success!!!",0 ; Mensaje de exito cuando hemos realizado las cosas bien
; Posibles mensajes de error.
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~
Error db "Error en ejecucion de patch",0
Error_CreateFile db "Error: No se pudo abrir el archivo", 0
Error_WriteFile db "Error: Se produjo un error al escribir sobre el archivo"
db 0Dh,0Ah,"Verifique que el archivo no este abierto", 0
Error_GetFileSize db "Error: El archivo seleccionado no corresponde con el tamagno del archivo esperado", 0
; Bytes y offset ubicados con respecto a las protecciones encontradas.
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;==============================================
; PROTECCION No.1 : LICENCIADO A:
OffsetProteccion1 dd 00003C7Dh
BytesOriginales1 db 75h,6Dh
BytesReemplazar1 db 74h,6Dh
;==============================================
;==============================================
; PROTECCION No. 2 : LIMITANTE EN BREAKPOINTS
; ESTABLECIDOS A LA CANCION
OffsetProteccion2 dd 00003DF5h
BytesOriginales2 db 0Fh,85h,89h,00h,00h,00h
BytesReemplazar2 db 0Fh,84h,89h,00h,00h,00h
;==============================================
;==============================================
; PROTECCION No. 3 : LIMITANTE EN BREAKPOINTS
; ESTABLECIDOS A LA CANCION
OffsetProteccion3 dd 00004319h
BytesOriginales3 db 75h,79h
BytesReemplazar3 db 74h,79h
;==============================================
; Iniciamos con la seccion de nuestros datos no-inicializados <.data?>
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.data?
hInstance HINSTANCE ? ; Instancia de la aplicacion
CommandLine LPSTR ? ; Puntero a la CmdLine
hFileOriginal DD ? ; Handle del archivo original.
BytesEscritos DD ? ; Para almacenar el valor retornado por WriteFile
; Iniciamos con el codigo
; ~~~~~~~~~~~~~~~~~~~~~~~
.code
_START: ; Tag de inicio
invoke GetModuleHandle,NULL ; Obtenemos el handle de la app
mov hInstance, EAX ; Se mueve el valor de la instancia a la vble
; hInstance, declarada en <.data>
invoke DialogBoxParam, \ ; Se crea el cuadro de dialogo principal del Patch.
hInstance, \ ; La instancia de la APP
ADDR dlgName, \ ; Offset del Nombre del dialogo ppal.
NULL, \
ADDR DlgProc, \ ; Offset del procedimiento de dialogo.
NULL
invoke ExitProcess, EAX ; Finaliza la aplicacion.
; Declaramos el procedimiento de dialogo
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg == WM_INITDIALOG
invoke GetDlgItem, hWnd, IDC_BUTTON_CANCEL
invoke SetFocus, EAX
.ELSEIF uMsg == WM_CLOSE
invoke SendMessage, hWnd, WM_COMMAND, IDM_EXIT, 0
.ELSEIF uMsg == WM_COMMAND
mov EAX, wParam
.IF lParam == 0
.IF AX == IDM_EXIT
invoke EndDialog, hWnd, NULL
.ELSEIF AX == IDM_CRACK
DisplayCommonDialog hWnd, hInstance ; Mostramos el cuadro de dialogo
; para seleccionar el archivo que
; se va a "Parchar". Ver MACRO.
.IF EAX == TRUE ; Si se selecciono algun archivo...
invoke CopyFile, \ ; Creamos una copia del original
ADDR Buffer, \ ; El archivo original
ADDR BackupFile, \ ; La copia
FALSE ; Especificacion del API.
invoke CreateFile, \ ; Abrimos el archivo original
ADDR Buffer, \
GENERIC_READ or GENERIC_WRITE, \
0, NULL, OPEN_EXISTING, 0, 0
.IF EAX == INVALID_HANDLE_VALUE ; Si hubo algun error en la apertura...
invoke MessageBox, NULL, ADDR Error_CreateFile, ADDR Error, MB_OK
.ELSE ; Si no hubo errores....
mov hFileOriginal, EAX
invoke GetFileSize, hFileOriginal, NULL
.IF EAX == TamagnoOriginal
;=================================================================================
; Parchado de la primera proteccion Licenciado A:
;=================================================================================
invoke SetFilePointer, hFileOriginal, OffsetProteccion1, NULL, FILE_BEGIN
invoke WriteFile, hFileOriginal, ADDR BytesReemplazar1, 2, ADDR BytesEscritos, 0
mov EAX, BytesEscritos
.IF EAX != 2
invoke MessageBox, NULL, ADDR Error_WriteFile, ADDR Error, MB_OK
.ELSE
;=================================================================================
; Parchado de la segunda proteccion No. de BreakPoints puestos a una cancion
;=================================================================================
invoke SetFilePointer, hFileOriginal, OffsetProteccion2, NULL, FILE_BEGIN
invoke WriteFile, hFileOriginal, ADDR BytesReemplazar2, 6, ADDR BytesEscritos, 0
mov EAX, BytesEscritos
.IF EAX != 6
invoke MessageBox, NULL, ADDR Error_WriteFile, ADDR Error, MB_OK
.ELSE
;=================================================================================
; Parchado de la tercera proteccion No. de BreakPoints puestos a una cancion
;=================================================================================
invoke SetFilePointer, hFileOriginal, OffsetProteccion3, NULL, FILE_BEGIN
invoke WriteFile, hFileOriginal, ADDR BytesReemplazar3, 2, ADDR BytesEscritos, 0
mov EAX, BytesEscritos
.IF EAX != 2
invoke MessageBox, NULL, ADDR Error_WriteFile, ADDR Error, MB_OK
.ELSE
invoke SendMessage, hWnd, WM_COMMAND, IDM_SETTEXT, 0
.ENDIF
.ENDIF
.ENDIF
;=========================================
; Se cierra el archivo abierto
;=========================================
invoke CloseHandle, hFileOriginal
.ELSE
invoke MessageBox, NULL, ADDR Error_GetFileSize, ADDR Error, MB_OK
.ENDIF
.ENDIF
.ENDIF
.ELSEIF AX == IDM_SETTEXT
invoke SetDlgItemText, hWnd, IDC_SUCCES, ADDR CrackSuccess
.ENDIF
.ELSE
mov EDX, wParam
shr EDX, 16
.IF DX == BN_CLICKED
.IF AX == IDC_BUTTON_CANCEL
invoke SendMessage, hWnd, WM_COMMAND, IDM_EXIT, 0
.ENDIF
.IF AX == IDC_BUTTON_CRACK
invoke SendMessage, hWnd, WM_COMMAND, IDM_CRACK, 0
.ENDIF
.ENDIF
.ENDIF
.ELSE
mov EAX, FALSE
ret
.ENDIF
mov EAX, TRUE
ret
DlgProc endp
end _START
::[EL ICONO]::
Pues si, que sería de este patch sin un icono que lo identifique.

::[FINAL]::
Ahhgg!!...a lo último me arrepentí y decidí colocar todo lo anterior aquí.

NO SE SI ALGUN DIA TE LO DIJE
NO SE SI ALGUN DIA TE LO DIJE, PERO ME SIENTO ORGULLOSA DE TI Y ASI NO ESTEMOS AHORA JUNTOS TAMBIEN ME ALEGRAN TUS LOGROS.
TE AMO MUCHO