Dia 04
NO MIREN ESTA INFORMACIÓN, TODAVIA NO LA HE ACTUALIZADO
Identificando variables locales en assembly
En assembly, las variables locales se pueden almacenar en displacemente negativos con relacion al EBP o displacemente positivos con relacion al ESP
---- ESP : direccion menor
----
----
----
---- EBP: direccion mayor
Por ejemplo, las siguientes guardan el valor 42 a una variable local (no necesariamente la misma):
mov 0x2a, -0x4(%ebp)
y
mov 0x2a, 0x10(%esp)
Organización común de stack frame
esp ---> argumento
argumento
argumento
var local
var local
var local
ebp ---> ebp viejo
ret address
Identificando argumentos en assembly
-
La gran mayoría de las funciones invocadas requieren argumentos.
-
Existen varias convenciones sobre cómo se pasan los argumentos.
-
Una de las convenciones más utilizadas es cdecl.
- se pasan los argumentos a través del stack
- valores enteros o direcciónes de memoria se regresan a través de EAX
- el invocante debe EAX, ECX, EDX
- otros detalles
Ejemplo (adapatado de wikipedia)
int foo(int a, int b, int c) {
return a + b + c;
}
int main()
{
int ret;
ret = foo(1, 2, 3);
ret += 5;
return ret;
}
main:
push %ebp ; \
mov %esp,%ebp ; } The prologue
sub $0x1c,%esp ; /
movl $0x3,0x8(%esp) ; \
movl $0x2,0x4(%esp) ; } Pushing the arguments in the stack
movl $0x1,(%esp) ; /
call 80483ed <foo> ; calling the function
mov %eax,-0x4(%ebp) ; \
addl $0x5,-0x4(%ebp) ; } reading the ret value, adding 5,...
mov -0x4(%ebp),%eax ; /
leave
ret
foo:
push %ebp ;
mov %esp,%ebp ; prologue
mov 0xc(%ebp),%eax ; \
mov 0x8(%ebp),%edx ; } - reading the arguments
add %eax,%edx ; }
mov 0x10(%ebp),%eax ; /
add %edx,%eax ; setting the return value
pop %ebp ; epilogue
ret
El stack justo antes de llamar a foo
,
El cuando se está ejecutando foo
,
LEA vs MOV
LEA -- Load Effective Address
LEA calculates the effective address and stores it in the specified register.
Ejemplo: La siguiente instrucción copy a EAX el resultado de la expresión EBP - 0x10. Si EBP contiene 0xfff8090, luego de esta instrucción EAX contendrá 0xfff8080.
lea -0x10(%ebp),%eax
La expresión del source puede contener varios términos. Por ejemplo: La siguiente instrucción copia a EAX el resultado de la expresion EDX - 0x6 + EDX * 4. Si EDX contiene 0x1100, luego de la instrucción EAX contiene 0x54fa.
leal -0x6 (%edx, %edx, 4 )
---- ---- ---- ----
\ \ \ \_ scalar factor
\ \ \_ register
\ \__ base register
\___ displacement
MOV -- Move Data
MOV copies (the content) the source to the destination.
La siguiente instrucción copia el contenido de EBX a EAX. Por ejemplo, si EBX contiene 0xfff8080, luego de la instrucción EAX también contendrá 0xfff8080.
mov %ebx, %eax
La siguiente instrucción copia el contenido de la memoria apuntada por EBX a EAX. Por ejemplo, si EBX contiene 0xfff8080, luego de la instrucción EAX contendrá los 4 bytes que están en la dirección de memoria 0xfff8080.
mov (%ebx), %eax
La siguiente instrucción copia el contenido de la memoria cuya dirección es el resultado de la expresión EBX - 0x10 a EAX. Por ejemplo, si EBX contiene 0xfff8080, luego de la instrucción EAX contendrá los 4 bytes que están en la dirección de memoria 0xfff8070.
mov -0x10(%ebx), %eax
En resumen, si la variable a
vive en el -0x10(%ebp)
, la variable b
en -0x18(%ebp)
y la variable c
en -0x20(%ebp)
El siguiente es equivalente a c = &b
.
lea -0x18(%ebp), %ebx
mov %ebx, -0x20(%ebp)
El siguiente es equivalente a b = a
.
mov -0x10(%ebp), %ebx
mov %ebx, -0x18(%ebp)
ATT vs INTEL
Formato ATT
- Opcode source, destination
- usa prefijo
$
para valores inmediatos,%
para registros. - el registro base se incluye entre paréntesis
int a = 42;
int b = a;
movl $0x2a,-0x10(%ebp)
mov -0x10(%ebp),%eax
mov %eax,-0xc(%ebp)
Formato Intel
- Opcode destination, source
- operaciones para calculo de memoria se incluyen en
[ ]
.
int a = 42;
int b = a;
mov [ebp-0x10],0x2a
mov eax,[ebp-0x10]
mov [ebp-0xc],eax
Estructuras de control en el 80386
El orden para comparar en formato ATT
La siguente instrucción esta la variable -0x8(%ebp) - 0x9
cmpl $0x9,-0x8(%ebp)
Jumps condicionales en x86
Opcode | Description | CPU Flags |
---|---|---|
JA | Above | CF = 0 and ZF = 0 |
JAE | Above or equal | CF = 0 |
JB | Bellow | CF |
JBE | Bellow or equal | CF or ZF |
JC | Carry | CF |
JE | Equality | ZF |
JG | Greater(s) | ZF = 0 and SF = OF |
JGE | Greater or equal(s) | SF = OF |
JL | Less(s) | SF ≠ OF |
JLE | Less equal(s) | ZF or SF ≠ OF |
JNA | Not above | CF or ZF |
JNAE | Neither above nor equal | CF |
JNB | Not bellow | CF = 0 |
JNBE | Neither bellow nor equal | CF = 0 and ZF = 0 |
JNC | Not carry | CF = 0 |
JNE | Not equal | ZF = 0 |
JNG | Not greater | ZF or SF ≠ OF |
JNGE | Neither greater nor equal | SF ≠ OF |
JNL | Not less | SF = OF |
JNLE | Not less nor equal | ZF = 0 and SF = OF |
JNO | Not overflow | OF = 0 |
JNP | Not parity | PF = 0 |
JNS | Not negative | SF = 0 |
JNZ | Not zero | ZF = 0 |
JO | Overflow(s) | OF |
JP | Parity | PF |
JPE | Parity | PF |
JPO | Not parity | PF = 0 |
JS | Negative(s) | SF |
JZ | Null | ZF |
Ejemplo: ¿Cuándo brinca al label02?
cmpl $0x9,-0x8(%ebp)
jge label02
Cómo las instrucciones cambian los flags
Aqui pueden ver como las instrucciones modifican los flags: http://css.csail.mit.edu/6.858/2013/readings/i386/appc.htm
Bit | Name | Function |
---|---|---|
0 | CF | Carry Flag: Set on high-order bit carry or borrow; cleared otherwise. |
2 | PF | Parity Flag -- Set if low-order eight bits of result contain an even number of 1 bits; cleared otherwise. |
4 | AF | Adjust flag -- Set on carry from or borrow to the low order four bits of AL; cleared otherwise. Used for decimal arithmetic. |
6 | ZF | Zero Flag -- Set if result is zero; cleared otherwise. |
7 | SF | Sign Flag -- Set equal to high-order bit of result (0 is positive, 1 if negative). |
11 | OF | Overflow Flag -- Set if result is too large a positive number or too small a negative number (excluding sign-bit) to fit in destination operand; cleared otherwise. |
Status Flag Summary
Key to Codes
T = instruction tests flag
M = instruction modifies flag
(either sets or resets depending on operands)
0 = instruction resets flag
-- = instruction's effect on flag is undefined
blank = instruction does not affect flag
Instruction OF SF ZF AF PF CF
AAA -- -- -- TM -- M
AAS -- -- -- TM -- M
AAD -- M M -- M --
AAM -- M M -- M --
DAA -- M M TM M TM
DAS -- M M TM M TM
ADC M M M M M TM
ADD M M M M M M
SBB M M M M M TM
SUB M M M M M M
CMP M M M M M M
CMPS M M M M M M
SCAS M M M M M M
NEG M M M M M M
DEC M M M M M
INC M M M M M
IMUL M -- -- -- -- M
MUL M -- -- -- -- M
RCL/RCR 1 M TM
RCL/RCR count -- TM
ROL/ROR 1 M M
ROL/ROR count -- M
SAL/SAR/SHL/SHR 1 M M M -- M M
SAL/SAR/SHL/SHR count -- M M -- M M
SHLD/SHRD -- M M -- M M
BSF/BSR -- -- M -- -- --
BT/BTS/BTR/BTC -- -- -- -- -- M
AND 0 M M -- M 0
OR 0 M M -- M 0
TEST 0 M M -- M 0
XOR 0 M M -- M 0
El instruction set completo está disponible en http://css.csail.mit.edu/6.858/2013/readings/i386/c17.htm
Ejemplo: instrucción TEST
TEST computes the bit-wise logical AND of its two operands. The result of the operation is discarded and only the flags are modified.
Usos comúnes: Si deseas probar si el contenido de EAX es 0:
TEST EAX,EAX
y luego verificas el zero flag (usando JE).
Por ejemplo, este pedazo verifica si el resultado de un strcmp
fue 0.
80484dd:call 8048350 <strcmp@plt>
80484e2:test %eax,%eax
80484e4:jne 80484f4 <main+0x57>
80484e6:movl $0x80485b0,(%esp)
80484ed:call 8048370 <puts@plt>
80484f2:jmp 8048500 <main+0x63>
80484f4:movl $0x80485b8,(%esp)
80484fb:call 8048370 <puts@plt>
8048500:mov $0x0,%eax
Figura ilustrando el flujo en esta parte del programa
Como revertir para invertir la lógica del flujo? reemplazar el jne por un je.
Truco mongo para saltar verificación por password :
La única forma de obtener 0 al hacer un AND entre un registro y si mismo es cuando el registro contiene 0.
La operación XOR entre un registro y si mismo siempre dará como resultado 0 (y encenderá el Z flag).
Suponga que tiene una situación como la siguiente. Esta caso si EAX no contiene 0 después de regresas de strcmp, el programa seguirá la ruta del dolor.
80484dd: call 8048350 <strcmp@plt>
80484e2: test %eax,%eax
80484e4: je placer
80484e6: dolor
Si usted quisiera evitarse el dolor (sin importar cuál fue el resultado de strcmp) puede cambiar el test
por xor
. Como xor
siempre da 0, el zero flag se enciende y el je
siempre bricará (de placer drumroll).
80484dd: call 8048350 <strcmp@plt>
80484e2: xor %eax,%eax
80484e4: je placer
80484e6: dolor
Si fueras a cambiar es instrucción en el ejecutable, eso implica buscar el código de xor %eax,%eax
. No te angusties, usa: https://defuse.ca/online-x86-assembler.htm. Algunos editores de hex te permiten entrar la instrucción en assembly, e.g. xor eax,eax
, y lo insertan en hex, e.g. 31 c0
.
Ejemplos de expresiones relacionales compuestas
if ( a > 20 && a < 78) then do A else do B
is changed to if ( a <= 20) jump to labelDoB if ( a > 77 ) jump to labelDoB do A jump to labelAfter labelDoB: do B labelAfter:
804842e: cmpl $0x14,0x1c(%esp) ;} if a <= 20 then jump to do B
8048433: jle 804844a <main+0x2d> ;}
8048435: cmpl $0x4d,0x1c(%esp) ;} if a > 77 then jump to do B
804843a: jg 804844a <main+0x2d> ;}
804843c: movl $0x80484f0,(%esp) ;} do A
8048443: call 80482f0 <puts@plt> ;}
8048448: jmp 8048456 <main+0x39> ;} jump to after
804844a: movl $0x80484f8,(%esp) ;} do B
8048451: call 80482f0 <puts@plt> ;}
8048456: mov $0x0,%eax
Programas útiles para explorar ejecutables
objdump
objdump: desplega informacion sobre archivos binarios (.o, ejecutables, .so). Algunos de los modos que utilizo:
-
objdump -h a.out
- muestra los headers de las secciones del ejecutablea.out
-
objdump -j .rodata -s a.out
- muestra el contenido de la seccion .rodata -
objdump -R a.out
- muestra los dynamic relocation records del ejecutable, i.e. las funciones que seran invocadas de librerias dinamicamente cargadas a memoria (dll en windows, .so en linux) -
objdump -d a.out
- desensambla (la seccion .text) del ejecutable.
readelf: también desplega información sobre archivos de tipo ELF.
hexedit: para modificar archivos en binario
* F3 - guardar
* Ctrl-C - salir
strings: despliega los strings que encuentra en un archivo binario.