⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄

📁 ★★DOS常驻内存程序[原创]★★ 也许大家不理解意思。 驻留内存的意思就是 1)不能影响其他程序的运行。 2)自我复制。 3)某种情况下进行破坏(比如4月16日)。 对于DOS程序(
💻
字号:
★★常驻内存程序[讨论]★★

作者:fanoble  Luckylai


也许大家不理解意思。
驻留内存的意思就是
1)不能影响其他程序的运行。
2)自我复制。
3)某种情况下进行破坏(比如4月16日)。
对于DOS程序(病毒)来说,你起码要篡改一个中断。然后在你的中断程序中把真实的中断做一次,就神不知鬼不觉了
下面我以篡改键盘中断的病毒解释一个例子。

由于WINDOWS的保护,所以这个程序是无法运行的(可能在DOS下也有问题,因为程序结束,内存被收回,病毒也就被KILL了这点请fanoble解决),只能提供一个思路。
建议:
1)最好使用汇编来写,资源很节约,而且可以把病毒程序自身保护好。
2)把中断程序放到系统一般不会使用的内存区域。
汇编这方面fanoble比较强,让他来写肯定没问题。


文件key.c
//++++++++++++++++++++
//拦截了9号中断,也就是键盘中断。这个中断对于我们VCOK的人很熟悉的。在《电脑游戏编程入门 (DOS)》
//《DOS游戏编程二十一条》(C高级版有)都篡改了这个中断。
//触发条件是按键100下。
#define MAX_COUNTER 100
long key_counter=0;
void interrupt far (*OldInt9Handler)(__CPPARGS); //保存旧的键盘中断
//3.新的键盘中断程序:也就是病毒主体
void far interrupt NewInt9(__CPPARGS)
{
 *OldInt9Handler();//运行旧的键盘中断
 if(key_counter>MAX_COUNTER)//当计数值大于100病毒爆发
 {
  key_counter=0;
  //printf("hello! you will be  killed");
  //插入你的破坏程序  
 }
 
}

//1.安装新的键盘中断程序的函数:
void InstallKeyboard(void)
{
OldInt9Handler=getvect(9);
setvect(9,NewInt9);
}
//2.恢复旧的键盘中断程序的函数:
void ShutDownKeyboard(void)
{
setvect(9,OldInt9Handler);
}

void main(void)
{
InstallKeyboard();
}


/--------------------------------------
以下fanoble著:



呵呵,承蒙斑竹夸奖,fanoble写了一个小的驻留程序
/***************************************************************
*             A small resident program with C code             *
*==============================================================*
*  (C) Copyright by fanoble QQ:87430545 Mail:fanoble@yeah.net  *
***************************************************************/
# include   <dos.h>

# define    MUTEX_NAME  "fanoble"   /* 用于检测驻留的互斥 */

typedef struct
{
    char        Flag;               /* 标志 'M' 或 'Z' */
    unsigned    Owner;              /* 内存拥有者      */
    unsigned    Size;               /* 内存大小(节)    */
    char        Res[3];             /* 保留            */
    char        Name[8];            /* 名称            */
}MCB;

extern unsigned _envseg;            /* 环境段          */

unsigned char  Color = 1;           /* 控制字符颜色    */
struct REGPACK r;

void interrupt (*OldInt9)();        /* 原中断          */

void interrupt NewInt9()            /* 新中断          */
{
    (*OldInt9)();                   /* 调用原中断      */

    disable();

    r.r_ax = 0x0920;
    r.r_cx = 1;
    r.r_bx = Color;
    intr(0x10, &r);                 /* 设置字符颜色    */

    Color++;                        /* 颜色加1         */
    if (16 == Color)
    {
        Color = 1;
    }

    r.r_ax  = 0x0200;
    intr(0x16, &r);                 /* 检测Ctrl和Alt  */
    r.r_ax &= 0x000C;

    if (0x000C == r.r_ax)           /* Ctrl + Alt按下 */
    {
        setvect(9, OldInt9);        /* 恢复原中断     */
        poke(_psp - 1, 1, 0);       /* 释放内存,注意:为
                                       防止DOS重入,不能
                                       用freemem释放  */
        poke(_psp - 1, 8, 0);       /* 删除互斥体     */
    }

    enable();
}

/***************************************************************
*   函数名称: CheckResident                                    *
*   函数作用: 检查是否驻留                                     *
*   输入参数: 无                                               *
*   返 回 值: 0 -> 未驻留                                      *
*             1 -> 驻留                                        *
***************************************************************/
int  CheckResident()
{
    MCB far*        pMCB;
    unsigned        nSegment;
    char            szName[8];

    /* 得到第一个MCB */
    r.r_ax   = 0x5200;
    intr(0x21, &r);
    nSegment = peek(r.r_es, r.r_bx - 2);
    pMCB     = (MCB far*)MK_FP(nSegment, 0);

    for (;;)
    {
        /* 拷贝互斥体 */
        movedata(nSegment, 8, _DS, szName, 8);
        /* 判断互斥体 */
        if (0 == strcmp(szName, MUTEX_NAME))
        {
            return 1;
        }
        /* 判断是否最后一个MCB */
        if ('Z' == pMCB->Flag)
        {
            break;
        }
        /* 得到下一个MCB */
        nSegment += pMCB->Size + 1;
        pMCB      = (MCB far*)MK_FP(nSegment, 0);
    }
    return 0;
}

void main()
{
    unsigned    nSize;
    MCB far*    pMCB;

    /* 检测是否驻留 */
    if (CheckResident())
    {
        printf("Program has already been loaded!");
        exit(0);
    }

    /* 得到本程序所对应的MCB */
    pMCB  = (MCB far*)MK_FP(_psp - 1, 0);
    /* 创建互斥体 */
    movedata(_DS, MUTEX_NAME, _psp - 1, 8, 8);

    /* 设置新中断 */
    OldInt9 = getvect(9);
    disable();
    setvect(9, NewInt9);
    enable();

    /* 释放环境段内存 */
    freemem(_envseg);
    /* 驻留退出 */
    printf("Program resident OK!\n");
    printf("To quit, press Ctrl + Alt.\n");
    printf("You can hit a key now :)");
    keep(0, pMCB->Size);
}

/***************************************************************
*                        END OF FILE                           *
***************************************************************/

 
程序运行驻留以后,在DOS窗口内每按一个键就换一次颜色,按Ctrl+Alt退出。
程序运行前后以及释放后的内存大小可以用MEM来查看。
下面是附带的一个小tool,可以查看MCB。

/***************************************************************
*                A small mcb viewer with C code                *
*==============================================================*
*  (C) Copyright by fanoble QQ:87430545 Mail:fanoble@yeah.net  *
***************************************************************/
# include   <dos.h>

typedef struct
{
    char        Flag;
    unsigned    Owner;
    unsigned    Size;
    char        Res[3];
    char        Name[8];
}MCB;

extern unsigned _envseg;

void main()
{
    MCB far*        pMCB;
    struct REGPACK  r;
    unsigned        nSize;
    unsigned        nSegment;
    char            szName[8];

    nSize = peek(_psp - 1, 3);
    printf("Size = %04X\n", nSize);
    printf("PSP  = %04X\n", _psp);
    printf("ENV  = %04X\n", _envseg);

    /*
    freemem(_envseg);
    freemem(_psp);
    */

    r.r_ax   = 0x5200;
    intr(0x21, &r);
    nSegment = peek(r.r_es, r.r_bx - 2);
    pMCB     = (MCB far*)MK_FP(nSegment, 0);

    printf("Flag\tOwner\tSize\tName\n");
    for (;;)
    {
        movedata(nSegment, 8, _DS, szName, 8);
        printf("%c\t%04X\t%04X\t%s\n", pMCB->Flag, pMCB->Owner, pMCB->Size, szName);
        if ('Z' == pMCB->Flag)
        {
            break;
        }
        nSegment += pMCB->Size + 1;
        pMCB      = (MCB far*)MK_FP(nSegment, 0);
    }
}

 
_envseg是环境段的段值,从TC的Start Up Code 得到:
c0.asm:

PSPHigh         equ     00002h
PSPEnv          equ     0002ch

mov     bp, ds:[PSPHigh]; BP = Highest Memory Segment Addr
mov     bx, ds:[PSPEnv]  BX = Environment Segment address
mov     ds, dx
mov     _version@, ax    Keep major and minor version number
mov     _psp@, es        Keep Program Segment Prefix address
mov     _envseg@, bx     Keep Environment Segment address

其实就是放在_psp段的0x2C处,用peek(_psp, 0x2C)也可以得到.

DOS为每个程序创建2个内存块,一个是环境块,一般很小,另一个紧接
环境块的是进程块即_psp,2个块都有MCB.程序运行退出时,DOS会把2个MCB的
Owner设置为0,表示这块内存是空闲的,然后就可以回收再利用了.

程序用keep来驻留退出的话,2个块都不释放,在这儿环境块没用了,就先
释放掉,当然也可以到最后和psp一起释放.

PS:对free和keep做一下说明

[freemem]

int  _Cdecl freemem (unsigned segx);
释放内存.
segx是要释放的段值.

freemem的执行过程是这样的:
_freemem:
 push bp
 mov bp,sp
 mov ah,49h
 mov es,word ptr [bp+004h]
 int 21h
 jc $L1
 xor ax,ax
 jmp short $L2
$L1: push ax
 call __IOERROR
 jmp short $L2
$L2: pop bp
 ret
仍然是DOS中断,加了出错处理.我估计这个中断所做的事情就是把MCB的Owner
设置为0,的确如此,这个可以验证.所以不用中断释放内存的话就变的很容易:
(1) 将段值减1,得到MCB段值.
(2) 将MCB段偏移为1的一个字,即Owner,设置为0.
释放_psp就是这样: poke(_psp - 1, 1, 0);

[keep]
void  _Cdecl keep (unsigned char status, unsigned size);
将_psp段驻留size个节并退出.
status是退出返回给系统的值,象main函数的return 0一样.
size  是驻留的大小,按节(每节16字节,一个段)计算.

keep的执行过程是这样的:
_keep: push bp
 mov bp,sp
 call __restorezero
 mov dx,[bp+006h]
 mov al,[bp+004h]
 mov ah,31h
 int 21h
 pop bp
 ret

把_psp驻留了,_envseg虽然没有去管,但并没有释放,这也是退出前手工释放
_envseg的原因.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -