COMO ROMPER LLAVES DE HARDWARE

rompiendo llaves de hardware


·  Aclaración

·  Introducción

·  Nuestro aliado: El Microprocesador

·  Rastreo de Instrucciones

·  Rastreo de las operaciones en los puertos de E/S

·  El Puerto Paralelo

·  Capturando los accesos a LPT1

·  Análisis de los datos capturados

·  Advertencia

·  Capturando los accesos a LPT1 de un programa protegido con llave de hardware

·  Emulando la llave de hardware

·  Conclusión

·  Bibliografía

·  Mensajitos para los más chiquitos

 


ACLARACION:

Las empresas y los productos mencionados en el presente texto NO EXISTEN.

Todo lo publicado en esta nota es absolutamente FALSO.

Lo que Ud. está a punto de leer es resultado de la decadente y absurda imaginación del autor que, al no tener otra cosa que hacer, se puso a escribir esto.

CUALQUIER PARECIDO CON LA REALIDAD ES PURA COINCIDENCIA.


Muchos desarrolladores de software utilizan, para proteger sus productos de eventuales copias, distintos tipos de llaves de hardware. Esto no es muy lógico en este país ya que el software argentino, principalmente aquellos programas orientados a gestión de empresas, son algo que dejan mucho que desear, pero bueno, la mayoría de la gente no sabe nada de computación y es bastante fácil engañarla y cobrarle sumas de dinero completamente absurdas. Con esto no quiero decir que todos los programas de gestión son truchos, aunque sí la gran mayoría (digamos un 99%) de los que corren en DOS y/o WINDOORS.

Todo el material que sigue es pura y exclusivamente para uso educativo. El autor no se hace responsable de los perjuicios que alguien pueda causar haciendo mal uso de las herramientas y métodos que aquí se dan.
La información no es mala, mala es la gente que la usa mal.



INTRODUCCION:

Pasemos a una descripción etérea sobre el funcionamiento del tipo de llave de la que habla el presente texto (no todas se comportan de la manera indicada):
Lo primero que hace un programa protegido cuando empieza a correr es cargar y ejecutar a otro programa de 'protección', el cuál se encarga de desencriptar al programa original (con datos que lee de la llave) y luego le devuelve el control.
Seguramente, el programa de protección debe tener bastantes vueltas como para confundir a cualquiera que se anime a querer abrirlo, si está medianamente bien hecho tendrá muchos artilugios para tratar de evitar su vulnerabilidad, pero tarde o temprano tiene que leer y/o escribir datos en la llave y es justamente ése momento el que nosotros aprovecharemos.
Lo que se propone es, simple y sencillamente, emular la llave.

Los temas que se tratan con mayor profundidad son los que hacen a la emulación de la llave. Si el lector desea profundizar sobre otros aspectos puede consultar la bibliografía que se presenta al final del texto.


NUESTRO ALIADO: EL MICROPROCESADOR

FLAGS:
Al estar en DOS, el microprocesador se encuentra en lo que se llama 'modo real': está funcionando como un 8088 muy rápido (este micro es el que tenían las viejas XT), por lo tanto, el desarrollo que sigue se va a basar en el funcionamiento de ese micro.
Como es sabido, el microprocesador posee varios registros, uno de ellos es el 'Flag Register' (tambien llamado 'Status Register') que posee 16 bits y se detallan a continuación:

 

 

15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

|   |   |   |   | O | D | I | T | S | Z |   | A |   | P |   | C |

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

 
bit  0: C: Carry
bit  2: P: Parity
bit  4: A: Auxiliar Carry
bit  6: Z: Zero
bit  7: S: Sign
bit  8: T: Trap
bit  9: I: Interrupt Enable
bit 10: D: Direction
bit 11: O: Overflow

Nos centraremos en solo dos de estos bits: el Interrupt Enable y el Trap.

INTERRUPCIONES:
Daremos una rápida mirada al concepto de interrupciones:
Las interrupciones se usan, generalmente, en la comunicación con dispositivos periféricos, por ejemplo: el teclado genera una interrupción cada vez que se pulsa una tecla, en este caso, el uso de interrupciones permite al microprocesador hacer otras tareas mientras uno piensa si va o no a escribir algo y, solamente cuando se presiona una tecla, procesarla. A este tipo de interrupciones se las llama de 'HARDWARE' ya que es un dispositivo externo el que las produce, pero tambien existen las de 'SOFTWARE' que se generan por programa (utilizando la instrucción INT). Todas las interrupciones se catalogan por tipos. Un tipo es un número entre 0 y 255 (Ej.: Para poder utilizar las rutinas del DOS hay que generar una interrupción de software tipo 21h -INT 21h-). Hay tipos que son de uso exclusivo del microprocesador, a saber:

Tipo 0: 'Divide Error': Se produce cada vez que aparece una división por 0.

Tipo 1: 'Single-Step' o 'Trace': Se produce cada vez que se ejecuta una instrucción (solamente cuando el Trap bit del flag register está activo).

Tipo 2: 'Nonmaskable Hardware Interrupt': Se genera cuando el pin NMI del microprocesador se pone en 1. Esta interrupción no puede obviarse ni desactivarse, por lo tanto se procesa sí o sí.

Tipo 3: 'Byte Interrupt Instruction': La provoca una instrucción especial.

Tipo 4: 'Overflow': Se genera cuando se ejecuta la instrucción INTO y además, el bit O del flag register está activo.

Cada vez que ocurre una interrupción se suspende la ejecución normal de un programa y el micro pasa a ejecutar el código de la misma; cuando termina, se vuelve al punto exacto donde estaba antes de producirse ésta. Para saber dónde se encuentra el código asociado a una interrupción existe el 'Vector de Interrupciones' que consta de una zona de 1K byte que contiene las direcciones de memoria a las que el micro debe saltar cada vez que se produce una de algún tipo. Este vector se comienza en el offset 0 del segmento 0 (0000:0000). Hay 4 bytes por cada tipo de interrupción (dos indican el offset y los otros dos el segmento donde se encuentra el código a ejecutar). Por ejmplo, el vector que indica la dirección de la interrupción tipo 21h se encuentra en 0000:4 * 21h = 0000:0084h.

OPERACION DE UNA INTERRUPCION:
Cuando el 8088 termina la ejecución de una instrucción se fija si debe o no procesar alguna interrupción observando, entre otras cosas, algunos bits del flag register en el siguiente orden:

  1. Trap y error de división por 0
  2. Interrupciones de software
  3. Interrupciones de hardware

Si debe procesar alguna interrupción realiza los siguientes pasos:

  1. Pone en la pila el contenido del flag register
  2. Limpia los bits I y T del flag register (de esta manera cancela interrupciones de harware y/o 'trap' durante el procesamiento de otra)
  3. Pone en la pila el contenido del 'code segment' CS y del 'instrucion pointer' IP (más fácil: salva la dirección actual del programa interrumpido)
  4. Pone en CS e IP el contenido de 0000:4 * X (donde X es el tipo de interrupción generado).

Una implementación de estos pasos podría ser:

 
paso 1:        pushf
paso 2:        push ax
               pushf
               pop  ax
               and  ax, ( 65535 - ( bit I | bit T ) )
               push ax
               popf
               pop  ax
pasos 3 y 4:   call far [ 0000 : 4*X ]


Cabe aclarar que el micro no los realiza de esta manera.

Cuando el bit I está activo están permitidas las interrupciones de hardware y se deshabilitan apagando este bit. Para encenderlo podemos usar la instrucción STI y para apagarlo CLI. Cuando el bit T está activo se produce una interrupción tipo 1 cada vez que se ejecuta una instrucción (siempre y cuando no se esté ejecutando el código de una interrupción -ver paso 2-), de aquí el nombre de 'single-step' (paso simple). A diferencia del bit I, no existen instrucciones para activar o desactivar el bit T, por lo tanto debemos rebuscarnoslá de otra manera.

Seguramente, el lector ya se habrá dado cuenta de que la niña bonita es la interrupción SINGLE-STEP o TRAP.


RASTREO DE INSTRUCCIONES:

El programa TRAP.ASM muestra como se puede utilizar la interrupción TRAP para rastrear las instrucciones que se van ejecutando (este es el principio básico de funcionamiento de un debugger).

 
--------------------BEGIN TRAP.ASM-------------------------------------
;
;TRAP.ASM - (c) 1998 - Maruja
;
;Ejemplo de funcionamiento de la interrupcion TRAP
;
 
.model tiny
.code
org 100h
 
inicio:        jmp  Arranque
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
settrap_msg    db      'TRAP ON', 13, 10, '$'
untrap_msg     db      'TRAP OFF', 13, 10, '$'
trap_msg       db      'TRAP!', 13, 10, '$'
 
vieja90        dd      ?
vieja91        dd      ?
vieja01        dd      ?
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetTrap:       push ax
               push bp
               mov  bp, sp
               mov  ax, [bp+8]        ;Obtener flags de la pila
               or   ah, 1             ;Activar bit T
               mov  [bp+8], ax        ;Colocar nuevos flags en la pila
 
               push dx                ;Imprimir mensaje 'TRAP ON'
               push ds
               push cs
               pop  ds
               lea  dx, settrap_msg
               mov  ah, 9
               int  21h
               pop  ds
               pop  dx
 
               pop  bp
               pop  ax
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
UnTrap:        push ax
               push bp
               mov  bp, sp
               mov  ax, [bp+8]        ;Obtener flags de la pila
               and  ah, 0FEh          ;Desactivar bit T
               mov  [bp+8], ax        ;Colocar nuevos flags en la pila
 
               push dx                ;Imprimir mensaje 'TRAP OFF'
               push ds
               push cs
               pop  ds
               lea  dx, untrap_msg
               mov  ah, 9
               int  21h
               pop  ds
               pop  dx
 
               pop  bp
               pop  ax
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Trap:          push dx                ;Imprimir mensaje 'TRAP!'
               push ds
               push ax
               push cs
               pop  ds
               lea  dx, trap_msg
               mov  ah, 9
               int  21h
               pop  ax
               pop  ds
               pop  dx
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetearVectores: mov  ax, 3501h         ;Obtener vector de interrupcion TRAP
               int  21h               ;(tipo 1) y guardarlo
               mov  word ptr vieja01, bx
               mov  bx, es
               mov  word ptr vieja01+2, bx
               
               mov  ax, 3590h         ;Obtener vector de interrupcion 90h
               int  21h               ;y guardarlo
               mov  word ptr vieja90, bx
               mov  bx, es
               mov  word ptr vieja90+2, bx
               
               mov  ax, 3591h         ;Obtener vector de interrupcion 91h
               int  21h               ;y guardarlo
               mov  word ptr vieja91, bx
               mov  bx, es
               mov  word ptr vieja91+2, bx
               
               mov  ax, 2590h         ;Hacer que una INT 90h ejecute el
               lea  dx, SetTrap       ;codigo 'SetTrap'
               int  21h
 
               mov  ax, 2591h         ;Hacer que una INT 91h ejecute el
               lea  dx, UnTrap        ;codigo 'UnTrap'
               int  21h
 
               mov  ax, 2501h         ;Hacer que la interrupcion TRAP
               lea  dx, Trap          ;provoque la ejecucion del codigo
               int  21h               ;'Trap'
               ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RestaurarVectores:
               mov  ax, 2501h                 ;Restaurar vector anterior
               lds  dx, dword ptr vieja01     ;interrupcion TRAP
               int  21h
 
               mov  ax, 2590h                 ;Restaurar vector anterior
               lds  dx, dword ptr cs:vieja90  ;interrupcion 90h
               int  21h
 
               mov  ax, 2591h                 ;Restaurar vector anterior
               lds  dx, dword ptr cs:vieja91  ;interrupcion 91h
               ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Arranque:      call SetearVectores
 
               int  90h                       ;Activar Trap
               mov  ax, 1
               mov  dx, 2
               nop
               int  91h                       ;Desactivar Trap
 
               Call RestaurarVectores
 
               mov  ax, 4C00h                 ;Terminar programa
               int  21h
 
end inicio
--------------------END TRAP.ASM---------------------------------------

Este programa se compila (usando el Turbette Assembler) y se ejecuta de la siguiente manera:

 
C:\>TASM TRAP.ASM
...
C:\>TLINK /t TRAP
...
C:\>TRAP.COM
TRAP ON
TRAP!
TRAP!
TRAP!
TRAP OFF
 
C:\>

No voy a entrar en detalles sobre la inicialización del programa ya que se asume que el lector tiene los conocimientos necesarios de assembler como para entenderlo por sí mismo (solo se recuerda que cuando comienza la ejecución de un archivo .COM es: CS = DS = ES).

En la rutina 'Arranque', la instrucción 'INT 90h' provoca la ejecución de 'SetTrap' que, luego de activar el bit T de los flags que se encuentran en la pila (ver 'Operación de una Interrrupción'), muestra el mensaje 'TRAP ON' utilizando la función 9 del DOS. Cuando esta rutina termina, el micro recupera los flags 'cambiados' de la pila quedando activo el bit T.
Luego aparecen 3 instrucciones cualquiera. Como el bit T está activo, la ejecución de cada una de estas instrucciones genera una interrupción tipo 1 que provoca ejecución de la rutina 'Trap', ésta muestra el mensaje 'TRAP!' y termina.
Finalmente, la instrucción 'INT 91h' llama a la rutina 'UnTrap' que desactiva el bit T y muestra el mensaje correspondiente.

Observar que los tres mensajes 'TRAP!' que se visualizan en la pantalla se corresponden con cada una de las tres instrucciones que se encuentran entre las dos INTs.


RASTREO DE LAS OPERACIONES EN LOS PUERTOS DE E/S:

Las llaves de hardware se conectan, por lo general, en el puerto paralelo, principalmente en LPT1 y tienen dos conectores: uno para la PC y otro para la impresora.
Cuando el programa protegido accede a la llave lo hace a través de dicho puerto, esto se logra con las instrucciones IN y OUT (la primera se utiliza para leer datos y la segunda para escribirlos). Lo que debemos hacer es rastrear la ejecución de estas instrucciones para poder capturar los datos que se leen y/o escriben en el puerto.

Para llevar a cabo nuestro cometido nos aprovecharemos de la forma en que se procesan las interrupciones:
Como ya se comentó, antes de pasarle el control al código de una interrupción, el microprocesador coloca en la pila los flags y la dirección actual de ejecución del programa principal (dirección de la instrucción que todavía no fué ejecutada), por lo tanto, la instrucción trapeada es la anterior a la que apunta el CS:IP que se encuentra en la pila.
Ejemplo: (Se considera bit T activo)

 
        0960:0001: xor  ax, ax
        0960:0002: inc  ax

Luego de ejecutarse el 'XOR' el CS:IP contiene 0960:0002, como el bit T está activo, en vez de ejecutarse el 'INC' se genera una interrupción TRAP. El estado de la pila dentro de la rutina Trap es el siguiente:

 
        +------+------+-------+-------------...--------------------+
        | 0002 | 0960 | FLAGS | XXXX XXXX XX...XXXX XXXX XXXX XXXX |
        +------+------+-------+-------------...--------------------+
          SP

El SP (stack pointer) está apuntando al último elemento guardado en la pila (al IP del programa original). En SP+2 se encuentra el CS y en SP+4 estan los flags (no olvidar que en la pila se guardan elementos de 16 bits). Lo que debemos hacer es obtener de la pila la dirección del código interrumpido y restarle a su IP el valor necesario para ubicarlo en la instrucción anterior (para que apunte al 'XOR'). Una vez hecho esto podemos leer el código de operación (opcode) de la instrucción trapeada y saber si es o no un IN o un OUT.
Ahora tenemos un nuevo problema: ¿ Cuáles son los opcodes de IN y de OUT ?
Todas sus posibles combinaciones son:

  1. in al, puerto
  2. in ax, puerto
  3. out puerto, al
  4. out puerto, ax
  5. in al, dx
  6. in ax, dx
  7. out dx, al
  8. out dx, ax

La 1 y 5 leen un byte de un puerto;
La 3 y 7 escriben un byte en un puerto;
La 2 y 6 leen un word (2 bytes);
La 4 y 8 escriben un word;
La 1, 2, 3, y 4 direccionan directamente al puerto (solamente se puede utilizar esta forma si el puerto es uno entre 0 y 0FFh);
La 5, 6, 7, y 8 acceden al puerto en forma indirecta a través del registro DX (el puerto en DX puede ser uno entre 0 y 0FFFFh).

Los puertos paralelos se encuentran en direcciones mayores a 0FFh, por lo tanto, la única manera de acceder a los mismos es por medio de alguna de las formas indicadas en 5, 6, 7, u 8. Son entonces 4 opcodes los que debemos conocer, para lo cuál utilizamos el programa OPCODES.ASM.

 
--------------------BEGIN OPCODES.ASM----------------------------------
;
;OPCODES.ASM - (c) 1998 - Maruja
;
;Programa para conocer los codigos de operacion de las
;instrucciones que permiten el acceso a los puertos de E/S
;
 
.model tiny
.code
org 100h
 
inicio:        in   al, dx
               in   ax, dx
               out  dx, al
               out  dx, ax
 
               nop
               nop
               nop
               nop
               nop
               nop
                                      
               mov  ax, 4C00h
               int  21h
 
end inicio
--------------------END OPCODES.ASM------------------------------------

Compilando y usando el debug del DOS:

 
C:\>TASM OPCODES.ASM
...
C:\>TLINK /t OPCODES
...
C:\>DEBUG OPCODES.COM
-d
144F:0100  EC ED EE EF 90 90 90 90-90 90 B8 00 4C CD 21 00   ............L.!.
144F:0110  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
144F:0120  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
144F:0130  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
144F:0140  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
144F:0150  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
144F:0160  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
144F:0170  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
-q
 
C:\>
 

Aquí se observan claramente los códigos (en hexadecimal) de cada una de las instrucciones:

 
               IN  AL, DX     =  EC
               IN  AX, DX     =  ED
               OUT DX, AL     =  EE
               OUT DX, AX     =  EF
               NOP            =  90
               MOV AX, 4C00h  =  B8 00 4C
               INT 21h        =  CD 21

Basandosé en los datos recién obtenidos, el programa IOTRAP.ASM se encarga de rastrear cada una de las operaciones de E/S que puedan ocurrir. Las diferencias entre este programa y el programa TRAP.ASM se encuentran en las rutinas 'Trap' y 'Arraque', es por esto que solamente se muestran estas dos:

 
--------------------BEGIN IOTRAP.ASM - TRAP & ARRANQUE-----------------
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Trap:
        SP_INICIAL     EQU     $
 
               push dx                ;Salvar registros utilizados
               push ds
               push ax
               push si
               push bp
 
        SP_FINAL       EQU     $
 
               mov  bp, sp            ;Obtener CS:IP Interrumpido
               mov  si, [bp + (SP_FINAL-SP_INICIAL)*2 + 2 ]
               mov  ds, si
               mov  si, [bp + (SP_FINAL-SP_INICIAL)*2 ]
               dec  si                ;DS:SI = CS:IP Instruccion previa
 
               mov  al, byte ptr [si] ;Obtener opcode instruccion previa
 
               cmp  al, 0ECh          ;El opcode es 0ECh ? 
               jb   Trap_salir        ;Si es menor salir
               cmp  al, 0EFh          ;El opcode es 0EFh ?
               ja   Trap_salir        ;Si es mayor salir
 
               push cs                ;Como el opcode es uno entre
               pop  ds                ;0ECh y 0EFh imprimir mensaje TRAP!
               lea  dx, trap_msg
               mov  ah, 9
               int  21h
 
Trap_salir:    pop  bp                ;Recuperar registros y salir
               pop  si
               pop  ax
               pop  ds
               pop  dx
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Arranque:      call SetearVectores
 
               int  90h                       ;Activar Trap
 
               mov  ax, 1
               mov  dx, 60h
               nop
               in   al, 60h
               in   al, dx
               in   ax, dx
               in   ax, 60h
 
               int  91h                       ;Desactivar Trap
 
               Call RestaurarVectores
 
               mov  ax, 4C00h                 ;Terminar programa
               int  21h
 
end inicio
--------------------END IOTRAP.ASM - TRAP & ARRANQUE-------------------

Compilando y ejecutando el programa se obtiene:

 
C:\>TASM IOTRAP.ASM
...
C:\>TLINK /t IOTRAP
...
C:\>IOTRAP.COM
TRAP ON
TRAP!
TRAP!
TRAP OFF
 
C:\>

Explicación de las rutinas:
Trap:
Lo primero que llama la atención son las definiciones 'SP_INICIAL' y 'SP_FINAL', están solamente para no tener que calcular el espacio que ocupan los registros en la pila cada vez que se agrega o quita algún 'PUSH' durante alguna etapa de desarrollo de esta rutina. Luego de esto, obtiene de la pila el CS:IP de la instrucción que se debe ejecutar cuando la interrupción TRAP termina, decrementa el IP en uno para otener el CS:IP de la instrucción anterior (más adelante se demuestra que esto está mal) y compara el opcode que se encuentra en esa dirección con los códigos de OUT e IN que se obtuvieron con anterioridad. Si esta instrucción previa posee alguno de estos códigos se imprime el mensaje 'TRAP!'.

Arranque:
La diferencia con la que se encuentra en TRAP.ASM es que aquí se agregaron cuatro instrucciones IN.

Si uno observa la salida de este programa luego de la ejecución del mismo se vé que el mensaje 'TRAP!' aprece solo dos veces, esto está bien ya que son dos las instrucciones IN que acceden al puerto en forma indirecta (a través del registro DX): 'IN AL,DX' e 'IN AX,DX'.

Durante la explicación de la rutina Trap se ha adelantado que en realidad el hecho de decrementar el IP en uno no necesariamente lo coloca sobre la instrucción anterior, por ejemplo, si trapeamos la siguiente sección de código:

 
               mov ax, 0EE00h  
               xor dx, dx

Luego del 'MOV' se ejecuta la Trap con el CS:IP del 'XOR' en la pila, cuando nuestra rutina decrementa en uno el IP va a parar sobre la última parte del dato que se carga en 'AX', osea sobre 0EEh, con lo cuál la Trap asumirá, erroneamente, que la instrucción reciente fué un 'OUT DX,AL' en vez de un 'MOV'. Lo verificamos en el programa IOTRAP2.ASM:

 
--------------------BEGIN IOTRAP2.ASM - ARRANQUE-----------------------
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Arranque:      call SetearVectores
 
               int  90h                       ;Activar Trap
 
               mov  ax, 1
               mov  dx, 60h
               nop
               in   al, 60h
               in   al, dx
               in   ax, dx
               in   ax, 60h
               mov  ax, 0EE00h
               xor  dx, dx
 
               int  91h                       ;Desactivar Trap
 
               Call RestaurarVectores
 
               mov  ax, 4C00h                 ;Terminar programa
               int  21h
 
end inicio
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
--------------------END IOTRAP2.ASM - ARRANQUE-------------------------

Las diferencias con IOTRAP.ASM están solamente en la rutina 'Arranque'. Compilando y ejecutando obtenemos:

 
C:\>TASM IOTRAP2.ASM
...
C:\>TLINK /t IOTRAP2
...
C:\>IOTRAP2.COM
TRAP ON
TRAP!
TRAP!
TRAP!
TRAP OFF
 
C:\>

¡Un mensaje más que en el ejemplo anterior! Esto significa que la Trap confundió el 'MOV AX,0EE00h' con un 'OUT DX,AL' ya que no calculó correctamente la dirección exacta de esa instrucción. Una posible solución a este problema puede ser:

Antes que nada:

  1. Crear dos variables (una para CS y otra para IP) e inicializarlas con una dirección errónea.

En la Trap:

  1. Si las variables tienen una dirección errónea es porque ésta es la primera vez que se ejecuta la Trap, por lo tanto hay que pasar al punto 4.
  2. Obtener el opcode de la instrucción que se encuentra en la dirección indicada por las variables y seguir con el rastreo normal.
  3. Actualizar las variables con la dirección de la instrucción que se ejecutará al salir de Trap.

Esto parece funcionar lindo pero pagamos un precio: la primera instrucción que se ejecuta luego de activar el 'traping' no será rastreada (punto 2). El precio es irrisorio ya que lo podemos solucionar poniendo un 'NOP' luego de activar el 'traping' con 'INT 90h'.
(NOTA: Para evitar el punto 2 se puede hacer que la rutina de 'INT 90h' se encargue de setear el CS:IP de la siguiente instrucción en las variables. Se deja este trabajo al lector).
Las modificaciones que hay que hacerle al programa anterior ( IOTRAP2.ASM) están solamente en la rutina Trap. Tenemos entonces el programa IOTRAP3.ASM:

 
--------------------BEGIN IOTRAP3.ASM - TRAP---------------------------
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IPanterior     dw      0
CSanterior     dw      0
 
Trap:
        SP_INICIAL     EQU     $
 
               push dx                ;Salvar registros utilizados
               push ds
               push ax
               push si
               push bp
 
        SP_FINAL       EQU     $
 
               cmp  cs:CSanterior, 0  ;CSanterior tiene un valor incorrecto ?
               jz   Trap_salir        ;Si: salir
               
               mov  si, cs:CSanterior
               mov  ds, si
               mov  si, cs:IPanterior ;DS:SI = CS:IP instruccion anterior
               mov  al, byte ptr [si] ;Obtener opcode 
 
               cmp  al, 0ECh          ;El opcode es 0ECh ? 
               jb   Trap_salir        ;Si es menor salir
               cmp  al, 0EFh          ;El opcode es 0EFh ?
               ja   Trap_salir        ;Si es mayor salir
 
               push cs                ;Como el opcode es uno entre
               pop  ds                ;0ECh y 0EFh imprimir mensaje TRAP!
               lea  dx, trap_msg
               mov  ah, 9
               int  21h
 
Trap_salir:    mov  bp, sp            ;Guardar CS:IP de proxima instruccion
               mov  si, [bp + (SP_FINAL-SP_INICIAL)*2 + 2 ]
               mov  cs:CSanterior, si
               mov  si, [bp + (SP_FINAL-SP_INICIAL)*2 ]
               mov  cs:IPanterior, si
 
               pop  bp                ;Recuperar registros y salir
               pop  si
               pop  ax
               pop  ds
               pop  dx
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
--------------------END IOTRAP3.ASM - TRAP-----------------------------

Al compilar y ejecutar se tiene:

 
C:\>TASM IOTRAP3.ASM
...
C:\>TLINK /t IOTRAP3
...
C:\>IOTRAP3.COM
TRAP ON
TRAP!
TRAP!
TRAP OFF
 
C:\>

¡Perfecto! Solamente hay 2 instrucciones IN válidas.



EL PUERTO PARALELO:

Para poder capturar los datos que vienen o que van al puerto paralelo debemos conocer las direcciones donde está mapeado, por lo general, la dirección base del puerto LPT1 se encuentra en 278h, pero esto no siempre es así ya que la mayoría de los mothers permiten cambiarla.
El BIOS escribe las direcciones base de cada LPTx en una zona particular de memoria:

            Dirección        Contenido
        -------------------------------------------
            0040:0008h   Dirección base de LPT1
            0040:000Ah   Dirección base de LPT2
            0040:000Ch   Dirección base de LPT3
            0040:000Eh   Dirección base de LPT4

Si bien existe la posibilidad de tener un cuarto puerto paralelo, el DOS no lo reconoce.
Cada LPTx está formado por tres registros mapeados en tres puertos consecutivos a partir de la dirección base (por ejemplo: si la dirección base de LPT1 es 278h entonces tenemos al primer registro en 278h, al segundo en 279h, y al tercero en 27Ah). Esto significa que si queremos rastrear los accesos a LPT1 nuestra rutina Trap debe capturar las lecturas y/o escrituras que se produzcan en cualquiera de estos tres puertos.


CAPTURANDO LOS ACCESOS A LPT1:

El programa LPT1CAP1.ASM captura las operaciones en LPT1 y las baja al archivo 'C:\LPT.DAT'.
Cada acceso al puerto genera una estructura de 8 bytes que contiene:

  1. CS de la instrucción (2 bytes)
  2. IP de la instrucción (2 bytes)
  3. Flags (2 bytes)
  4. Dato (2 bytes)

Descripción de los flags:
bit 15 (32768):
Si está activo indica que la operación es un OUT (caso contrario un IN). Osea que 'Dato' contiene el dato que se escribe en el puerto.

bit 14 (16384):
Si está activo indica que el 'Dato' leído o escrito en el puerto es un word (caso contrario un byte).

bits 13 a 11 (8192 a 2048):
No se utilizan.

bits 10 a 0 (1024 a 1):
Aquí se almacena el puerto accedido.

 
--------------------BEGIN LPT1CAP1.ASM---------------------------------
;
;LPT1CAP1.ASM - (c) 1998 - Maruja
;
;Ejemplo de rastreo de operaciones en el puerto LPT1
;
 
.model tiny
.code
org 100h
 
inicio:        jmp  Arranque
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IN_BYTE        EQU     0ECh           ;IN  AL, DX
IN_WORD        EQU     0EDh           ;IN  AX, DX
OUT_BYTE       EQU     0EEh           ;OUT DX, AL
OUT_WORD       EQU     0EFh           ;OUT DX, AX
 
ES_OUT         EQU     32768          ;Bit 15 flags
ES_WORD        EQU     16384          ;Bit 14 flags
 
vieja90        dd      ?              ;Direccion original INT 90h
vieja91        dd      ?              ;Direccion original INT 91h
vieja01        dd      ?              ;Direccion original TRAP
 
IPanterior     dw      0              ;CS:IP Instruccion anterior
CSanterior     dw      0
 
lpt11          dw      ?              ;Direccion base (1er registro) de LPT1
lpt13          dw      ?              ;Direccion 3er registro de LPT1
 
TAMBUF         EQU     256*8          ;Longitud buffer
buffer         db      TAMBUF  dup (0) ;Buffer temporal para datos capturados
index          dw      0              ;Posicion en buffer
 
filename       db      'C:\LPT.DAT', 0 ;Archivo con datos capturados
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetTrap:       push ax
               push bp
 
               mov  bp, sp
               mov  ax, [bp+8]        ;Obtener flags de la pila
               or   ah, 1             ;Activar bit T
               mov  [bp+8], ax        ;Colocar nuevos flags en la pila
 
               pop  bp
               pop  ax
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
UnTrap:        push ax
               push bp
 
               mov  bp, sp
               mov  ax, [bp+8]        ;Obtener flags de la pila
               and  ah, 0FEh          ;Desactivar bit T
               mov  [bp+8], ax        ;Colocar nuevos flags en la pila
 
               cmp  cs:index, 0       ;El buffer esta vacio ?
               jz   UnTrap_salir      ;Si: salir
 
               push bx
               push cx
               push dx
               push ds
               call GrabarBuffer      ;Forzar la grabacion del buffer
               pop  ds
               pop  dx
               pop  cx
               pop  bx
 
UnTrap_salir:  pop  bp
               pop  ax
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Trap:
        SP_INICIAL     EQU     $
 
               push ax                ;Salvar registros utilizados
               push bx
               push cx
               push dx
               push si
               push ds
               push bp
 
        SP_FINAL       EQU     $
 
               cmp  cs:CSanterior, 0  ;CSanterior tiene un valor incorrecto ?
               jz   Trap_salir        ;Si: salir
               
               mov  si, cs:CSanterior
               mov  ds, si
               mov  si, cs:IPanterior ;DS:SI = CS:IP instruccion anterior
               mov  cl, byte ptr [si] ;Obtener opcode 
 
               cmp  cl, IN_BYTE       ;El opcode es alguno entre
               jb   Trap_salir        ;IN_BYTE u OUT_WORD ?
               cmp  cl, OUT_WORD
               ja   Trap_salir        ;No: salir
 
               push cs
               pop  ds
               cmp  dx, lpt11         ;Acceso a alguno de los puertos LPT1 ?
               jb   Trap_salir
               cmp  dx, lpt13
               ja   Trap_salir        ;No: salir
 
               call CapturarAcceso
 
Trap_salir:    mov  bp, sp            ;Guardar CS:IP de proxima instruccion
               mov  si, [bp + (SP_FINAL-SP_INICIAL)*2 + 2 ]
               mov  cs:CSanterior, si
               mov  si, [bp + (SP_FINAL-SP_INICIAL)*2 ]
               mov  cs:IPanterior, si
 
               pop  bp                ;Recuperar registros y salir
               pop  ds
               pop  si
               pop  dx
               pop  cx
               pop  bx
               pop  ax
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CapturarAcceso: ;AX = Dato; DX = Puerto; CL = Opcode
 
               cmp  cl, OUT_WORD      ;Es un OUT ?
               je   CA_setout
               cmp  cl, OUT_BYTE
               jne  CA_verdata
CA_setout:     or   dx, ES_OUT        ;Si: setear bit 15
 
CA_verdata:    cmp  cl, IN_WORD       ;El dato es word ?
               je   CA_setword
               cmp  cl, OUT_WORD
               jne  CA_push
CA_setword:    or   dx, ES_WORD       ;Si: setear bit 14
 
CA_push:       lea  si, buffer        ;Guardar estructura en buffer
               add  si, index
               mov  cx, CSanterior
               mov  [si], cx          ;Guardar CS
               mov  cx, IPanterior
               mov  [si+2], cx        ;Guardar IP
               mov  [si+4], dx        ;Guardar Flags
               mov  [si+6], ax        ;Guardar Dato
               add  index, 8          ;Actualizar indice
 
               cmp  index, TAMBUF     ;El buffer esta lleno ?
               je   GrabarBuffer      ;Si: grabar buffer en disco
 
               ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GrabarBuffer:  mov  ax, 3D02h                 ;Abrir archivo para L/E
               lea  dx, filename
               int  21h
               jnc  GB_append
               mov  ah, 3Ch                   ;Si no existe crearlo
               xor  cx, cx
               int  21h
               jc   GB_salir                  ;Si hubo error salir
 
GB_append:     mov  bx, ax                    ;Poner archivo en modo append
               mov  ax, 4202h
               xor  dx, dx
               xor  cx, cx
               int  21h
 
               mov  ah, 40h                   ;Grabar buffer
               mov  cx, index
               lea  dx, buffer
               int  21h
 
               mov  ah, 3Eh                   ;Cerrar archivo
               int  21h
               mov  index, 0                  ;Resetear indice
 
GB_salir:      ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetearVectores: mov  ax, 3501h         ;Obtener vector de interrupcion TRAP
               int  21h               ;(tipo 1) y guardarlo
               mov  word ptr vieja01, bx
               mov  bx, es
               mov  word ptr vieja01+2, bx
               
               mov  ax, 3590h         ;Obtener vector de interrupcion 90h
               int  21h               ;y guardarlo
               mov  word ptr vieja90, bx
               mov  bx, es
               mov  word ptr vieja90+2, bx
               
               mov  ax, 3591h         ;Obtener vector de interrupcion 91h
               int  21h               ;y guardarlo
               mov  word ptr vieja91, bx
               mov  bx, es
               mov  word ptr vieja91+2, bx
               
               mov  ax, 2590h         ;Hacer que una INT 90h ejecute el
               lea  dx, SetTrap       ;codigo 'SetTrap'
               int  21h
 
               mov  ax, 2591h         ;Hacer que una INT 91h ejecute el
               lea  dx, UnTrap        ;codigo 'UnTrap'
               int  21h
 
               mov  ax, 2501h         ;Hacer que la interrupcion TRAP
               lea  dx, Trap          ;provoque la ejecucion del codigo
               int  21h               ;'Trap'
               ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RestaurarVectores:
               mov  ax, 2501h                 ;Restaurar vector anterior
               lds  dx, dword ptr vieja01     ;interrupcion TRAP
               int  21h
 
               mov  ax, 2590h                 ;Restaurar vector anterior
               lds  dx, dword ptr cs:vieja90  ;interrupcion 90h
               int  21h
 
               mov  ax, 2591h                 ;Restaurar vector anterior
               lds  dx, dword ptr cs:vieja91  ;interrupcion 91h
               ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GetLPT1:       mov  di, 40h
               mov  es, di
               mov  di, 8                     ;ES:DI = 0040:0008h
               mov  ax, word ptr es:[di]
               mov  lpt11, ax
               add  ax, 2
               mov  lpt13, ax
               ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Arranque:      call GetLPT1                   ;Obtener direcciones de LPT1
 
               call SetearVectores
 
               int  90h                       ;Activar Trap
 
               xor  ax, ax
               mov  dx, lpt11                 ;DX = LPT1 registro 1
               out  dx, al
               inc  dx                        ;DX = LPT1 registro 2  
               in   ax, dx
               out  dx, ax
               inc  dx                        ;DX = LPT1 registro 3
               in   al, dx
 
               inc  dx                        ;DX = LPT1Base+4: NO es LPT1
               in   ax, dx
 
               int  91h                       ;Desactivar Trap
 
               Call RestaurarVectores
 
               mov  ax, 4C00h                 ;Terminar programa
               int  21h
 
end inicio
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
--------------------END LPT1CAP1.ASM-----------------------------------

Compilando y ejecutando:

 
C:\>TASM LPT1CAP1.ASM
...
C:\>TLINK /t LPT1CAP1
...
C:\>LPT1CAP1.COM
 
C:\>DIR *.DAT
 
 Volumen en unidad C es PINDONGA
 Número de serie de volumen es 2D4B-1CD6
 Directorio de C:\
 
LPT      DAT        32 01/09/98   23:44
        1 archivo(s)         32 bytes
                   804421632 bytes libres
 
C:\>

Se ha creado un archivo de 32 bytes de longitud, esto significa que se capturaron 4 accesos al puerto LPT1. Antes de examinar este archivo se comentará el programa ya que hubo algunos cambios importantes con respecto a los anteriores:

Variables:
Se han colocado todas las variables y definiciones al comienzo. Las que merecen explicación son:
'lpt11' y 'lpt13': aquí se guardan los registros 1 y 3 del LPT1;
'buffer': es un buffer donde se guardan momentaneamente los datos capturados, se utiliza para no tener que hacer un acceso a disco cada vez que se encuentra una operación en el puerto (de lo contrario se alentaría mucho la ejecución normal del programa trapeado);
'index': se utiliza para indicar en qué posición del buffer hay que poner los datos.

SetTrap y UnTrap:
Cumplen la misma función que en los programas anteriores salvo que ahora no imprimen ningún mensaje. Observar que UnTrap fuerza la grabación del buffer en el archivo en caso que este no se haya llenado por completo.

Trap:
Se eliminó el mensaje 'TRAP!' que mostraban los programas anteriores. En caso de accederse a alguno de los registros de LPT1 se ejecuta la rutina 'CapturarAcceso'.
Como Trap se ejecuta cada vez que se termina una instrucción, entonces, luego de una operación de E/S (Ej.: OUT AX,DX) el registro AX contiene el dato y DX el puerto.

CapturarAcceso:
Esta rutina necesita tres parámetros en los registros AX, DX, y CL.
AX debe contener el dato escrito o leído del puerto;
DX debe contener el puerto al que se tuvo acceso;
CL debe contener el opcode de la instrucción ejecutada;
Con esta información 'CapturarAcceso' genera los flags y pone CS, IP, Flags, y Dato en el buffer. Si el buffer está lleno llama a 'GrabarBuffer'.

GrabarBuffer:
Abre el archivo 'C:\LPT.DAT' para lectura/escritura (si no existe lo crea) y lo pone en modo 'append', luego graba el buffer y cierra el archivo.

GetLPT1:
Obtiene la dirección base del puerto LPT1 y coloca en las variables 'lpt11' y 'lpt13' las direcciones de los registros 1 y 3.

Arranque:
A diferencia con el programa anterior ahora se llama a 'GetLPT1' y, entre las 'INT 90h' e 'INT 91h', se provocan 5 accesos a varios puertos (los cuatro primeros son en LPT1).

Como se dijo antes, se capturaron 4 accesos y, justamente, son 4 las operaciones que hace nuestro programa en LPT1.


ANALISIS DE LOS DATOS CAPTURADOS:

Para poder analizar sín problemas la información capturada debemos convertir los datos del archivo en algo que se entienda a simple vista. Este es el objetivo del programa IOVIEW.C:

 
--------------------BEGIN IOVIEW.C-------------------------------------
/*
** IOVIEW.C - (c) 1998 - Maruja
** Muestra (en forma entendible) los datos capturados en operaciones de E/S
**
** Modo de uso:  IOVIEW  file
** Donde  file  es el nombre del archivo con los datos capturados
*/
 
 
#include <stdio.h>
#include <stdlib.h>
 
 
/* Teseteo de Flags */
#define TEST_OUT(flag)         (flag & 32768)         /* bit 15 = OUT */
#define TEST_WORD(flag)               (flag & 16384)         /* bit 14 = WORD */
#define GET_PORT(flag)         (flag & 2047)
 
 
/* Estructura basica */
typedef struct {
 
    unsigned int       cs, 
                       ip, 
                       flags, 
                       data;
 
    } TRAP;
 
 
 
int main (int can, char *arg[])
{
FILE    *f;
TRAP    i;
 
 
/* Verificar que se encuentre el nombre del file */
if (can < 2) {
 
        fprintf (stderr, 
                "%s: Falta el nombre del archivo con los datos capturados\n\r",
                arg[0]);
 
        exit (-1);
 
        }
 
 
/* Abrir archivo de datos */
if (! (f = fopen (arg[1], "rb")) ) {
 
        fprintf (stderr, "%s: ", arg[0]);
        perror (arg[1]);
        exit (-1);
 
        }
 
 
/* Mostrar informacion */
printf ("\nArchivo: '%s'", arg[1]);
for (;;) {
 
        /* Leer estructura */
        if (!fread (&i, sizeof (TRAP), 1, f)) break;
 
        /* Mostrar en forma humana */
        printf ("\n%04X:%04X\t%s\t%03X, ", i.cs, i.ip,
                       TEST_OUT(i.flags) ? "OUT" : "IN", GET_PORT(i.flags));
 
        if (TEST_WORD(i.flags))
 
               printf ("%04X\t(WORD)", i.data);
 
        else printf ("%02X  \t(BYTE)", i.data & 255);
 
        }
 
printf ("\n");
return 0;
}
--------------------END IOVIEW.C---------------------------------------

Compilando con cualquier compilador de C y luego ejecutando...

 
C:\>CC IOVIEW.C
...
C:\>IOVIEW LPT.DAT
 
Archivo: 'LPT.DAT'
0E61:0AA5      OUT     278, 00        (BYTE)
0E61:0AA7      IN      279, CC87      (WORD)
0E61:0AA8      OUT     279, CC87      (WORD)
0E61:0AAA      IN      27A, CC        (BYTE)
 
C:\>

Esto se lee así:
En la dirección 0E61:0AA5h se ejecutó un 'OUT DX, AL': se escribió el byte 00 en el puerto 278h;
En la dirección 0E61:0AA7h se ejecutó un 'IN AX, DX': se leyó el word 0CC87h del puerto 279h;
En la dirección 0E61:0AA8h se ejecutó un 'OUT DX, AX': se escribió el word 0CC87h en el puerto 279h;
En la dirección 0E61:0AAAh se ejecutó un 'IN AL, DX': se leyó el byte 0CCh del puerto 27Ah;

Comparar con la rutina 'Arranque' de LPT1CAP1.ASM.


ADVERTENCIA:

A partir de este momento el lector podrá observar un cambio mas o menos abrupto del vocabulario utilizado, motivado éste, por el pésimo nivel de los 'programadores/analistas/ingenieros' que hicieron el soft y la llave aquí analizados (tanto el programa protegido como el protector).


CAPTURANDO LOS ACCESOS A LPT1 DE UN PROGRAMA PROTEGIDO CON LLAVE DE HARDWARE:

El primer paso fué gastar unos $600 por un programa de facturación berreta que no valía (ni vale) para nada esa plata. Este coso fué 'creado' por la empresa VeniQueTeCagoBien Software (un pésimo y mal diseñado programa originado en clipper y portado a clarion), estaba protegido con una llave de fabricación argentina marca SOStuare Look.
(A diferencia de lo que piensan algunos asquerosos e inmundos cerdos, el autor considera cualquier suma de dinero destinada a la educación y aprendizaje como inversión y no como gasto -se pide disculpas al reino porcino por haber llamdo cerdos a estos repugnantes entes-).


SOStuare Look


Para poder emular la llave primero hay que obtener los datos que están grabados en esta, como no conocemos los chips raros que puede tener dejaremos que el programa que la utiliza haga lo suyo mientras que nosotros capturamos todos los accesos al puerto paralelo.
Si bien todo lo que se ha dicho hasta ahora se puede aplicar para esto, no hay que subestimar a los fabricantes de la llave que, seguramente, habrán tomado algún tipo de recaudo para evitar nuestra forma de ataque, por lo tanto hay que analizar cada caso en particular (Aquí es donde el cracking pasa a ser más un arte que una ciencia).

Luego de colocar la llave en LPT1 y, con algún buen debugger en mano (como ser el debugger freeware de GNU), iniciamos la ejecución del programa:

 
C:\>LDR GESTION.EXE
 
Loading C:\GESTION.EXE
...
...
:bpio 278                             ;Breakpoint on I/O access
:bpio 279
:bpio 27a

[ Suspender ejecución si hay algún acceso al puerto LPT1 ]

 
:bpint 21 ah=4b                       ;Breakpoint on Interrupt

[ Suspender ejecución cuando se carga y/o ejecuta un programa ]

 
:bpint 21 ah=4c

[ Suspender ejecución cuando finaliza un programa ]

 
:x                                    ;Run
Break Point at 0E1B:03BB
    0E1B:03B8  B8004B         MOV AX, 4B00
>   0E1B:03BB  CD21           INT 21         ;Load and execute program
    0E1B:03BD  7236           JB  03F5 
    ...

[ El programa protegido (gestion.exe) carga y ejecuta al programa de protección (protect.exe) ]

 
:t                                    ;One Step
>   0123:109E  90             NOP
    0123:109F  90             NOP
    0123:10A0  E8CC00         CALL 116F
    ...

[ Inicio del código de la interrupción tipo 21h ]

 
:p ret                                ;Run until return
>   FDC9:423C  CF             IRET
    ...

[ Punto final de la funcion 4Bh del DOS ]

 
:t
>   1AE3:0000  BA3E1C         MOV DX, 1C3E
    1AE3:0003  8EDA           MOV DS, DX
    1AE3:0005  8C066801       MOV [0168], ES
    1AE3:0009  33ED           XOR BP, BP
    1AE3:000B  8BC4           MOV AX, BP
    ...

[ Punto de entrada del programa de protección ]

 
:x
Break Point at 18B4:0855
    18B4:0854  EC             IN AL, DX
>   18B4:0855  EB01           JMP 0858
    18B4:0857  28             .
    18B4:0858  2EA20200       MOV CS:[0002], AL
    18B4:085C  BB0100         MOV BX, 0001
    18B4:085F  B055           MOV AL, 55
    18B4:0861  EE             OUT DX, AL
    ...

[ Rutina que accede a la llave ]

Luego de observar durante un buen rato el comportamiento de este muchachín se obtuvieron ciertas conclusiones que nos permitirán actuar en forma:
El programa de facturación (que se encuentra parcialmente encriptado) carga y ejecuta a otro programa de protección.
El programa de protección realiza unas cuantas interesantes, pero abusrdas payasadas, para tratar de evitar, inútilmente, su debugging:
Por ejemplo, durante un tiempo cambia el stack segment y el stack pointer (SS:SP) a la zona que contiene los vectores de interrupción tipos 1, 2, y 3 (Trap, NMI, y BII), luego genera unos cuantos calls sín sentido para que se modifique el contenido de esta zona (con esto se puede colgar fácilmente cualquier debugger viejo, cosa que no pasa con un debugger moderno); hacer esto con la Trap y la BII podría resultar útil, pero hacerlo con la NMI es una animalada, es algo que no tiene nombre y no es digno de programador alguno que se jacte de serlo, menos aún de un analista y menos aún todavía de un ingeniero (el nivel de las facultades argentinas -tanto privadas como estatales- es lamentable, por lo tanto no hay que sorprenderse si algunos de los idiotas que hicieron esta cagada tienen algún título por el estilo), la NMI es una interrupción que se reserva para fallas fatales del sistema y no debe tocarse... salvo que haya algún tipo de hardware especial (como ser alguna hipotética UPS) que también la utilice.
Se han observado ciertas rutininas que calculan el tiempo que tardan en ejecutarse otras rutinitas: si el tiempo calculado es muy grande (cracker utilizando el comando ONE STEP de un debugger que no se cuelga), el programa de protección entra en un bucle infinito de calls.
Otra de las estupideces que se manda este particular programita es setear sus propios vectores para esa zona utilizando la función 25h del DOS. La pegunta es: ¿Para qué carajo hizo el quilombo que hizo cambiando el stack a la zona de los vectores de interrupción si ahora utiliza una simple función del DOS recontra re visible y super re debugueable?... Aparentemente los creadores del coso este pensaron que sus estúpidos métodos son infalibles para detener a cualquiera... Bue.. sigamos...

Una de las cosas más interesantes de este programilla es que el código que accede a la llave (la sección de código que realiza los INs y OUTs) está encriptada. Este señorito desencripta este código para, en algún momento, ejecutarlo y así poder acceder a los puertos de LPT1 y leer de la llave los datos escritos en ésta para desencriptar el código del programa protegido y pasarle, finalmente, el control.

Lo que vamos a hacer es desviar la ejecución normal del programa y activar nuestro sistema, esto se puede lograr generando una interrupción en alguna parte después de los desastres hechos sobre el vector de interrupciones. Además de inicializar el sistema de captura de datos, nuestra rutina debe encargarse de ejecutar la instrucción que fué cambiada por nuestra modificación del código original.
Lo ideal sería hacer esto en la zona de código que realiza los INs y OUTs, lamentablemente no puede hacerse porque, como ya se dijo, esta parte se encuentra encriptada, lo haremos entonces sobre la rutina que desencripta este código. Para encontrarla tenemos que realizar unos pasos bastantes simples: Gracias a los breakpoints de accesos a los puertos conocemos la dirección de memoria que realiza los accesos a LPT1, con este dato colocamos otro breakpoint para que se suspenda la ejecución cuando algo (o alguien) intenta escribir en esta zona (osea, ponemos un breakpoint que paraliza la ejecución normal en el momento en que la rutina de desencripción desencripta el código que accede a la llave), en nuestro caso la dirección es 18B4:0854:

 
C:\>LDR GESTION.EXE
 
Loading C:\GESTION.EXE
...
...
:bc *                                 ;Clear all breakpoints
:bpm 18b4:0854                        ;Breakpoint on memory access
:x
...
:x
Break Point at 179D:021C
>   179D:021C  C47E8F          LES DI, [BP-08]
    179D:021F  03F8            ADD DI, AX
    179D:0221  268B15          MOV DX, ES:[DI]
    179D:0224  8B46FE          MOV AX, [BP-02]
    179D:0227  D1E0            SHL AX, 1
    179D:0229  C47E8F          LES DI, [BP-08]
    179D:022C  03F8            ADD DI, AX
    179D:022E  268B05          MOV AX, ES:[DI]
    179D:0231  33C2            XOR AX, DX
    179D:0233  8BD0            MOV DX, AX
    179D:0235  8B46FE          MOV AX, [BP-02]
    179D:0238  D1E0            SHL AX, 1
    179D:023A  C47E8F          LES DI, [BP-08]
    179D:023D  03F8            ADD DI, AX
    179D:023F  268915          MOV ES:[DI], DX
    179D:0242  837EFE01       CMP WORD PTR [BP-02], 1
    179D:0246  75CB           JNZ 0213
    ...

[ Rutina que desencripta el codigo que accede a la llave ]

Pondremos nuestro desvío en la dirección 179D:023Dh y quedará con la siguiente forma:

 
               ...
               C47EF8   LES DI, [BP-08]
    179D:023D  CD90     INT 90
               268915   MOV ES:[DI], DX
               ...

Podemos hacerlo desde el debugger pero para un cambio permanente tenemos que modificar directamente al ejecutable, esto lo podemos hacer con algún tipo de editor de archivos como ser el 'disquetitor' del 'MarronOrton Utilitis':

 
C:\>COPY PROTECT.EXE ORIGINAL.EXE
 
C:\>DISQUETITOR PROTECT.EXE /W

Pedimos a este utilitario que busque la secuencia:

 
        C4 7E 8F 03 F8 26 8B 15 8B 46 FE D1 E0 C4 7E 8F 03 F8 26
        8B 05 33 C2 8B D0 8B 46 FE D1 E0 C4 7E 8F 03 F8 26 89 15

y cambiamos la última ocurrencia del '03 F8' con un 'CD 90' de tal manera que quede así:

 
        C4 7E 8F 03 F8 26 8B 15 8B 46 FE D1 E0 C4 7E 8F 03 F8 26
        8B 05 33 C2 8B D0 8B 46 FE D1 E0 C4 7E 8F CD 90 26 89 15

El 'CD' es el código de operación de la instrucción INT, el siguiente byte es el tipo de interrupción a generar, por eso 'CD 90' es el código de máquina de la instrucción 'INT 90h'. (Observar la salida generada por el debug del DOS cuando se lo utilizó para obtener los códigos de operación de los INs y OUTs).
Si ejecutamos el programa luego de grabar los cambios, el sistema se va a colgar ya que no hay ningún vector válido para la INT 90h. Este problemita lo solucionamos con el programa residente LPT1CAP.ASM:

 
--------------------BEGIN LPT1CAP.ASM----------------------------------
;
;LPT1CAP.ASM - (c) 1998 - Maruja
;
;Programa residente que captura todos los accesos al puerto LPT1
;Se activa con 'INT 90h' y se desactiva con 'INT 91h'
;
 
.model tiny
.code
org 100h
 
inicio:        jmp  Arranque
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IN_BYTE        EQU     0ECh           ;IN  AL, DX
IN_WORD        EQU     0EDh           ;IN  AX, DX
OUT_BYTE       EQU     0EEh           ;OUT DX, AL
OUT_WORD       EQU     0EFh           ;OUT DX, AX
 
ES_OUT         EQU     32768          ;Bit 15 flags
ES_WORD        EQU     16384          ;Bit 14 flags
 
IPanterior     dw      0              ;CS:IP Instruccion anterior
CSanterior     dw      0
 
lpt11          dw      ?              ;Direccion base (1er registro) de LPT1
lpt13          dw      ?              ;Direccion 3er registro de LPT1
 
TAMBUF         EQU     4096*8         ;Longitud buffer (grande)
buffer         db      TAMBUF  dup (0) ;Buffer temporal para datos capturados
index          dw      0              ;Posicion en buffer
 
filename       db      'C:\LPT.DAT', 0 ;Archivo con datos capturados
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetTrap:       push ax
               push bp
 
               mov  bp, sp
               mov  ax, [bp+8]        ;Obtener flags de la pila
               or   ah, 1             ;Activar bit T
               mov  [bp+8], ax        ;Colocar nuevos flags en la pila
 
               push dx
               push ds
               push cs
               pop  ds
               mov  ax, 2501h         ;Setear nuestro vector de int TRAP
               lea  dx, Trap
               int  21h
               pop  ds
               pop  dx
 
               pop  bp
               pop  ax
 
 
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ; INSTRUCCION ORIGINAL EN EL ARCHIVO DE PROTECCION
        ; QUE FUE CAMBIADA POR EL 'INT 90h' (CD 90)
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
               ADD  DI, AX
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
UnTrap:        push ax
               push bp
 
               mov  bp, sp
               mov  ax, [bp+8]        ;Obtener flags de la pila
               and  ah, 0FEh          ;Desactivar bit T
               mov  [bp+8], ax        ;Colocar nuevos flags en la pila
 
               cmp  cs:index, 0       ;El buffer est  vac¡o ?
               jz   UnTrap_salir      ;Si: salir
 
               push bx
               push cx
               push dx
               push ds
               push cs
               pop  ds
               call GrabarBuffer      ;Forzar la grabacion del buffer
               pop  ds
               pop  dx
               pop  cx
               pop  bx
 
UnTrap_salir:  pop  bp
               pop  ax
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Trap:
        SP_INICIAL     EQU     $
 
               push ax                ;Salvar registros utilizados
               push bx
               push cx
               push dx
               push si
               push ds
               push bp
 
        SP_FINAL       EQU     $
 
               cmp  cs:CSanterior, 0  ;CSanterior tiene un valor incorrecto ?
               jz   Trap_salir        ;Si: salir
               
               mov  si, cs:CSanterior
               mov  ds, si
               mov  si, cs:IPanterior ;DS:SI = CS:IP instrucci¢n anterior
               mov  cl, byte ptr [si] ;Obtener opcode 
 
               cmp  cl, IN_BYTE       ;El opcode es alguno entre
               jb   Trap_salir        ;IN_BYTE u OUT_WORD ?
               cmp  cl, OUT_WORD
               ja   Trap_salir        ;No: salir
 
               push cs
               pop  ds
               cmp  dx, lpt11         ;Acceso a alguno de los puertos LPT1 ?
               jb   Trap_salir
               cmp  dx, lpt13
               ja   Trap_salir        ;No: salir
 
               call CapturarAcceso
 
Trap_salir:    mov  bp, sp            ;Guardar CS:IP de proxima instruccion
               mov  si, [bp + (SP_FINAL-SP_INICIAL)*2 + 2 ]
               mov  cs:CSanterior, si
               mov  si, [bp + (SP_FINAL-SP_INICIAL)*2 ]
               mov  cs:IPanterior, si
 
               pop  bp                ;Recuperar registros y salir
               pop  ds
               pop  si
               pop  dx
               pop  cx
               pop  bx
               pop  ax
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CapturarAcceso: ;AX = Dato; DX = Puerto; CL = Opcode
 
               cmp  cl, OUT_WORD      ;Es un OUT ?
               je   CA_setout
               cmp  cl, OUT_BYTE
               jne  CA_verdata
CA_setout:     or   dx, ES_OUT        ;Si: setear bit 15
 
CA_verdata:    cmp  cl, IN_WORD       ;El dato es word ?
               je   CA_setword
               cmp  cl, OUT_WORD
               jne  CA_push
CA_setword:    or   dx, ES_WORD       ;Si: setear bit 14
 
CA_push:       lea  si, buffer        ;Guardar estructura en buffer
               add  si, index
               mov  cx, CSanterior
               mov  [si], cx          ;Guardar CS
               mov  cx, IPanterior
               mov  [si+2], cx        ;Guardar IP
               mov  [si+4], dx        ;Guardar Flags
               mov  [si+6], ax        ;Guardar Dato
               add  index, 8          ;Actualizar indice
 
               cmp  index, TAMBUF     ;El buffer esta lleno ?
               je   GrabarBuffer      ;Si: grabar buffer en disco
 
               ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GrabarBuffer:  mov  ax, 3D02h         ;Abrir archivo para L/E
               lea  dx, filename
               int  21h
               jnc  GB_append
               mov  ah, 3Ch           ;Si no existe crearlo
               xor  cx, cx
               int  21h
               jc   GB_salir          ;Si hubo error salir
 
GB_append:     mov  bx, ax            ;Poner archivo en modo append
               mov  ax, 4202h
               xor  dx, dx
               xor  cx, cx
               int  21h
 
               mov  ah, 40h           ;Grabar buffer
               mov  cx, index
               lea  dx, buffer
               int  21h
 
               mov  ah, 3Eh           ;Cerrar archivo
               int  21h
               mov  index, 0          ;Resetear indice
 
GB_salir:      ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FINRESID       EQU     $              ;Aca termina el residente
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetearVectores: mov  ax, 2590h         ;Hacer que una INT 90h ejecute el
               lea  dx, SetTrap       ;codigo 'SetTrap'
               int  21h
 
               mov  ax, 2591h         ;Hacer que una INT 91h ejecute el
               lea  dx, UnTrap        ;codigo 'UnTrap'
               int  21h
 
               mov  ax, 2501h         ;Hacer que la interrupcion TRAP
               lea  dx, Trap          ;provoque la ejecucion del codigo
               int  21h               ;'Trap'
 
               ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GetLPT1:       push es                        ;Obtener registros de LPT1
               mov  di, 40h
               mov  es, di
               mov  di, 8                     ;ES:DI = 0040:0008h
                mov  ax, word ptr es:[di]
               mov  lpt11, ax                 ;lpt11 = Registro 1 LPT1
               add  ax, 2
               mov  lpt13, ax                 ;lpt13 = Registro 3 LPT1
               pop  es
               ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mok            db      13, 10, 'OK', 13, 10, '$'
myaestoy       db      13, 10, 'Ya estaba residente', 13, 10, '$'
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Arranque:      push ds                        ;El offset del vector de
               xor  si, si                    ;interrupcion 90h es igual
               mov  ds, si                    ;al offset de la SetTrap ?
               mov  si, 240h
               mov  ax, word ptr [si]
               pop  ds
               cmp  ax, offset SetTrap
               jne  A_instalar                ;No: instalar residente
 
               lea  dx, myaestoy              ;Como el residente ya estaba
               mov  ah, 9                     ;instalado mostrar mensaje
               int  21h                       ;y salir
               mov  ax, 4C00h
               int  21h
 
A_instalar:    call GetLPT1                   ;Obtener direcciones de LPT1
               call SetearVectores            ;Setear nuevos vectores de ints
               lea  dx, mok                   ;Mostrar mensaje 'OK'
               mov  ah, 9
               int  21h
               mov  ax, 3100h                 ;Terminar y quedar residente
               lea  dx, FINRESID
               shr  dx, 4
               inc  dx
               int  21h
 
end inicio
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
--------------------END LPT1CAP.ASM------------------------------------

Operamos:

 
C:\>TASM LPT1CAP.ASM
...
C:\>TLINK /t LPT1CAP
...
C:\>DEL LPT.DAT
 
C:\>LPT1CAP
 
OK
 
C:\>LPT1CAP
 
Ya estaba residente
 
C:\>GESTION.EXE
...
...
 
C:\>DIR *.DAT
 Volumen en unidad C es PINDONGA
 Número de serie de volumen es 2D4B-1CD6
 Directorio de C:\
 
Archivo no se encontró
 
C:\>

¿Qué pasó que no apareció el archivo con los datos capturados? Nada malo: el nuevo buffer del residente tiene capacidad para 4096 accesos y el programa de protección no realizó tantos, para vaciarlo usamos al programa FLUSH.ASM:

 
--------------------BEGIN FLUSH.ASM------------------------------------
;
;FLUSH.ASM - (c) 1998 - Maruja
;
;Baja el contenido del buffer de la rutina TRAP residente a disco
;
 
.model tiny
.code
 
org 100h
 
inicio: int 91h
        mov ax, 4C00h
        int 21h
 
end inicio
--------------------END FLUSH.ASM--------------------------------------

Luego:

 
C:\>TASM FLUSH.ASM
...
C:\>TLINK /t FLUSH
...
C:\>FLUSH.COM
 
C:\>DIR *.DAT
 
 Volumen en unidad C es PINDONGA
 Número de serie de volumen es 2D4B-1CD6
 Directorio de C:\
 
LPT      DAT     14032 06/09/98   23:10
 
        1 archivo(s)       2048 bytes
                   804409628 bytes libres
                  
C:\>

¡Muejejee! Se han hecho 1754 accesos en LPT1.

Explicación de las rutinas de LPT1CAP.ASM:
SetTrap:
Activa el TRAP bit, setea el propio vector para la interrupción Trap y ejecuta el código original del programa de protección que fué alterado por el 'INT 90h' en la rutina de desencripción ('ADD DI, AX').

Arranque:
Se fija si el vector de la interrupción 90h tiene el mismo offset que el de la rutina 'SetTrap', si es así, asume que el residente ya está instalado y termina la ejecución del programa. En caso contrario, obtiene los puertos de LPT1, cambia los vectores de las interrupciones utilizadas y sale al DOS quedando residente.


NOTA: Una forma más sencilla de provocar la interrupción 90h puede hacerse en el momento en que el programa de protección setea los vectores de las interrupciones TRAP, NMI, y BII luego de producir esa 'colitis' utilizando la pila: ¡Basta solamente con cambiar el INT 21h por un INT 90h modificando solamente 1 byte del código original! Se optó por ponerla en otra parte ya que este tipo de estupidismos por parte de los creadores de ese archivo no debería ser común, además se demuestra que cualquier lugar estratégico es bueno, incluso dentro de un bucle.



EMULANDO LA LLAVE DE HARDWARE


NIVEL 1: ENGAÑANDO AL PROGRAMA DE 'PROTECCION':

En este momento disponemos de las herramientas necesarias para capturar varios accesos a LPT1 y hacer un análisis mas o menos profundo del contenido de la llave y de la forma con la que el programa de protección accede a ella:

 
C:\>REN LPT.DAT 1.DAT
 
C:\>GESTION.EXE
...
C:\>FLUSH.COM
 
C:\>REN LPT.DAT 2.DAT
 
C:\>GESTION.EXE
...
C:\>FLUSH.COM
 
C:\>REN LPT.DAT 3.DAT
 
C:\>GESTION.EXE
...
C:\>FLUSH.COM
 
C:\>REN LPT.DAT 4.DAT
 
C:\>GESTION.EXE
...
C:\>FLUSH.COM
 
C:\>REN LPT.DAT 5.DAT
 
C:\>DIR C:\*.DAT
 
 Volumen en unidad C es PINDONGA
 Número de serie de volumen es 2D4B-1CD6
 Directorio de C:\
 
1        DAT     14032 10/09/98   18:09
2        DAT     14912 10/09/98   18:10
3        DAT     15488 10/09/98   18:10
4        DAT     14048 10/09/98   18:11
5        DAT     15792 10/09/98   18:11
        5 archivo(s)      74272 bytes
                   757170176 bytes libres
 
C:\>

¡Ooohh! ¡Parece que los muchachos quieren guerra! Por cada ejecución se hicieron 1754, 1864, 1936, 1756, y 1974 accesos respectivamente, veamos el contenido del primero:

 
C:\>IOVIEW 1.DAT
 
Archivo: '1.dat'
1BCB:0854      IN      278, 00        (BYTE)
1BCB:0861      OUT     278, 55        (BYTE)
1BCB:0865      IN      278, 55        (BYTE)
1BCB:0874      OUT     278, AA        (BYTE)
1BCB:0878      IN      278, AA        (BYTE)
1BCB:0887      OUT     278, 00        (BYTE)
1BCB:00E2      IN      278, 00        (BYTE)
1BCB:00F9      IN      27A, CC        (BYTE)
1BCB:00FF      OUT     27A, CC        (BYTE)
1BCB:010D      OUT     278, 92        (BYTE)
1BCB:011D      OUT     278, B2        (BYTE)
1BCB:014A      IN      279, 96        (BYTE)
1BCB:0195      OUT     278, 40        (BYTE)
1BCB:01B8      OUT     278, 00        (BYTE)
1BCB:0195      OUT     278, FA        (BYTE)
1BCB:01B8      OUT     278, BA        (BYTE)
1BCB:0195      OUT     278, F8        (BYTE)
1BCB:01B8      OUT     278, B8        (BYTE)
1BCB:0195      OUT     278, F2        (BYTE)
1BCB:01B8      OUT     278, B2        (BYTE)
1BCB:0195      OUT     278, F0        (BYTE)
1BCB:01B8      OUT     278, B0        (BYTE)
1BCB:0195      OUT     278, EA        (BYTE)
1BCB:01B8      OUT     278, AA        (BYTE)
1BCB:0195      OUT     278, E8        (BYTE)
1BCB:01B8      OUT     278, A8        (BYTE)
1BCB:0195      OUT     278, E2        (BYTE)
1BCB:01B8      OUT     278, A2        (BYTE)
1BCB:0195      OUT     278, E0        (BYTE)
1BCB:01B8      OUT     278, A0        (BYTE)
1BCB:0195      OUT     278, DA        (BYTE)
1BCB:01B8      OUT     278, 9A        (BYTE)
1BCB:0195      OUT     278, D8        (BYTE)
1BCB:01B8      OUT     278, 98        (BYTE)
1BCB:0195      OUT     278, D2        (BYTE)
1BCB:01B8      OUT     278, 92        (BYTE)
1BCB:0195      OUT     278, D0        (BYTE)
1BCB:01B8      OUT     278, 90        (BYTE)
1BCB:0195      OUT     278, CA        (BYTE)
1BCB:01B8      OUT     278, 8A        (BYTE)
1BCB:0195      OUT     278, C8        (BYTE)
1BCB:01B8      OUT     278, 88        (BYTE)
1BCB:0195      OUT     278, C2        (BYTE)
1BCB:01B8      OUT     278, 82        (BYTE)
1BCB:0195      OUT     278, C0        (BYTE)
1BCB:01B8      OUT     278, 80        (BYTE)
1BCB:0195      OUT     278, 7A        (BYTE)
1BCB:01B8      OUT     278, 3A        (BYTE)
1BCB:0195      OUT     278, 78        (BYTE)
1BCB:01B8      OUT     278, 38        (BYTE)
1BCB:0195      OUT     278, 72        (BYTE)
1BCB:01B8      OUT     278, 32        (BYTE)
1BCB:0195      OUT     278, 70        (BYTE)
1BCB:01B8      OUT     278, 30        (BYTE)
1BCB:0195      OUT     278, 6A        (BYTE)
1BCB:01B8      OUT     278, 2A        (BYTE)
1BCB:0195      OUT     278, 68        (BYTE)
1BCB:01B8      OUT     278, 28        (BYTE)
1BCB:0195      OUT     278, 62        (BYTE)
1BCB:01B8      OUT     278, 22        (BYTE)
1BCB:0195      OUT     278, 60        (BYTE)
1BCB:01B8      OUT     278, 20        (BYTE)
1BCB:0195      OUT     278, 5A        (BYTE)
1BCB:01B8      OUT     278, 1A        (BYTE)
1BCB:01C5      OUT     278, A2        (BYTE)
1BCB:01EC      OUT     278, E2        (BYTE)
1BCB:020F      OUT     278, A2        (BYTE)
1BCB:0219      OUT     278, B2        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:0244      OUT     278, F2        (BYTE)
1BCB:0267      OUT     278, B2        (BYTE)
1BCB:0272      IN      279, 96        (BYTE)
1BCB:02FD      OUT     278, 40        (BYTE)
1BCB:0320      OUT     278, 00        (BYTE)
1BCB:02FD      OUT     278, FA        (BYTE)
1BCB:0320      OUT     278, BA        (BYTE)
1BCB:02FD      OUT     278, F8        (BYTE)
1BCB:0320      OUT     278, B8        (BYTE)
1BCB:02FD      OUT     278, F2        (BYTE)
1BCB:0320      OUT     278, B2        (BYTE)
1BCB:02FD      OUT     278, F0        (BYTE)
1BCB:0320      OUT     278, B0        (BYTE)
1BCB:02FD      OUT     278, EA        (BYTE)
1BCB:0320      OUT     278, AA        (BYTE)
1BCB:02FD      OUT     278, E8        (BYTE)
1BCB:0320      OUT     278, A8        (BYTE)
1BCB:02FD      OUT     278, E2        (BYTE)
1BCB:0320      OUT     278, A2        (BYTE)
1BCB:02FD      OUT     278, E0        (BYTE)
1BCB:0320      OUT     278, A0        (BYTE)
1BCB:02FD      OUT     278, DA        (BYTE)
1BCB:0320      OUT     278, 9A        (BYTE)
1BCB:02FD      OUT     278, D8        (BYTE)
1BCB:0320      OUT     278, 98        (BYTE)
1BCB:02FD      OUT     278, D2        (BYTE)
1BCB:0320      OUT     278, 92        (BYTE)
1BCB:02FD      OUT     278, D0        (BYTE)
1BCB:0320      OUT     278, 90        (BYTE)
1BCB:02FD      OUT     278, CA        (BYTE)
1BCB:0320      OUT     278, 8A        (BYTE)
1BCB:02FD      OUT     278, C8        (BYTE)
1BCB:0320      OUT     278, 88        (BYTE)
1BCB:02FD      OUT     278, C2        (BYTE)
1BCB:0320      OUT     278, 82        (BYTE)
1BCB:02FD      OUT     278, C0        (BYTE)
1BCB:0320      OUT     278, 80        (BYTE)
1BCB:02FD      OUT     278, 7A        (BYTE)
1BCB:0320      OUT     278, 3A        (BYTE)
1BCB:02FD      OUT     278, 78        (BYTE)
1BCB:0320      OUT     278, 38        (BYTE)
1BCB:02FD      OUT     278, 72        (BYTE)
1BCB:0320      OUT     278, 32        (BYTE)
1BCB:02FD      OUT     278, 70        (BYTE)
1BCB:0320      OUT     278, 30        (BYTE)
1BCB:02FD      OUT     278, 6A        (BYTE)
1BCB:0320      OUT     278, 2A        (BYTE)
1BCB:02FD      OUT     278, 68        (BYTE)
1BCB:0320      OUT     278, 28        (BYTE)
1BCB:02FD      OUT     278, 62        (BYTE)
1BCB:0320      OUT     278, 22        (BYTE)
1BCB:02FD      OUT     278, 60        (BYTE)
1BCB:0320      OUT     278, 20        (BYTE)
1BCB:02FD      OUT     278, 5A        (BYTE)
1BCB:0320      OUT     278, 1A        (BYTE)
1BCB:02FD      OUT     278, 58        (BYTE)
1BCB:0320      OUT     278, 18        (BYTE)
1BCB:02FD      OUT     278, 52        (BYTE)
1BCB:0320      OUT     278, 12        (BYTE)
1BCB:02FD      OUT     278, 50        (BYTE)
1BCB:0320      OUT     278, 10        (BYTE)
1BCB:02FD      OUT     278, 4A        (BYTE)
1BCB:0320      OUT     278, 0A        (BYTE)
1BCB:02FD      OUT     278, 48        (BYTE)
1BCB:0320      OUT     278, 08        (BYTE)
1BCB:02FD      OUT     278, 42        (BYTE)
1BCB:0320      OUT     278, 02        (BYTE)
1BCB:02FD      OUT     278, 40        (BYTE)
1BCB:0320      OUT     278, 00        (BYTE)
1BCB:02FD      OUT     278, FA        (BYTE)
1BCB:0320      OUT     278, BA        (BYTE)
1BCB:02FD      OUT     278, F8        (BYTE)
1BCB:0320      OUT     278, B8        (BYTE)
1BCB:02FD      OUT     278, F2        (BYTE)
1BCB:0320      OUT     278, B2        (BYTE)
1BCB:032D      OUT     278, 92        (BYTE)
1BCB:0338      IN      279, 96        (BYTE)
1BCB:0357      OUT     27A, 0C        (BYTE)
1BCB:07CD      OUT     278, 00        (BYTE)
1BCB:00E2      IN      278, 00        (BYTE)
1BCB:040B      IN      278, 00        (BYTE)
1BCB:0423      OUT     278, 73        (BYTE)
1BCB:0435      OUT     27A, 0C        (BYTE)
1BCB:043F      IN      27A, CC        (BYTE)
1BCB:0474      OUT     278, 05        (BYTE)
1BCB:0484      OUT     278, 85        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:0498      OUT     278, 85        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0398      OUT     278, 85        (BYTE)
1BCB:03AA      OUT     27A, 04        (BYTE)
1BCB:03B8      OUT     278, C5        (BYTE)
1BCB:03C4      OUT     278, 85        (BYTE)
1BCB:03D6      OUT     27A, 0C        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:0498      OUT     278, 85        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0474      OUT     278, 05        (BYTE)
1BCB:0484      OUT     278, 85        (BYTE)
1BCB:0398      OUT     278, 85        (BYTE)
1BCB:03AA      OUT     27A, 04        (BYTE)
1BCB:03B8      OUT     278, C5        (BYTE)
1BCB:03C4      OUT     278, 85        (BYTE)
1BCB:03D6      OUT     27A, 0C        (BYTE)
1BCB:04E8      OUT     278, 97        (BYTE)
1BCB:04F8      OUT     278, B7        (BYTE)
1BCB:04E8      OUT     278, 97        (BYTE)
1BCB:04F8      OUT     278, B7        (BYTE)
1BCB:04E8      OUT     278, 87        (BYTE)
1BCB:04F8      OUT     278, A7        (BYTE)
1BCB:04E8      OUT     278, 87        (BYTE)
1BCB:04F8      OUT     278, A7        (BYTE)
1BCB:04E8      OUT     278, 87        (BYTE)
1BCB:04F8      OUT     278, A7        (BYTE)
1BCB:04E8      OUT     278, 87        (BYTE)
1BCB:04F8      OUT     278, A7        (BYTE)
1BCB:04E8      OUT     278, 87        (BYTE)
1BCB:04F8      OUT     278, A7        (BYTE)
1BCB:04E8      OUT     278, 87        (BYTE)
1BCB:04F8      OUT     278, A7        (BYTE)
1BCB:04E8      OUT     278, 87        (BYTE)
1BCB:04F8      OUT     278, A7        (BYTE)
1BCB:05A5      OUT     278, 85        (BYTE)
1BCB:05B1      OUT     278, 95        (BYTE)
1BCB:05C4      IN      279, 86        (BYTE)
1BCB:05F7      OUT     278, A5        (BYTE)
1BCB:0602      IN      279, 86        (BYTE)
1BCB:0616      OUT     278, 95        (BYTE)
1BCB:0638      IN      279, 96        (BYTE)
1BCB:05F7      OUT     278, A5        (BYTE)
1BCB:0602      IN      279, 96        (BYTE)
1BCB:0616      OUT     278, 95        (BYTE)
1BCB:0638      IN      279, 96        (BYTE)
1BCB:05F7      OUT     278, A5        (BYTE)
1BCB:0602      IN      279, 96        (BYTE)
1BCB:0616      OUT     278, 95        (BYTE)
1BCB:0638      IN      279, 96        (BYTE)
1BCB:05F7      OUT     278, A5        (BYTE)
1BCB:0602      IN      279, 96        (BYTE)
1BCB:0616      OUT     278, 95        (BYTE)
1BCB:0638      IN      279, 96        (BYTE)
1BCB:05F7      OUT     278, A5        (BYTE)
1BCB:0602      IN      279, 96        (BYTE)
1BCB:0616      OUT     278, 95        (BYTE)
1BCB:0638      IN      279, 96        (BYTE)
1BCB:05F7      OUT     278, A5        (BYTE)
1BCB:0602      IN      279, 96        (BYTE)
1BCB:0616      OUT     278, 95        (BYTE)
1BCB:0638      IN      279, 86        (BYTE)
1BCB:05F7      OUT     278, A5        (BYTE)
1BCB:0602      IN      279, 86        (BYTE)
1BCB:0616      OUT     278, 95        (BYTE)
1BCB:0638      IN      279, 86        (BYTE)
1BCB:0474      OUT     278, 05        (BYTE)
1BCB:0484      OUT     278, 85        (BYTE)
1BCB:0398      OUT     278, 85        (BYTE)
1BCB:03AA      OUT     27A, 04        (BYTE)
1BCB:03B8      OUT     278, C5        (BYTE)
1BCB:03C4      OUT     278, 85        (BYTE)
1BCB:03D6      OUT     27A, 0C        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:0498      OUT     278, 85        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 86        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0474      OUT     278, 05        (BYTE)
1BCB:0484      OUT     278, 85        (BYTE)
1BCB:040B      IN      278, 85        (BYTE)
1BCB:0423      OUT     278, 73        (BYTE)
1BCB:0435      OUT     27A, 0C        (BYTE)
1BCB:043F      IN      27A, CC        (BYTE)
1BCB:0474      OUT     278, 05        (BYTE)
1BCB:0484      OUT     278, 85        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:0498      OUT     278, 85        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0398      OUT     278, 85        (BYTE)
1BCB:03AA      OUT     27A, 04        (BYTE)
1BCB:03B8      OUT     278, C5        (BYTE)
1BCB:03C4      OUT     278, 85        (BYTE)
1BCB:03D6      OUT     27A, 0C        (BYTE)
1BCB:03EE      OUT     278, C5        (BYTE)
1BCB:03FA      OUT     278, 85        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:0498      OUT     278, 85        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:040B      IN      278, 95        (BYTE)
1BCB:0423      OUT     278, 73        (BYTE)
1BCB:0435      OUT     27A, 0C        (BYTE)
1BCB:043F      IN      27A, CC        (BYTE)
1BCB:0474      OUT     278, 05        (BYTE)
1BCB:0484      OUT     278, 85        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:0498      OUT     278, 85        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0398      OUT     278, 85        (BYTE)
1BCB:03AA      OUT     27A, 04        (BYTE)
1BCB:03B8      OUT     278, C5        (BYTE)
1BCB:03C4      OUT     278, 85        (BYTE)
1BCB:03D6      OUT     27A, 0C        (BYTE)
1BCB:03EE      OUT     278, C5        (BYTE)
1BCB:03FA      OUT     278, 85        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 95        (BYTE)
1BCB:04F8      OUT     278, B5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:04E8      OUT     278, 85        (BYTE)
1BCB:04F8      OUT     278, A5        (BYTE)
1BCB:0498      OUT     278, 85        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:0515      OUT     278, A5        (BYTE)
1BCB:0521      OUT     278, 95        (BYTE)
1BCB:0537      OUT     278, 85        (BYTE)
1BCB:0543      OUT     278, 95        (BYTE)
1BCB:0561      IN      279, 96        (BYTE)
1BCB:07CD      OUT     278, 00        (BYTE)

¡Que lo parió! Si hacemos lo mismo con los otros archivos observaremos cosas similarmente asquerosas. ¡Pero no os desesperéis! ¡Pensad! ¡Pensad un cachito!
Por un lado se observa que la cantidad de accesos a la llave es variable por cada ejecución del programa de protección, pero por otro lado se sabe que los datos de la llave se utilizan para desencriptar al programa protegido, podemos inferir entonces que lo que se lee es siempre lo mismo (pueden haber variaciones con los OUTs pero los INs deberían ser siempre iguales). Verificamos esta sospecha con el programa IOINS.C:

 
--------------------BEGIN IOINS.C--------------------------------------
/*
** IOINS.C - (c) 1998 - Maruja
** Muestra (en forma entendible) los datos capturados en operaciones IN
**
** Modo de uso:  IOINS  file
** Donde  file  es el nombre del archivo con los datos
*/
 
 
#include <stdio.h>
#include <stdlib.h>
 
 
/* Teseteo de Flags */
#define TEST_OUT(flag)         (flag & 32768)         /* bit 15 = OUT */
#define TEST_WORD(flag)               (flag & 16384)         /* bit 14 = WORD */
#define GET_PORT(flag)         (flag & 2047)
 
 
/* Estructura basica */
typedef struct {
 
    unsigned int       cs, 
                       ip, 
                       flags, 
                       data;
 
    } TRAP;
 
 
 
int main (int can, char *arg[])
{
FILE    *f;
TRAP    i;
 
 
/* Verificar que se encuentre el nombre del file */
if (can < 2) {
 
        fprintf (stderr, 
                "%s: Falta el nombre del archivo con los datos capturados\n\r",
                arg[0]);
 
        exit (-1);
 
        }
 
 
/* Abrir archivo de datos */
if (! (f = fopen (arg[1], "rb")) ) {
 
        fprintf (stderr, "%s: ", arg[0]);
        perror (arg[1]);
        exit (-1);
 
        }
 
 
/* Mostrar informacion */
printf ("\nArchivo: '%s'", arg[1]);
for (;;) {
 
        /* Leer estructura */
        if (!fread (&i, sizeof (TRAP), 1, f)) break;
 
        /* Mostrar en forma humana */
        if (!TEST_OUT(i.flags)) {
               
               printf ("\n%04X:%04X\tIN\t%03X, ", i.cs, i.ip, 
                                                     GET_PORT(i.flags));
 
               if (TEST_WORD(i.flags))
 
                       printf ("%04X\t(WORD)", i.data);
 
               else printf ("%02X  \t(BYTE)", i.data & 255);
 
               }
 
        }
 
printf ("\n");
return 0;
}
--------------------END IOINS.C----------------------------------------

Hagamos lo siguiente:

 
C:\>CC IOINS.C
..
C:\>IOINS 1.DAT > IN1.ASC
 
C:\>IOINS 2.DAT > IN2.ASC
 
C:\>IOINS 3.DAT > IN3.ASC
 
C:\>IOINS 4.DAT > IN4.ASC
 
C:\>IOINS 5.DAT > IN5.ASC
 
C:\>DIR C:\IN*.ASC
 
 Volumen en unidad C es PINDONGA
 Número de serie de volumen es 2D4B-1CD6
 Directorio de C:\
 
IN1      ASC     13784 15/09/98    0:15
IN2      ASC     13784 15/09/98    0:16
IN3      ASC     13784 15/09/98    0:16
IN4      ASC     13784 15/09/98    0:17
IN5      ASC     13784 15/09/98    0:17
        5 archivo(s)      68920 bytes
                   757334016 bytes libres
 
C:\>

[ Jejejejeje... La cantidad de INs es siempre la misma. Veamos si los datos tambien son los mismos... ]

 
C:\>FC IN1.ASC IN2.ASC
Comparando archivos IN1.ASC y IN2.ASC
***** IN1.ASC
 
Archivo: '1.DAT'
1BCB:0854       IN      278, 00         (BYTE)
***** IN2.ASC
 
Archivo: '2.DAT'
1BCB:0854       IN      278, 00         (BYTE)
*****
 
C:\>FC IN1.ASC IN3.ASC
Comparando archivos IN1.ASC y IN3.ASC
***** IN1.ASC
 
Archivo: '1.DAT'
1BCB:0854       IN      278, 00         (BYTE)
***** IN3.ASC
 
Archivo: '3.DAT'
1BCB:0854       IN      278, 00         (BYTE)
*****
 
C:\>FC IN1.ASC IN4.ASC
Comparando archivos IN1.ASC y IN4.ASC
***** IN1.ASC
 
Archivo: '1.DAT'
1BCB:0854       IN      278, 00         (BYTE)
***** IN4.ASC
 
Archivo: '4.DAT'
1BCB:0854       IN      278, 00         (BYTE)
*****
 
C:\>FC IN1.ASC IN5.ASC
Comparando archivos IN1.ASC y IN5.ASC
***** IN1.ASC
 
Archivo: '1.DAT'
1BCB:0854       IN      278, 00         (BYTE)
***** IN5.ASC
 
Archivo: '5.DAT'
1BCB:0854       IN      278, 00         (BYTE)
*****
 
C:\>

Jurujujája... Sabemos que los 5 archivos tienen los mismos datos leídos y que las operaciones son de a bytes (osea: 'IN AL,DX' y 'OUT DX,AL'). Para poner los datos de la llave en un programa emulador necesitamos un conversor .DAT a .ASM, el programa DBIN.C se encarga de esto:

 
--------------------BEGIN DBIN.C---------------------------------------
/*
** DBIN.C - (c) 1998 - Maruja
** Muestra (en forma de codigo para ensamblador) los datos 
** capturados en operaciones IN en orden de aparicion
**
** Modo de uso:  DBIN  file
** Donde  file  es el nombre del archivo con los datos
**
** IMPORTANTE: LOS DATOS DEBEN SER TODOS BYTES!! (IN AL, XX)
*/
 
 
#include <stdio.h>
#include <stdlib.h>
 
 
/* Bytes por linea */
#define COLUMNAS               10
 
 
/* Teseteo de Flags */
#define TEST_OUT(flag)         (flag & 32768)         /* bit 15 = OUT */
#define TEST_WORD(flag)               (flag & 16384)         /* bit 14 = WORD */
#define GET_PORT(flag)         (flag & 2047)
 
 
/* Estructura basica */
typedef struct {
 
    unsigned int       cs, 
                       ip, 
                       flags, 
                       data;
 
    } TRAP;
 
 
 
int main (int can, char *arg[])
{
FILE    *f;
TRAP    i;
int     cols,
        datos;
 
 
/* Verificar que se encuentre el nombre del file */
if (can < 2) {
 
        fprintf (stderr, 
                "%s: Falta el nombre del archivo con los datos capturados\n\r",
                arg[0]);
 
        exit (-1);
 
        }
 
 
/* Abrir archivo de datos */
if (! (f = fopen (arg[1], "rb")) ) {
 
        fprintf (stderr, "%s: ", arg[0]);
        perror (arg[1]);
        exit (-1);
 
        }
 
 
/* Mostrar informacion */
datos = 0;
cols = 0;
for (;;) {
 
    /* Leer estructura */
    if (!fread (&i, sizeof (TRAP), 1, f)) break;
 
 
    /* Solamente si es IN */
    if (!TEST_OUT(i.flags) ) {
 
        /* Contador de cantidad de INs */
        datos++;
 
        /* Iniciar linea */
        if (!cols) printf ("\n\t\tdb\t");
 
        /* Mostrar en decimal */
        printf ("%03u", i.data & 255);
        if (++cols == COLUMNAS) cols = 0;
        else printf (", ");
 
        }
 
    }
 
/* Mostrar cantidad de datos */
printf ("\n\nKEYBUF\t\tEQU\t%u\n", datos);
return 0;
}
--------------------END DBIN.C-----------------------------------------

Ojo: Este programa asume que los INs son de la forma 'IN AL,DX'. Si el lector está experimentando con otra implementación del programa de protección debe hacer los cambios pertinentes.
Al compilar y ejecutar obtenemos:

 
C:\>CC DBIN.C
..
C:\>DBIN 1.DAT > 1.ASM
 
C:\>DBIN 2.DAT > 2.ASM
 
C:\>DBIN 3.DAT > 3.ASM
 
C:\>DBIN 4.DAT > 4.ASM
 
C:\>DBIN 5.DAT > 5.ASM
 
C:\>DIR C:\?.ASM
 
 Volumen en unidad C es PINDONGA
 Número de serie de volumen es 2D4B-1CD6
 Directorio de C:\
 
1        ASM      2468 16/09/98   22:14
2        ASM      2468 16/09/98   22:14
3        ASM      2468 16/09/98   22:14
4        ASM      2468 16/09/98   22:14
5        ASM      2468 16/09/98   22:14
        5 archivo(s)      12340 bytes
                   756776960 bytes libres
 
C:\>FC 1.ASM 2.ASM
Comparando archivos 1.ASM y 2.ASM
FC: no se encontraron diferencias
 
C:\>FC 1.ASM 3.ASM
Comparando archivos 1.ASM y 3.ASM
FC: no se encontraron diferencias
 
C:\>FC 1.ASM 4.ASM
Comparando archivos 1.ASM y 4.ASM
FC: no se encontraron diferencias
 
C:\>FC 1.ASM 5.ASM
Comparando archivos 1.ASM y 5.ASM
FC: no se encontraron diferencias
 
C:\>TYPE 1.ASM
 
               db      000, 085, 170, 000, 204, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
                db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 000, 000, 204, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 134, 134, 150, 134, 134, 150
               db      134, 150, 134, 134, 134, 150, 150, 134, 134, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 134
               db      134, 134, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 134, 134, 134, 134, 134, 134
               db      134, 134, 150, 150, 150, 134, 150, 134, 134, 150
               db      150, 150, 150, 134, 134, 150, 134, 134, 150, 134
               db      150, 134, 134, 134, 150, 150, 133, 204, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      149, 204, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 
 
KEYBUF         EQU     444
 
C:\>

Sabiendo que:

  1. Para leer se utiliza SIEMPRE la instrucción 'IN AL,DX';
  2. Se leen SIEMPRE la misma cantidad de datos;
  3. Se leen SIEMPRE los mismos datos;

el programa KEYEMU1.ASM puede engañar perfectamente al archivo de protección:

 
--------------------BEGIN KEYEMU1.ASM-----------------------------------
;
;KEYEMU1.ASM - (c) 1998 - Maruja
;
;Programa residente de prueba que emula la llave de harware
;marca 'SOStuare Look' que protege a un programa berreta de facturacion
;
;Confunde al programa de proteccion pero no al programa protegido
;
 
.model tiny
.code
org 100h
 
inicio:        jmp  Arranque
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IN_BYTE        EQU     0ECh           ;IN  AL, DX
 
IPanterior     dw      0              ;CS:IP Instruccion anterior
CSanterior     dw      0
 
lpt11          dw      ?              ;Direccion base (1er registro) de LPT1
lpt13          dw      ?              ;Direccion 3er registro de LPT1
 
KEYBUF         EQU     444
keyindex       dw      0
keydata        db      000, 085, 170, 000, 204, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 000, 000, 204, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 134, 134, 150, 134, 134, 150
               db      134, 150, 134, 134, 134, 150, 150, 134, 134, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 134
               db      134, 134, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 134, 134, 134, 134, 134, 134
               db      134, 134, 150, 150, 150, 134, 150, 134, 134, 150
               db      150, 150, 150, 134, 134, 150, 134, 134, 150, 134
               db      150, 134, 134, 134, 150, 150, 133, 204, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      149, 204, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetTrap:       push ax
               push bp
 
               mov  bp, sp
               mov  ax, [bp+8]        ;Obtener flags de la pila
               or   ah, 1             ;Activar bit T
               mov  [bp+8], ax        ;Colocar nuevos flags en la pila
 
               push dx
               push ds
               push cs
               pop  ds
               mov  ax, 2501h         ;Setear nuestro vector de int TRAP
               lea  dx, Trap
               int  21h
               pop  ds
               pop  dx
 
               pop  bp
               pop  ax
 
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ; INSTRUCCION ORIGINAL EN EL ARCHIVO DE PROTECCION
        ; QUE FUE CAMBIADA POR EL 'INT 90h' (CD 90)
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
               ADD  DI, AX
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
UnTrap:        push ax
               push bp
 
               mov  bp, sp
               mov  ax, [bp+8]        ;Obtener flags de la pila
               and  ah, 0FEh          ;Desactivar bit T
               mov  [bp+8], ax        ;Colocar nuevos flags en la pila
 
               mov  cs:keyindex, 0    ;Resetear posicion en buffer de llave
 
               pop  bp
               pop  ax
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Trap:
        SP_INICIAL     EQU     $
 
               push cx                ;Salvar registros utilizados
               push si
               push ds
               push bp
 
        SP_FINAL       EQU     $
 
               cmp  cs:CSanterior, 0  ;CSanterior tiene un valor incorrecto ?
               jz   Trap_salir        ;Si: salir
               
               mov  si, cs:CSanterior
               mov  ds, si
               mov  si, cs:IPanterior ;DS:SI = CS:IP instruccion anterior
               mov  cl, byte ptr [si] ;Obtener opcode 
 
               cmp  cl, IN_BYTE       ;El opcode es IN_BYTE ?
               jne  Trap_salir        ;No: salir
 
               push cs
               pop  ds
               cmp  dx, lpt11         ;Acceso a alguno de los puertos LPT1 ?
               jb   Trap_salir
               cmp  dx, lpt13
               ja   Trap_salir        ;No: salir
 
               call EmularKey         ;Si: emular llave
 
Trap_salir:    mov  bp, sp            ;Guardar CS:IP de proxima instruccion
               mov  si, [bp + (SP_FINAL-SP_INICIAL)*2 + 2 ]
               mov  cs:CSanterior, si
               mov  si, [bp + (SP_FINAL-SP_INICIAL)*2 ]
                mov  cs:IPanterior, si
 
               pop  bp                ;Recuperar registros y salir
               pop  ds
               pop  si
               pop  cx
               iret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
EmularKey:     ;En AL pone el mismo dato que pondria la llave
 
               lea  si, keydata       ;Posicionarse en el buffer
               add  si, keyindex
               mov  al, byte ptr [si] ;Obtener dato de la llave ;)
 
               inc  keyindex
               cmp  keyindex, KEYBUF  ;Ya llego al ultimo dato ?
               jne  EK_salir
 
               mov  keyindex, 0       ;Si: resetear posicion en el buffer
 
EK_salir:      ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FINRESID       EQU     $              ;Aca termina el residente
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetearVectores: mov  ax, 2590h         ;Hacer que una INT 90h ejecute el
               lea  dx, SetTrap       ;codigo 'SetTrap'
               int  21h
 
               mov  ax, 2591h         ;Hacer que una INT 91h ejecute el
               lea  dx, UnTrap        ;codigo 'UnTrap'
               int  21h
 
               ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GetLPT1:       push es                        ;Obtener registros de LPT1
               mov  di, 40h
               mov  es, di
               mov  di, 8                     ;ES:DI = 0040:0008h
               mov  ax, word ptr es:[di]
               mov  lpt11, ax                 ;lpt11 = Registro 1 LPT1
               add  ax, 2
               mov  lpt13, ax                 ;lpt13 = Registro 3 LPT1
               pop  es
               ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mok            db      13, 10, 'OK', 13, 10, '$'
myaestoy       db      13, 10, 'Ya estaba residente', 13, 10, '$'
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Arranque:      push ds                        ;El offset del vector de
               xor  si, si                    ;interrupcion 90h es igual
               mov  ds, si                    ;al offset de la SetTrap ?
               mov  si, 240h
               mov  ax, word ptr [si]
               pop  ds
               cmp  ax, offset SetTrap
               jne  A_instalar                ;No: instalar residente
 
               lea  dx, myaestoy              ;Como el residente ya estaba
               mov  ah, 9                     ;instalado mostrar mensaje
               int  21h                       ;y salir
               mov  ax, 4C00h
               int  21h
 
A_instalar:    call GetLPT1                   ;Obtener direcciones de LPT1
               call SetearVectores            ;Setear nuevos vectores de ints
               lea  dx, mok                   ;Mostrar mensaje 'OK'
               mov  ah, 9
               int  21h
               mov  ax, 3100h                 ;Terminar y quedar residente
               lea  dx, FINRESID
               shr  dx, 4
               inc  dx
               int  21h
 
end inicio
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
--------------------END KEYEMU1.ASM-------------------------------------

Descripción de las variables:
keydata:
Es un buffer con datos que el programa de protección necesita para desencriptar al archivo protegido (aquí están los mismos datos que se leerían de la llave si estuviera conectada).

keyindex:
Esta variable indica la posición dentro del buffer (número de órden de lectura).

KEYBUF:
Definición que contiene la longitud del buffer.

Descripción de las rutinas:
Trap:
Rastrea la ejecución de todas las instrucciones y, cuando encuentra un 'IN AL, DX' llama a la rutina 'EmularKey'.

EmularKey:
Pone en AL el dato que corresponde para que el programa de protección se 'coma' que la instrucción recién ejecutada (la IN) tuvo acceso a la llave.


Este programa funciona de la siguiente manera:
Antes de realizar los accesos a LPT1, el programa de protección modificado activa el sistema de rastreo con la 'INT 90h'. Si la llave no está conectada, luego de ejecutarse una instrucción 'IN AL,DX' el registro AL contiene basura, en ése momento la rutina Trap toma el control y ejecuta un EmularKey que coloca en AL el mismo valor que se hubiera leído del puerto si la llave hubiese estado conectada.
Un ejemplo gráfico de este procedimiento puede ser:

EJECUCION NORMAL
comportamiento normal

EJECUCION UTILIZANDO KEYEMU1
comportamiento de keyemu1.asm




NIVEL 2: ENGAÑANDO AL PROGRAMA PROTEGIDO:

Si el programa LPT1CAP1 está residente debemos quitarlo, ya sea resetenado la máquina o utilizando algún programa preparado para tal fín (como ser el par MARK/RELEASE), luego sacamos la llave y realizamos:

 
C:\>TASM KEYEMU1.ASM
...
C:\>TLINK /t KEYEMU1
...
C:\>REN PROTECT.EXE MODIFIC.EXE
 
C:\>COPY ORIGINAL.EXE PROTECT.EXE
 
C:\>GESTION.EXE
 
* El módulo 'SOStuare Look' con número de serie: 00-00000 no está instalado.
 
C:\>DEL PROTECT.EXE
 
C:\>COPY MODIFIC.EXE PROTECT.EXE
 
C:\>KEYEMU1
 
OK
 
C:\>GESTION.EXE
...
...
...
...
...
...
...
        +---------------------------------------------------------------+
        |      El módulo SOStuare Look ha sido retirado              |
        |       Oprima cualquier tecla para reiniciar el sistema      |
        +---------------------------------------------------------------+

Se ha engañado totalmente al archivo de protección pero el programa protegido dijo: '¡No contaban con mi astucia!'.
Calma calma que no panda el cúnico. El chipote chillón es nuestro.

Si ejecutamos el programa original (sín las modificaciones en el archivo de protección) y, en algún momento sacamos la llave, después de un instante aparecerá el mensaje anterior, esto significa que el programa protegido accede al puerto paralelo en forma periódica verificando la existencia de la llave. No sabemos para qué utiliza estos datos pero, utilizando el método KISS (Keep It Simple, Stupid! -técnica que deberían adoptar los infelices que hicieron el programa de factucarión-) asumamos, como primera medida, que el programa protegido no usa para un pito los datos de ésta.
Con esto último en mente, tenemos que debuggear la rutina del programa de facturación que accede a la llave y cancelarla (si esto no llega a funcionar hay que emular de la misma forma que se hizo con el archivo de protección).

Sín el residente KEYEMU1.COM, con la llave colocada en el puerto, y con el programa original sín modificaciones, corremos el debugger:

 
C:\>DEL PROTECT.EXE
 
C:\>COPY ORIGINAL.EXE PROTECT.EXE
 
C:\>LDR GESTION.EXE
 
Loading C:\GESTION.EXE
...
...
:bpint 21 ah=4c
:x
Break Point at 1AE3:01A3
    1AE3:018F  E85500         CALL 01E7
    1AE3:0192  A16401         MOV AX, [0164]
    1AE3:0195  E83500         CALL 01CD
    1AE3:0198  BB1502         MOV BX, 0215
    1AE3:019B  E80700         CALL 01A5
    1AE3:019E  A16201         MOV AX, [0162]
    1AE3:01A1  B44C           MOV AH, 4C
>   1AE3:01A3  CD21           INT 21         ;Terminate process
    ...

[ El programa de protección termina y le devuelve el control al programa protegido ]

 
:t
>   0123:109E  90             NOP
    0123:109F  90             NOP
    0123:10A0  E8CC00         CALL 116F
    ...

[ Inicio del código de la interrupción tipo 21h ]

 
:p ret
>   FDC9:423C  CF             IRET
    ...

[ Punto final de la función 4Ch del DOS ]

 
:t
>   0E0B:05D6  7303           JAE 05BD
    ...

[ Inicio del código del programa de facturación ya desencriptado ]

 
:bpio 278
:bpio 279
:bpio 27a
:x
Break Point at 0E0B:0AF9
    0E0B:0AF8  EC             IN AL, DX
>   0E0B:0AF9  EB01           JMP 0AFC
    ...

[ Código que accede al puerto paralelo ]

 
:p ret
>   0E0B:12D9  C3             RET
    ...

[ Termina la ejecución del código que accede a la llave ]

 
:t
    0E0B:1300  2E8C0E0105     MOV CS:[0501], CS
    0E0B:1307  E8CEF7         CALL 0ADD
>   0E0B:130F  2E803EFE0401   CMP BYTE PTR CS:[04FE], 01     ;CS:[04FE]=01
    0E0B:1315  7502           JNZ 1319
    0E0B:1317  EB0B           JMP 1324
    0E0B:1319  E8C1F7         CALL 0ADD
    ...

[ 0E0B:0ADD es la dirección de la rutina que accede a la llave directamente, pero esta sección de código genera dos accesos, por lo tanto, asumimos que es parte de un sistema de verificación de los datos de ésta, veamos como termina... ]

 
:p ret
:t
    0E0B:0892  2EFF1EDD03     CALL FAR CS:[03DD]
>   0E0B:0897  2E803ED50300   CMP BYTE PTR CS:[03D5], 00     ;CS:[03D5]=00
    0E0B:089D  7409           JZ 08A8
    0E0B:089F  2EC706D8031200 MOV WORD PTR CS:[03D8], 0012
    0E0B:08A6  EB07           JMP 08AF
    0E0B:08A8  2EC706D8038F00 MOV WORD PTR CS:[03D8], 008F
    0E0B:08AF  2EC606D40300   MOV BYTE PTR CS:[03D4], 00
    0E0B:08B5  2E833EF80300   CMP WORD PTR CS:[03D8], 00
    0E0B:08BB  7405           JZ 08C2
    0E0B:08BD  2EFF0ED803     DEC WORD PTR CS:[03D8]
    0E0B:08C2  CF             IRET

[ Era de esperar: el sistema que accede a la llave está dentro de una interrupción -la última instrucción es un IRET-, veamos cuál es... ]

 
:p ret
:t
    3799:00F0  55             PUSH BP
    3799:00F1  CD16           INT 16
>   3799:00F3  5D             POP BP

[ ¡Já! En vez de utilizar la obvia interrupción Timer Tick usa la 16h del BIOS que se encarga de casi todo lo que tiene que ver con el teclado.
Todo lo que está desde 0E0B:0892 hasta el IRET es sumamente sospechoso, por lo tanto, vamos a finalizar la interrupción justamente en ése punto... ]

 
:a e0b:892
0E0B:0892 iret
0E0B:0893

[ Ahora limpiamos todos los breakpoints, sacamos la llave, y dejamos correr al programa como si nada... ]

 
:bc *
:x
...
...
...
...
...
C:\>

Hemos solucionado el problema: el programa protegido ya no accede a la llave. Tenemos que hacer algo para que el IRET se ponga en forma automática. No podemos modificar al programa de facturación porque está encriptado, por lo tanto, tendremos que provocar otro desvío en el archivo de protección en algún lugar después de la desencripción. El mejor lugar para esto es el momento en que dicho programa termina su ejecución. Recordando esa parte del código:

 
    1AE3:018F  E85500         CALL 01E7
    1AE3:0192  A16401         MOV AX, [0164]
    1AE3:0195  E83500         CALL 01CD
    1AE3:0198  BB1502         MOV BX, 0215
    1AE3:019B  E80700         CALL 01A5
    1AE3:019E  A16201         MOV AX, [0162]
    1AE3:01A1  B44C           MOV AH, 4C
    1AE3:01A3  CD21           INT 21

Con la gran ayuda del 'disquetitor':

 
C:\>DISQUETITOR MODIFIC.EXE /W

Buscamos la secuencia:

 
    E8 55 00 A1 64 01 E8 35 00 BB 15 02 E8 07 00 A1 62 01 B4 4C CD 21

y reemplazamos el 'B4 4C' con un 'CD 92' quedando:

 
    E8 55 00 A1 64 01 E8 35 00 BB 15 02 E8 07 00 A1 62 01 CD 92 CD 21

luego se graban los cambios y, después de modificar al programa de emulación anterior, obtenemos a KEYEMU.ASM:

 
--------------------BEGIN KEYEMU.ASM------------------------------------
;
;KEYEMU.ASM - (c) 1998 - Maruja
;
;Programa residente que emula a la perfeccion a la llave de hardware
;marca 'SOStuare Look' que protege a un programa berreta de facturacion
;
 
.model tiny
.code
org 100h
 
inicio:        jmp  Arranque
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IN_BYTE        EQU     0ECh           ;IN  AL, DX
 
IPanterior     dw      0              ;CS:IP Instruccion anterior
CSanterior     dw      0
 
lpt11          dw      ?              ;Direccion base (1er registro) de LPT1
lpt13          dw      ?              ;Direccion 3er registro de LPT1
 
IRET_CODE      EQU     0CFh           ;Opcode de 'IRET'
OFF_PROTEGIDO  EQU     0892h          ;Offset del programa protegido en el
                                      ;que se anula el llamado a la rutina
                                      ;de la llave
 
KEYBUF         EQU     444
keyindex       dw      0
keydata        db      000, 085, 170, 000, 204, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 000, 000, 204, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 134, 134, 150, 134, 134, 150
               db      134, 150, 134, 134, 134, 150, 150, 134, 134, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 134
               db      134, 134, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 134, 134, 134, 134, 134, 134
               db      134, 134, 150, 150, 150, 134, 150, 134, 134, 150
               db      150, 150, 150, 134, 134, 150, 134, 134, 150, 134
               db      150, 134, 134, 134, 150, 150, 133, 204, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      149, 204, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150, 150, 150, 150, 150, 150, 150
               db      150, 150, 150, 150
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetTrap:       push ax
               push bp
 
               mov  bp, sp
               mov  ax, [bp+8]        ;Obtener flags de la pila
               or   ah, 1             ;Activar bit T
               mov  [bp+8], ax        ;Colocar nuevos flags en la pila
 
               push dx
               push ds
               push cs
               pop  ds
               mov  ax, 2501h         ;Setear nuestro vector de int TRAP
               lea  dx, Trap
               int  21h
 
               pop  ds
               pop  dx
               pop  bp
               pop  ax
               
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ; INSTRUCCION ORIGINAL EN EL ARCHIVO DE PROTECCION
        ; QUE FUE CAMBIADA POR EL 'INT 90h' (CD 90)
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
               ADD  DI, AX
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
               iret
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Trap:
        SP_INICIAL     EQU     $
 
               push cx                ;Salvar registros utilizados
               push si
               push ds
               push bp
 
        SP_FINAL       EQU     $
 
               cmp  cs:CSanterior, 0  ;CSanterior tiene un valor incorrecto ?
               jz   Trap_salir        ;Si: salir
               
               mov  si, cs:CSanterior
               mov  ds, si
               mov  si, cs:IPanterior ;DS:SI = CS:IP instruccion anterior
               mov  cl, byte ptr [si] ;Obtener opcode 
 
               cmp  cl, IN_BYTE       ;El opcode es IN_BYTE ?
               jne  Trap_salir        ;No: salir
 
               push cs
               pop  ds
               cmp  dx, lpt11         ;Acceso a alguno de los puertos LPT1 ?
               jb   Trap_salir
               cmp  dx, lpt13
               ja   Trap_salir        ;No: salir
 
               call EmularKey         ;Si: emular llave
 
Trap_salir:    mov  bp, sp            ;Guardar CS:IP de proxima instruccion
               mov  si, [bp + (SP_FINAL-SP_INICIAL)*2 + 2 ]
               mov  cs:CSanterior, si
               mov  si, [bp + (SP_FINAL-SP_INICIAL)*2 ]
               mov  cs:IPanterior, si
 
               pop  bp                ;Recuperar registros y salir
               pop  ds
               pop  si
               pop  cx
               iret
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
EmularKey:     ;En AL pone el mismo dato que pondria la llave
 
               lea  si, keydata       ;Posicionarse en el buffer
               add  si, keyindex
               mov  al, byte ptr [si] ;Obtener dato de la llave ;)
 
               inc  keyindex
               cmp  keyindex, KEYBUF  ;Ya llego al ultimo dato ?
               jne  EK_salir
 
               mov  keyindex, 0       ;Si: resetear posicion en el buffer
 
EK_salir:      ret
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetJMP:        push si
               push ds
               push bx
               push ax
 
               mov  ah, 51h           ;Obtener direccion del PSP
               int  21h
               mov  ds, bx
               mov  si, 0Ch           ;El offset 0Ch del PSP contiene el
                                      ;segmento del codigo al que se debe
                                      ;volver cuando termine el programa de
                                      ;proteccion
 
               mov  bx, word ptr [si] ;Cancelar llamada a la rutina de 
               mov  ds, bx            ;lectura de la llave
               mov  si, OFF_PROTEGIDO
               mov  byte ptr [si], IRET_CODE
 
               pop  ax
               pop  bx
               pop  ds
               pop  si
 
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ; INSTRUCCION ORIGINAL EN EL ARCHIVO DE PROTECCION
        ; QUE FUE CAMBIADA POR EL 'INT 92h'
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
               MOV  AH, 4Ch
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
               iret
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FINRESID       EQU     $              ;Aca termina el residente
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetearVectores: mov  ax, 2590h         ;Hacer que una INT 90h ejecute el
               lea  dx, SetTrap       ;codigo 'SetTrap'
               int  21h
 
               mov  ax, 2592h         ;Hacer que una INT 92h ejecute el
               lea  dx, SetJMP        ;codigo 'SetJMP'
               int  21h
 
               ret
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GetLPT1:       push es                        ;Obtener registros de LPT1
               mov  di, 40h
               mov  es, di
               mov  di, 8                     ;ES:DI = 0040:0008h
               mov  ax, word ptr es:[di]
               mov  lpt11, ax                 ;lpt11 = Registro 1 LPT1
               add  ax, 2
               mov  lpt13, ax                 ;lpt13 = Registro 3 LPT1
               pop  es
               ret
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mok            db      13, 10, 'OK', 13, 10, '$'
myaestoy       db      13, 10, 'Ya estaba residente', 13, 10, '$'
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Arranque:      push ds                        ;El offset del vector de
               xor  si, si                    ;interrupcion 90h es igual
               mov  ds, si                    ;al offset de la SetTrap ?
               mov  si, 240h
               mov  ax, word ptr [si]
               pop  ds
               cmp  ax, offset SetTrap
               jne  A_instalar                ;No: instalar residente
 
               lea  dx, myaestoy              ;Como el residente ya estaba
               mov  ah, 9                     ;instalado mostrar mensaje
               int  21h                       ;y salir
               mov  ax, 4C00h
               int  21h
 
A_instalar:    call GetLPT1                   ;Obtener direcciones de LPT1
               call SetearVectores            ;Setear nuevos vectores de ints
               lea  dx, mok                   ;Mostrar mensaje 'OK'
               mov  ah, 9
               int  21h
               mov  ax, 3100h                 ;Terminar y quedar residente
               lea  dx, FINRESID
               shr  dx, 4
                inc  dx
               int  21h
 
end inicio
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
--------------------END KEYEMU.ASM--------------------------------------

Explicación de las variables:
IRET_CODE:
Definición que contiene el código de operación de la instrucción IRET.

OFF_PROTEGIDO:
Definición que contiene el offset dentro del programa protegido donde se pondrá el IRET (0892h).

Explicación de las rutinas:
SetJMP:
La ejecuta el programa de protección a través de un 'INT 92h' colocado antes de terminar la ejecución del mismo. Obtiene el segmento del programa protegido a través del PSP, coloca el IRET en el offset que corresponde de ése segmento, y ejecuta la instrucción original que fué 'tapada' por el 'INT 92h' (en este caso un 'MOV AH, 4Ch').
NOTA: Observar que el segmento del punto de entrada del programa protegido luego de la desencripción es el mismo que el segmento de la rutina de interrupción que accede a la llave.

Si sacamos la llave, activamos al programa de protección modificado, compilamos y ejecutamos al programa de emulación...

 
C:\>DEL PROTECT.EXE
 
C:\>REN MODIFIC.EXE PROTECT.EXE
 
C:\>TASM KEYEMU.ASM
...
C:\>TLINK /t KEYEMU
...
C:\>KEYEMU
 
OK
 
C:\>GESTION
...
...
...
...
...
...
...
...
C:\>

El programa funciona sín llave de hardware.
Para finalizar, se ilustra el comportamiento de KEYEMU:

comportamiento de keyemu.asm




CONCLUSION:

 


REFERENCIAS BIBLIOGRAFICAS:

En Inglés:

En Castellano:

 


MENSAJITOS PARA LOS MAS CHIQUITOS:

resina epoxi

pcb