Perl读取wtmpx日志文件
作者:半点闲 正文 ? 在大多数Unix变种中,登录和注销这两个行为会被跟踪到名为wtmpx(或者是wtmp)的文件中①。通常,如果对某个用户登录行为产生怀疑(比如说某个用户经常从哪台主机登录,但某次他从其他地方登录),我们一般会检查这个文件。在不同的操作系统上,这个文件所处位置也可能不同(比如说,在SCO Unix上它在/etc和/var/adm②中,在Ubuntu上它在/var/log中)。 使用unpack() ? Perl有个函数叫unpack(),它是被特别设计用来解析二进制和结构化数据的。让我们看看如何使用它来处理wtmpx文件。wtmp和wtmpx文件的格式在不同的Unix变种之间会有所不同。就这点,我将介绍SCO Unix上的wtmpx文件。下面(图1-1)是SCO Unix上的wtmpx文件的头两个记录的纯文本化的样子: (图1-1 SCO Unix wtmpx记录文本化样式) ? 除非你已经熟悉了这种文件的结构,否则这种被称为“ASCII dump”的数据对你而言和乱码没什么区别。那么,我们该怎么去认识这种文件结构呢?要了解这种文件格式最简单的方式就是查看读写该文件的程序源代码。如果你不熟悉C语言,这个任务可能会让你感到气馁。幸运的是,实际上我们并不需要了解,甚至也不需要去查看大部分源代码,我们可以只看定义了该文件格式的那部分内容就够了。 struct ut_exit_status { short __e_termination ; /* Process termination status */ short __e_exit ; /* Process exit status */ }; #defined e_termination __e_termination #defined e_exit __e_exit /* * Structure used to specify timeout in select(2) system call. */ struct timeval { long tv_sec; /* seconds */ long tv_usec; /* and microseconds */ }; struct utmpx { char ut_user[32]; /* user login name */ char ut_id[4]; /* inittab id */ char ut_line[32]; /* device name (console,lnxx) */ #ifdef MOD_FOR_GEMINI long ut_pid; /* process id */ #else pid_t ut_pid; /* process id */ #endif short ut_type; /* type of entry */ struct ut_exit_status ut_exit ;/* process termination/exit status */ struct timeval ut_tv; /* time entry was made */ long ut_session; /* session ID,used for windowing */ long ut_pad[5]; /* reserved for future use */ short ut_syslen; /* significant length of ut_host */ /* including terminating null */ char ut_host[257]; /* remote host name */ } ; 下面这个片断来自Ubuntu 12.04 LTS 64Bit的utmp.h文件: struct utmp { short ut_type; /* Type of record */ pid_t ut_pid; /* PID of login process */ char ut_line[UT_LINESIZE]; /* Device name of tty - "/dev/" */ char ut_id[4]; /* Terminal name suffix,or inittab(5) ID */ char ut_user[UT_NAMESIZE]; /* Username */ char ut_host[UT_HOSTSIZE]; /* Hostname for remote login,or kernel version for run-level messages */ struct exit_status ut_exit; /* Exit status of a process marked as DEAD_PROCESS; not used by Linux init(8) */ /* The ut_session and ut_tv fields must be the same size when compiled 32- and 64-bit. This allows data files and shared memory to be shared between 32- and 64-bit applications. */ #if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32 int32_t ut_session; /* Session ID (getsid(2)),used for windowing */ struct { int32_t tv_sec; /* Seconds */ int32_t tv_usec;/* Microseconds */ } ut_tv; /* Time entry was made */ #else long ut_session; /* Session ID */ struct timeval ut_tv; /* Time entry was made */ #endif int32_t ut_addr_v6[4]; /* Internet address of remote host; IPv4 address uses just ut_addr_v6[0] */ char __unused[20]; /* Reserved for future use */ }; ? 这些文件给我们提供了所有用以构造unpack()语句的必需线索。unpack()取一个数据格式模板作为它的第一个参数。然后它使用该模板来决定如何对从第二个参数取得的二进制(通常是二进制)数据进行反汇编。unpack()将按格式拆分这些数据,返回一个列表,列表中的每个元素对应于所提供的模板中的相应元素。 表1-1:将utmpx.h的C代码转换为unpack()模板
|