1.inotify
linux下inotify能够实现监控文件系统事件(打开,读写删除等),inotify最多见的api有如下几个:linux
- inotify_init:用于建立一个 inotify 实例的系统调用,并返回一个指向该实例的文件描述符。
- inotify_add_watch:增长对文件或者目录的监控,并指定须要监控哪些事件。
- read:读取包含一个或者多个事件信息的缓存。
- inotify_rm_watch:从监控列表中移出监控项目。
inotify_add_watch原型以下:api
int inotify_add_watch(int fd, const char* pathname, int mask)
- 第一个参数fd是inotify_init的返回值。
- 第二个参数是要监控的文件目录。
- 第三个参数表示要监控哪些事件。
inotify的mask类型具体定义见:linux-3.18.6/include/uapi/linux/inotify.h#29缓存
1
2
3
4
5
6
7
8
9
10
11
12
|
#define IN_ACCESS 0x00000001 /* File was accessed */
#define IN_MODIFY 0x00000002 /* File was modified */
#define IN_ATTRIB 0x00000004 /* Metadata changed */
#define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */
#define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */
#define IN_OPEN 0x00000020 /* File was opened */
#define IN_MOVED_FROM 0x00000040 /* File was moved from X */
#define IN_MOVED_TO 0x00000080 /* File was moved to Y */
#define IN_CREATE 0x00000100 /* Subfile was created */
#define IN_DELETE 0x00000200 /* Subfile was deleted */
#define IN_DELETE_SELF 0x00000400 /* Self was deleted */
#define IN_MOVE_SELF 0x00000800 /* Self was moved */
|
从read函数读出的内容是多个 inotify_event 结构体,该结构体定义以下:cookie
|
struct
inotify_event
{
int
wd
;
/* Watch descriptor */
uint32_t
mask
;
/* Mask of events */
uint32_t
cookie
;
/* Unique cookie associating related
events (for rename(2)) */
uint32_t
len
;
/* Size of name field */
char
name
[
]
;
/* Optional null-terminated name */
}
;
|
每一个触发的事件都对应了一个inotify_event结构体,只要判断这个结构体中的mask是否为指定的事件(open,read等)便可判断这个发生的事件是否对咱们有用。函数
2.select函数
select系统调用是用来让咱们的程序监视多个文件句柄的状态变化,select函数原型及参数说明以下:ui
|
int
select
(
int
maxfd
,
fd_set *
rdset
,
fd_set *
wrset
,
\
fd_set *
exset
,
struct
timeval *
timeout
)
;
|
- 参数maxfd是须要监视的最大的文件描述符值+1;
- rdset,wrset,exset分别对应于须要检测的可读文件描述符的集合,可写文件描述符的集合及异常文件描述符的集合。
- struct timeval结构用于描述一段时间长度,若是在这个时间内,须要监视的描述符没有事件发生则函数返回,返回值为0。
3.经过inotify实现反调试
经过inotify监控/proc/pid文件夹下的关键文件变化(maps的读,mem的读等),若想查看某进程的的虚拟地址空间或者想dump内存,则会触发打开或读取的事件,只要接收到这些事件,则说明进程正在被调试,直接kill主进程。主要代码以下:spa
//fork子进程调用该函数,而且传入父进程pid
void
AntiDebug
(
int
ppid
)
{
char
buf
[
1024
]
,
readbuf
[
MAXLEN
]
;
int
pid
,
wd
,
ret
,
len
,
i
;
int
fd
;
fd_set
readfds
;
//防止调试子进程
ptrace
(
PTRACE_TRACEME
,
0
,
0
,
0
)
;
fd
=
inotify_init
(
)
;
sprintf
(
buf
,
"/proc/%d/maps"
,
ppid
)
;
//wd = inotify_add_watch(fd, "/proc/self/mem", IN_ALL_EVENTS);
wd
=
inotify_add_watch
(
fd
,
buf
,
IN_ALL_EVENTS
)
;
if
(
wd
<
0
)
{
LOGD
(
"can't watch %s"
,
buf
)
;
return
;
}
while
(
1
)
{
i
=
0
;
//注意要对fd_set进行初始化
FD_ZERO
(
&
readfds
)
;
FD_SET
(
fd
,
&
readfds
)
;
//第一个参数固定要+1,第二个参数是读的fdset,第三个是写的fdset,最后一个是等待的时间
//最后一个为NULL则为阻塞
ret
=
select
(
fd
+
1
,
&
readfds
,
0
,
0
,
0
)
;
if
(
ret
==
-
1
)
break
;
if
(
ret
)
{
len
=
read
(
fd
,
readbuf
,
MAXLEN
)
;
while
(
i
<
len
)
{
//返回的buf中可能存了多个inotify_event
struct
inotify_event *
event
=
(
struct
inotify_event*
)
&
readbuf
[
i
]
;
LOGD
(
"event mask %d\n"
,
(
event
->
mask
&
IN_ACCESS
)
||
(
event
->
mask
&
IN_OPEN
)
)
;
//这里监控读和打开事件
if
(
(
event
->
mask
&
IN_ACCESS
)
||
(
event
->
mask
&
IN_OPEN
)
)
{
LOGD
(
"kill!!!!!\n"
)
;
//事件出现则杀死父进程
int
ret
=
kill
(
ppid
,
SIGKILL
)
;
LOGD
(
"ret = %d"
,
ret
)
;
return
;
}
i
+=
sizeof
(
struct
inotify_event
)
+
event
->
len
;
}
}
}
inotify_rm_watch
(
fd
,
wd
)
;
close
(
fd
)
;
}