/*---------------------------------------------------------------------------- This program logs INT 21h calls made by a DOS program that it launches. Chris Giese http://SisAndHappy.com/ChrisGiese/ I, the copyright holder of this work, hereby release it into the public domain. This applies worldwide. If this is not legally possible: I grant any entity the right to use this work for any purpose, without any conditions, unless such conditions are required by law. Compile with Turbo C or 16-bit Watcom C 7 Sep 2015: initial release; works quite well now There were earlier versions that didn't work well because I was stupidly trying to use fwrite()/write()/_dos_write() from the interrupt handler. ----------------------------------------------------------------------------*/ #include /* P_WAIT, spawnvp() */ #include /* stderr, fprintf(), printf() */ /* Watcom C: union INTPACK defined in DOS.H */ #include /* _dos_getvect(), _dos_setvect(), _chain_intr() */ #if defined(__TURBOC__) /* OK */ #elif defined(__WATCOMC__) #if defined(__386__) #error This is a 16-bit program. Compile with WCC.EXE #endif #else #error Sorry, unsupported compiler #endif #define COUNT(X) (sizeof(X) / sizeof((X)[0])) #define LOG_SIZE 32768u static unsigned g_log_pos; static unsigned char g_log[LOG_SIZE]; void interrupt (*g_old_handler)(void); /****************************************************************************/ #if defined(__TURBOC__) #pragma argsused static void interrupt int21(volatile unsigned junk, volatile unsigned di, volatile unsigned si, volatile unsigned ds, volatile unsigned es, volatile unsigned dx, volatile unsigned cx, volatile unsigned bx, volatile unsigned REG_AX, volatile unsigned ip, volatile unsigned cs, volatile unsigned flags) #else #define REG_AX regs.x.ax static void interrupt int21(union INTPACK regs) #endif { unsigned ah; ah = REG_AX >> 8; /* just wrap to 0 if log overflows */ if(g_log_pos + 2 > LOG_SIZE) g_log_pos = 0; /* store values of AH and AL */ g_log[g_log_pos + 0] = ah; g_log[g_log_pos + 1] = REG_AX; /* AL */ g_log_pos += 2; _chain_intr(g_old_handler); } /****************************************************************************/ int main(int arg_c, char *arg_v[]) { static const char *syscall[] = { /* 0 */ "?", "?", "?", "?", /* 4 */ "?", "?", "?", "?", /* 8 */ "?", "?", "?", "GET STDIN STATUS", /* 0C */ "?", "?", "SET DEFAULT DRIVE", "?", /* 10 */ "?", "?", "?", "?", /* 14 */ "?", "?", "?", "?", /* 18 */ "?", "GET DEFAULT DRIVE", "SET DTA", "?", /* 1C */ "?", "?", "?", "?", /* 20 */ "?", "?", "?", "?", /* 24 */ "?", "SETVECT", "?", "?", /* 28 */ "?", "NAME TO FCB", "?", "?", /* 2C */ "?", "?", "?", "GET DTA", /* 30 */ "DOS VERSION", "TERM. & STAY RESIDENT", "?", "EXT. BREAK CHECK", /* 34 */ "GET INDOS ADDR.", "GETVECT", "GET FREE DISK SPACE", "GET SWITCH CHAR.", /* 38 */ "?", "?", "?", "SET CURR. DIR.", /* 3C */ "CREATE", "OPEN", "CLOSE", "READ", /* 40 */ "WRITE", "DELETE", "LSEEK", "?", /* 44 */ "IOCTL", "DUP. FILE HANDLE", "?", "GET CURR. DIR.", /* 48 */ "ALLOC MEM", "FREE MEM.", "RESIZE MEM", "EXEC", /* 4C */ "EXIT", "ERRORLEVEL", "FIND FIRST", "FIND NEXT", /* 50 */ "SET PSP ADDR.", "GET PSP ADDR.", "?", "?", /* 54 */ "?", "?", "?", "?", /* 58 */ "?", "?", "?", "?", /* 5C */ "?", "SERVER FN. CALL", "?", "?", /* 60 */ "?", "?", "GET PSP ADDR.", "?", /* 64 */ "?", "COUNTRY", "CODE PAGE", "?", /* 68 */ "?", "?", "?", "?", /* 6C */ "?", "?", "?", "?", /* 70 */ "?", "LFN", "?", "?" }; /**/ unsigned i, ah; int err; if(arg_c < 2) { printf("Logs INT 21h calls. Specify a DOS program to run.\n"); return 1; } g_old_handler = _dos_getvect(0x21); _dos_setvect(0x21, int21); /* Turbo C: int spawnvpe(int mode, char *path, char *argv[], char *envp[]); Watcom C: int spawnvp( int mode, const char *path, const char * const *argv ); Watcom issues a warning here about const correctness. */ err = spawnvp(P_WAIT, arg_v[1], &arg_v[1]); _dos_setvect(0x21, g_old_handler); fprintf(stderr, "Call of '%s' returned %d\n", arg_v[1], err); for(i = 0; i < g_log_pos; i += 2) { ah = g_log[i + 0]; printf("AH=0x%02X", ah); if(ah < COUNT(syscall)) printf(" (%s)", syscall[ah]); printf(", AL=0x%02X\n", g_log[i + 1]); } return 0; }