Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
static_asm — Ensamblador de solo cabecera en tiempo de compilación en C++2x para la codificación de instrucciones x86/x86-64 | Kitploit
Herramientas/GitHubGitHub/mahmoudimus/static_asm
Generación de PayloadsAnálisis de CódigoExplotaciónIngeniería InversaShellcodeAnálisis de BinariosAprendizaje y EducaciónGeneración de ShellcodeRutas de Aprendizaje y Cursos
GitHubmahmoudimus/static_asm

static_asm

Ensamblador de solo cabecera en tiempo de compilación en C++2x para la codificación de instrucciones x86/x86-64

311hace 6 mesesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
Ver RepositorioSitio web

static_asm

CI License

Una biblioteca C++20 de solo encabezado para codificación de instrucciones x86/x86-64 en tiempo de compilación.

Este proyecto tiene doble licencia bajo la Boost Software License 1.0 y la MIT License. Puedes elegir cualquiera de las dos.

Propósito

  • Aprender codificación de ensamblador x86 de forma práctica y divertida
  • Generar instrucciones de ensamblador en tiempo de compilación con total seguridad de tipos
  • Crear plantillas de shellcode y código JIT sin sobrecarga en tiempo de ejecución

Inicio rápido

root@kitploit:~
#include "static_asm.hpp"

using namespace static_asm::x86::registers;
using namespace static_asm::x86::instructions;

// Construir código máquina en tiempo de compilación
constexpr auto code = core::assemble(
    mov(rax, 0x12345678),    // mov rax, imm32
    add(rax, rcx),           // add rax, rcx
    xor_(r8, r8),            // xor r8, r8
    call(rax),               // call rax
    ret()                    // ret
);
// code es std::array<uint8_t, N> - ¡completamente constexpr!

Ejemplos por categoría

Operaciones ALU

root@kitploit:~
// Registro a registro
add(rax, rbx);           // 48 01 D8
sub(ecx, edx);           // 29 D1
and_(r8, r9);            // 4D 21 C8
or_(rsi, rdi);           // 48 09 FE
xor_(eax, eax);          // 31 C0 (idioma común para poner a cero un registro)
cmp(rax, rcx);           // 48 39 C8

// Registro con inmediato
add(rax, 0x10);          // 48 83 C0 10 (sign-extended imm8)
add(rax, 0x10000);       // 48 05 00 00 01 00 (imm32)
sub(ecx, 100);           // 83 E9 64
and_(rdx, 0xFF);         // 48 83 E2 FF

// Con operandos de memoria
add(eax, dword_ptr(rbx));              // 03 03
add(rax, qword_ptr(rcx + 0x10));       // 48 03 41 10
sub(dword_ptr(rsp + 0x20), eax);       // 29 44 24 20

Movimiento de datos

root@kitploit:~
// Registro a registro
mov(rax, rbx);           // 48 89 D8
mov(eax, ecx);           // 89 C8
mov(r8, r9);             // 4D 89 C8

// Inmediato a registro
mov(rax, 0x12345678);    // 48 C7 C0 78 56 34 12
mov(eax, 0xDEADBEEF);    // B8 EF BE AD DE

// Operaciones de memoria
mov(rax, qword_ptr(rbx));              // 48 8B 03
mov(eax, dword_ptr(rcx + 0x10));       // 8B 41 10
mov(qword_ptr(rsp + 0x8), rax);        // 48 89 44 24 08
mov(dword_ptr(rbp - 0x20), 0x100);     // C7 45 E0 00 01 00 00

// Extensión de cero/signo
movzx(eax, bl);          // 0F B6 C3 (extensión cero de byte a dword)
movzx(rax, bx);          // 48 0F B7 C3 (extensión cero de word a qword)
movsx(eax, cl);          // 0F BE C1 (extensión de signo de byte a dword)
movsx(rax, dx);          // 48 0F BF C2 (extensión de signo de word a qword)
movsxd(rax, ecx);        // 48 63 C1 (extensión de signo de dword a qword)

// Cargar dirección efectiva
lea(rax, qword_ptr(rbx + rcx * s4));           // 48 8D 04 8B
lea(rax, qword_ptr(rbx + rcx * s8 + 0x10));    // 48 8D 44 CB 10

// Intercambio
xchg(rax, rbx);          // 48 87 D8

Direccionamiento SIB (Escala-Índice-Base)

root@kitploit:~
// [base + índice*escala]
mov(eax, dword_ptr(rbx + rcx * s1));   // 8B 04 0B
mov(eax, dword_ptr(rbx + rcx * s2));   // 8B 04 4B
mov(eax, dword_ptr(rbx + rcx * s4));   // 8B 04 8B
mov(eax, dword_ptr(rbx + rcx * s8));   // 8B 04 CB

// [base + índice*escala + desplazamiento]
mov(rax, qword_ptr(rbx + rcx * s4 + 0x10));     // 48 8B 44 8B 10
mov(rax, qword_ptr(r12 + r13 * s8 + 0x1000));   // 4B 8B 84 EC 00 10 00 00

// Almacenar en dirección SIB
mov(dword_ptr(rax + rdx * s4), ecx);            // 89 0C 90
mov(qword_ptr(rbx + rsi * s8 + 0x20), rax);     // 48 89 44 F3 20

// LEA con SIB (útil para cálculos de direcciones)
lea(rax, qword_ptr(rbx + rcx * s4));            // 48 8D 04 8B
lea(rax, qword_ptr(rdi + rsi * s8 + 0x100));    // 48 8D 84 F7 00 01 00 00

Desplazamiento y rotación

root@kitploit:~
// Desplazar por 1
shl(eax, 1);             // D1 E0
shr(rax, 1);             // 48 D1 E8
sar(ecx, 1);             // D1 F9

// Desplazar por inmediato
shl(eax, 4);             // C1 E0 04
shr(rax, 8);             // 48 C1 E8 08
sar(rdx, 16);            // 48 C1 FA 10

// Desplazar por registro CL
shl(eax, cl);            // D3 E0
shr(rax, cl);            // 48 D3 E8

// Rotar
rol(eax, 1);             // D1 C0
ror(rax, 8);             // 48 C1 C8 08
rcl(ecx, cl);            // D3 D1
rcr(rdx, 1);             // 48 D1 DA

Multiplicación y división

root@kitploit:~
// Un solo operando (resultado en rdx:rax)
mul(rbx);                // 48 F7 E3 (sin signo: rdx:rax = rax * rbx)
imul(rcx);               // 48 F7 E9 (con signo: rdx:rax = rax * rcx)
div(rbx);                // 48 F7 F3 (sin signo: rax = rdx:rax / rbx, rdx = resto)
idiv(rcx);               // 48 F7 F9 (división con signo)

// IMUL de dos operandos (dest = dest * src)
imul(rax, rbx);          // 48 0F AF C3
imul(ecx, edx);          // 0F AF CA

// IMUL de tres operandos (dest = src * imm)
imul(rax, rbx, 10);      // 48 6B C3 0A
imul(ecx, edx, 1000);    // 69 CA E8 03 00 00

Flujo de control

root@kitploit:~
// Saltos incondicionales
jmp(0x10);               // EB 10 (corto, offset de 8 bits)
jmp(0x1000);             // E9 00 10 00 00 (cercano, offset de 32 bits)
jmp(rax);                // FF E0 (indirecto)
jmp(here);               // EB FE (jmp $, bucle infinito)

// Saltos condicionales (offset de 8 bits)
jz(0x10);                // 74 10
jnz(0x20);               // 75 20
jb(0x08);                // 72 08 (por debajo/acarreo)
jae(0x08);               // 73 08 (por encima o igual/sin acarreo)
jl(0x10);                // 7C 10 (menor que, con signo)
jge(0x10);               // 7D 10 (mayor o igual, con signo)

// Saltos condicionales (offset de 32 bits para ramas largas)
jz_near(0x10000);        // 0F 84 00 00 01 00
jnz_near(0x20000);       // 0F 85 00 00 02 00

// Llamada y retorno
call(rax);               // FF D0 (llamada indirecta)
call(0x100);             // E8 00 01 00 00 (llamada relativa)
ret();                   // C3
ret(0x10);               // C2 10 00 (retorno y extrae 16 bytes)

Movimientos condicionales

root@kitploit:~
// Mover si la condición es verdadera (¡sin penalización de bifurcación!)
cmovz(rax, rbx);         // 48 0F 44 C3 (mover si cero)
cmovnz(eax, ecx);        // 0F 45 C1 (mover si no cero)
cmovl(rax, rdx);         // 48 0F 4C C2 (mover si menor, con signo)
cmovge(ecx, esi);        // 0F 4D CE (mover si mayor o igual, con signo)
cmovb(rax, rbx);         // 48 0F 42 C3 (mover si por debajo, sin signo)
cmovae(edx, edi);        // 0F 43 D7 (mover si por encima o igual, sin signo)

// Con fuente de memoria
cmovz(rax, qword_ptr(rbx));           // 48 0F 44 03
cmovnz(eax, dword_ptr(rcx + 0x10));   // 0F 45 41 10

Operaciones de bits

root@kitploit:~
// Prueba de bit
bt(eax, 5);              // 0F BA E0 05
bt(rax, rbx);            // 48 0F A3 D8

// Prueba de bit y establecer/restablecer/complementar
bts(eax, 10);            // 0F BA E8 0A (prueba y establece)
btr(rax, rcx);           // 48 0F B3 C8 (prueba y restablece)
btc(edx, 3);             // 0F BA FA 03 (prueba y complementa)

// Escaneo de bits
bsf(eax, ecx);           // 0F BC C1 (escanear hacia adelante el primer 1)
bsr(rax, rbx);           // 48 0F BD C3 (escanear hacia atrás el primer 1)

// Conteo de población y ceros iniciales/finales
popcnt(eax, ecx);        // F3 0F B8 C1
lzcnt(rax, rbx);         // F3 48 0F BD C3
tzcnt(eax, edx);         // F3 0F BC C2

// Intercambio de bytes
bswap(eax);              // 0F C8 (invierte el orden de bytes)
bswap(rax);              // 48 0F C8

Operaciones de cadenas

root@kitploit:~
// Operaciones básicas de cadena (operan sobre [rsi] y/o [rdi])
movsb();                 // A4 (mover byte [rsi] -> [rdi])
movsw();                 // 66 A5
movsd();                 // A5
movsq();                 // 48 A5

cmpsb();                 // A6 (comparar [rsi] con [rdi])
stosb();                 // AA (almacenar al -> [rdi])
lodsb();                 // AC (cargar [rsi] -> al)
scasb();                 // AE (comparar al con [rdi])

// Con prefijo REP (repetir rcx veces)
rep_movsb();             // F3 A4 (memcpy)
rep_movsq();             // F3 48 A5 (memcpy rápida, 8 bytes a la vez)
rep_stosb();             // F3 AA (memset)
rep_stosq();             // F3 48 AB

// Con prefijo REPE/REPNE (repetir mientras igual/no igual)
repe_cmpsb();            // F3 A6 (comparar cadenas hasta discrepancia)
repne_scasb();           // F2 AE (escanear byte en cadena)

Operaciones de pila

root@kitploit:~
push(rax);               // 50
push(rbx);               // 53
push(r8);                // 41 50
push(0x10);              // 6A 10 (push imm8)
push(0x1000);            // 68 00 10 00 00 (push imm32)

pop(rax);                // 58
pop(rbx);                // 5B
pop(r15);                // 41 5F

Instrucciones del sistema

root@kitploit:~
// Llamadas al sistema
syscall_();              // 0F 05 (syscall de 64 bits)
sysenter();              // 0F 34
sysexit();               // 0F 35

// Interrupciones
int3();                  // CC (punto de interrupción)
int_(0x80);              // CD 80 (syscall de Linux de 32 bits)
int_(0x21);              // CD 21 (interrupción de DOS)

// Información de CPU
cpuid();                 // 0F A2
rdtsc();                 // 0F 31
rdtscp();                // 0F 01 F9

// Privilegios
cli();                   // FA (deshabilitar interrupciones)
sti();                   // FB (habilitar interrupciones)
hlt();                   // F4 (detener)

// Retorno de interrupción
iret();                  // CF (16 bits)
iretd();                 // CF (32 bits)
iretq();                 // 48 CF (64 bits)

Ensamblado de múltiples instrucciones

Usa core::assemble() para concatenar arrays de bytes de instrucciones:

root@kitploit:~
constexpr auto prologue = core::assemble(
    push(rbp),
    mov(rbp, rsp),
    sub(rsp, 0x20)
);

constexpr auto epilogue = core::assemble(
    add(rsp, 0x20),
    pop(rbp),
    ret()
);

// Combinarlos
constexpr auto full_function = core::assemble(prologue, epilogue);

Instalación

Opción 1: CMake FetchContent (Recomendado)

Agrega a tu CMakeLists.txt:

root@kitploit:~
include(FetchContent)
FetchContent_Declare(
    static_asm
    GIT_REPOSITORY https://github.com/mahmoudimus/static_asm.git
    GIT_TAG v1.0.0  # o commit específico
)
FetchContent_MakeAvailable(static_asm)

target_link_libraries(your_target PRIVATE static_asm::static_asm)

Opción 2: CMake add_subdirectory

Clona o agrega como submódulo git:

root@kitploit:~
git submodule add https://github.com/mahmoudimus/static_asm.git external/static_asm

Luego en tu CMakeLists.txt:

root@kitploit:~
add_subdirectory(external/static_asm)
target_link_libraries(your_target PRIVATE static_asm::static_asm)

Al incluirse mediante add_subdirectory o FetchContent, solo se agrega a tu proyecto el objetivo de biblioteca de interfaz static_asm::static_asm. Las pruebas y ejemplos no se construyen a menos que se habilite explícitamente con -DSTATIC_ASM_BUILD_TESTS=ON.

Opción 3: Encabezado único

Descarga static_asm.hpp desde la página de versiones e inclúyelo directamente:

root@kitploit:~
#include "static_asm.hpp"

Opción 4: Instalación del sistema

root@kitploit:~
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --install build --prefix /usr/local

Luego usa find_package:

root@kitploit:~
find_package(static_asm REQUIRED)
target_link_libraries(your_target PRIVATE static_asm::static_asm)

Compilación

root@kitploit:~
# Configurar
cmake -B build -DCMAKE_BUILD_TYPE=Release

# Compilar
cmake --build build

# Ejecutar pruebas
ctest --test-dir build --output-on-failure

# Compilar con ejemplos (solo Clang, usa ensamblado en línea)
cmake -B build -DCMAKE_BUILD_TYPE=Release -DSTATIC_ASM_BUILD_EXAMPLES=ON

Soporte de plataformas:

  • Linux (GCC 11+, Clang 14+)
  • macOS (Apple Clang, Clang)
  • Windows (MSVC 2022+)

Nota: La función core::emit() de ensamblado en línea requiere Clang con optimización -O2.

Instrucciones soportadas

Soporte de operandos:

  • Todos los registros de propósito general de 8/16/32/64 bits (AL-R15)
  • Registros extendidos (R8-R15, R8D-R15D, R8W-R15W, R8B-R15B)
  • Valores inmediatos (8/16/32/64 bits)
  • Operandos de memoria con registro base y desplazamiento
  • Direccionamiento SIB: [base + índice*escala + desplazamiento] con factores de escala 1, 2, 4, 8

Nota: Aún no hay extensiones SIMD/AVX.

Desarrollo

Configuración del entorno

Este proyecto usa uv para herramientas Python (generación de código, amalgamación de encabezado único).

root@kitploit:~
# Instalar uv (si aún no está instalado)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Verificar instalación
uv --version

# Todos los scripts Python se pueden ejecutar directamente con uv (las dependencias se gestionan automáticamente)
uv run scripts/gen_from_x86ref.py --help
uv run scripts/amalgamate.sh

Herramientas requeridas:

Herramientas opcionales para desarrollo:

HerramientaPropósitoInstalación
clang-formatFormateo de códigoVía LLVM o paquete del sistema
clang-tidyAnálisis estáticoVía LLVM o paquete del sistema

Añadir nuevas instrucciones

Opción 1: Usar el generador de código

El proyecto incluye un generador que analiza la base de datos XML de x86reference:

root@kitploit:~
# Mostrar resumen de la base de datos de instrucciones
uv run scripts/gen_from_x86ref.py

# Mostrar detalles de una instrucción específica
uv run scripts/gen_from_x86ref.py -i lea
uv run scripts/gen_from_x86ref.py -i imul

# Generar archivos de base de datos de instrucciones
uv run scripts/gen_from_x86ref.py --generate-db

# Generar archivo de pruebas exhaustivas
uv run scripts/gen_from_x86ref.py --generate-tests

Opción 2: Adición manual

  1. Agregar al archivo db de instrucciones (arrays instdb, prefix_db, prefix_0fdb)
  2. Codificar el codificador en encoder.hpp o extender un codificador existente
  3. Agregar pruebas

Técnicas para crear una biblioteca de solo un encabezado

Ninguna herramienta automática puede convertir de manera confiable una biblioteca C++ arbitraria de varios archivos en una versión limpia y de solo encabezado sin cierta preparación manual. Las siguientes técnicas ayudan a garantizar que tu biblioteca pueda amalgamarse exitosamente en un solo archivo de encabezado manteniendo corrección, mantenibilidad y conformidad con los estándares.

Nota: Este proyecto usa quom para amalgamación y clang-tidy con la verificación google-build-using-namespace para automatizar la aplicación de estas reglas. quom también maneja parcialmente la técnica #4 (marcadores inline) a través de sus capacidades de procesamiento.

1. Evitar using namespace en archivos fuente

using namespace a nivel de archivo en archivos .cpp es peligroso cuando esos archivos se incluyen posteriormente en un encabezado: contamina el espacio de nombres global para cada unidad de traducción que incluya tu encabezado.

Patrones recomendados en su lugar:

root@kitploit:~
// Preferido: envolver la implementación en un espacio de nombres
namespace MyLib {
    Foo::Foo() {
        // ...
    }
}

o

root@kitploit:~
// Calificación explícita (más verbosa pero muy clara)
MyLib::Foo::Foo() {
    // ...
}

2. Colocar las API internas/privadas en un espacio de nombres anidado

Las API públicas deben residir en el espacio de nombres principal. Todo lo que no esté destinado a usuarios finales debe ocultarse en un espacio de nombres anidado como detail o impl.

Convenciones comunes:

root@kitploit:~
namespace MyLib {
    namespace detail {           // muy utilizado
        // clases internas, funciones, etc.
    }
}

o

root@kitploit:~
namespace MyLib::impl {          // más corto, también común
    // detalles internos de implementación
}

C++17 y posteriores admiten definiciones de espacios de nombres anidados en línea, que son más limpias:

root@kitploit:~
namespace MyLib::detail {
    class InternalHelper { /* ... */ };
}

3. Convertir datos estáticos a nivel de archivo en miembros de clase static inline

Las variables static a nivel de archivo definidas en archivos .cpp se vuelven problemáticas en un mundo de solo encabezado (definiciones múltiples, violaciones de ODR).

Solución moderna (C++17+):

root@kitploit:~
// Antes (en .cpp)
namespace MyLib {
    static int s_counter = 0;

    int next_id() {
        return ++s_counter;
    }
}
root@kitploit:~
// Después (seguro para encabezado)
namespace MyLib::detail {
    struct Globals {
        static inline int counter = 0;
    };
}

inline int MyLib::next_id() {
    return ++detail::Globals::counter;
}

La variable static inline tiene garantizada una única definición incluso cuando se incluye múltiples veces.

4. Marcar funciones definidas fuera de cuerpos de clase como inline

Cualquier función, función miembro, constructor o destructor cuyo cuerpo aparezca en el encabezado (pero no dentro de la definición de la clase) debe marcarse como inline para evitar violaciones de la Regla de Definición Única (ODR).

Debido a que muchos scripts de amalgamación son puramente textuales y no analizan la semántica de C++, una convención común es usar una macro de marcador de posición (por ejemplo, inline_t) durante el desarrollo:

root@kitploit:~
// MyLib.h (o encabezado común)
#define inline_t   /* vacío durante compilaciones normales */

// MyLib.cpp (durante desarrollo)
namespace MyLib::detail {
    inline_t void Helper::do_work() {
        // implementación
    }
}

Durante la amalgamación, la herramienta reemplaza inline_t con inline:

root@kitploit:~
// Después de amalgamación / transformación
inline void MyLib::detail::Helper::do_work() {
    // ...
}

Puedes elegir cualquier nombre de macro que prefieras (ej. MYLIB_INLINE, INLINE_IMP, etc.) y configurar tu script de amalgamación en consecuencia.

Nota: Herramientas como quom pueden automatizar parcialmente esto al comprender las semánticas de inclusión de C++ y manejar adecuadamente las definiciones de funciones durante la amalgamación, reduciendo la necesidad de marcadores inline manuales en muchos casos.

Resumen: las cuatro reglas clave

  1. Nunca escribas using namespace … a nivel de espacio de nombres/archivo en archivos de implementación.
  2. Coloca todos los símbolos internos/no públicos en un espacio de nombres anidado (detail / impl).
  3. Reemplaza los datos static a nivel de archivo con miembros static inline de una estructura/clase.
  4. Marca los cuerpos de funciones fuera de línea con una macro marcadora inline (reemplazada durante la amalgamación).

Seguir estas cuatro prácticas hace que la transición a una distribución de solo encabezado sea mucho más suave y menos propensa a errores, incluso cuando se utilizan herramientas de amalgamación puramente basadas en texto.

Créditos

  • Godbolt para prototipado
  • Manual de Intel x86-64 manual
  • Defuse.ca para verificar salidas
  • Referencia Geek ABC
  • mazegen/x86reference para la base de datos XML de instrucciones

Agradecimientos

Este proyecto está basado en cx_assembler de Midi12. La biblioteca original proporcionó la base para la codificación de ensamblador x86 en tiempo de compilación en C++.

Descargar herramienta
CategoríaInstrucciones
ALUADD, ADC, SUB, SBB, AND, OR, XOR, CMP, TEST
UnarioINC, DEC, NEG, NOT
Multiplicación/DivisiónMUL, IMUL (formas de 1/2/3 operandos), DIV, IDIV
Movimiento de datosMOV, MOVABS, MOVZX, MOVSX, MOVSXD, LEA, XCHG, PUSH, POP
Desplazamiento/RotaciónSHL, SHR, SAL, SAR, ROL, ROR, RCL, RCR
Flujo de controlJMP, CALL, RET, RETF
Saltos condicionalesJZ/JE, JNZ/JNE, JB/JC, JNB/JNC, JBE/JNA, JNBE/JA, JL, JNL, JLE, JNLE, JO, JNO, JS, JNS, JP, JNP (offsets de 8 bits y 32 bits)
Movimientos condicionalesCMOVA, CMOVAE, CMOVB, CMOVBE, CMOVE, CMOVG, CMOVGE, CMOVL, CMOVLE, CMOVNE, CMOVNO, CMOVNP, CMOVNS, CMOVO, CMOVP, CMOVS
Operaciones de bitsBT, BTC, BTR, BTS
Escaneo/Conteo de bitsBSF, BSR, POPCNT, LZCNT, TZCNT, BSWAP
Operaciones de cadenasMOVSB/W/D/Q, CMPSB/W/D/Q, LODSB/W/D/Q, STOSB/W/D/Q, SCASB/W/D/Q (con prefijos REP/REPE/REPNE)
SistemaSYSCALL, SYSENTER, SYSEXIT, INT, INT3, IRET/D/Q, CLI, STI, HLT, CPUID, RDTSC, RDTSCP
MisceláneaNOP, UD2
HerramientaPropósitoInstalación
uvGestor de paquetes/proyectos Pythoncurl -LsSf https://astral.sh/uv/install.sh | sh
quomAmalgamación de encabezado únicouv tool install quom
CMake 3.19+Sistema de compilacióncmake.org
Compilador C++20GCC 11+, Clang 14+, MSVC 2022+-