Las instrucciones indocumentadas, o los op_codes, son un tipo de instrucciones presentes en muchos procesadores antiguos y actuales, pero son también unas completas desconocidas para muchos, resultando incluso hasta misteriosas o sospechosas para los más paranoicos con los temas de la seguridad. En este artículo vamos a ver qué son estas instrucciones y por qué están ahí…
Índice de contenidos
Una instrucción, código de operación u op_code, como tantas veces he explicado, es un código binario que cuando llega a la CPU, la unidad de control mediante el decodificador la decodificará para determinar qué operación tiene implícita para operar con los datos que la acompañan. Por ejemplo, una instrucción puede ser ADD (suma), SUB (resta), MUL (multiplicación), DIV (división), AND (Y lógico), OR (O lógico), etc., es decir, operaciones aritmeticológicas aplicadas sobre datos enteros o de coma flotante, que son los operandos.
Como debes saber, un programa no es más que una consecución de instrucciones de este tipo. Por ejemplo, veamos un código fuente en C para un programa simple que muestra en pantalla un Hola mundo:
#include <stdio.h>
int main() {
printf("¡Hola mundo!");
return 0;
}
Cuando este código se pasa a lenguaje ensamblador, por ejemplo el de la ISA x86-64, obtenemos estas instrucciones que la CPU deberá procesar para que este programa se pueda ejecutar:
global _start
section .text
_start:
mov rax, 1 ; escribe
mov rdi, 1 ; en la salida estándar (pantalla)
mov rsi, msg ; el mensaje Hola mundo.
mov rdx, msglen ; con una determinada longitud
syscall ; y esta es la llamada al systema o sycall para esta escritura
mov rax, 60 ; finalmente
mov rdi, 0 ; se carga el valor
syscall ; para la syscall que finaliza el programa
section .rodata
msg: db "¡Hola mundo!", 12
msglen: equ $ - msg
Como ves, lo que tendría que ejecutar la CPU para que este programa funcione es una serie de instrucciones MOV, que son movimientos de datos a registros, y la instrucción syscall que en x86-64 corresponde a la llamada al sistema, aunque en x86 más antiguos puede usarse la instrucción int. Por otro lado están los datos, que en este programa son una serie de constantes y el mensaje Hola mundo…
Estos op_codes o instrucciones son los que están definidos en la ISA de la CPU, es decir, en la arquitectura. Por tanto, si la ISA cambia, también deben hacerlo el código ensamblador para que sea comprensible por la CPU. El código ensamblador no es más que una serie de mnemónicos para representar las instrucciones de la ISA.
Una vez que este código se pasa a binario, es decir, se convierte en código máquina o unos y ceros, ya es comprensible por la CPU y la electrónica.
El sistema operativo puede cargarlo en la memoria RAM como un proceso cuando se ejecuta el binario ejecutable y desde allí la CPU comenzará a acceder a las instrucciones y datos que componente este programa. Lo hará de forma secuencial, es decir, en orden, instrucción por instrucción.
Cuando, por ejemplo, llegue la primera instrucción MOV a la CPU, primero pasará a la unidad de control, concretamente al decodificador. Éste, gracias al microcódigo, sabrá decodificar la instrucción, que representa un movimiento de datos al registro en este caso.
Una vez decodificada, la unidad de control sabrá que es una instrucción de movimiento, por lo que generará unas señales de control que indicarán a las unidades de ejecución lo que deben hacer. En este caso el movimiento. Pero igual si fuese una suma, una multiplicación, etc. Así es como funciona la base de la informática.
Es decir, la instrucción MOV, es un op_code (tipo: b8 01 00 00 00) que corresponde en x86 a una serie de códigos binarios, y MOV RAX, 1, lo que hará es grabar una constante, en este caso 1, al registro RAX de la CPU. Cuando llegue este código, el decodificador buscará en la ROM del microcódigo para obtener la interpretación.
Y ¿por qué te cuento esto? Muy sencillo, quería que entendieses esto para saber qué es un op_code o instrucción, y cómo funciona.
Como puedes deducir, existen op_codes o instrucciones de varios tipos, para que la CPU pueda ejecutar cualquier programa. En el ejemplo anterior hemos usado solamente un hola mucho, para lo cual con instrucciones MOV y syscall es suficiente. Por ejemplo, veamos este otro código en C para sumar dos números enteros:
#include <stdio.h>
int main() {
int num1, num2, suma;
printf("Introduce dos números enteros: ");
scanf("%d %d", &num1, &num2);
// calcula la suma
suma = num1 + num2;
//Muestra el resultado
printf("%d + %d = %d", num1, num2, suma);
return 0;
}
El ensamblador para este sería este otro código:
.LC0: .string"Introduce dos numeros enteros: " .LC1: .string"%d %d" .LC2: .string"%d + %d = %d" main: push rbp mov rbp, rsp sub rsp, 16 mov edi, OFFSETFLAT:.LC0 mov eax, 0 call printf lea rdx, [rbp-12] lea rax, [rbp-8] mov rsi, rax mov edi, OFFSETFLAT:.LC1 mov eax, 0 call__isoc99_scanf mov edx, DWORDPTR [rbp-8] mov eax, DWORDPTR [rbp-12] add eax, edx mov DWORDPTR [rbp-4], eax mov edx, DWORDPTR [rbp-12] mov eax, DWORDPTR [rbp-8] mov ecx, DWORDPTR [rbp-4] mov esi, eax mov edi, OFFSETFLAT:.LC2 mov eax, 0 call printf mov eax, 0 leave ret
Como ves, en este otro programa también se usan otras instrucciones, como es el caso de ADD EAX, EDX, es decir, los valores de num1 y num2 que se han cargado previamente en estos registros.
Lo que pretendo decirte con esto es que las instrucciones no solo son de movimiento de datos, también podemos encontrar tipos como:
También te interesará conocer cuáles son las mejores CPUs del mercado. ¿Tendrán este tipo de instrucciones? ¿Te atreves a averiguarlo?
Un illegal op_code, o instrucción no documentada, o instrucción no deseada, es aquella instrucción que el fabricante de la CPU no ha documentado para que sea usada por los programadores. Y el motivo para que esto ocurra pueden ser varios:
En las actuales CPUs, si hubiese algún fallo, se podría corregir mediante un parche del microcódigo o firmware. Antes era más difícil con las ROMs o las unidades de control cableadas, donde simplemente no se podía hacer nada…
Sea como sea, estas instrucciones ilegales son más populares de lo que muchos creen.
Por ejemplo, uno de los primeros casos de illegal op_codes detectados fue el Intel 8086, el Zilog Z80, el Texas Instruments TM9900, o el MOS Technology 6502 de la década de los 1970. Pero no solo estaban presentes en estas CPUs antiguas, también en otras actuales.
Muchos usuarios han descubierto este tipo de códigos realizando técnicas de fuzzing, viendo que existen algunas instrucciones no documentadas en multitud de modelos de CPU. Un caso muy actual que os comentamos es el de las instrucciones Apple AMX.
CHIEFTEC acaba de presentar dos nuevas cajas para PC, Visio y Visio Air con un…
Asus ZenWiFi BT8 es un sistema Mesh Wi-Fi 7 el cual se sitúa por debajo…
Qualcomm anuncia nuevos SoC Snapdragon X, pero no se trata de una nueva generación, sino…