org 100h bits 16 section .text jmp _start yesDosbox db "Yep, that is a DOSBox!",0dh,0ah,'$' noDosbox db "Probably not a DOSBox.",0dh,0ah,'$' oldUDAddr dw 0 oldUDSeg dw 0 isDosbox db 1 _catchUD: push ax push bx mov bx, sp mov bx, WORD [ss:bx+4] mov ax, bx mov bx, WORD [cs:bx] and bh, 38h ; Keep only the opcode bits cmp bx, 38feh ; little-endian FE 38 je .notDosbox ; uhh, we shouldn't end up here. clean up the IVT and IRET so the actual ; #UD handler is called. push es xor ax, ax mov es, ax mov bx, [oldUDAddr] mov [es:18h], bx mov bx, [oldUDSeg] mov [es:1ah], bx pop es jmp .catchDone .notDosbox: ; Not DOSBox -- increment the IP and unset the flag add ax, 4 mov bx, sp mov WORD [ss:bx+4], ax mov [isDosbox], 0 .catchDone: pop bx pop ax iret _start: push es ; store the old #UD... xor ax, ax mov es, ax mov bx, [es:18h] mov [oldUDAddr], bx mov bx, [es:1ah] mov [oldUDSeg], bx ; ... and set the new #UD handler mov bx, cs mov [es:1ah], bx mov bx, _catchUD mov [es:18h], bx pop es ; DOSBoxCB 0x0000 db 0xfe, 0x38, 0x00, 0x00 mov ax, [isDosbox] cmp ax, 0 jz .notDosbox mov dx, yesDosbox jmp .printAndQuit .notDosbox: mov dx, noDosbox .printAndQuit: mov ah, 09h int 21h ; restore the old #UD handler push es xor ax, ax mov es, ax mov [es:1ah], oldUDSeg mov [es:18h], oldUDAddr pop ax ; and we're done! mov ax, 4c00h int 21h hlt