Skip to main content

A brief practical use of reverse engineering

::[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