80186 código máquina + DOS, 91 bytes
Versión de texto:
hm j j PPjzjzjgaAAA JSJJ RU Sq ReAA JdJJJ RfiJElK JEiS GtI And she said But that s his
Versión de texto, con pestañas (código 9) reemplazadas por 9
y espacios (código 32) reemplazados por *
:
hm9j9j9PPjzjzjgaAAA9JSJJ9RU9Sq9ReAA9JdJJJ9RfiJElK9JEiS*GtI*And*she*said***But*that*s*his***
Hexdump:
68 6D 09 6A 09 6A 09 50 50 6A 7A 6A 7A 6A 67 61
41 41 41 09 4A 53 4A 4A 09 52 55 09 53 71 09 52
65 41 41 09 4A 64 4A 4A 4A 09 52 66 69 4A 45 6C
4B 09 4A 45 69 53 20 47 74 49 20 41 6E 64 20 73
68 65 20 73 61 69 64 20 20 20 42 75 74 20 74 68
61 74 20 73 20 68 69 73 20 20 20
El código de la máquina aparece en un archivo con extensión .com
. Cuando lo ejecuto, imprime el mensaje requerido y luego se cuelga (ejecutando datos aleatorios).
Explicación de alto nivel sobre lo que hace:
- Inicializa registros con valores constantes.
- Reemplaza espacios en el mensaje por los símbolos especiales requeridos (
,'.$
)
- Parchea el código para generar la
int 21
instrucción, que imprime el mensaje
- Llamadas DOS
Código de ensamblaje (se puede compilar con tasm
):
my_bp equ 7ah
my_si equ 7ah
my_di equ 67h
my_msg equ 13bh
.model tiny
.code
.startup
.186
org 100h
push 96dh ; ax (ah = 0; al = don't care, but see below)
push 9 ; cx
push 9 ; dx
push ax ; bx = don't care
push ax ; don't care
push my_bp
push my_si
push my_di
popa
inc cx
inc cx
inc cx
or [bp+si+my_msg-my_bp-my_si+12], cx ; ,
dec dx
dec dx
or [bp+si+my_msg-my_bp-my_si+14], dx ; '
or [bp+di+my_msg-my_bp-my_di+23], dx ; '
or [bp+si+my_msg-my_bp-my_si+30], dx ; '
inc cx
inc cx
or [bp+si+my_msg-my_bp-my_si+29], cx ; .
dec dx
dec dx
dec dx
or [bp+si+my_msg-my_bp-my_si+31], dx ; $
; 0x2049 * 0x4b6c = 0x98301cc
; So this sets cx to 1cc (a temporary constant used to patch code)
imul cx, [bp+si+my_msg-my_bp-my_si-2], 4b6ch
; 0x1cc | 0x2049 = 0x21cd (the instruction which calls DOS int 21)
; Here ah = 9 ("print" mode)
or [bp+si+my_msg-my_bp-my_si-2], cx
; At address 101, there is the constant 96d, which was loaded into ax
; 0x96d * 0x7447 = 0x448013b
; So the following sets dx to 13b (adddress of the message)
imul dx, [bp+di+101h-my_bp-my_di], 7447h
int21:
dw 2049h
db 'And she said But that s his '
end
Utiliza la popa
instrucción para abrir todos los registros, porque regular pop
no puede completar todos los registros necesarios (por ejemplo, pop di
es un código de operación prohibido).
Las direcciones de bytes a parche están en el rango 0x100 ... 0x160. Por suerte, se pueden representar como una suma de 3 bytes con valores permitidos:
- 0x7a en
bp
- 0x7a o 0x67 en
si
odi
- Valor inmediato
El parcheo de bytes en el mensaje funciona haciendo lógica OR
en 0x20 (carácter de espacio) y una pequeña constante (4, 7, 12 o 14). La constante pequeña se obtiene inicializando cx
y dx
hasta 9 (carácter de tabulación) y haciendo INC
o DEC
según sea necesario.
El parcheo de código utiliza las IMUL
instrucciones. Encontré las constantes de 16 bits necesarias para multiplicar usando la búsqueda de fuerza bruta.
Finalmente, la dirección del mensaje (0x13b) se obtiene por multiplicación. Para ahorrar espacio, tomé una de las constantes de una de las instrucciones, que contiene un valor inmediato 0x96d
. Aquí la 9
parte elige una función de impresión de DOS, y la 6d
parte es un parámetro libre. Resulta que esa 6d
es la única posibilidad que puede dar 0x13b después de la multiplicación.
Desmontaje de la parte del código:
06BA:0100 686D09 PUSH 096D
06BA:0103 6A09 PUSH +09
06BA:0105 6A09 PUSH +09
06BA:0107 50 PUSH AX
06BA:0108 50 PUSH AX
06BA:0109 6A7A PUSH +7A
06BA:010B 6A7A PUSH +7A
06BA:010D 6A67 PUSH +67
06BA:010F 61 POPA
06BA:0110 41 INC CX
06BA:0111 41 INC CX
06BA:0112 41 INC CX
06BA:0113 094A53 OR [BP+SI+53],CX
06BA:0116 4A DEC DX
06BA:0117 4A DEC DX
06BA:0118 095255 OR [BP+SI+55],DX
06BA:011B 095371 OR [BP+DI+71],DX
06BA:011E 095265 OR [BP+SI+65],DX
06BA:0121 41 INC CX
06BA:0122 41 INC CX
06BA:0123 094A64 OR [BP+SI+64],CX
06BA:0126 4A DEC DX
06BA:0127 4A DEC DX
06BA:0128 4A DEC DX
06BA:0129 095266 OR [BP+SI+66],DX
06BA:012C 694A456C4B IMUL CX,[BP+SI+45],4B6C
06BA:0131 094A45 OR [BP+SI+45],CX
06BA:0134 6953204774 IMUL DX,[BP+DI+20],7447
06BA:0139 CD21 INT 21 (after the code patches itself)
Dato curioso: Normalmente, usaría en offset message
lugar del codificado 13bh
, pero en este caso, porque al momento de analizar su dirección es desconocida, tasm genera un desplazamiento inmediato de 16 bits, desperdiciando 1 byte de código:
06BA:0131 098A4600 OR [BP+SI+0046],CX