Chkrootkit Sourcecode Learning

Andrew.Hann發表於2014-08-18

目錄

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

 

相關文章