Interrupt handler chaining in real mode

1

I'm trying to hook BIOS Int 13h to add my custom functionality to it and hijack some of existing one. Old Int 13h vector is stored in global variable. When interrupt handler is called the DS is set to some value that doesn't match the original data segment of caller. Therefore accessing global variables of caller turns into a headache.

What is best practice to chain interrupt handlers?

Hook is installed this way:

#ifdef __cplusplus
#  define INTARGS ...
#else
#  define INTARGS unsigned bp, unsigned di, unsigned si,\
                  unsigned ds, unsigned es, unsigned dx,\
                  unsigned cx, unsigned bx, unsigned ax
#endif

void interrupt (far *hackInt13h)(INTARGS) = NULL;
void interrupt (far *biosInt13h)(INTARGS) = (void interrupt (far *)(INTARGS))0xDEADBEEF;

void main(void)
{
  struct REGPACK reg;

  biosInt13h = getvect(0x13);
  hackInt13h = int13h;

  setvect(0x13, hackInt13h);

  // Calling CAFE
  reg.r_ax = 0xCAFE;
  intr(0x13, &reg);
  printf("Cafe returned: 0x%04x\n", reg.r_ax);

  // Resetting FDD just to check interrupt handler chaining
  reg.r_ax = 0;
  reg.r_dx = 0;
  intr(0x13, &reg);
  printf("CF=%i\n", reg.r_flags & 0x01);

  setvect(0x13, biosInt13h);
}

Int 13h hook code:

    P286
    .MODEL TINY

_Data   SEGMENT PUBLIC 'DATA'
    EXTRN _biosInt13h:FAR
_Data   ENDS


_Text   SEGMENT PUBLIC 'CODE'
    PUBLIC _int13h
_int13h PROC FAR
    pusha
    cmp AX,0CAFEh
    jnz chain
    popa
    mov AX, 0BEEFh
    iret
chain:
    popa
    call    far ptr [_biosInt13h]   ; <-- at this moment DS points to outer space
                                    ;     and _biosInt13h is not valid
_int13h ENDP
_Text   ENDS
    END

I'm using Borland C++ if it matters

c
assembly
interrupt-handling
tasm
real-mode

1 Answer

0

Thanks guys, I've found solution!

First thing I've missed is moving variable to code segment and explicitly specifying it.

Second one is using hacked (pushed on stack) return address and retf instead of call that adds real return address on stack.

No need to pushf explicitly 'cause flags are already on stack after int. And flags will be popped on iret no matter in my handler or in chained one.

    P286
    .MODEL TINY

_Text   SEGMENT PUBLIC 'CODE'
    EXTRN _biosInt13h:FAR ; This should be in CODE 'cause CS is only segreg reliable
    PUBLIC _int13h
_int13h PROC FAR
    pusha
    cmp AX, 0CAFEh
    jnz chain
    popa
    mov AX, 0BEEFh
    iret
chain:
    popa
    push    word ptr cs:[_biosInt13h + 2]   ; Pushing chained handler SEG on stack
    push    word ptr cs:[_biosInt13h]       ; Pushing chained handler OFFSET on stack
    retf                        ; ...actually this is JMP FAR to address on stack
_int13h ENDP
_Text   ENDS
    END

User contributions licensed under CC BY-SA 3.0