4

Some joker (BIOS/DOS/TSR...) has written random data in the Interrupt Vector Table. I know this because disassembling told me so.

Ordinarily before seizing an interrupt vector, I verify that the selected IVT slot is empty. But with all this left-behind-data, how can an humble application know that it is nonetheless safe to hook a particular interrupt vector?

Although my programmer's reference describes the DOS function 25h SetInterruptVector as

"Safely modifies an interrupt vector to point to a specified interrupt handler"

I don't think it cares too much about this pre-existing bogus content. So far for safely!


Is there some ingenious way to be absolutely sure that an interrupt vector is free?

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • 2
    "Safely" likely means making sure that no interrupts happen *while* the vector is updated. The answer to the rest of the question is almost certainly: No. – Bo Persson Nov 27 '16 at 17:10
  • 1
    You could use the multiplex interrupt (2Fh) or the alternate multiplex interrupt (AMIS, 2Dh). But you can also just pick some random interrupt that the BIOS and MS-DOS aren't documented as using. If you're actually running any TSRs it's not too hard to figure out if one happens to be using the interrupt you picked. Just overwrite the vector and see if anything breaks. – Ross Ridge Nov 27 '16 at 17:46

1 Answers1

7

No, there is no ingenious absolutely sure way to check if a vector is free.

This is because every of the possible 232 values for an interrupt is potentially a valid value.

Some value can be very suspicious, yet valid:

  • 0ffffh:0ffffh can be valid (pointing to 0ffefh with the A20 masked).
  • 0000h:0000h can be valid, even on vector 0. A DWORD of value zero decodes to a pair of add [bx+si], al which are valid.
  • 0b800h:0000h and other similar ROM addresses can be valid as expansion ROMs can be used to carry code. Though it's unlikely that the standard video memory will.
  • Addresses in reserved BIOS areas, like (E)BDA, can be valid in theory if the data is specially crafted to be both valid code and valid info.

Of course some of the above are very stretched and involve having data executed as code, but the main reason you should not trust vector pointers is that the BIOS is likely to fill every vector slot with at least a dummy ISR.
This won't let an unintentionally bad crafted int instruction hang the system.


There are a couple of things you could do:

  1. Chaining
    Pick a not overcrowded interrupt number N. Pick up a set of input values I not yet used (say AH=d0-ff). Attach your ISR to N and handle only those I values, delegating the other inputs to the previous ISR.

  2. Target a specific platform
    Some interrupt vectors, like int EA, are used only in specific systems. Since most of those systems are gone, you can reclaim their interrupts.
    If you steal an interrupt vector and everything keeps working and nobody is complaining, then it's your interrupt. Just double check the premises.

  3. Use interrupt 2F
    The Int 2F and its variant Alternate Multiplex Interrupt Specification (AMIS) at Int 2D can be used as a shared/multiplexed interrupt.
    The AMIS did not gain much popularity however.

  4. Try to find an empty spot anyway
    As a first attempt you can try to search for null entries1 in the IVT, though valid in theory, they are likely empty slots.
    You can also try to find a pointer that is present more than one or two times, suggesting the presence of a dummy ISR (as an ISR cannot identify its vector number easily).

I would go with n. 1 personally, if not possible I would implement n. 3. If not possible I would use n. 4 with fallback to n. 2.


1 Catching all the "suspicious" values is impractical and would only give a little gain, so just shoot for the big ones.

ecm
  • 2,583
  • 4
  • 21
  • 29
Margaret Bloom
  • 41,768
  • 5
  • 78
  • 124
  • A vector of 0000:0000 can't really be valid. It's not interpreted as an instruction. Chaining won't work if there isn't an already valid interrupt handler installed on the vector, so it doesn't eliminate the need to check if there is one. – Ross Ridge Nov 27 '16 at 18:33
  • I have used *AMIS* before and found it introduced a big overhead. *Chaining* on the other hand seems much simpler. I'll explore this. Since I particularly want to use interrupt B1h for sentimental reasons, I think I'm left with the riskier brute force method of just seizing what is needed. Alternatively I could stop being sentimental! – Sep Roland Nov 27 '16 at 18:48
  • 3
    Don't forget that some interrupt vectors do not point to code but to data. Of course they cannot be called via `int xx` instruction but the BIOS will rely on the fact that they point to certain data areas. – Martin Rosenau Nov 27 '16 at 19:02
  • 3
    @SepRoland INT B1h should be safe to use, at least on any system without a BASIC ROM. I wouldn't bother chaining it though, since it's normally initialized to 0000:0000 by the BIOS and not used by MS-DOS. If anything else uses it, it's likely your functions will conflict anyways. – Ross Ridge Nov 27 '16 at 19:23
  • @RossRidge Why chaining won't work if there is not an interrupt handler already? The new ISR will call the old one only on legacy input. There is a legacy input iif there is an interrupt handler. – Margaret Bloom Nov 27 '16 at 19:38
  • @MargaretBloom Yah, thinking about it doesn't matter if there isn't a valid vector there already, but it does matter that if there's something already installed there with a conflicting interface. – Ross Ridge Nov 27 '16 at 19:42