Está en la página 1de 33

Ensamblador en GNU/Linux

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Introducción
¿Para qué vale saber programar en ensamblador?
Optimización
en cuanto a tamaño.
en cuanto a velocidad de ejecución (desenrollado
de bucles, sin redundancias, etc.).
Modificación de binarios (no tenemos el código
fuente):
adaptación de drivers
cracking
virus

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Ensamblador en UNIX
Llamadas al sistema (syscalls):

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Ensamblador en UNIX
Llamadas al sistema (syscalls):
Normalmente los programas no hacen syscalls,
llaman a funciones de la libC:

...
push string printf:
...
call printf ...
... ... KERNEL
int 80h

Programa en C libC Núcleo


Pablo Garaizar Sagarminaga
Copyleft, all rights reversed
Ensamblador en UNIX
Llamadas al sistema (syscalls):
Diferentes maneras de utilizarlas en Linux, BSD, etc:
open(path, flags, mode);
Linux FreeBSD
open: syscall:
mov eax, 05h int 80h
mov ebx, path ret
mov ecx, flags open:
mov edx, mode push dword mode
int 80h push dword flags
push dword path
mov eax, 05h
call syscall
Pablo Garaizar Sagarminaga
Copyleft, all rights reversed
Ensamblador en UNIX
Diferentes sintaxis para programar:
Intel: nasm
operación destino, fuente: mov eax, 05h
AT&T: gas, as
operación fuente, destino: movl $0x05, %eax
Sufijos en los opcodes (l(ong), w(ord), b(byte))
indicando el tamaño de los operandos.
Los registros han de ir precedidos de “%” y los literales
de “$”.
Diferencias en referencias:
mov edx, [ebp+ecx*4+040000000h] =
movl $0x4000000(%ebp,%ecx,4), %edx

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Primer programa con nasm
section .text
global _start

msg db 'Hello, world!',0Ah


len equ $ - msg
_start:
mov edx,len
mov ecx,msg
mov ebx,1
mov eax,4
int 80h
mov eax,1
int 80h

nasm –f elf hello.asm –o hello.o


ld hello.o –o hello
Pablo Garaizar Sagarminaga
Copyleft, all rights reversed
Ensamblar y enlazar
Ensamblado y enlazado:
Ensamblar con nasm:
nasm –f elf fichero.asm –o fichero.o

Enlazado:

ld:
ld -s --dynamic-linker /lib/ld-linux.so.2
-lc fichero.o -o fichero

gcc:
gcc fichero.o -o fichero
Pablo Garaizar Sagarminaga
Copyleft, all rights reversed
Demostración

Programar un "hola, mundo!" con nasm.


Ensamblarlo y enlazarlo.
Ejecutarlo.
Pablo Garaizar Sagarminaga
Copyleft, all rights reversed
Programando en GNU/Linux
Estructura de un programa con nasm:
section .bss: datos sin inicializar:
temporal resb 255

section .data: datos inicializados:


contador db 0Ah ( contador EQU 0Ah)
zerobuf: times 64 db 0

section .text: código del programa


mov eax, 01h
...
Pablo Garaizar Sagarminaga
Copyleft, all rights reversed
Programando en GNU/Linux
Condiciones iniciales:
Registros
En kernels > 2.2: todos los registros a 0.
En kernels < 2.2: ebp y ecx distintos de 0.
Pila:
[esp] = argc
[esp+4] = argv[0]
[esp+8] = argv[1]
...
[esp+n*4] = envp

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Programando en GNU/Linux
Estructura de un ejecutable en GNU/Linux (ELF):

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Herramientas disponibles
Editores:
BIEW, HTE, ELFe...
Volcadores:
od, objdump, ELFDump...
Desensambladores:
IDA (desde dosemu/wine), LDasm, DCC, Monodis,
jad...
Depuradores:
GDB, Fenris, PrivateICE, front-ends de GDB...
Trazadores:
ltrace, strace, gccchecker...

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
BIEW
BIEW:
Interfaz intuitivo, similar al HIEW o MC.
Múltiples vistas: binario, octal,
hexadecimal, desensamblado.
Análisis de la cabecera de los ELF.
Modificación sencilla del binario.

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Demostración

Abrir un ejecutable con BIEW.


Analizar sus secciones y cabeceras.
Desensamblarlo.
Editarlo.
Comprobar el cambio en su funcionamiento.
Pablo Garaizar Sagarminaga
Copyleft, all rights reversed
GDB
GNU Debugger, escrito inicialmente por Richard
Stallman.
Orientado al debugging durante el desarrollo de
software (junto con el código fuente).
Optimizado para ejecutables con código fuente en C y
C++ principalmente.
Es un debugger de RING-3, que utiliza la syscall ptrace
para funcionar.
Interfaz de usuario en modo texto y mediante
comandos.
Muchos emplean GDB a través de un “front-end” que
oculta los engorros de utilizar comandos.
Pablo Garaizar Sagarminaga
Copyleft, all rights reversed
GDB
Syscall ptrace:
Permite a un programa (típicamente un
debugger), “pegarse” o “attachearse” a
otro proceso ya en ejecución con el
objeto de analizar su comportamiento.
Debugging en modo usuario.
Tiene un historial de seguridad un tanto
triste.

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
GDB
Front-ends:
Xxgdb: el primero y más simple.
GVD: GNU Visual Debugger, algo rústico.
KDBG: wrapper para KDE del GDB.
DDD: quizá el front-end más sofisticado,
combinando las funcionalidades del
GDB, con muchas ventajas del modo
gráfico.

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
GDB
Primeros pasos, carga del ejecutable:
gdb ejecutable
gdb PID
gdb –args ejecutable arg1 arg2
Ejecución del programa:
set / show args
path / show paths
show / set / unset environment var
run
run parámetros
attach PID
detach

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
GDB
Breakpoints:
info break
break [TAB] [lista de símbolos]
break *0x08040808
clear *0x08040808
Watchpoints:
info watchpoints
watch expresión (write)
rwatch expresión (read)
awatch expresión (acceso: r||w)
Catchpoints:
catch evento

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
GDB
Ejecutando instrucciones:
n, next (una línea)
s, step (una línea y entra)
ni, nexti (una instrucción)
si, stepi (una instr. y entra)
finish
c, continue
Examinando la pila:
frame n
up, down
info frame n
bt, backtrace
Pablo Garaizar Sagarminaga
Copyleft, all rights reversed
GDB
Desensamblado:
disassemble
set disassembly-flavor intel
set disassembly-flavor att
Registros:
info registers
info all-registers
Memoria:
x 0x8048080
x/100 0x8048080
x/100s 0x8048080

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Demostración

Cargar un ejecutable con GDB.


Desensamblarlo.
Ejecutarlo y trazarlo.
Pablo Garaizar Sagarminaga
Copyleft, all rights reversed
Técnicas anti-debugging
Método 1: descriptores de ficheros.
Cuando se carga un proceso en memoria, antes de que se
ejecute se realizan diversas operaciones de lectura sobre
varios ficheros implicados en la creación de la imagen del
proceso en ejecución.
El GDB abre más descriptores que los necesarios y el
intento de cierre de los mismos produce un error:

if(close(3)==-1)
printf(“Hello shell...\n”);
else
printf(“Being traced...\n”);

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Técnicas anti-debugging
Método 2: argumentos y variables de entorno.
La documentación de la shell bash explica que el valor de
la variable de entorno “_” contiene el nombre completo de
cada aplicación que se haya ejecutado.
Los diferentes debuggers modifican esa variable:

argv[0] getenv(“_”)
shell ./test ./test
strace ./test /usr/bin/strace
ltrace ./test /usr/bin/ltrace
fenris ./test /usr/bin/fenris
gdb /home/user/test (NULL)

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Técnicas anti-debugging
Método 3: Identificación de procesos.
Existe un identificador para el proceso interactivo que se
llama proceso “líder” de la sesión: SID.
La diferencia entre el proceso padre (PPID) y el proceso
líder (SID) determinará si existe un programa intermedio
desde el que se está ejecutando la aplicación:

shell gdb strace ltrace fenris


getsid 0x1968 0x1968 0x1968 0x1968 0x1968
getppid 0x1968 0x3a6f 0x3a71 0x3a73 0x3a75
getpgid 0x3a6e 0x3a70 0x3a71 0x3a73 0x3a75
getpgrp 0x3a6e 0x3a70 0x3a71 0x3a73 0x3a75

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Técnicas anti-debugging
Metodo 4: Forzar un falso desensamblado
Mediante un salto a mitad de una instrucción, dado un
alineamiento, conseguimos engañar al desensamblador:

jmp antidebug + 2
antidebug:
db 0666h
call reloc
reloc:
pop esi
...

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Técnicas anti-debugging
Método 5: Detectando Int 3.
Cuando un debugger quiere parar en un punto
determinado (breakpoint), introduce un Int 3 (0xCC)
que se puede detectar:
void foo(){ printf("Hello\n");}
int main(){
if ((*(volatile unsigned *)((unsigned)foo + 3) &
0xff) == 0xcc) {
printf("BREAKPOINT\n");
exit(1);
}
foo();
}

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Técnicas anti-debugging
Método 6: Introduciendo Int 3.
Podemos introducir 0xCCs en el código para “molestar” al
debugger:

#include <signal.h>

void handler(int signo){}

int main(){
signal(handler, SIGTRAP);
__asm__("int3");
printf("Hello\n");
}

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Técnicas anti-debugging
Método 7: Llamando a ptrace.
Cuando estamos siendo debuggeados por GDB o
strace/ltrace sólo es posible llamar a
ptrace[PTRACE_TRACEME] una vez por proceso:

if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
printf("DEBUGGING... Bye\n");
return 1;
}

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed
Demostración

Compilar ejemplos de los métodos propuestos.


Intentar depurarlos y trazarlos.
Pablo Garaizar Sagarminaga
Copyleft, all rights reversed
Conclusiones
Programar y conocer ensamblador nos da una potencia
asombrosa, aunque es un trabajo arduo en ocasiones.
GNU/Linux, y UNIX en general, no está afectado todavía
por las problemáticas que normalmente requieren su
uso: virus, cracking de programas comerciales,
modificación de programas sin tener su código fuente,
etc.
Esto provoca que no haya muchas herramientas
disponibles, ya que suelen ser creadas por grupos
underground.
Parece que todo esto esta progresivamente cambiando,
así que se auguran desarrollos importantes.
Pablo Garaizar Sagarminaga
Copyleft, all rights reversed
Referencias
LinuxAssembly:
http://linuxassembly.org
The Int80h Page:
http://int80h.org
List of Linux/i386 system calls:
http://www.lxhp.in-berlin.de/lhpsyscal.html
Phrack Magazine:
http://phrack.org

Pablo Garaizar Sagarminaga


Copyleft, all rights reversed

También podría gustarte