ENSAMBLADOR & DESENSAMBLADO
A la hora de crackear hay que tener unos conocimientos basicos de ASM,
mientras mas mejor. Los programas son un listado de ordenes que se reproducen
en lenguaje maquina, pero que para poder realizarlos tenemos este lenguaje que
consiste en una serie de mnemotecnicos que facilitan su interpretacion,
cada una de las instrucciones se codifican en una serie de numeros binarios,
a traves de un compilador, que lo que hace es traducir una serie de instrucciones
dando igual si se programaron en C, C++, pascal, a unos y ceros....
Espero que te hayas bajado los tutoriales que te recomende en el primer
capitulo, porque lo que voy a hacer aqui es una breve introduccion a
la forma de trabajo y a sus principales instrucciones.
Este lenguaje consta de una instruccion y dos operandos llamados registros
en los que se almacenan las cosas, osea que un registro es igual a una
variable en otro lenguaje.
Los registros
- AX BX CX DX
Voy a explicar el primero por que los otros tres, quitando algunas
particularidades que sirven a la hora de programar son basicamente
igual.AX: AX es un registro de 16 bits (16 unos o ceros, o dos bytes)
se divide a su vez en otros dos de ocho AL (Low) y AH (High), esto
era principalmente en ordenadores anteriores al 386 ya que a partir
de estos se expandio creando el registro EAX (Extended) de tamaño 32
bits (Ademas, hoy en dia ¿quien tiene menos de un 486?). Veamoslo
graficamente:
EAX
|----------------|----------------|
AX
|--------|--------|
AH AL
Creo que se entiende.
La funcion basica de AX es la de ACUMULADOR en diversas operaciones
como MUL o DIV Hay otras funciones, como la de indicar la funcion de
cada interrupcion, pero esto no nos interesa para nuestro proposito
ya que es para la programacion en DOS
BX Tambien se divide en EBX, BX, BH y BL y el nombre del registro es BASE
CX Se divide igual que los anteriores, el interes de este radica
en que se usa como el numero de repeticiones en los contadores.
DX Uno de los usos mas comunes del registro de Datos, es cuando
al realizar un MUL o un DIV el resultado no cabe en AX y se guarda en DX:AX
Ahora vamos a ver los Registros Indices:
SI DI BP SP.
SI Source Index, Indice Fuente
DI Indice Destino
BP Base pointer, Puntero Base
SP Stack Pointer, puntero de la pila
Los 4 son registros de 16 bits y no se dividen en una parte alta y otra baja
Registros de Segmento:
CS DS SS ES.
CS: Code segment, o segmento de Codigo, indica donde se halla el
programa que se esta ejecutando
DS: Data Segment, o segmento de datos, indica donde lee y
escribe el programa los datos por defecto
SS: Stack Segment, segmento de la pila, indica el lugar de la pila
ES: Extra Segment, segmento extra. Es una extension de DS.
Puntero de instruccion: IP (16 bits)
Instruction Pointer, Indica la siguiente instruccion a ejecutar,
se encuentra en el segmento especificado por CS
CS e IP en Forman la direcci¢n real de la siguiente instruccion
FLAGS
Bueno, yo creo que con esto andamos sobrados de registros :)
Ahora vamos a ver otra de las cosas importantes y mas sencillas,
los FLAGS o BANDERAS. Existe un regitro de 16 bits de tamaño de
los cuales 7 no se usan
y que guardan todos los flags
* * * * * * * O D I T S Z A C
Estas son las iniciales, quedate con que cada uno de ellos puede
tener un valor, segun la logica booleana un 1 o un 0 y que en funcion
de este se produciran distintos eventos.
LA PILA
La pila es un lugar donde se almacenan variables para poder
usarlas posteriormente, su modo de funcionamiento corresponde
a las siglas inglesas LIFO (Last Input First Output, o lo que
es lo mismo ultima entrada primera salida, pero UEPS no queda
muy bien ;)) Para entenderlo piensa en lo siguiente, una pila
de platos, no puedes sacar el de abajo del todo, que es el
primero que hemos puesto porque se romperia todo, tendremos
que coger el ultimo que hemos puesto. Los comandos para usar
la pila son
PUSH registro
POP registro
Simplemente PUSH pone un valor y POP lo saca
Bueno pues ahora vamos a ver las Ordenes rapidamente, para
empezar cuanto antes a desensamblar:
MOV
Sintaxis MOV destino, fuente
El proposito de esta orden es obviamente el de mover un valor
de sitio a otro, se copia el termino de mas a la derecha sobre
el del centro
Vamos a ver unos ejemplos:
mov ax,bx ;copia el valor de bx en ax
mov ax,5 ;copia el valor 5 decimal en ax
mov ax,05h ;copia el valor 5 hexadecimal en ax (5 decimal = 5 hexadecimal)
mov ax,0Eh ;copia el valor E hexadecimal en ax (E = 14)
mov ax,[bx] ;copia el valor del offset de bx a ax
CALL
Un call simplemente "llama" a una direccion para continuar
con la ejecucion del programa desde alli y hasta encontrar
un ret en el que se regresaria al punto anterior:
Se puede hacer un call a una etiqueta o a una direccion,
a la hora de crackear nos vamos a encontrar con lo segundo,
un ejemplo:
111:110 mov ax, 08h
111:111 call 116
saltariamos a
111:116 mov bx, 0f9H
111:117 ret
ahora continuarimos en
111:112 lo que fuera
Espero que se entienda. Un call lo que hace es romper la
ejecucion lineal del programa dando un salto a otro lado.
LOOP
Esto es un bucle, repite un numero de veces (Especificado
en CX) una serie de operaciones.
ejemplo:
mov ax,01h ;AX = 1
mov cx,05h ;CX = 5 numero de veces a repetir el bucle
XX:
cmp ax,04h ;Compara AX con 4
je end ;Si AX es igual a 4 saltara a END
inc ax ;Sino le sumamos uno
LOOP XX ;y volvemos a realizar el bucle
JUMP (Salto Incondicional)
Esto es un salto, simplemente, como un goto en otros lenguajes
Se puede usar como un salto a una etiqueta o a una direccion,
tambien hay saltos lejanos y cercanos, pero no nos interesa mucho.
SALTOS CONDICIONALES
Si no habiais entendido bien el sentido de los FLAGS ahora
lo hareis A diferencia de un JUMP aqui se solo se produce el
salto si se cumple una determinada condicion, seria algo asi
como un IF... THE ... ELSE en PASCAL
Hay una gran cantidad de saltos y en muchos casos dos o mas
son equivalentes aqui va una lista de ellos
JA, JAE JB JBE JNA JNAE JNB JNBE JZ JE JNZ JNE JG JGE JL JLE JNG JNGE
JNL JNLE JC JNC JO JNO JP JNP JPE JPO JS JNS
Bueno, he contado unos 30 pero quedaros de momento con
estos dos basicamente
- JZ jump zero, salta cuando el resultado de una operacion es igual
- JNZ jump not zero Lo contrario a lo anterior
- JE igual a JZ
- JNZ jeje, tu mismo :)
MUL
Esta operacion realiza una multiplicacion de un operando por
AX y lo guarda aqui, o si excede de tamaño en DX:AX
ejemplo
Tomamos AX con valor 4 y CX con valor 2
pues un MUL CX daria como resultado AX = 8
DIV Similar a MUL pero con la division
IMUL Multiplicacion con signo
IDIV Division con signo
ADD
Su funcion es la de sumar dos terminos,
Si bx = 11010111
y cx = 00110100 un haria esto ADD bx,cx
-----------
100001011 y lo almacenaria en bx
SUB Igual a ADD pero con la resta
DEC
El proposito es el de restar una unidad a un registro
si cx = 09h un DEC CX dejaria las cosas asi: CX=08h
INC
Igual que DEC pero en lugar de restar 1 ud. sumandola
NOP
Esta es la mejor de todas :) Simplemente, no hace nada NO OPERATING
XCHG
Esto intercambia el contenido de dos registros
Tenemos ax=2 y bx=4
XCHG ax,bx ahora ax=4 y bx=2. Facil ¿no?
CMPOtra de las ordenes principales para nuestro proposito,
compara dos registros o un registro y un valor o dos valores....
NOT
Niega el contenido de un registro
Si AX = 01010101 NOT AX => 10101010ANDUna de las operaciones
logicas, actuaria según la siguiente tabla de la verdad
Termino primeroTermino segundoResultado000010100111OR
Otra operación logica,
Termino primeroTermino segundoResultado000011101111NOR
Un OR negado
Termino primeroTermino segundoResultado001010100110XOR
Esta es una instrucción util para encriptar pero de momento
no nos interesa mucho esto
Termino primeroTermino segundoResultado000011101110
Hasta aquí una pequeña introduccion al ensamblador, espero
que haya sido facil de entender, si teneis alguna duda o
algo ya sabeis donde encontrarme
DESENSAMBLADO DE PROGRAMAS CON W32DASM
El W32DASM es uno de los mejores programas a la hora de
obtener el codigo de un programa para windows junto con
el IDA PRO. Vamos a ver para que sirve cada funcion:
Esta es la barra principal del programa
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1º Selecciona un programa a desensamblar
2º Salva el desensamblado a un archivo de texto ASCII
3º Buscar texto
4º Copiar al portapapeles
5º Ir al inicio del programa
6º Ir al punto de entrada
7º Ir a una pagina
8º Ir una localizacion de codigo determinada
9º Saltar a
10º Regresar del salto
11º Llamar
12º Regresar de la llamada
13º Funciones Importadas
14º Datos headecimales
15º Codigos hexadecimales
16º Funciones Exportadas
17º Referencias al Menu
18º Referencias a los dialogos
19º Referencias a las cadenas
20º Imprimir
Vamos a desensamblar un programa para ver como funciona:
En este caso he elegido Add/Remover Cleaner 2.01 un programa
que se usa para eliminar las entradas del menu agregar o
quitar programas de windows que han sido mal instaladas, es
muy facil y nos vendra bien para ver como funcionan, En este
caso lo que vamos a hacer:
Crackearlo para que nos acepte cualquier clave
Antes de nada, tenemos que abrir el programa y familiarizarnos
como funciona Lo primero que vemos es una pantalla diciendonos:
Que bienvenidos al programa que el autor gasto una importante
cantidad de su tiempo y que le enviemos 5$ por la copia. 5$ No
son nada asi que podriamos registrarnos, pero yo soy mas
partidario de +ORC y de KarlitoxZ, y prefiero gastarmelo
en copas :). A lo que vamos, Le damos a Ok... Ill Register
later y nos aparece la ventana principal del programa le
damos a REGISTER e introducimos cualquier clave, en mi caso
nombre: Stomper y Numero: 123456789, pulsamos en DONE y nos
sale una ventanita que nos dice INVALID REGISTRATION INFORMATION,
Llegados a este punto hacemos lo siguiente:
Apuntamos el mensaje de error anterior
Desensamblamos el programa
Pulsamos sobre el boton de String Reference, Esta es una de
las caracteristicas mas importantes de un desensamblador, nos
muestras las cadenas de texto que vemos en el programa.
Buscamos la nuestra, hacemos doble click, un par de veces para
ver si hay una o mas coincidencias, en este caso no.
Aparecemos en algo como esto:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00434FED(U)
|
:00434FDF 8B45F8 mov eax, dword ptr [ebp-08]
:00434FE2 E879DCFCFF call 00402C60
:00434FE7 C3 ret
:00434FE8 E9EBE1FCFF jmp 004031D8
:00434FED EBF0 jmp 00434FDF
Possible StringData Ref from Code Obj ->"Thank you for registering!"
|
:00434FEF B8BC504300 mov eax, 004350BC
:00434FF4 E8D7CFFFFF call 00431FD0
:00434FF9 EB0A jmp 00435005*
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00434F42(C)
|
* Possible StringData Ref from Code Obj ->"Invalid registration information"
|
:00434FFB B8E0504300 mov eax, 004350E0 ;Aqui aparecemos
:00435000 E8CBCFFFFF call 00431FD0
Si os dais cuenta justo encima tenemos una referencia a nuestra
cadena por un salto, lo mas seguro es que en la direccion 434F42
tengamos un salto condicional del tipo JE/JNE a nuestra cadena,
asi que damos al boton GOTO CODE LOCATION y ponemos 434F42. Ahora
estaremos aqui.
:00434F3C 58 pop eax
:00434F3D E87EEBFCFF call 00403AC0
:00434F42 0F85B3000000 jne 00434FFB
:00434F48 B201 mov dl, 01
Lo que os decia, un salto incondicional precedido de un
CALL 403AC0, esto significa que en el CALL se calcula el
numero de registro para nuestro nombre y en funcion de si
coincide con el que hemos metido se sale con un valor 0 o 1
(¿Recordais los flags?) y dependiendo de ello saltariamos.
Lo que tenemos que hacer es situarnos encima del jne, dando
doble click y nos fijamos en la pantalla de abajo del programa
y vemos algo como esto @ Offset 00034342 Apuntar este numerito.
Es lo que identifica nuestra instruccion del resto, abrimos un
editor hexadecimal, y buscamos la opcion goto y ponemos el offset
anterior, pero ten cuidado esta en hexadecimal, ahora sustuimos
el 0F85 (jne) por un 0F84 (je), lo que hemos hecho es que cuando
metamos la clave correcta nos levara al lugar malo. Antes de
haber modificado el ejecutable tenemos que haber hecho una copia
de seguridad para poder restaurarlo en caso de error. Ahora
intentamos registrarlo. ¿Que ocurre? Nos da las gracias por
registrarlo, pero en realidad no lo esta, lo unico que hemos
hecho ha sido cambiar la pantalla de error por la que queriamos
ver. Es muy normal que los programadores pongan dos o mas rutinas
para registrar el programa. En este caso vamos a hacer una cosa,
vamos a seguir observando las String Refences a ver si vemos algo
importante:
No se si os llama la atencion una cosa:
Hay dos entradas muy parecidas
Add/Remove Cleaner - Registered
Add/Remove Cleaner
JEJE :) Vamos a hacer doble click sobre la que pone registered
La primera
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00435C4B(C)
|
* Possible StringData Ref from Code Obj ->"Add/Remove Cleaner - Registered "
->"Copy"
|
:00435C8F BACC5D4300 mov edx, 00435DCC
:00435C94 A154874300 mov eax, dword ptr [00438754
Vamos a ver que hay en la direccion 435C4B
:00435C46 E875DEFCFF call 00403AC0
:00435C4B 7442 je 00435C8F
:00435C4D 8B0D147B4300 mov ecx, dword ptr [00437B14]
Apuntamos el OFFSET del salto (3504b) y lo cambiamos por un jump EB
Ahora hacemos doble click y aparecemos aqui
:00436013 E8A8DAFCFF call 00403AC0
:00436018 754C jne 00436066
* Possible StringData Ref from Code Obj ->"Add/Remove Cleaner - Registered "
->"Copy"
|
:0043601A BA18614300 mov edx, 00436118
:0043601F A154874300 mov eax, dword ptr [00438754
En este caso nos interesa que el programa continue con su
ejecucion es decir que no se produzca el salto, asi que lo
que tenemos que poner es un par de NOPS en lugar del 754C, 9090.
Apunta el OFFSET 35418 y realiza los dos cambios.
Abrimos el programa y directamente aparecemos en modo
registrado ¡COJONUDO!
Bueno, espero que no os haya resultado muy dificil, y que hayais
visto el modo de usar el listado muerto de un programa. Esto era un
programa muy simple, lo que teneis que hacer es practicar con todos
los programas que caigan en vuestras manos para poder coger soltura
y no perderos con el SOFTICE. Si teneis alguna duda o pregunta, ya
sabeis donde podeis encontrarme.