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