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

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);
}

Copyright (c) 2014 LittleHann All rights reserved

Chkrootkit Sourcecode Learning

时间: 2024-10-25 01:20:40

Chkrootkit Sourcecode Learning的相关文章

Rootkit Hunter Sourcecode Learning

目录 1. Rootkit Hunter Introduce 2. Source Code Anylist 1. Rootkit Hunter Introduce rkhunter (Rootkit Hunter) is a Unix-based tool that scans for 1. rootkits 2. backdoors 3. possible local exploits It does this by 1. comparing SHA-1 hashes of important

TCP Socket Establish;UDP Send Package Process In Kernel Sourcecode Learning

目录 0. 引言 1. TCP握手流程 2. TCP connect() API原理 3. TCP listen() API原理 4. UDP交互过程 5. UDP send() API原理 6. UDP bind() API原理 0. 引言 Monitoring project 1. outer link connect: connect()->inet_stream_connect 2. Suspicious port monitor: listen()->inet_listen 3. S

【机器学习实战】Machine Learning in Action 代码 视频 项目案例

MachineLearning 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远 Machine Learning in Action (机器学习实战) | ApacheCN(apache中文网) 视频每周更新:如果你觉得有价值,请帮忙点 Star[后续组织学习活动:sklearn + tensorflow] ApacheCN - 学习机器学习群[629470233] 第一部分 分类 1.) 机器学习基础 2.) k-近邻算法 3.) 决策树 4.) 基于概率论的分类方法:朴素

Neural Networks and Deep Learning学习笔记ch1 - 神经网络

近期開始看一些深度学习的资料.想学习一下深度学习的基础知识.找到了一个比較好的tutorial,Neural Networks and Deep Learning,认真看完了之后觉得收获还是非常多的.从最主要的感知机開始讲起.到后来使用logistic函数作为激活函数的sigmoid neuron,和非常多其它如今深度学习中常使用的trick. 把深度学习的一个发展过程讲得非常清楚,并且还有非常多源代码和实验帮助理解.看完了整个tutorial后打算再又一次梳理一遍,来写点总结.以后再看其它资料

Deep Learning Enables You to Hide Screen when Your Boss is Approaching

https://github.com/Hironsan/BossSensor/ 背景介绍 学生时代,老师站在窗外的阴影挥之不去.大家在玩手机,看漫画,看小说的时候,总是会找同桌帮忙看着班主任有没有来. 一转眼,曾经的翩翩少年毕业了,新的烦恼来了,在你刷知乎,看视频,玩手机的时候,老板来了! 不用担心,不用着急,基于最新的人脸识别+手机推送做出的BossComing.老板站起来的时候,BossComing会通过人脸识别发现老板已经站起来,然后通过手机推送发送通知“BossComing”,并且震动告

Machine Learning In Action 第二章学习笔记: kNN算法

本文主要记录<Machine Learning In Action>中第二章的内容.书中以两个具体实例来介绍kNN(k nearest neighbors),分别是: 约会对象预测 手写数字识别 通过“约会对象”功能,基本能够了解到kNN算法的工作原理.“手写数字识别”与“约会对象预测”使用完全一样的算法代码,仅仅是数据集有变化. 约会对象预测 1 约会对象预测功能需求 主人公“张三”喜欢结交新朋友.“系统A”上面注册了很多类似于“张三”的用户,大家都想结交心朋友.“张三”最开始通过自己筛选的

repost: Deep Reinforcement Learning

From: http://wanghaitao8118.blog.163.com/blog/static/13986977220153811210319/ accessed 2016-03-10 深度强化学习(Deep Reinforcement Learning)的资源 Google的Deep Mind团队2013年在NIPS上发表了一篇牛x闪闪的文章,亮瞎了好多人眼睛,不幸的是我也在其中.前一段时间收集了好多关于这方面的资料,一直躺在收藏夹中,目前正在做一些相关的工作(希望有小伙伴一起交流)

Spark MLlib Deep Learning Convolution Neural Network (深度学习-卷积神经网络)3.1

3.Spark MLlib Deep Learning Convolution Neural Network (深度学习-卷积神经网络)3.1 http://blog.csdn.net/sunbow0 Spark MLlib Deep Learning工具箱,是根据现有深度学习教程<UFLDL教程>中的算法,在SparkMLlib中的实现.具体Spark MLlib Deep Learning(深度学习)目录结构: 第一章Neural Net(NN) 1.源码 2.源码解析 3.实例 第二章D

Spark MLlib Deep Learning Convolution Neural Network (深度学习-卷积神经网络)3.2

3.Spark MLlib Deep Learning Convolution Neural Network(深度学习-卷积神经网络)3.2 http://blog.csdn.net/sunbow0 第三章Convolution Neural Network (卷积神经网络) 2基础及源码解析 2.1 Convolution Neural Network卷积神经网络基础知识 1)基础知识: 自行google,百度,基础方面的非常多,随便看看就可以,只是很多没有把细节说得清楚和明白: 能把细节说清