title: How do I properly hook Interrupt 28h in assembly for DOS, and restore it?
body: <p>I'm trying to set the handler of Interrupt 28h to my own routine, restore all the registers and flags involved, and restore the original Interrupt handler.
  I'm using NASM Assembler, under DOSBox and MS-DOS 6.22 in VirtualBox.</p>
  
  <p>I've thought about debugging, but doing so on a TSR program sounds impossible. I've tried pushing the Data Segment onto the Code Segment, and saving the original Data Segment for restoring later, but it seems to hang the machine even after restoring the Data Segment. </p>
  
  <pre><code>section .text   ;Code Section
  org 100h        ;DOS Executable Start
  mov ah,35h      ;Get Interrupt Vector
  mov al,28h      ;Of Interrupt 28h
  int 21h         ;Call DOS Kernel
  push cs         ;Push Code Segment
  pop ds          ;Onto Data Segment
  mov [oldseg],es ;Save Old Interrupt Vector Segment
  mov [oldoff],bx ;Save Old Interrupt Vector Offset
  mov ah,25h      ;Set Interrupt Vector
  mov dx,resstart ;To Resstart
  int 21h         ;Call DOS Kernel
  mov dx,resend   ;Set Data Offset to Resend
  sub dx,resstart ;Subtract Resstart
  shr dx,4h       ;Shift Right 4 Bits for Paragraph
  inc dx          ;One Extra Paragraph for PSP
  mov ah,31h      ;Terminate and Stay Resident
  xor al,al       ;Return Code
  int 21h         ;Call DOS Kernel
  
  resstart:       ;Resident Code Start
  push ax         ;Save AX
  push es         ;Save ES
  push di         ;Save DI
  push cx         ;Save CX
  push ds         ;Save DS
  push dx         ;Save DX
  mov ah,00h      ;Set Video Mode
  mov al,13h      ;To Mode 13h
  int 10h         ;Call BIOS Video
  mov ax,0A000h   ;VGA Segment
  mov es,ax       ;Stored in ES
  xor di,di       ;VGA Offset in DI
  mov cx,0FA00h   ;Fill Entire Screen
  mov al,09h      ;With Light Blue Color
  rep stosb       ;Repeat Store AL at ES:DI
  mov ah,25h      ;Set Interrupt Vector
  mov al,28h      ;Of Interrupt 28h
  mov ds,[oldseg] ;Restore Old Interrupt Vector Segment
  mov dx,[oldoff] ;Restore Old Interrupt Vector Offset
  int 21h         ;Call DOS Kernel
  pop dx          ;Restore DX
  pop ds          ;Restore DS
  pop cx          ;Restore CX
  pop di          ;Restore DI
  pop es          ;Restore ES
  pop ax          ;Restore AX
  iret            ;Return and Restore Flags
  resend:         ;Resident Code End
  
  section .data
  oldseg dw 0     ;Old Interrupt Vector Segment
  oldoff dw 0     ;Old Interrupt Vector Offset
  </code></pre>
  
  <p>After returning the original interrupt vector address, and setting the new interrupt vector address to "resstart", the program should terminate and stay resident. After this, Interrupt 28h would be triggered automatically since DOS has nothing else to do, which would in turn run my Interrupt handler.</p>
  
  <p>The Interrupt handler sets the video mode to 13h, tries to fill the entire screen with a light blue color, restores the original Interrupt 28h handler, restores all registers and flags involved, and returns to DOS. Executing this program yields no results, the system doesn't even hang. While running the part of setting video mode 13h and filling the entire screen with blue on its own separately, it works perfectly fine.</p>