
TSR Programming http://amitmathur.8m.com
|
Further Suggested Readings
|
This tutorial is also available here
TSR which give programming in
C and C++ a Big and Wide Diversion and opens a new world of
Hackers and Crackers and normal programmers.
What are Hackers and what
are Crackers.
What are TSR?
Programs which remain running and resident in memory while
other programs are running are the most exciting line of
programming for many PC developers. This type of program is known
as a "Terminate and Stay Resident" or "TSR"
program. eg.(Operating Doskey, etc.)
In theory a TSR is quite simple. It is an ordinary program which terminates not through the usual DOS terminate function, but through the DOS "keep" function - interrupt 27h. This function reserves an area of memory, used by the program so that no other programs will overwrite it. This in itself is not a very difficult task, excepting that the program needs to tell DOS how much memory to leave it!
Basically to make a TSR
program we have to decide which interrupt to catch.What i mean is
that we have to decide when to pop up the TSR. Like if we want
that it should popup when user has pressed F1 key or any key we
have to catch the keyboard interrupt.
Likewise if you wanna popup TSR after every 2 minutes we have
to capture Timer interrupt or if you wanna make TSR active when
any reading or writing on hard disk is done you have to capture
that interrupt which governs the task.
Poping a TSR means that the code executes from the ashes ie. the code portion which we make resident and was not responding is now to be executed.
In our TSR code first we have
to capture the interrupt ie we have to get it's address where in
the memory it is stored then we have to replace the address with
the address of our code and then within our code we have to call
the actual procedure after or before executing our code.
The difficulties in programming TSRs comes from the
limitations of DOS which is not a multi-tasking operating system,
and does not react well to re-enterant code. That is it's own
functions (interrupts) calling themselves.
The problems stem mainly from not being able to use DOS
function calls within the TSR program once it has "gone
resident".
There are a few basic rules which help to clarify the problems
encountered in programming TSRs:
1. Avoid DOS function calls
2. Monitor the DOS busy flag, when this flag is nonzero, DOS is executing an interrupt 21h function and MUST NOT be disturbed!
3. Monitor interrupt 28h. This reveals when DOS is busy waiting for console input. At this time you can disturb DOS regardless of the DOS busy flag setting.
4. Provide some way of checking whether the TSR is already loaded to prevent multiple copies occuring in memory.
5. Remember that other TSR programs may be chained to interrupts, and so you must chain any interrupt vectors that your program needs.
6. Your TSR program must use its own stack, and NOT that of the running process.
7. TSR programs must be compiled in a small memory model with stack checking turned off.
8. When control passes to
your TSR program, it must tell DOS that the active process has
changed.
Note: The following is not an advertisement for the sake of earning money out of it. I am telling you about this because I myself was benefited by this CD ROM and I want that every computer science professional should have such a resource. I do not earn ANY commission out of this, just a satisfaction that my attempt to tell all the people about this resource via my website proved to be successful. I do not persuade you to buy it, but I would certainly like you to have a look at it completely. If you are really serious about programming, I think, you should go through it once. Rest is your choice. My role is over !
|
Contents of CD ROM
100
Such eBooks worth over Rs. 25,000, in a CDROM License for the sale of
15,000 CDs Only. Prices and CD ROM Offer valid only till stock lasts. |
A simple tsr to trap the timer interrupt
/*TimeTsr.c*/
#include<dos.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<conio.h>
void interrupt our(...);
void interrupt (*prev)(...);
char far *scr=(char far*)0xB0008000L;
int ticks;
int i=67;
int j=0;
char str[]="Amit Mathur ";
void main()
{
prev=getvect(8);/*get the timer ISR address*/
setvect(8,our);/*set our function address*/
keep(0,500);
}
void interrupt our(...)
{
ticks++;
if(ticks==18)
{
*(scr+5*2)=str[j];
*(scr+72*2)=str[j];
*(scr+24*80*2+5*2)=str[j];
*(scr+24*80*2+72*2)=str[j++];
if(j==13)
j=0;
ticks=1;
}
(*prev)();/*call the actual ISR*/
}
This is a simple program which displays my name starting from 'K' to 'P' and then again starting from 'K' at the top of screen at fifth position
To run this program at the dos
prompt type TimeTsr.exe and see the output at top of the screen.
now start the edit or tc you will see the effect there also.
Tsr to trap the
keyboard interrupt/*keydel.c*/
#include<dos.h>
void interrupt our();
void interrupt (*prev)();
char far *kb=(char *)0x417;
void main()
{
prev=getvect(9);/*get the keyboard ISR address*/
setvect(9,our);/*set our function address*/
keep(0,1000);
}
void interrupt our()
{
if(inportb(0x60)==0x53 &&(*kb&12)==12)
outportb(0x20,0x20);
else
(*prev)();/*call the ISR*/
}
this program if you press DEL
key from the keyboard it automatically adds the CTRL and ALT
key so that your system(if run from dos mode) or your dos prompt
To run this program at the dos prompt type keydel.exe and see the
output at top of the screen.
now start the edit or tc you will see the effect there also.
DanceDol.c
void main()
{
char far *scr;
int i;
scr=(char
far*)0xb00080000L;
while(1)
{
for(i=0;i<4000;i+=2)
{
if(*(scr+i)>='A'&&*(scr+i)<='Z')
*(scr+i)=*(scr+i)+32;
else
{
if(*(scr+i)>='a'&&*(scr+i)<='z')
*(scr+i)=*(scr+i)-32;
}
}
}
}
This Program makes all small characters capital and capital small
so they appear like dancing but will run infinite so to
stop press CTRL +BREAK.
To run this program press CTRL + F9 and see the output at top of
the screen.
now start the edit or tc you will see the effect there also.
/*
A practical TSR program (a pop-up address book database)
Compile in small memory model with stack checking OFF
*/
#include <dos.h>
#include <stdio.h>
#include <string.h>
#include <dir.h>
static union REGS rg;
/*
Size of the program to remain resident
experimentation is required to make this as small as possible
*/
unsigned sizeprogram = 28000/16;
/* Activate with Alt . */
unsigned scancode = 52; /* . */
unsigned keymask = 8; /* ALT */
char signature[]= "POPADDR";
char fpath[40];
/*
Function prototypes
*/
void curr_cursor(int *x, int *y);
int resident(char *, void interrupt(*)());
void resinit(void);
void terminate(void);
void restart(void);
void wait(void);
void resident_psp(void);
void exec(void);
/*
Entry point from DOS
*/
main(int argc, char *argv[])
{
void interrupt ifunc();
int ivec;
/*
For simplicity, assume the data file is in the root directory
of drive C:
*/
strcpy(fpath,"C:\\ADDRESS.DAT");
if ((ivec = resident(signature,ifunc)) != 0)
{
/* TSR is resident */
if (argc > 1)
{
rg.x.ax = 0;
if (strcmp(argv[1],"quit") == 0)
rg.x.ax = 1;
else if (strcmp(argv[1],"restart") == 0)
rg.x.ax = 2;
else if (strcmp(argv[1],"wait") == 0)
rg.x.ax = 3;
if (rg.x.ax)
{
int86(ivec,&rg,&rg);
return;
}
}
printf("\nPopup Address Book is already resident");
}
else
{
/* Initial load of TSR program */
printf("Popup Address Book Resident.\nPress Alt . To Activate....\n");
resinit();
}
}
void interrupt ifunc(bp,di,si,ds,es,dx,cx,bx,ax)
{
if(ax == 1)
terminate();
else if(ax == 2)
restart();
else if(ax == 3)
wait();
}
popup()
{
int x,y;
curr_cursor(&x,&y);
/* Call the TSR C program here */
exec();
cursor(x,y);
}
Second source module
*/
#include <dos.h>
#include <stdio.h>
static union REGS rg;
static struct SREGS seg;
static unsigned mcbseg;
static unsigned dosseg;
static unsigned dosbusy;
static unsigned enddos;
char far *intdta;
static unsigned intsp;
static unsigned intss;
static char far *mydta;
static unsigned myss;
static unsigned stack;
static unsigned ctrl_break;
static unsigned mypsp;
static unsigned intpsp;
static unsigned pids[2];
static int pidctr = 0;
static int pp;
static void interrupt (*oldtimer)();
static void interrupt (*old28)();
static void interrupt (*oldkb)();
static void interrupt (*olddisk)();
static void interrupt (*oldcrit)();
void interrupt newtimer();
void interrupt new28();
void interrupt newkb();
void interrupt newdisk();
void interrupt newcrit();
extern unsigned sizeprogram;
extern unsigned scancode;
extern unsigned keymask;
static int resoff = 0;
static int running = 0;
static int popflg = 0;
static int diskflag = 0;
static int kbval;
static int cflag;
void dores(void);
void pidaddr(void);
void resinit()
{
segread(&seg);
myss = seg.ss;
rg.h.ah = 0x34;
intdos(&rg,&rg);
dosseg = _ES;
dosbusy = rg.x.bx;
mydta = getdta();
pidaddr();
oldtimer = getvect(0x1c);
old28 = getvect(0x28);
oldkb = getvect(9);
olddisk = getvect(0x13);
setvect(0x1c,newtimer);
setvect(9,newkb);
setvect(0x28,new28);
setvect(0x13,newdisk);
stack = (sizeprogram - (seg.ds - seg.cs)) * 16 - 300;
rg.x.ax = 0x3100;
rg.x.dx = sizeprogram;
intdos(&rg,&rg);
}
void interrupt newdisk(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs)
{
diskflag++;
(*olddisk)();
ax = _AX;
newcrit();
flgs = cflag;
--diskflag;
}
void interrupt newcrit(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs)
{
ax = 0;
cflag = flgs;
}
void interrupt newkb()
{
if (inportb(0x60) == scancode)
{
kbval = peekb(0,0x417);
if (!resoff && ((kbval & keymask) ^ keymask) == 0)
{
kbval = inportb(0x61);
outportb(0x61,kbval | 0x80);
outportb(0x61,kbval);
disable();
outportb(0x20,0x20);
enable();
if (!running)
popflg = 1;
return;
}
}
(*oldkb)();
}
void interrupt newtimer()
{
(*oldtimer)();
if (popflg && peekb(dosseg,dosbusy) == 0)
if(diskflag == 0)
{
outportb(0x20,0x20);
popflg = 0;
dores();
}
}
void interrupt new28()
{
(*old28)();
if (popflg && peekb(dosseg,dosbusy) != 0)
{
popflg = 0;
dores();
}
}
resident_psp()
{
intpsp = peek(dosseg,*pids);
for(pp = 0; pp < pidctr; pp++)
poke(dosseg,pids[pp],mypsp);
}
interrupted_psp()
{
for(pp = 0; pp < pidctr; pp++)
poke(dosseg,pids[pp],intpsp);
}
void dores()
{
running = 1;
disable();
intsp = _SP;
intss = _SS;
_SP = stack;
_SS = myss;
enable();
oldcrit = getvect(0x24);
setvect(0x24,newcrit);
rg.x.ax = 0x3300;
intdos(&rg,&rg);
ctrl_break = rg.h.dl;
rg.x.ax = 0x3301;
rg.h.dl = 0;
intdos(&rg,&rg);
intdta = getdta();
setdta(mydta);
resident_psp();
popup();
interrupted_psp();
setdta(intdta);
setvect(0x24,oldcrit);
rg.x.ax = 0x3301;
rg.h.dl = ctrl_break;
intdos(&rg,&rg);
disable();
_SP = intsp;
_SS = intss;
enable();
running = 0;
}
static int avec = 0;
unsigned resident(char *signature,void interrupt(*ifunc)())
{
char *sg;
unsigned df;
int vec;
segread(&seg);
df = seg.ds-seg.cs;
for(vec = 0x60; vec < 0x68; vec++)
{
if (getvect(vec) == NULL)
{
if (!avec)
avec = vec;
continue;
}
for(sg = signature; *sg; sg++)
if (*sg != peekb(peek(0,2+vec*4)+df,(unsigned)sg))
break;
if (!*sg)
return vec;
}
if (avec)
setvect(avec,ifunc);
return 0;
}
static void pidaddr()
{
unsigned adr = 0;
rg.h.ah = 0x51;
intdos(&rg,&rg);
mypsp = rg.x.bx;
rg.h.ah = 0x52;
intdos(&rg,&rg);
enddos = _ES;
enddos = peek(enddos,rg.x.bx-2);
while(pidctr < 2 && (unsigned)((dosseg<<4) + adr) < (enddos <<4))
{
if (peek(dosseg,adr) == mypsp)
{
rg.h.ah = 0x50;
rg.x.bx = mypsp + 1;
intdos(&rg,&rg);
if (peek(dosseg,adr) == mypsp + 1)
pids[pidctr++] = adr;
rg.h.ah = 0x50;
rg.x.bx = mypsp;
intdos(&rg,&rg);
}
adr++;
}
}
static resterm()
{
setvect(0x1c,oldtimer);
setvect(9,oldkb);
setvect(0x28,old28);
setvect(0x13,olddisk);
setvect(avec,(void interrupt (*)()) 0);
rg.h.ah = 0x52;
intdos(&rg,&rg);
mcbseg = _ES;
mcbseg = peek(mcbseg,rg.x.bx-2);
segread(&seg);
while(peekb(mcbseg,0) == 0x4d)
{
if(peek(mcbseg,1) == mypsp)
{
rg.h.ah = 0x49;
seg.es = mcbseg+1;
intdosx(&rg,&rg,&seg);
}
mcbseg += peek(mcbseg,3) + 1;
}
}
terminate()
{
if (getvect(0x13) == (void interrupt (*)()) newdisk)
if (getvect(9) == newkb)
if(getvect(0x28) == new28)
if(getvect(0x1c) == newtimer)
{
resterm();
return;
}
resoff = 1;
}
restart()
{
resoff = 0;
}
wait()
{
resoff = 1;
}
void cursor(int y, int x)
{
rg.x.ax = 0x0200;
rg.x.bx = 0;
rg.x.dx = ((y << 8) & 0xff00) + x;
int86(16,&rg,&rg);
}
void curr_cursor(int *y, int *x)
{
rg.x.ax = 0x0300;
rg.x.bx = 0;
int86(16,&rg,&rg);
*x = rg.h.dl;
*y = rg.h.dh;
}
This article is the copyright of Amit Online Resource Center. For reproduction of any part of this article in any form, contact from here