Category : System Diagnostics for your computer
Archive   : INTERCE.ZIP
Filename : INTERCEP.C

 
Output of file : INTERCEP.C contained in archive : INTERCE.ZIP
/* intercept.c -- spawn a process and intercept BIOS and DOS
* SWI (software interrupt) calls, recording register data to
* a file.
* Demonstrates chaining interrupt handlers.
*************************************************************
* Solely for compilation under Borland's Turbo C.
*************************************************************
* Written 7/31/1987 by:
* Ned Konz
* 210 Oleeta St.
* Ormond Bch, FL 32074 (904)672-2431
* BIX:nkonz CIS:76046,223
*
* Released into the public domain by the author.
*
* Modified 4/11/1989 by:
* Russell Nelson
* 11 Grant St.
* Potsdam, NY 13676 (215)265-5655
* CIS: 70441,205 GEnie: BH01 Internet: [email protected]
* BITNET: nelson@clutx UUCP: uunet!clutx.clarkson.edu!nelson
*
* No copyright is claimed by Russell Nelson
*
**************************************************************/

/*************************************************************
* This program was written so I could find out quickly what
* an unknown program's interface with the outside world was.
* It does not currently handle hardware interrupts.
* What it does:
*
* 1. Runs the specified program, intercepting certain interrupts
* and recording data in memory.
* 2. Writes an intermediate file filled with Swi_info structures (binary)
* 3. Runs a program called "INTERPRE.EXE" to interpret the
* intermediate file (It's a separate program to keep
* this one small and so you can write your own.)
* It's called like this:
* interpre.exe [-l] infilename outfilename progname [args...]
* where -l denotes long output format.
**************************************************************/

#include
#include
#include
#include
#include
#include
#include
#include
#include "intercept.h"

char *usage =
"[-l] [-T tmpdir] [-s maxcalls] [-o outfile] [-d datafile]\n"
"\tprogram [args...]\n"
" -l sets long format output: explanation AND register values\n"
" -T sets temporary directory for intermediate file to \"tmpdir\"\n"
" (will use TMP or TMPDIR environment vars. if found otherwise)\n"
" -s sets the maximum number of SWI records to \"maxcalls\"\n"
" -o names the output filename to \"outfile\" rather than\n"
" the default name (\"intercep.out\")\n"
" -d sets the interrupt data file to use, defaults to INTERPRE.DAT\n"
" program is the name of the program to monitor\n"
" args are any command-line arguments to be passed\n"
" to the monitored program.\n";

char *logo = "INTERCEPT -- monitor DOS and BIOS calls. By:\n"
" Ned Konz\n"
" 210 Oleeta St.\n"
" Ormond Bch, FL 32074\n"
" BIX:nkonz CIS:76046,223 (904)672-2431\n"
" 08/02/1987\n"
" Datafile option and parsing added by Russell Nelson\n";

char switchar, /* DOS parameter switch char (from int 0x21, fn 0x3700) */
sepchar = '\\'; /* DOS filename separator */

void interrupt inthandler ( Regpack r, Intpack i );
int get_swi_list(unsigned);
void install(void);
void uninstall(void);

/* the 8086/8088 INT instruction */
#define SWI_INSTRUCTION 0xCD

/* int_table[] --
* table containg numbers of interrupts we're catching
* and their old handlers
* should be sorted by most common interrupts first.
* NO HARDWARE INTERRUPTS!!!
* Note: some of these may be commented out because they tend to
* quickly fill up the output file. Uncomment and re-compile
* if you want them too.
*/
Intblock
int_table[MAX_INTS + 1]; /* leave room for a terminator */

/* swi_list[] --
* area in memory into which we store data about each SWI
*/
Swi_info huge *swi_list = NULL; /* beginning of swi_list */
Swi_info huge *swi_list_end = NULL; /* just past end of swi_list */
volatile Swi_info huge *swi_next = NULL; /* pointer to next block */

/* our single interrupt handler
* which merely records our registers and interrupt number
* in swi_list[]
* and chains to old handler.
*/
void interrupt
inthandler ( Regpack r, Intpack i )
{
/* the following variables are declared as static to get them
* off the caller's stack and to ensure that t[] is where
* we want it to be: from [BP-01] through [BP-06]
*/
static unsigned char far * caller;
static unsigned char which_int;
static IFP oldhandler;
static Intblock *ibp;
volatile unsigned t[3]; /* to move stack values down by 3 words into */

/* point to next instruction */
caller = (char far *)i.ipcs;

if (caller[-2] != SWI_INSTRUCTION) { /* was this a non-SWI? (uh-oh!) */
uninstall();
exit(-1);
}

which_int = caller[-1]; /* which SWI is this? */

if (FP_SEG(i.ipcs) > _CS && FP_SEG(i.ipcs) < 0xA000
&& swi_next < swi_list_end) {
swi_next->regs = r;
swi_next->caller = i;
swi_next->intnum = which_int;
swi_next++;
}

/* get old handler value */
for (ibp=int_table; ibp->intnum>=0 && ibp->intnum!=which_int; ibp++)
;

if (ibp->intnum < 0) /* can't happen... */
return; /* but if it does, just return "safely" */

oldhandler = ibp->oldint;

/* move all our registers down by 3 words on the stack */
movedata(_SS, FP_OFF(&r), _SS, FP_OFF(t), sizeof(Regpack));

/* supply a mock flag value with interrupts masked OFF */
r.ovl.new.flags = i.flags & ~0x0200;

/* get the address of the routine to chain to */
r.ovl.new.ipcs = oldhandler;

/* bump our frame pointer value down by 3 words --
* the stack pointer will be loaded from this new value next.
*/
_BP -= 6;

/* unstack all registers and do an IRET */
return;
}

int
get_swi_list(unsigned n)
{
if (!(swi_list = farcalloc(n, sizeof(Swi_info))))
return 0;

swi_next = swi_list;
swi_list_end = swi_list + n;
return n;
}


/* install our handler for all the named interrupts
*/
void
install()
{
Intblock *ibp;
IFPP vp;

for (ibp = int_table; ibp->intnum >= 0; ibp++) {
vp = (IFPP) MK_FP(0, ibp->intnum*4);
ibp->oldint = *vp;
disable();
*vp = inthandler;
enable();
}
}

/* un-install our handler for all the named interrupts
*/
void
uninstall()
{
Intblock *ibp;
IFPP vp;

for (ibp = int_table; ibp->intnum >= 0; ibp++) {
if (ibp->oldint != NULL) {
vp = (IFPP) MK_FP(0, ibp->intnum*4);
disable();
*vp = ibp->oldint;
enable();
}
}
}


/* Read template file into buffer, setting pointers to
* beginning of lines.
* Sets template_text, templates and ntemplates.
* Pads out interrupt IDs to 6 characters.
* Returns number of lines.
*/
int
read_template_file(char *filename)
{
FILE *ifile;
char inline[ 100 ];
Intblock *ibp = int_table;
int i;

if (! (ifile = fopen(filename, "rt")))
return 0;
while (fgets(inline, sizeof(inline), ifile)) {
if (ibp - int_table >= MAX_INTS)
return 0;
if (sscanf(inline, "%2x", &i) != 1)
continue;
if (ibp > int_table && i == (ibp-1)->intnum)
continue; /* same as the previous one */
ibp->intnum = i;
ibp->oldint = NULL;
ibp++;
}
ibp->intnum = -1; /* terminate the list */
fclose(ifile);
return 1;
}


/* output structures to intermediate file, call filter program
* return child return code (zero if OK)
*/
int
output_file(char *tmpdir, char *outfilename, int longmode,
char *progname, char *tfilename)
{
Swi_info huge *swip;
Swi_info outrec;
FILE *ofp;
char tempname[ 80 ];
int rval = 0;

sprintf(tempname, "%s%c%s", tmpdir, sepchar, "intercXXXXXX");

if (! mktemp(tempname)) {
fprintf(stderr, "%s: Bad temp file: %s\n", progname, tempname);
return -1;
}
if (! (ofp = fopen(tempname, "wb"))) {
fprintf(stderr, "%s: Can't open intermediate file %s\n",
progname, tempname);
return -1;
}
#ifdef DEBUG
fprintf(stderr, "%s: Using \"%s\" as intermediate file\n",
progname, tempname);
#endif
for (swip = swi_list; swip < (Swi_info huge *)swi_next; swip++) {
outrec = *swip;
if (fwrite(&outrec, sizeof(outrec), 1, ofp) != 1) {
fprintf(stderr, "%s: Write error on file %s\n", progname, tempname);
fclose(ofp);
unlink(tempname);
return -1;
}
}
fclose(ofp);
#ifdef DEBUG
fprintf(stderr, "Running: " OFILTER " %s %s %s %s %s\n",
(longmode ? "-l" : " "), "-t", tfilename, tempname, outfilename
);
#endif
rval = spawnlp(P_WAIT, OFILTER, OFILTER,
(longmode ? "-l" : " "), "-t", tfilename, tempname, outfilename
, NULL);
#ifndef DEBUG
unlink(tempname);
#endif
return rval;
}

void
main(int argc, char *argv[])
{
static unsigned nswi = MAX_INTERRUPTS; /* how many to record? */
static char *ofilename; /* output file name */
static char *tfilename; /* template file name */
static int childret;
static int longmode = 0;
static char tmpdir[ 64 ] = ".";
char *progname;

/* spit out logo */
fprintf(stderr, "%s", logo);

if ((switchar = getswitchar()) != '/')
sepchar = '/';
progname = strrchr(argv[0], sepchar) + 1;
*strchr(progname, '.') = '\0';

/* process cmdline arguments */
if (argc < 2) {
fprintf(stderr, "Usage: %s %s", progname, usage);
exit(1);
}

/* get TMP or TMPDIR (use ofilename as tmp var) */
if ((ofilename = getenv("TMPDIR")) || (ofilename = getenv("TMP")))
strncpy(tmpdir, ofilename, sizeof(tmpdir));

ofilename = OFILENAME;
tfilename = TFILENAME;

while (argv[1][0] == '-') {
char *dummy; /* is this needed? */
switch (argv[1][1]) {
case 's': /* specify max swi calls */
case 'S':
nswi = (unsigned)strtol(argv[2], &dummy, 0);
argv++;
break;

case 'o': /* specify output filename */
case 'O':
ofilename = argv[2];
argv++;
break;

case 'd': /* specify data filename */
case 'D':
tfilename = argv[2];
argv++;
break;

case 'l': /* set long-mode output */
case 'L':
longmode++;
break;

case 't':
case 'T':
strncpy(tmpdir, argv[2], sizeof(tmpdir));
argv++;
break;

default:
fprintf(stderr, "%s: unknown option \"%s\"\n",progname,argv[1]);
fprintf(stderr, "Usage: %s\t%s", progname, usage);
exit(2);
break;
}
argv++;
}

if (! read_template_file( searchpath(tfilename) )) {
fprintf(stderr, "%s: error during read of \"%s\"\n",
progname, tfilename);
exit(5);
}

/* obtain far segment for recording calls */
if (! get_swi_list(nswi)) {
fprintf(stderr, "%s: Can't get enough memory for %u swi records\n",
progname, nswi);
exit(3);
}
else
fprintf(stderr, "%s: Recording up to %u SWI records to file \"%s\"\n",
progname, nswi, ofilename);

/* install our interrupt handler for each interrupt in the list */
install();

/* now run the process */
childret = spawnvp(P_WAIT, argv[1], argv+1);

/* and restore our captured interrupts */
uninstall();

/* report on child return value */
if (childret == -1) {
fprintf(stderr, "%s: Spawn of \"%s\" failed: %s\n",
progname, argv[1], strerror(NULL));
exit(4);
}
if (childret != 0)
fprintf(stderr, "%s: Child process \"%s\" exit value: %d\n",
progname, argv[1], childret);

/* output intermediate file and run output filter program */
if (output_file(tmpdir, ofilename, longmode, progname, tfilename))
fprintf(stderr, "%s: couldn't run output filter program " OFILTER "\n",
progname);

farfree(swi_list);

exit(0);
}


  3 Responses to “Category : System Diagnostics for your computer
Archive   : INTERCE.ZIP
Filename : INTERCEP.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/