Ensamblador en GNU/Linux - e

Anuncio
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
call printf
...
Programa en C
printf:
...
...
...
int 80h
libC
KERNEL
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:
mov eax,
mov ebx,
mov ecx,
mov edx,
int 80h
syscall:
int 80h
ret
open:
push dword mode
push dword flags
push dword path
mov eax, 05h
call syscall
05h
path
flags
mode
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:
shell
strace
ltrace
fenris
gdb
argv[0]
./test
./test
./test
./test
/home/user/test
getenv(“_”)
./test
/usr/bin/strace
/usr/bin/ltrace
/usr/bin/fenris
(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
getsid 0x1968
getppid 0x1968
getpgid 0x3a6e
getpgrp 0x3a6e
gdb
0x1968
0x3a6f
0x3a70
0x3a70
strace
0x1968
0x3a71
0x3a71
0x3a71
ltrace
0x1968
0x3a73
0x3a73
0x3a73
fenris
0x1968
0x3a75
0x3a75
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
Descargar