Registros x86 y x64: Proposito General, Segmento y Flags
Guia completa de registros en arquitecturas x86 y x64. Registros de proposito general (EAX-ESP, RAX-RSP), registros de segmento, EFLAGS/RFLAGS y su papel en el analisis de malware y reverse engineering.
Los registros como estado del procesador
Cuando depuras malware en x64dbg o analizas estaticamente en Ghidra, los registros son lo primero que observas. Representan el estado instantaneo del procesador: que valores esta manejando, donde apunta el siguiente codigo a ejecutar, cual es la cima de la pila. Dominar los registros es dominar la lectura de ensamblador.
Este articulo cubre los tres grupos de registros que necesitas conocer: proposito general (donde ocurre el trabajo), flags (que controlan el flujo de ejecucion) y segmento (que el malware abusa para tecnicas avanzadas).
Registros de proposito general en x86 (32 bits)
La arquitectura x86 tiene 8 registros de proposito general de 32 bits. Aunque se llaman "de proposito general", cada uno tiene un uso convencional que los compiladores y los programadores de malware respetan la mayoria del tiempo.
EAX: el acumulador
EAX es el registro mas importante en analisis de malware. Todas las funciones de la API de Windows devuelven su resultado en EAX. Cuando ves un CALL a CreateFileA seguido de un MOV [ebp-0x10], eax, sabes que el handle del archivo se guarda en una variable local.
EAX tambien se usa para operaciones aritmeticas. En multiplicaciones (MUL, IMUL) y divisiones (DIV, IDIV), EAX es un operando implicito. El resultado de MUL se almacena en EDX:EAX (64 bits entre los dos registros).
Subdivision del registro:
| Nombre | Bits | Descripcion |
|---|---|---|
| RAX | 63-0 | Registro completo de 64 bits (solo x64) |
| EAX | 31-0 | 32 bits inferiores |
| AX | 15-0 | 16 bits inferiores de EAX |
| AH | 15-8 | Byte alto de AX |
| AL | 7-0 | Byte bajo de AX |
En malware es comun ver operaciones sobre AL para manipular bytes individuales. Por ejemplo, un loop de descifrado XOR tipicamente opera sobre AL: xor al, 0x5A.
EBX: registro base
EBX se usa convencionalmente como puntero base a datos. En malware de 32 bits compilado con MSVC, EBX suele preservarse entre llamadas a funciones (es un registro "callee-saved"), lo que lo hace util para almacenar valores que deben sobrevivir a llamadas a API.
En shellcode y malware que resuelve APIs dinamicamente, EBX frecuentemente almacena la direccion base de kernel32.dll obtenida via PEB.
ECX: contador y parametro
ECX tiene un doble rol. Historicamente es el registro contador: las instrucciones REP (repeat) y LOOP decrementan ECX automaticamente. Todavia ves esto en malware que usa REP MOVSB para copiar bloques de memoria.
En la convencion de llamada __thiscall de C++ (usada por MSVC), ECX contiene el puntero this del objeto. Si el malware esta escrito en C++, veras el puntero this en ECX antes de llamadas a metodos virtuales.
En la convencion __fastcall de Windows (32 bits), ECX y EDX reciben los dos primeros parametros enteros. Esto es relevante porque algunas APIs internas de Windows usan fastcall.
EDX: datos y extension
EDX funciona como extension de EAX en operaciones de 64 bits sobre registros de 32 bits. En multiplicaciones, el resultado de 64 bits se almacena en EDX:EAX (EDX tiene los 32 bits altos). En divisiones, EDX contiene el resto.
En __fastcall, EDX recibe el segundo parametro entero.
ESI y EDI: indices de origen y destino
ESI (Source Index) y EDI (Destination Index) se usan en operaciones de copia de bloques de memoria con las instrucciones REP MOVSB/MOVSW/MOVSD. ESI apunta al origen, EDI al destino.
En malware, el patron tipico es:
mov esi, direccion_origen
mov edi, direccion_destino
mov ecx, longitud_bytes
rep movsb ; copia ECX bytes de [ESI] a [EDI]
Este patron aparece en malware que copia shellcode a memoria asignada con VirtualAlloc, o que mueve codigo desempaquetado a su ubicacion final.
EBP: puntero base del stack frame
EBP apunta a la base del stack frame de la funcion actual. En el esquema clasico de stack frames (que MSVC y GCC usan por defecto en 32 bits), EBP sirve como referencia fija para acceder a parametros y variables locales:
; Parametros de la funcion (pasados por el caller)
[ebp+0x8] ; primer parametro
[ebp+0xC] ; segundo parametro
[ebp+0x10] ; tercer parametro
; Variables locales (asignadas en el prologo)
[ebp-0x4] ; primera variable local
[ebp-0x8] ; segunda variable local
[ebp-0xC] ; tercera variable local
; Valores guardados
[ebp+0x0] ; EBP del caller (guardado por PUSH EBP)
[ebp+0x4] ; direccion de retorno (guardada por CALL)
Algunos compiladores pueden omitir EBP como frame pointer (optimizacion "frame pointer omission" o FPO). En ese caso, todas las referencias al stack usan ESP directamente, lo que hace el analisis mas dificil porque ESP cambia con cada PUSH/POP.
ESP: puntero de pila
ESP siempre apunta al tope de la pila. PUSH decrementa ESP en 4 (32 bits) y escribe el valor. POP lee el valor y incrementa ESP en 4. ESP cambia constantemente durante la ejecucion, lo que lo diferencia de EBP (que permanece fijo dentro de una funcion).
Nunca debes perder de vista ESP cuando depuras malware. Un ESP corrupto (por un stack buffer overflow o un desbalance de PUSH/POP) causa crashes inmediatos.
Registros de proposito general en x64 (64 bits)
La extension a 64 bits mantiene todos los registros de x86 y los extiende a 64 bits. RAX contiene EAX como sus 32 bits inferiores. Ademas, x64 anade 8 registros nuevos.
Registros extendidos: RAX-RSP
Cada registro de 32 bits tiene su version de 64 bits con el prefijo R:
| x86 (32 bits) | x64 (64 bits) | Tamano |
|---|---|---|
| EAX | RAX | 64 bits |
| EBX | RBX | 64 bits |
| ECX | RCX | 64 bits |
| EDX | RDX | 64 bits |
| ESI | RSI | 64 bits |
| EDI | RDI | 64 bits |
| EBP | RBP | 64 bits |
| ESP | RSP | 64 bits |
| EIP | RIP | 64 bits |
Una regla importante: escribir en un subregistro de 32 bits (EAX) automaticamente pone a cero los 32 bits superiores del registro de 64 bits (RAX). Pero escribir en un subregistro de 16 u 8 bits (AX, AL) NO afecta a los bits superiores. Esto puede causar bugs sutiles que el malware a veces explota.
Registros nuevos: R8-R15
x64 anade 8 registros completamente nuevos, numerados R8 a R15. Cada uno tiene subregistros:
| 64 bits | 32 bits | 16 bits | 8 bits |
|---|---|---|---|
| R8 | R8D | R8W | R8B |
| R9 | R9D | R9W | R9B |
| R10 | R10D | R10W | R10B |
| R11 | R11D | R11W | R11B |
| R12 | R12D | R12W | R12B |
| R13 | R13D | R13W | R13B |
| R14 | R14D | R14W | R14B |
| R15 | R15D | R15W | R15B |
En la convencion de llamada de Windows x64, los primeros cuatro parametros enteros van en RCX, RDX, R8 y R9 (en ese orden). Los demas van en el stack. El valor de retorno sigue en RAX.
Esto cambia significativamente como lees el ensamblador de malware de 64 bits respecto al de 32 bits. En lugar de buscar una secuencia de PUSH para los parametros antes de un CALL, buscas MOVs a RCX, RDX, R8, R9.
Registro de flags: EFLAGS / RFLAGS
El registro de flags es de 32 bits en x86 (EFLAGS) y 64 bits en x64 (RFLAGS, aunque los bits superiores no se usan). Cada bit individual es un flag que refleja el resultado de la ultima operacion aritmetica o logica.
Los flags que importan para analisis de malware:
Zero Flag (ZF, bit 6)
Se activa (ZF=1) cuando el resultado de la ultima operacion fue cero. Es el flag mas comun en analisis de malware porque las comparaciones (CMP) y los tests (TEST) lo usan:
cmp eax, 0 ; compara EAX con 0
jz no_encontrado ; salta si EAX era 0 (ZF=1)
test eax, eax ; AND logico de EAX consigo mismo
jnz encontrado ; salta si EAX no era 0 (ZF=0)
El patron test eax, eax seguido de jnz es la forma estandar en que los compiladores verifican si una funcion devolvio un valor no nulo (exito en muchas APIs de Windows).
Sign Flag (SF, bit 7)
Se activa cuando el resultado de la ultima operacion fue negativo (el bit mas significativo es 1). Relevante en comparaciones con signo.
Carry Flag (CF, bit 0)
Se activa cuando hay un acarreo en operaciones aritmeticas sin signo. Por ejemplo, si sumas dos numeros de 32 bits y el resultado excede 0xFFFFFFFF, CF se activa.
Las instrucciones JB (Jump if Below) y JAE (Jump if Above or Equal) leen CF para comparaciones sin signo.
Overflow Flag (OF, bit 11)
Se activa cuando hay desbordamiento en operaciones aritmeticas con signo. La diferencia con CF es que OF se refiere a la interpretacion con signo del resultado.
Direction Flag (DF, bit 10)
Controla la direccion de las instrucciones de cadena (REP MOVSB, REP STOSB). Si DF=0, ESI/EDI se incrementan (copian hacia adelante). Si DF=1, se decrementan (copian hacia atras). En malware, a veces se manipula DF con STD (Set Direction) y CLD (Clear Direction) para copias inversas.
Trap Flag (TF, bit 8)
Activa el modo single-step: el procesador genera una excepcion de debug despues de cada instruccion. El malware usa TF como tecnica anti-debug. Si un debugger esta presente, puede manejar la excepcion. Si no hay debugger, el programa la maneja con un SEH handler, lo que le permite detectar si esta siendo depurado.
Tabla de saltos condicionales y flags
| Instruccion | Condicion | Flags | Uso tipico |
|---|---|---|---|
| JZ / JE | Igual / Cero | ZF=1 | Despues de CMP a, b |
| JNZ / JNE | No igual / No cero | ZF=0 | Despues de TEST eax, eax |
| JG / JNLE | Mayor (con signo) | ZF=0, SF=OF | Comparacion con signo |
| JGE / JNL | Mayor o igual | SF=OF | Comparacion con signo |
| JL / JNGE | Menor (con signo) | SF!=OF | Comparacion con signo |
| JLE / JNG | Menor o igual | ZF=1 o SF!=OF | Comparacion con signo |
| JA / JNBE | Mayor (sin signo) | CF=0, ZF=0 | Comparacion sin signo |
| JAE / JNB | Mayor o igual (sin signo) | CF=0 | Comparacion sin signo |
| JB / JNAE | Menor (sin signo) | CF=1 | Comparacion sin signo |
| JBE / JNA | Menor o igual (sin signo) | CF=1 o ZF=1 | Comparacion sin signo |
Registros de segmento
Los registros de segmento son CS (Code Segment), DS (Data Segment), SS (Stack Segment), ES (Extra Segment), FS y GS. En el modelo de memoria flat que usan Windows y Linux modernos, CS, DS, SS y ES tienen base 0 y limite 4GB, asi que son efectivamente transparentes.
Los registros que importan para analisis de malware son FS y GS:
FS en Windows 32 bits
FS apunta al Thread Environment Block (TEB), tambien conocido como Thread Information Block (TIB). El TEB contiene informacion critica que el malware explota:
; Acceder al PEB (Process Environment Block) via TEB
mov eax, fs:[0x30] ; TEB.ProcessEnvironmentBlock = PEB
; Acceder a la lista de modulos cargados via PEB
mov eax, [eax+0x0C] ; PEB.Ldr (PEB_LDR_DATA)
mov eax, [eax+0x14] ; InMemoryOrderModuleList
; El primer modulo es el propio exe, el segundo ntdll.dll, el tercero kernel32.dll
Este patron es fundamental en shellcode y malware que resuelve APIs sin usar la Import Address Table. Recorriendo la lista de modulos cargados, el malware encuentra kernel32.dll, busca su Export Directory y localiza funciones como LoadLibraryA y GetProcAddress. A partir de ahi, puede cargar cualquier DLL y resolver cualquier funcion.
Otro acceso comun via FS:
mov eax, fs:[0x00] ; Puntero al SEH handler actual (anti-debug)
mov eax, fs:[0x18] ; Puntero al propio TEB (self-reference)
mov eax, fs:[0x20] ; Process ID
mov eax, fs:[0x24] ; Thread ID
GS en Windows 64 bits
En x64, GS reemplaza a FS para acceder al TEB:
mov rax, gs:[0x60] ; TEB.ProcessEnvironmentBlock = PEB (offset diferente en x64)
mov rax, gs:[0x30] ; Puntero al propio TEB
Los offsets cambian entre 32 y 64 bits porque las estructuras TEB y PEB tienen tamanos diferentes debido a los punteros de 8 bytes.
GS en Linux 64 bits
En Linux, FS se usa para Thread Local Storage (TLS) y GS para el kernel. La estructura es diferente a Windows, pero el concepto es similar: un registro de segmento apunta a datos per-thread que el malware de Linux puede explotar.
Registros SIMD: XMM y YMM
Los registros XMM0-XMM15 (128 bits) y YMM0-YMM15 (256 bits) son registros SIMD (Single Instruction Multiple Data) para operaciones vectoriales. En el contexto de malware:
La convencion de Windows x64 pasa parametros de punto flotante en XMM0-XMM3. Si ves movss o movsd antes de un CALL, se estan pasando parametros float/double.
Algunos malware usan instrucciones SSE/AVX para cifrado rapido (AES-NI usa registros XMM) o para mover grandes bloques de datos (MOVDQA mueve 16 bytes de una vez).
Los registros XMM tambien se usan como tecnica anti-emulacion. Algunos emuladores y sandboxes no implementan correctamente todas las instrucciones SSE, asi que el malware ejecuta una operacion SSE especifica para detectar si esta en un entorno virtualizado.
Aplicacion practica: leer registros en un debugger
Cuando depuras malware en x64dbg, la ventana de registros muestra el estado actual de todos los registros. Un flujo tipico de analisis:
- Pon un breakpoint en una llamada a API sospechosa (por ejemplo, VirtualAlloc)
- Cuando el breakpoint se active, lee los parametros en los registros (RCX=direccion, RDX=tamano, R8=tipo, R9=proteccion en x64)
- Si R9 contiene 0x40 (PAGE_EXECUTE_READWRITE), sabes que el malware esta asignando memoria ejecutable, probablemente para shellcode
- Deja que la funcion retorne y lee RAX: contiene la direccion de la memoria asignada
- Pon un breakpoint de escritura en esa direccion para ver cuando el malware escribe el shellcode
Este flujo muestra por que conocer los registros es esencial: te permite interpretar parametros y valores de retorno de funciones del sistema operativo sin necesidad de documentacion adicional.
Resumen
Los registros de proposito general (EAX-ESP en x86, RAX-R15 en x64) son donde ocurre el trabajo computacional. EAX/RAX almacena valores de retorno. ECX/RCX es el primer parametro en convenciones modernas. ESP/RSP controla la pila.
EFLAGS/RFLAGS controla el flujo de ejecucion mediante flags de condicion. ZF (cero), SF (signo), CF (acarreo) y OF (overflow) determinan si los saltos condicionales se toman o no.
FS y GS son los registros de segmento que importan en malware: proporcionan acceso al TEB/PEB, que es la puerta de entrada para resolucion dinamica de APIs, anti-debug y otras tecnicas avanzadas.
Con este conocimiento de registros, el siguiente articulo cubre las instrucciones basicas que operan sobre ellos: MOV, ADD, SUB, CMP, JMP y sus variantes.
Preguntas frecuentes
Libros recomendados
Artículos relacionados
Este contenido tiene fines exclusivamente educativos y de investigación en ciberseguridad defensiva. No se proporcionan binarios maliciosos ni payloads ejecutables. El uso indebido de esta información es responsabilidad exclusiva del usuario. Leer disclaimer completo.