Principianteensambladorx86x64registrosreverse-engineering

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.

MalwareIntel Research··13 min lectura
Serie: Lenguaje Ensamblador — Parte 2

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:

NombreBitsDescripcion
RAX63-0Registro completo de 64 bits (solo x64)
EAX31-032 bits inferiores
AX15-016 bits inferiores de EAX
AH15-8Byte alto de AX
AL7-0Byte 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
EAXRAX64 bits
EBXRBX64 bits
ECXRCX64 bits
EDXRDX64 bits
ESIRSI64 bits
EDIRDI64 bits
EBPRBP64 bits
ESPRSP64 bits
EIPRIP64 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 bits32 bits16 bits8 bits
R8R8DR8WR8B
R9R9DR9WR9B
R10R10DR10WR10B
R11R11DR11WR11B
R12R12DR12WR12B
R13R13DR13WR13B
R14R14DR14WR14B
R15R15DR15WR15B

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

InstruccionCondicionFlagsUso tipico
JZ / JEIgual / CeroZF=1Despues de CMP a, b
JNZ / JNENo igual / No ceroZF=0Despues de TEST eax, eax
JG / JNLEMayor (con signo)ZF=0, SF=OFComparacion con signo
JGE / JNLMayor o igualSF=OFComparacion con signo
JL / JNGEMenor (con signo)SF!=OFComparacion con signo
JLE / JNGMenor o igualZF=1 o SF!=OFComparacion con signo
JA / JNBEMayor (sin signo)CF=0, ZF=0Comparacion sin signo
JAE / JNBMayor o igual (sin signo)CF=0Comparacion sin signo
JB / JNAEMenor (sin signo)CF=1Comparacion sin signo
JBE / JNAMenor o igual (sin signo)CF=1 o ZF=1Comparacion 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:

  1. Pon un breakpoint en una llamada a API sospechosa (por ejemplo, VirtualAlloc)
  2. Cuando el breakpoint se active, lee los parametros en los registros (RCX=direccion, RDX=tamano, R8=tipo, R9=proteccion en x64)
  3. Si R9 contiene 0x40 (PAGE_EXECUTE_READWRITE), sabes que el malware esta asignando memoria ejecutable, probablemente para shellcode
  4. Deja que la funcion retorne y lee RAX: contiene la direccion de la memoria asignada
  5. 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

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.