Chkrootkit Sourcecode Learning

目录

1. Chkrootkit Introduce
2. Source Code Frame
3. chklastlog.c
4. chkwtmp.c
5. ifpromisc.c
6. chkproc.c
7. chkdirs.c
8. check_wtmpx.c
9. strings.c
10. chkrootkit的使用场景及其局限

 

1. Chkrootkit Introduce

chkrootkit是一个Linux系统下的查找检测rootkit后门的工具,需要明白的是,chkrootkit是一款ring3级别的rootkit检测工具,所以从某种程序上来说,chkrootkit能做的事也很有限,但是我们也必须明白,攻防对抗中并不是一味的追求底层kernel的hacking技术,往往多种技术结合(ring3、ring0)能够获得更好的效果

关于ring3、ring0下的rootkit攻防的平衡取舍,请参阅另一篇文章

http://www.cnblogs.com/LittleHann/p/3910696.html

Relevant Link:

http://www.centospub.com/make/chkrootkit.html
http://www.bootf.com/556.html
http://www.chkrootkit.org/

 

2. Source Code Frame

chkrootkit的总体代码功能框架如下

1. 系统日志审计检查
    1.1 chklastlog.c
        1) 根据"/var/log/wtmp""/var/log/lastlog"进行交叉比较,检查当前系统是否存在新增帐号异常登录
        2) 检测本次登录的用户是否有在/etc/passwd中出现 
        3) 检查/etc/passwd中是否有白名单之外的"超级用户(uid)",这是一种异常现象 

    1.2 chkwtmp.c
        1) 对登录日志进行清除,造成日志文件中存在一段的"登录日志空档期",chkwtmp.c的目的就是发现这个"空档期",从而发现可疑的入侵现象

2. 网络状态审计检测
    2.1 ifpromisc.c
        1) 检测当前系统的网卡接口是否正在进行"raw packet"的处理(sniffer的特征)
        检测当前系统中是否有sniffer程序在进行嗅探操作,"/proc/net/packet"这个虚拟目录保存了那些需要处理"raw network packets"的进程、及相关网络信息,正常情况下,一般的进程是不需要收发、处理"raw network packets"的,如果发现这类进程,则说明这是一个可疑sniffer进程(有可能是rootkit在进行嗅探操作)
        2) 检测当前系统的网卡是否处于"PROMISC(混杂模式)"

3. 进程隐藏状态检测 
    3.1 chkproc.c
        1) 针对readdir句柄劫持的检测
    很多rootkit常常会对"/proc/的readdir句柄"句柄(而内部还是调用的Sys_getdents64)进行劫持从而进行进程隐藏,针对这个现象,chkrootkit采取了2种策略
        1.1) 采用read原生系统调用来对/proc进行读写(绕过rootkit对Sys_getdents64系统调用的劫持)
        1.2) 将/proc/number/(进程列表的枚举结果和"ps -edf、ps auxw、ps mauxw 2>&1、ps auxw -T | tr -s ' '| cut -d' ' -f2-"的结果进行对比,因为ps这类进程枚举命令内部调用的系统调用是/proc/的readdir句柄(),可以发现进程隐藏的迹象 
        2) 针对进程枚举指令劫持的检测
    进程隐藏是LKM Rootkit常用的功能,rootkit常常会通过替换ps等指令程序为恶意程序(会自动过滤掉对rootkit自身的枚举)

 

3. chklastlog.c

1) 根据"/var/log/wtmp""/var/log/lastlog"进行交叉比较,检查当前系统是否存在新增帐号异常登录
2) 检测本次登录的用户是否有在/etc/passwd中出现 
3) 检查/etc/passwd中是否有白名单之外的"超级用户(uid)",这是一种异常现象 

code

#if defined(SOLARIS2) || defined(__linux__)
  #define HAVE_LASTLOG_H 1
#else
  #undef HAVE_LASTLOG_H
#endif

#if __FreeBSD__ > 9
  int main () { return 0; }
#else
  #include <stdio.h>

#ifdef __linux__
  #include <stdlib.h>
#endif

#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include <sys/types.h>
#include <utmp.h>

#if (HAVE_LASTLOG_H)
  #include <lastlog.h>
#endif

#include <sys/file.h>

#ifdef SOLARIS2
  #include <fcntl.h>
#endif

#ifdef __FreeBSD__ 
  #define WTMP_FILENAME "/var/log/wtmp"
  #define LASTLOG_FILENAME "/var/log/lastlog"
#endif

#ifdef __OpenBSD__
  #include <stdlib.h> 
  #define WTMP_FILENAME "/var/log/wtmp"
  #define LASTLOG_FILENAME "/var/log/lastlog"
#endif

#ifndef WTMP_FILENAME
  #define WTMP_FILENAME "/var/adm/wtmp"
#endif

#ifndef LASTLOG_FILENAME
  #define LASTLOG_FILENAME "/var/adm/lastlog"
#endif

#define TRUE 1L
#define FALSE 0L

long total_wtmp_bytes_read = 0;
size_t wtmp_file_size;
uid_t *uid;
void read_status();

struct s_localpwd 
{
     int numentries;
     uid_t *uid;
     char  **uname;
};

#ifndef SOLARIS2
  int nonuser(struct utmp utmp_ent);
#endif
struct s_localpwd *read_pwd();
void free_results(struct s_localpwd *);
uid_t *localgetpwnam(struct s_localpwd *, char *);
int getslot(struct s_localpwd *, uid_t);

#define MAX_ID 99999

int main(int argc, char*argv[]) 
{
    int        fh_wtmp;
    int        fh_lastlog;
  /*
  struct lastlog 
  {
        int32_t ll_time;                // When user logged in 
        char    ll_line[UT_LINESIZE];   // Terminal line name 
        char    ll_host[UT_HOSTSIZE];   // Host user came from 
  };
  用于查看那所用账号的最后登录时间
  */
    struct lastlog    lastlog_ent;

  /*
  struct utmp {
        char    ut_line[UT_LINESIZE];   // Terminal line name  
        char    ut_name[UT_NAMESIZE];   // User’s login name  
        char    ut_host[UT_HOSTSIZE];   // Host user came from 
        int32_t ut_time;                // When user logged in  
  }; 
  /var/log/wtmp 
  记录当前和历史上登录到系统的用户的登录tty、登录用户名、来源和时间等信息。和/var/log/lastlog一样,这个文件是一个二进制文件,需要用last命令查看
  last -f /var/log/wtmp
  */
    struct utmp    utmp_ent;
    long        userid[MAX_ID];
    long        i, slot;
    int        status = 0;
    long        wtmp_bytes_read;

  /*
  struct stat  
  {   
      dev_t       st_dev;     // ID of device containing file -文件所在设备的ID  
      ino_t       st_ino;     // inode number -inode节点号  
      mode_t      st_mode;    // protection -保护模式
      nlink_t     st_nlink;   // number of hard links -链向此文件的连接数(硬连接)   
      uid_t       st_uid;     // user ID of owner -user id 
      gid_t       st_gid;     // group ID of owner - group id 
      dev_t       st_rdev;    // device ID (if special file) -设备号,针对设备文件  
      off_t       st_size;    // total size, in bytes -文件大小,字节为单位  
      blksize_t   st_blksize; // blocksize for filesystem I/O -系统块的大小   
      blkcnt_t    st_blocks;  // number of blocks allocated -文件所占块数
      
      time_t      st_atime;   // time of last access - 最近存取时间  
      time_t      st_mtime;   // time of last modification - 最近修改时间  
      time_t      st_ctime;   // time of last status change - 最近创建时间 
  };  
  */
    struct stat    wtmp_stat;
    struct s_localpwd    *localpwd;
  struct passwd *user;
    uid_t        *uid;
  char wtmpfile[128], lastlogfile[128];

  memcpy(wtmpfile, WTMP_FILENAME, 127);
  memcpy(lastlogfile, LASTLOG_FILENAME, 127);

  while (--argc && ++argv) /* poor man getopt */
  {
     if (!memcmp("-f", *argv, 2))
     {
        if (!--argc)
        {
          break;
        } 
        ++argv;
        memcpy(wtmpfile, *argv, 127);
     }
     else if (!memcmp("-l", *argv, 2))
     {
        if (!--argc)
        {
          break;
        } 
        ++argv;
        memcpy(lastlogfile, *argv, 127);
     }
  }

  //信号的安装(确定要接收和处理的信号),指定read_status()作为信号处理函数
    signal(SIGALRM, read_status);
  //信号的发送,专门为SIGALRM信号而设,在指定的时间seconds秒后,将向进程本身发送SIGALRM信号,又称为闹钟时间
    alarm(5);
    for (i=0; i < MAX_ID; i++)
  {
    userid[i]=FALSE;
  } 
  //打开"/var/log/lastlog"文件
    if ((fh_lastlog = open(lastlogfile, O_RDONLY)) < 0) 
  {
        fprintf(stderr, "unable to open lastlog-file %s\n", lastlogfile);
        return(1);
    }
  //打开"/var/log/wtmp"文件
    if ((fh_wtmp = open(wtmpfile, O_RDONLY)) < 0) 
  {
        fprintf(stderr, "unable to open wtmp-file %s\n", wtmpfile);
        close(fh_lastlog);
        return(2);
    }
  //获取/var/log/wtmp的文件属性: struct stat,保存在wtmp_stat结构体中
    if (fstat(fh_wtmp, &wtmp_stat)) 
  {
        perror("chklastlog::main: ");
        close(fh_lastlog);
        close(fh_wtmp);
        return(3);
    }
    wtmp_file_size = wtmp_stat.st_size;
  //获取"/etc/passwd"文件结构化内容
    localpwd = read_pwd();
  /*
  3. 检查/etc/passwd中是否有白名单之外的"超级用户(uid)",这是一种异常现象
  */ 
  while((user = getpwent())!=0)
  { 
    //默认白名单只有root用户
    if ((user->pw_uid == 0 || user->pw_gid == 0) && user->pw_name != "root")
    {
      printf("dedect Suspicious Account\n");
      printf("\n%s:%d:%d:%s:%s:%s\n",user->pw_name, user->pw_uid, user->pw_gid, user->pw_gecos,user->pw_dir,user->pw_shell);
    }
  }
  endpwent();


  /*
  "/var/log/wtmp"是一个记录用户登录信息的列表,每一行都记录了一次用户的登录信息,接下来的代码对其进行逐行遍历
  */
    while ((wtmp_bytes_read = read(fh_wtmp, &utmp_ent, sizeof (struct utmp))) >0) 
  {
    if (wtmp_bytes_read < sizeof(struct utmp))
    {
      fprintf(stderr, "wtmp entry may be corrupted");
      break;
    }
    total_wtmp_bytes_read += wtmp_bytes_read;
    /*
    对当前遍历中的"struct utmp"进行过滤检查
    1. 是否是"shutdonw"用户
    2. 当前登录用户账户命是否在"/etc/passwd"中存在
    */
    if ( !nonuser(utmp_ent) && /*strncmp(utmp_ent.ut_line, "ftp", 3)*/ && (uid = localgetpwnam(localpwd, utmp_ent.ut_name)) != NULL )
    {
      if (*uid > MAX_ID)
      {
        fprintf(stderr, "MAX_ID is %ld and current uid is %ld, please check\n\r", MAX_ID, *uid );
        exit (1); 
      }
      if (!userid[*uid])
      {
        lseek(fh_lastlog, (long)*uid * sizeof (struct lastlog), 0);
        if ((wtmp_bytes_read = read(fh_lastlog, &lastlog_ent, sizeof (struct lastlog))) > 0)
        {
          if (wtmp_bytes_read < sizeof(struct lastlog))
          {
            fprintf(stderr, "lastlog entry may be corrupted");
            break;
          }
          if (lastlog_ent.ll_time == 0)
          {
            if (-1 != (slot = getslot(localpwd, *uid)))
            {
              //1. 如果本次登录的用户在lastlog中的没有对应的登录记录(即这是一个突然新增的新用户登录),则表明是一个可疑用户登录行为
              printf("user %s deleted or never logged from lastlog!\n", NULL != localpwd->uname[slot] ? (char*)localpwd->uname[slot] : "(null)");
            } 
            else
            {
              //2. 检测本次登录的用户是否有在/etc/passwd中出现
              printf("deleted user uid(%d) not in passwd\n", *uid);
            } 
            ++status;
          }
          userid[*uid]=TRUE;
        }
      }
    }
    }
#if 0
    printf("\n");
#endif
    free_results(localpwd);
    close(fh_wtmp);
    close(fh_lastlog);
    return(status);
}

#ifndef SOLARIS2
/* minimal funcionality of nonuser() */
int nonuser(struct utmp utmp_ent)
{
   return (!memcmp(utmp_ent.ut_name, "shutdown", sizeof ("shutdown")));
}
#endif

void read_status() 
{
   double remaining_time;
   static long last_total_bytes_read=0;
   int diff;

   diff = total_wtmp_bytes_read-last_total_bytes_read;
   if (diff == 0) diff = 1;
   remaining_time=(wtmp_file_size-total_wtmp_bytes_read)*5/(diff);
   last_total_bytes_read=total_wtmp_bytes_read;

   printf("Remaining time: %6.2f seconds\n", remaining_time);
  /*
     signal(SIGALRM,read_status); 
     alarm(5);
  */
}

struct s_localpwd *read_pwd() 
{
  /*
  struct passwd  
  {  
      char * pw_name; // Username, POSIX.1  
      char * pw_passwd; //Password  
      __uid_t pw_uid; // User ID, POSIX.1   
      __gid_t pw_gid; // Group ID, POSIX.1  
      char * pw_gecos; // Real Name or Comment field 
      char * pw_dir; // Home directory, POSIX.1 
      char * pw_shell; // Shell Program, POSIX.1  
  };  
  */
  struct passwd *pwdent;
  int numentries=0,i=0;
  struct s_localpwd *localpwd;

  //setpwent()用来将getpwent()的读写地址指回密码文件开头
  setpwent();
  /*
  获取"/etc/passw"文件的信息,getpwent()用来从密码文件(/etc/passwd)中读取一项用户数据,该用户的数据以passwd 结构返回。第一次调用时会取得第一位
  用户数据,之后每调用一次就会返回下一项数据,直到已无任何数据时返回NULL
  */
  while ((pwdent = getpwent())) 
  {
    numentries++;
  }
  endpwent();
  localpwd = (struct s_localpwd *)malloc((size_t)sizeof(struct s_localpwd));
  localpwd->numentries=numentries;
  localpwd->uid = (uid_t *)malloc((size_t)numentries*sizeof(uid_t));
  localpwd->uname = (char **)malloc((size_t)numentries*sizeof(char *));
  for (i=0;i<numentries;i++) 
  {
    localpwd->uname[i] = (char *)malloc((size_t)30*sizeof(char));
  }
  i=0;
  setpwent();
  while ((pwdent = getpwent()) && (i<numentries)) 
  {
    localpwd->uid[i] = pwdent->pw_uid;
    memcpy(localpwd->uname[i], pwdent->pw_name, (strlen(pwdent->pw_name)>29)?29:strlen(pwdent->pw_name)+1);
    i++;
  }
  endpwent();
  return(localpwd);
}

void free_results(struct s_localpwd *localpwd) 
{
   int i;
   free(localpwd->uid);
   for (i=0;i<(localpwd->numentries);i++)
   {
      free(localpwd->uname[i]);
   }
   free(localpwd->uname);
   free(localpwd);
}

uid_t *localgetpwnam(struct s_localpwd *localpwd, char *username) 
{
   int i;
   size_t len;

   for (i=0; i<(localpwd->numentries);i++) 
   {
      len = (strlen(username) > 9) ? 30 : strlen(username) + 1;
      if (!memcmp(username, localpwd->uname[i],len)) 
      {
        return &(localpwd->uid[i]);
      }
   }
   return NULL;
}

int getslot(struct s_localpwd *localpwd, uid_t uid)
{
  int i; 
  for (i=0; i<(localpwd->numentries);i++)
  {
    if (localpwd->uid[i] == uid)
    {
      return i;
    }  
  }
  return -1;
}
#endif

Relevant Link:

https://www.mirbsd.org/htman/i386/man5/lastlog.htm

 

4. chkwtmp.c

"/var/log/wtmp"记录了当前和历史上登录到系统的用户的登录tty、登录用户名、来源和时间等信息,黑客在入侵了主机后,会对登录日志进行清除,造成日志文件中存在一段的"登录日志空档期",chkwtmp.c的目的就是发现这个"空档期",从而发现可疑的入侵现象

#if __FreeBSD__ > 9 
int main () { return 0; } 
#else
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <utmp.h>
#include <time.h>
#include <sys/time.h>
#include <sys/file.h>
#ifdef SOLARIS2
#include <fcntl.h>
#endif

#ifdef __FreeBSD__
#define WTMP_FILENAME "/var/log/wtmp"
#else
#ifndef WTMP_FILENAME
#define WTMP_FILENAME "/var/adm/wtmp"
#endif
#endif

void printit(counter, start, end)
int counter;
long start,end;
{
    char        buffer[30]; 
    printf("%d deletion(s) between ", counter);
    strncpy(buffer, ctime( (time_t *) &start), 30);
    buffer[24]='\0';
    printf("%s and %s", buffer, ctime( (time_t *) &end));
}


int main(int argc, char*argv[]) 
{
    int        filehandle;
    struct     utmp    utmp_ent;
    struct     timeval    mytime;
    struct     timezone    dummy;
    long    start_time, act_time;
    int        del_counter, t_del;
    char     wtmpfile[128];

    del_counter=t_del=0;
    start_time=0;

    gettimeofday(&mytime, &dummy);
    act_time=mytime.tv_sec;
    wtmpfile[127]='\0';
    memcpy(wtmpfile, WTMP_FILENAME, 127);
    if ( argc == 3 && !memcmp("-f", argv[1], 2) && *argv[2])
    {
        memcpy(wtmpfile, argv[2], 127);
    } 
    if ((filehandle = open(wtmpfile,O_RDONLY)) < 0) 
    {
        fprintf(stderr, "unable to open wtmp-file %s\n", wtmpfile);
        return(2);
    }

    while (read (filehandle, (char *) &utmp_ent, sizeof (struct utmp)) > 0) 
    {
        if (utmp_ent.ut_time == 0)
        {
            del_counter++;
        } 
        else 
        {
            if (del_counter) 
            {
                printit(del_counter, start_time, utmp_ent.ut_time);
                t_del++;
                del_counter=0;
            }
            start_time=utmp_ent.ut_time;
        }
    }
    close(filehandle);
    if (del_counter)
    {
        printit(del_counter, start_time, act_time);
    } 
    exit((int) t_del+del_counter);
}
#endif

 

5. ifpromisc.c

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#ifdef __linux__
  #include <linux/if.h>
  #include <linux/if_arp.h>
  #include <linux/if_ether.h>
  #include <dirent.h>
  #include <sys/stat.h>
#else
  #include <net/if.h> 
  #ifndef __OpenBSD__
    #include <net/if_arp.h>
  #endif
#endif

#ifdef SOLARIS2
  #include <sys/sockio.h>
#endif

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

struct interface
{
  char            name[IFNAMSIZ];        // interface name 
  short            type;             // if type         
  short            flags;            // various flags     
#ifdef __linux__
  int            index;                    //interface index     
#endif
};

char *Release = "chkrootkit package", *Version = "@(#) ifpromisc)"; 

int skfd = -1;                /* AF_INET or AF_PACKET raw socket desc.    */
int q = 0;            /* Quiet mode on or off                */

struct packet_info
{
    int index;
    int type;
    int proto;
    int inode;
    char *cmd;
    struct packet_info *next;
};

#ifdef __linux__
/*
 * the contents of /proc/net/packet
 */
static struct packet_info *proc_net_packet = 0;


/*
 * read the entries from /proc/net/packet
 */
static void read_proc_net_packet()
{
    FILE                *proc;
    char                buf[80];

    proc = fopen("/proc/net/packet", "r");
    if (!proc)
    {
        if (errno != ENOENT)
        {
            perror("opening /proc/net/packet");
        }
        return;
    }

    /* skip the header */
    fgets(buf, 80, proc);
    while (fgets(buf, 80, proc))
    {
        int             type = 0;
        unsigned int    proto = 0;
        int             index = 0;
        unsigned int    inode = 0;

        if (sscanf(buf, "%*p %*d %d %x   %d %*d %*u %*u %u", &type, &proto, &index, &inode) == 4)
        {
            struct packet_info *pi;

            pi = (struct packet_info *)malloc(sizeof(struct packet_info));
            pi->type = type;
            pi->proto = proto;
            pi->index = index;
            pi->inode = inode;
            pi->cmd = 0;

            pi->next = proc_net_packet;
            proc_net_packet = pi;
        }
        else
        {
            fprintf(stderr, "cannot grok /proc/net/packet: %s", buf);
        }
    }

    fclose(proc);
}

/* look up an entry from /proc/net/packet by inode */
static struct packet_info *find_packet_info(int inode)
{
    struct packet_info *p;
    for (p = proc_net_packet; p; p = p->next)
    {
        if (p->inode == inode)
        {
            return p;
        }
    }
    return NULL;
}

/* 
walk a processes fd dir looking for sockets with inodes that match the
inodes from /proc/net/packet, when a match is found, the processes exe
is stored 
获取正在进行处理"raw network packets"的进程(疑似sniffer进程)的进程列表
*/
static void walk_process(char *process)
{
    DIR                 *dir;
    struct dirent       *ent;
    char                path[1024];

    if (snprintf(path, sizeof(path), "/proc/%s/fd", process) == -1)
    {
        fprintf(stderr, "giant process name! %s\n", process);
        return;
    }

    if ((dir = opendir(path)) == NULL)
    {
        if (errno != ENOENT)
        {
          perror(path);
        } 
        return;
    }

    while ((ent = readdir(dir)))
    {
        struct stat             statbuf;
        struct packet_info     *info;

        if (snprintf(path, sizeof(path), "/proc/%s/fd/%s", process, ent->d_name) == -1)
        {
            fprintf(stderr, "giant fd name /proc/%s/fd/%s\n", process, ent->d_name);
            continue;
        }

        if (stat(path, &statbuf) == -1)
        {
            perror(path);
            continue;
        }

        if (S_ISSOCK(statbuf.st_mode) && (info = find_packet_info(statbuf.st_ino)))
        {
            char link[1024]; 
            memset(link, 0, sizeof(link));
            /* no need to check rv since it has to be long enough,
             * otherwise, one of the ones above will have failed */
            snprintf(path, sizeof(path), "/proc/%s/exe", process);
            readlink(path, link, sizeof(link) - 1);
            info->cmd = strdup(link);
        }
    }

    closedir(dir);
}

/* walk the proc file system looking for processes, call walk_proc on each
 * process */
static void walk_processes()
{
    DIR                 *dir;
    struct dirent       *ent;

    if ((dir = opendir("/proc")) == NULL)
    {
        perror("/proc");
        return;
    }

    while ((ent = readdir(dir)))
    {
        /* we only care about dirs that look like processes */
        if (strspn(ent->d_name, "0123456789") == strlen(ent->d_name))
        {
            walk_process(ent->d_name);
        }
    }

    closedir(dir);

}

/* return 1 if index is a member of pcap_session_list, 0 otherwise. */
static int has_packet_socket(int index)
{
    struct packet_info *p;
    for (p = proc_net_packet; p; p = p->next)
    {
        if (p->index == index)
        {
            return 1;
        }
    }
    return 0;
}
#endif /* __linux__ */

static void ife_print(struct interface *ptr)
{
#ifdef __linux__
    //检测当前网卡接口是否处于"PROMISC(混杂模式)"
    int promisc = ptr->flags & IFF_PROMISC;
    //检测当前网卡接口是否正在进行"raw packet"的处理(同样也是sniffer的特征)
    int has_packet = has_packet_socket(ptr->index);

    if (promisc || has_packet)
    {
        printf("%s:", ptr->name);
        if (promisc)
            printf(" PROMISC");
        if (has_packet)
        {
            struct packet_info *p;
            printf(" PF_PACKET(");
            p = proc_net_packet;
            if (p)
            {
                printf("%s", p->cmd);

                for (p = p->next; p; p = p->next)
                {
                    if (p->index == ptr->index)
                    {
                        printf(", %s", p->cmd);
                    }
                }
            }
            printf(")");
        }
        printf("\n");
    }
    else
    {
        if (!q)
            printf("%s: not promisc and no PF_PACKET sockets\n", ptr->name);
    }
#else
   if (ptr->flags & IFF_PROMISC)
      printf("%s is %s", ptr->name, "PROMISC");
   else
   {
      if (!q)
         printf("%s is %s", ptr->name, "not promisc");
   }
   putchar('\n');
#endif
}


/* Fetch the inteface configuration from the kernel. */
static int if_fetch(char *ifname, struct interface *ife)
{
  struct ifreq ifr;

  memset((char *) ife, 0, sizeof(struct interface));
  strncpy(ife->name, ifname, sizeof(ife->name));

  strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
  //获得接口标志
  if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
      return(-1);
  ife->flags = ifr.ifr_flags;

#ifdef __linux__
  /* store the device index */
  if (ioctl(skfd, SIOCGIFINDEX, &ifr) < 0)
      return(-1);
  ife->index = ifr.ifr_ifindex;
#endif

  return(0);
}

static void if_print()
{
   char buff[1024];
   /*
    struct interface
    {
      char      name[IFNAMSIZ];   // interface name 
      short     type;             // if type     
      short     flags;            // various flags   
    #ifdef __linux__
      int     index;              //interface index  
    #endif
    };
   */
   struct interface ife;
   struct ifconf ifc;
   struct ifreq *ifr;
   int i;

   ifc.ifc_len = sizeof(buff);
   ifc.ifc_buf = buff;
   //获取所有网卡接口的信息
   if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
   {
      fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
      return;
   }

   ifr = ifc.ifc_req;
   for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
   {
      if (if_fetch(ifr->ifr_name, &ife) < 0)
      {
#ifdef __linux__
         fprintf(stderr, "%s: unknown interface.\n", ifr->ifr_name);
#endif
     continue;
      }
      if (!memcmp(ifr->ifr_name, "lo", 2))
         continue;
      ife_print(&ife);
   }
}

int main(int argc, char **argv)
{
  if (argc == 2 && !memcmp(argv[1], "-q", 2))
  {
    q++;
  } 

  /* Create a channel to the NET kernel. */
  if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
  {
    perror("socket");
    exit(-1);
  }
#ifdef __linux__
  read_proc_net_packet();
  walk_processes();
#endif

  if_print();
  (void) close(skfd);
  exit(0);
}

Relevant Link:

http://blog.cloudpassage.com/2012/09/05/warn-packet-sniffer-running/

 

6. chkproc.c

#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__sun)
int main (){ return 0; }
#else
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <dirent.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#if defined(__sun)
#include <procfs.h>
#include <fcntl.h>
#endif
#include <sys/resource.h>

#define PS_SUN 0
#define PS_LOL 1
#define PS_COM 2
#define PS_LNX 3
#define PS_MAX 3
#define ENYELKM "/proc/12345"
// #define ENYELKM "/tmp/12345"

#if defined(__sun)
#define FIRST_PROCESS 0
#else
#define FIRST_PROCESS 1
#endif
#define MAX_PROCESSES 99999
#define MAX_BUF 1024

#if !defined (SIGXFSZ)
#define SIGXFSZ 25
#endif

static char *ps_cmds[] = {
        "ps -edf",
        "ps auxw",
        "ps mauxw 2>&1 ",
      "ps auxw -T | tr -s ' '| cut -d' ' -f2-",
    };

int psproc [MAX_PROCESSES+1];
int dirproc[MAX_PROCESSES+1];
#if defined(__linux__)
  int isathread[MAX_PROCESSES+1];
#endif

/*
 * read at most the first (size-1) chars into s and terminate with a '\0'.
 * stops reading after a newline or EOF.  if a newline is read, it will be
 * the last char in the string.  if no newline is found in the first
 * (size-1) chars, then keep reading and discarding chars until a newline
 * is found or EOF.
 */
char *readline(char *s, int size, FILE *stream)
{
  char *rv = fgets(s, size, stream);

  if (strlen(s) == (size-1) && s[size-1] != '\n')
  {
    char buf[MAX_BUF];
    fgets(buf, MAX_BUF, stream);
    while (strlen(buf) == (MAX_BUF-1) && buf[MAX_BUF-1] != '\n')
    {
      fgets(buf, MAX_BUF, stream);
    }
  }

  return rv;
}

int main(int argc, char **argv)
{
   char buf[MAX_BUF], *p, path[MAX_BUF];
   char *pscmd = (char *)0;
   FILE *ps;
   //打开/proc虚拟目录
   DIR *proc = opendir("/proc");
   struct dirent *dir;
   struct stat sb;
   int i, j, retps, retdir, pv, verbose;
   long ret = 0L;
   char * tmp_d_name;
#if defined(__linux__)
   int maybeathread;
#endif
#if defined(__sun)
   psinfo_t psbuf;
#endif

   pv = verbose = 0;

   if (!proc)
   {
      perror("proc");
      exit (1);
   }
   for (i = 1; i < argc; i++)
   {
      if (!memcmp(argv[i], "-v", 2))
      {
        verbose++;
      } 
      else if (!memcmp(argv[i], "-?", 2))
      {
          printf("Usage: %s [-v] [-v] -p <num>\n", argv[0]);
          return 0;
      }
#if defined(__linux__)
      else if (!memcmp(argv[i], "-p", 2))
      {
         if (i+1 < argc)
         {
            pv = atoi(argv[++i]);
        } 
         else
         {
              printf("Usage: %s [-v] [-v] [-p procps version]\n", argv[0]);
              return 0;
         }
      }
#endif
   }
#if defined(__sun)
   pscmd = ps_cmds[PS_SUN];
#elif !defined (__linux__)
   pscmd = ps_cmds[PS_COM];
#endif
#if defined(__linux__)
   if (pv < 1 || pv > PS_MAX)
      pv = 1;
   pscmd = ps_cmds[pv];
/*  printf("pv = %d\n\r", pv); /* -- DEBUG */
#endif

/* printf("pscmd = %s\n\r", pscmd); /* -- DEBUG */
   if (!(ps = popen(pscmd, "r")))
   {
       perror("ps");
       exit(errno);
   }

   *buf = 0;
   readline(buf, MAX_BUF, ps); /* Skip header */
#if defined(__sun)
   if (!isspace(*buf))
#else
   if (!isalpha(*buf))
#endif
   {
     readline(buf, MAX_BUF, ps); /* Skip header */
     if (!isalpha(*buf) && pv != PS_LNX)
     {
    if (pv != PS_LOL)
       execlp(argv[0], argv[0], "-p 1", NULL);
        fprintf(stderr, "OooPS!\n");
        exit(2);
     }
   }
   if (!memcmp(buf, "ps:", 3) && (pv != PS_LOL))
      execlp(argv[0], argv[0], "-p 1", NULL);

   for (i = FIRST_PROCESS; i <= MAX_PROCESSES; i++) 
   { /* Init matrix */
     psproc[i] = dirproc[i] = 0;
#if defined(__linux__)
     isathread[i] = 0;
#endif
   }

   while (readline(buf, MAX_BUF, ps))
   {
      p = buf;
#if defined(__sun)
      while (isspace(*p)) /* Skip spaces */
          p++;
#endif
      while (!isspace(*p)) /* Skip User */
          p++;
      while (isspace(*p)) /* Skip spaces */
          p++;
/*  printf(">>%s<<\n", p);  /* -- DEBUG */
      ret = atol(p);
      if ( ret < 0 || ret > MAX_PROCESSES )
      {
         fprintf (stderr, " OooPS, not expected %ld value\n", ret);
         exit (2);
      }
      psproc[ret] = 1;
   }
   pclose(ps);

   while ((dir = readdir(proc)))
   {
#if defined(__linux__)
      maybeathread = 0;
#endif
      tmp_d_name = dir->d_name;
      if (!strcmp(tmp_d_name, ".") || !strcmp(tmp_d_name, ".."))
         continue;
#if defined(__linux__)
      if (*tmp_d_name == '.') { /* here we catch the new NTPL threads in linux.  They are listed in /proc as PIDs with a period prepended */
         tmp_d_name++;
         maybeathread = 1;
      }
#endif
      if(!isdigit(*tmp_d_name))
         continue;
#if defined(__linux__)
      else if (maybeathread) {
         isathread[atol(tmp_d_name)] = 1; /* mark it as a linux NTPL thread if it's in the form of "\.[0-9]*" */
         if (verbose)
            printf("%ld is a Linux Thread, marking as such...\n", atol(tmp_d_name));
      }
#endif

/*      printf("%s\n", tmp_d_name); /* -- DEBUG */
      dirproc[atol(tmp_d_name)] = 1;
   }
   closedir(proc);

   /* Brute force */
   strcpy(buf, "/proc/");
   retps = retdir = 0;
   for (i = FIRST_PROCESS; i <= MAX_PROCESSES; i++)
   {
      snprintf(&buf[6], 6, "%d", i);
      if (!chdir(buf))
      {
         if (!dirproc[i] && !psproc[i])
         {
#if defined(__linux__)
            if (!isathread[i]) {
#endif
            retdir++;
            if (verbose)
           printf ("PID %5d(%s): not in readdir output\n", i, buf);
#if defined(__linux__)
            }
#endif
         }
         if (!psproc[i] ) /* && !kill(i, 0)) */
         {
#if defined(__linux__)
            if(!isathread[i]) {
#endif
            retps++;
            if (verbose)
           printf ("PID %5d: not in ps output\n", i);
#if defined(__linux__)
            }
#endif
     }
#if defined(__linux__)
         if(!isathread[i]) {
#endif
/*     if ((!dirproc[i] || !psproc[i]) && !kill(i, 0) && (verbose > 1)) */
     if ((!dirproc[i] || !psproc[i]) && (verbose > 1))
     {
#if defined(__linux__)
        j = readlink ("./cwd", path, sizeof(path));
        path[(j < sizeof(path)) ? j : sizeof(path) - 1] = 0;
        printf ("CWD %5d: %s\n", i, path);
        j = readlink ("./exe", path, sizeof(path));
        path[(j < sizeof(path)) ? j : sizeof(path) - 1] = 0;
        printf ("EXE %5d: %s\n", i, path);
#elif defined(__FreeBSD__)
        j = readlink ("./file", path, sizeof(path));
        path[(j < sizeof(path)) ? j : sizeof(path) - 1] = 0;
        printf ("FILE %5d: %s\n", i, path);
#elif defined(__sun)
        if ((j = open("./psinfo", O_RDONLY)) != -1)
            {
               if (read(j, &psbuf, sizeof(psbuf)) == sizeof(psbuf))
                  printf ("PSINFO %5d: %s\n", i, psbuf.pr_psargs);
               else
                  printf ("PSINFO %5d: unknown\n", i);
               close(j);
            }
            else
               printf ("PSINFO %5d: unknown\n", i);
#endif
         }
#if defined(__linux__)
         }
#endif
      }
#ifndef __FreeBSD__
      else
      {
         errno = 0;
         getpriority(PRIO_PROCESS, i);
         if (!errno)
         {
            retdir++;
            if (verbose)
           printf ("PID %5d(%s): not in getpriority readdir output\n", i, buf);
     }
      }
#endif
   }
   if (retdir)
      printf("You have % 5d process hidden for readdir command\n", retdir);
   if (retps)
      printf("You have % 5d process hidden for ps command\n", retps);
#if defined(__linux__)
   kill(1, 100); /*  Check for SIGINVISIBLE Adore signal */
   if (kill (1, SIGXFSZ) < 0  && errno == 3)
   {
      printf("SIGINVISIBLE Adore found\n");
      retdir+= errno;
   }
   /* Check for Enye LKM */
   if (stat(ENYELKM, &sb) && kill (12345, 58) >= 0)
   {
      printf("Enye LKM found\n");
      retdir+= errno;
   }
#endif
   return (retdir+retps);
}
#endif

 

7. chkdirs.c

#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || defined (hpux) || defined (__bsdi__) || defined (bsdi) || defined (__APPLE__)
#include <limits.h>
#elif defined(__APPLE__) && defined(__MACH__)
#include <sys/syslimits.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>

#ifndef NAME_MAX
#define NAME_MAX        PATH_MAX
#endif

struct dirinfolist 
{
  char                   dil_name[NAME_MAX+1];
  int                    dil_lc;
  struct dirinfolist     *dil_next;
};


void usage ()
{
  fprintf(stderr, "chkdirs [-n] dir ...\n");
  exit(255);
}

char *make_pathname (char *path, char *dir, char **buffer)
{
  int plen, pathname_len, bufsize, offs;
  
  bufsize = 0; 

  plen = strlen(path);
  pathname_len = plen + strlen(dir) + 2;

  if (!(*buffer) || (sizeof(*buffer) < pathname_len)) {
    if (buffer) free((void *)*buffer);
    bufsize = (pathname_len > PATH_MAX) ? pathname_len : PATH_MAX;
    if (!(*buffer = (char *)malloc(bufsize))) {
      return((char *)NULL);
    }
  }

  if (dir[0] == '/') {   /* "dir" is absolute pathname, don't prepend "path" */
    offs = 0;
  }
  else {
    strncpy(*buffer, path, bufsize);
    if ((*buffer)[plen-1] == '/') {   /* "path" ends in "/", don't add extra */
      offs = plen;
    }
    else {
      (*buffer)[plen] = '/';
      offs = plen + 1;
    }
  }
  strncpy((*buffer)+offs, dir, bufsize - offs);
  return((*buffer));
}

int check_dir (char *dir, char *path, int linkcount, int norecurse)
{
  int diff = -1;
  int plen, buflen, numdirs;
  char *curpath, *fullpath;
  DIR *dirhandle;
  struct dirent *finfo;
  struct dirinfolist *dl, *dptr;
  struct stat statinfo;

  /* When called recursively, "path" will be the full path of the cwd,
     but when called from main() "path" is empty.  We need the cwd path
     so we can chdir() back at the end of this routine, as well as when
     printing errors and other output.
  */
  if (!path || !(plen = strlen(path))) 
  {
    buflen = PATH_MAX;
  retry:
    if (!(curpath = (char *)malloc(buflen))) {
      fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
      return(-1);
    }
    if (!getcwd(curpath, buflen)) 
    {
      if (errno == ERANGE) 
      {
          free((void *)curpath);
          buflen = buflen * 2;
          goto retry;
      }
      else 
      {
           fprintf(stderr, "getcwd() failed: %s\n", strerror(errno));
           return(-1);
      }
    }
  }
  else {             /* "path" is set, so just copy it into "curpath" */
    if (!(curpath = (char *)malloc(plen+1))) {
      fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
      return(-1);
    }
    strncpy(curpath, path, plen+1);
  }

  /* Now set "fullpath" to be the absolute path name of the directory
     we will be checking (prepend "curpath" if "dir" is not already an
     absolute pathname).
  */
  fullpath = (char *)NULL;
  if (!make_pathname(curpath, dir, &fullpath)) {
    fprintf(stderr, "make_pathname() failed: %s\n", strerror(errno));
    free((void *)curpath);
    return(-1);
  }

  if (chdir(dir)) {
    fprintf(stderr, "chdir(%s): %s\n", fullpath, strerror(errno));
    free((void *)curpath);
    free((void *)fullpath);
    return(-1);
  }

  /* Again, "linkcount" (the link count of the current directory) is set
     only if check_dir() is called recursively.  Otherwise, we need to
     stat the directory ourselves.
  */
  if (!linkcount) {
    if (lstat(".", &statinfo)) {
      fprintf(stderr, "lstat(%s): %s\n", fullpath, strerror(errno));
      goto abort;
    }
    linkcount = statinfo.st_nlink;
  }

  if (!(dirhandle = opendir("."))) {
    fprintf(stderr, "opendir(%s): %s\n", fullpath, strerror(errno));
    goto abort;
  }

  numdirs = 0;
  dl = (struct dirinfolist *)NULL;
  while ((finfo = readdir(dirhandle))) {
    if (!strcmp(finfo->d_name, ".") || !strcmp(finfo->d_name, ".."))
      continue;

    if (lstat(finfo->d_name, &statinfo)) {
      fprintf(stderr, "lstat(%s/%s): %s\n",
          fullpath, finfo->d_name, strerror(errno));
      closedir(dirhandle);
      goto abort;
    }

    if (S_ISDIR(statinfo.st_mode)) {
      numdirs++;

      if (norecurse) continue;               /* just count subdirs if "-n" */

      /* Otherwise, keep a list of all directories found that have link
     count > 2 (indicating directory contains subdirectories).  We'll
     call check_dir() on each of these subdirectories in a moment...
      */
      if (statinfo.st_nlink > 2) {
    dptr = dl;
    if (!(dl = (struct dirinfolist *)malloc(sizeof(struct dirinfolist)))) {
      fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
      norecurse = 1;
      while (dptr) {
        dl = dptr->dil_next;
        free((void *)dptr);
        dptr = dl;
      }
      continue;
    }

    strncpy(dl->dil_name, finfo->d_name, sizeof(dl->dil_name));
    dl->dil_lc = statinfo.st_nlink;
    dl->dil_next = dptr;
      }
    }
  }
  closedir(dirhandle);

  /* Parent directory link count had better equal #subdirs+2... */
  diff = linkcount - numdirs - 2;
  if (diff) printf("%d\t%s\n", diff, fullpath);

  /* Now check all subdirectories in turn... */
  while (dl) {
    check_dir(dl->dil_name, fullpath, dl->dil_lc, norecurse);
    dptr = dl->dil_next;
    free((void *)dl);
    dl = dptr;
  }

 abort:
  if (chdir(curpath)) {
    fprintf(stderr, "Final chdir(%s) failed (%s) -- EXIT!\n",
        curpath, strerror(errno));
    exit(255);
  }
  free((void *)fullpath);
  free((void *)curpath);
  return(diff);
}


int main (int argc, char **argv)
{
  int norecurse = 0;
  int i, retval;
  int c;

  opterr = 0;
  while ((c = getopt(argc, argv, "n")) > 0) 
  {
    switch (c) 
    {
      case 'n':
        norecurse = 1;
        break;
      default:
        usage();
    }
  }
  if (argc <= optind) usage();
  {
    for (i = optind; i < argc; i++) 
    {
      retval = check_dir(argv[i], (char *)NULL, 0, norecurse);
    }
  }
 
  exit(retval);
}

 

8. check_wtmpx.c

#if !defined(__SunOS__) && !defined(SOLARIS2)
int main () { return 0; }
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <time.h>
#include <utmp.h>
#include <utmpx.h>
#include <lastlog.h>
#include <fcntl.h>
#include <unistd.h>

#define WTMP_FILENAME  "/var/adm/wtmp"
#define WTMPX_FILENAME "/var/adm/wtmpx"


struct file_utmp_entry
{
    char        ut_user[8];     /* User login name              */
    char        ut_id[4];       /* /etc/inittab id              */
    char        ut_line[12];    /* device name (console, lnxx)  */
    int16_t     ut_pid;         /* process id                   */
    int16_t     ut_type;        /* type of entry                */
    struct
    {
        int16_t e_termination;  /* Process termination status   */
        int16_t e_exit;         /* Process exit status          */
    } ut_exit;                  /* The exit status of a process */
    uint32_t    ut_time;        /* time entry was made          */
};

struct timeval_32
{
    uint32_t tv_sec;   /* seconds          */
    int32_t  tv_usec;  /* and microseconds */
};

/*
 * This data structure describes the utmp *file* contents using
 * fixed-width data types.  It should only be used by the implementation.
 *
 * Applications should use the getutxent(3c) family of routines to interact
 * with this database.
 */
struct file_utmpx_entry
{
    char              ut_user[32];   /* user login name                */
    char              ut_id[4];      /* inittab id                     */
    char              ut_line[32];   /* device name (console, lnxx)    */
    uint32_t          ut_pid;        /* process id                     */
    int16_t           ut_type;       /* type of entry                  */
    struct
    {
        int16_t e_termination;       /* process termination status     */
        int16_t e_exit;              /* process exit status            */
    } ut_exit;                       /* exit status of a process       */
    struct timeval_32 ut_tv;         /* time entry was made            */
    int32_t           ut_session;    /* session ID, user for windowing */
    int32_t           pad[5];        /* reserved for future use        */
    int16_t           ut_syslen;     /* significant length of ut_host  */
    char              ut_host[257];  /* remote host name               */
};

static void usage ( char * arg )
{
    fprintf( stderr, " Usage: %s [-h] [-w wtmp] [-x wtmpx]\n", arg );
    exit( EXIT_FAILURE );
}  /* end of usage */

int main ( int argc, char * argv[] )
{
    int                     fd_wtmp, fd_wtmpx;
    char                    filename_wtmp[128]  = WTMP_FILENAME;
    char                    filename_wtmpx[128] = WTMPX_FILENAME;
    ssize_t                 wtmp_bytes_read;
    ssize_t                 wtmpx_bytes_read;
    uint32_t                wtmp_read_counter   = 0; 
    uint32_t                wtmpx_read_counter  = 0;
    int                     c;
    struct file_utmp_entry  utmp_entry;
    struct file_utmpx_entry utmpx_entry;

    opterr = 0;  /* Don't want getopt() writing to stderr */
    while ( ( c = getopt( argc, argv, "hw:x:" ) ) != EOF )
    {
        switch ( c )
        {
        case 'w':
            strncpy( filename_wtmp, optarg, 128 );
            filename_wtmp[127]  = '\0';
            break;
        case 'x':
            strncpy( filename_wtmpx, optarg, 128 );
            filename_wtmpx[127] = '\0';
            break;
        case 'h':
        case '?':
            usage( argv[0] );
            break;
        }  /* end of switch */
    }  /* end of while */

    fd_wtmp = open( filename_wtmp, O_RDONLY );
    if ( fd_wtmp < 0 )
    {
        fprintf( stderr, "Unable to open %s\n", filename_wtmp );
        return( EXIT_FAILURE );
    }
    fd_wtmpx = open( filename_wtmpx, O_RDONLY );
    if ( fd_wtmpx < 0 )
    {
        fprintf( stderr, "Unable to open %s\n", filename_wtmpx );
        close( fd_wtmp );
        return( EXIT_FAILURE );
    }
    while ( 1 )
    {
        wtmpx_bytes_read = read( fd_wtmpx, &utmpx_entry, sizeof( struct file_utmpx_entry ) );
        if ( wtmpx_bytes_read > 0 )
        {
            if ( wtmpx_bytes_read < sizeof( struct file_utmpx_entry ) )
            {
                fprintf( stderr, "wtmpx entry may be corrupted\n" );
                break;
            }
            wtmpx_read_counter++;
        }
        wtmp_bytes_read = read( fd_wtmp, &utmp_entry, sizeof( struct file_utmp_entry ) );
        if ( wtmp_bytes_read > 0 )
        {
            if ( wtmp_bytes_read < sizeof( struct file_utmp_entry ) )
            {
                fprintf( stderr, "wtmp entry may be corrupted\n" );
                break;
            }
            wtmp_read_counter++;
        }
        if ( ( wtmpx_bytes_read <= 0 ) || ( wtmp_bytes_read <= 0 ) )
        {
            break;
        }
        if ( strncmp( utmp_entry.ut_user, utmpx_entry.ut_user, 8 ) != 0 )
        {
            fprintf( stderr, "[ %u ] ut_user %s <-> %s\n", wtmp_read_counter, 
                     utmp_entry.ut_user, utmpx_entry.ut_user );
            break;
        }
        if ( memcmp( utmp_entry.ut_id, utmpx_entry.ut_id, 4 ) != 0 )
        {
            fprintf( stderr, "[ %u ] utmp_entry.ut_id != utmpx_entry.ut_id\n", wtmp_read_counter );
            break;
        }
        if ( strcmp( utmp_entry.ut_line, utmpx_entry.ut_line ) != 0 )
        {
            fprintf( stderr, "[ %u ] ut_line %s <-> %s\n", wtmp_read_counter, 
                     utmp_entry.ut_line, utmpx_entry.ut_line );
            break;
        }
        if ( utmp_entry.ut_pid != utmpx_entry.ut_pid )
        {
            fprintf( stderr, "[ %u ] ut_pid %d <-> %d\n", wtmp_read_counter, 
                     utmp_entry.ut_pid, utmpx_entry.ut_pid );
            break;
        }
        if ( utmp_entry.ut_type != utmpx_entry.ut_type )
        {
            fprintf( stderr, "[ %u ] ut_type %d <-> %d\n", wtmp_read_counter, 
                     utmp_entry.ut_type, utmpx_entry.ut_type );
            break;
        }
        if ( utmp_entry.ut_time != utmpx_entry.ut_tv.tv_sec )
        {
            fprintf( stderr, "[ %u ] ut_time %08X <-> %08X\n", wtmp_read_counter, 
                     utmp_entry.ut_time, utmpx_entry.ut_tv.tv_sec );
            break;
        }
    }  /* end of while */
    if ( wtmpx_read_counter != wtmp_read_counter )
    {
        fprintf( stderr, "wtmpx or wtmp entry may be deleted\n" );
    }
    close( fd_wtmpx );
    close( fd_wtmp );
    return( EXIT_SUCCESS );
}  /* end of main */
#endif

 

9. strings.c

#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdlib.h>
#ifdef __FreeBSD__
#include <string.h> 
#endif

#define MAXFILESIZE (4 * 1024 * 1024)

/*
 * Many options here. The current choice produces a little more output
 * than gnu strings
 */

/*
 * Try to get the filesize via stat, and get a buffer to match
 * Naievely allocate a 4MB buffer if we can't
 * Fails badly if it allocate a buffer big enough to load a file
 */
unsigned char *filebuf(FILE *pf, int *sz) {
  struct stat buf;
  unsigned char *cdata;

  if (fstat(fileno(pf), &buf) < 0) {
    perror("fstat");
    exit (1);
  }

  *sz = buf.st_size;
  if(*sz == 0) *sz = MAXFILESIZE;

  if ((cdata = malloc(*sz+1)) == NULL) {
    perror("malloc");
    exit (1);
  }
  return cdata;
}

/*
 * Find printable strings of 4 or more characters
 * Always scans entire file (-a option of gnu strings)
 */
void strings(FILE *pf) {
  static char printme[1024];
  int sz;
  unsigned char *cdata;
  int nread;
  int printmeindex;
  cdata = filebuf(pf,&sz);
  nread = fread(cdata, 1, sz, pf);
  printmeindex = 0;
  if (nread > 0) {
    int i;
    unsigned char c;
    int isprintable;
    int iseol;
    for (i = 0; i < nread; i++) {
      c = cdata[i];
      isprintable = isprint(c);
      iseol = 0;
      if (c == 0 || c == '\n' || printmeindex >= sizeof(printme)-1) iseol = 1;
      if (iseol || !isprintable) {
    if (printmeindex > 3 && iseol) {
      printme[printmeindex++] = 0;
      printf("%s\n", printme);
      printmeindex = 0;
    }
      }
      else if (isprintable) {
    printme[printmeindex++] = c;
      }
    }
  }
  if (printmeindex > 3) {
    printme[printmeindex++] = 0;
    printf("%s\n", printme);
    printmeindex = 0;
  }
  free(cdata);
}

/*
 * Silently accepts the -a option
 */
int main(int argc, char **argv)
{
  if (argc > 1) {
    int i;
    for (i = 1; i < argc; i++) {
      FILE *pf;
      if (strcmp(argv[i], "-a") == 0) continue;

      if ((pf = fopen(argv[i],"rb")) == NULL) {
        perror("fopen");
        return(1);
      }
      strings(pf);
    }
  }
  else {
    strings(stdin);
  }
  return(0);
}

 

10. chkrootkit的使用场景及其局限

Relevant Link:

http://xteam.baidu.com/?p=237&qq-pf-to=pcqq.group

 

Copyright (c) 2014 LittleHann All rights reserved

 

posted @ 2014-08-18 14:48  郑瀚Andrew  阅读(1433)  评论(0编辑  收藏  举报