diff options
author | We-unite <3205135446@qq.com> | 2024-07-30 19:37:48 +0800 |
---|---|---|
committer | We-unite <3205135446@qq.com> | 2024-07-30 19:37:48 +0800 |
commit | d6c6e13796435f9e1e59fec891aa53680748a2d7 (patch) | |
tree | 8a43fc36ec69a67dd5fd9809ac4588b5fbbac61c | |
parent | 5d244e33672d0dd29a10c40c923c1decd645a1f7 (diff) | |
download | godo-d6c6e13796435f9e1e59fec891aa53680748a2d7.tar.gz godo-d6c6e13796435f9e1e59fec891aa53680748a2d7.zip |
Try to use kernel connector
-rw-r--r-- | connector/hello.c | 162 | ||||
-rwxr-xr-x | connector/proc_collector_linux.cpp | 618 | ||||
-rwxr-xr-x | connector/proc_mon_linux.cpp | 487 | ||||
-rw-r--r-- | connector/test.c | 64 | ||||
-rw-r--r-- | src/deal.go | 57 | ||||
-rw-r--r-- | src/global.go | 48 |
6 files changed, 1417 insertions, 19 deletions
diff --git a/connector/hello.c b/connector/hello.c new file mode 100644 index 0000000..5240c15 --- /dev/null +++ b/connector/hello.c | |||
@@ -0,0 +1,162 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <poll.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <sys/types.h> | ||
5 | #include <sys/socket.h> | ||
6 | #include <sys/time.h> | ||
7 | #include <sys/select.h> | ||
8 | #include <signal.h> | ||
9 | #include <linux/netlink.h> | ||
10 | #include <linux/connector.h> | ||
11 | // #include <linux/cn_proc.h> | ||
12 | #include <unistd.h> | ||
13 | #include <errno.h> | ||
14 | #include <time.h> | ||
15 | #include "cn_proc.h" | ||
16 | |||
17 | typedef struct __attribute__((aligned(NLMSG_ALIGNTO))) | ||
18 | { | ||
19 | struct nlmsghdr nl_hdr; | ||
20 | struct __attribute__((__packed__)) | ||
21 | { | ||
22 | struct cn_msg cn_msg; | ||
23 | enum proc_cn_mcast_op cn_mcast; | ||
24 | }; | ||
25 | } register_msg_t; | ||
26 | |||
27 | typedef struct __attribute__((aligned(NLMSG_ALIGNTO))) | ||
28 | { | ||
29 | struct nlmsghdr nl_hdr; | ||
30 | struct __attribute__((__packed__)) | ||
31 | { | ||
32 | struct cn_msg cn_msg; | ||
33 | struct proc_event proc_ev; | ||
34 | }; | ||
35 | } event_msg_t; | ||
36 | |||
37 | event_msg_t proc_msg; | ||
38 | |||
39 | void Now() | ||
40 | { | ||
41 | struct timespec ts; | ||
42 | struct tm *tm_info; | ||
43 | char buffer[64]; | ||
44 | |||
45 | if (clock_gettime(CLOCK_REALTIME, &ts) == -1) | ||
46 | { | ||
47 | perror("clock_gettime"); | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | tm_info = localtime(&ts.tv_sec); | ||
52 | strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info); | ||
53 | printf("Localtime %s.%03ld ", buffer, ts.tv_nsec / 1000000); | ||
54 | } | ||
55 | |||
56 | void printEvent() | ||
57 | { | ||
58 | union unnamed *procEvent = &proc_msg.proc_ev.event_data; | ||
59 | switch (proc_msg.proc_ev.what) | ||
60 | { | ||
61 | case PROC_EVENT_FORK: | ||
62 | Now(); | ||
63 | printf("Fork\t%6d\t%6d\t%6d\t%6d\n", procEvent->fork.parent_pid, procEvent->fork.parent_tgid, procEvent->fork.child_pid, procEvent->fork.child_tgid); | ||
64 | break; | ||
65 | case PROC_EVENT_EXIT: | ||
66 | Now(); | ||
67 | printf("Exit\t%6d\t%6d\t%6d\t%6d\n", procEvent->exit.process_pid, procEvent->exit.process_tgid, procEvent->exit.exit_code, procEvent->exit.exit_signal); | ||
68 | break; | ||
69 | case PROC_EVENT_EXEC: | ||
70 | default: | ||
71 | break; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | int main() | ||
76 | { | ||
77 | int s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); | ||
78 | |||
79 | register_msg_t nlcn_msg; | ||
80 | struct sockaddr_nl l_local; | ||
81 | l_local.nl_family = AF_NETLINK; | ||
82 | l_local.nl_groups = 12345; | ||
83 | l_local.nl_pid = 0; | ||
84 | |||
85 | if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) | ||
86 | { | ||
87 | perror(bind); | ||
88 | close(s); | ||
89 | return -1; | ||
90 | } | ||
91 | |||
92 | // int on = l_local.nl_groups; | ||
93 | // setsockopt(s,270,1,&on,sizeof(on)); | ||
94 | memset(&nlcn_msg, 0, sizeof(nlcn_msg)); | ||
95 | nlcn_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg); | ||
96 | nlcn_msg.nl_hdr.nlmsg_pid = getpid(); | ||
97 | nlcn_msg.nl_hdr.nlmsg_type = NLMSG_DONE; | ||
98 | |||
99 | nlcn_msg.cn_msg.id.idx = CN_IDX_PROC; | ||
100 | nlcn_msg.cn_msg.id.val = CN_VAL_PROC; | ||
101 | nlcn_msg.cn_msg.len = sizeof(enum proc_cn_mcast_op); | ||
102 | |||
103 | nlcn_msg.cn_mcast = PROC_CN_MCAST_LISTEN; | ||
104 | |||
105 | if (send(s, &nlcn_msg, sizeof(nlcn_msg), 0) == -1) | ||
106 | { | ||
107 | perror("can't register to netlink"); | ||
108 | close(s); | ||
109 | return -1; | ||
110 | } | ||
111 | |||
112 | // 震惊,拿到socket了,开听! | ||
113 | printf("Hello, kernel-connector!\n"); | ||
114 | // fd_set readfds; | ||
115 | // struct timeval tv = { | ||
116 | // .tv_sec = 5, | ||
117 | // .tv_usec = 0}; | ||
118 | struct pollfd fds; | ||
119 | |||
120 | fds.fd = s; | ||
121 | fds.events = POLLIN; | ||
122 | int rc; | ||
123 | |||
124 | while (1) | ||
125 | { | ||
126 | // FD_ZERO(&readfds); | ||
127 | // FD_SET(s, &readfds); | ||
128 | |||
129 | // int rc = select(s + 1, &readfds, NULL, NULL, &tv); | ||
130 | rc = poll(&fds, 1, 5000); | ||
131 | |||
132 | if (rc == -1) | ||
133 | { | ||
134 | if (errno == EINTR) | ||
135 | { | ||
136 | continue; | ||
137 | } | ||
138 | fprintf(stderr, "Failed to listen to netlink socket: %s\n", strerror(errno)); | ||
139 | return -1; | ||
140 | } | ||
141 | else if (rc == 0) | ||
142 | { | ||
143 | printf("No message in 5s...\n"); | ||
144 | } | ||
145 | else | ||
146 | { | ||
147 | rc = recv(s, &proc_msg, sizeof(proc_msg), 0); | ||
148 | if (rc == -1) | ||
149 | { | ||
150 | if (errno == EINTR) | ||
151 | { | ||
152 | continue; | ||
153 | } | ||
154 | fprintf(stderr, "Failed to listen to netlink socket: %s\n", strerror(errno)); | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | printEvent(); | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | } \ No newline at end of file | ||
diff --git a/connector/proc_collector_linux.cpp b/connector/proc_collector_linux.cpp new file mode 100755 index 0000000..478ac2b --- /dev/null +++ b/connector/proc_collector_linux.cpp | |||
@@ -0,0 +1,618 @@ | |||
1 | #ifndef WIN32 | ||
2 | #include <sys/socket.h> | ||
3 | #include <linux/netlink.h> | ||
4 | #include <linux/connector.h> | ||
5 | #include <linux/cn_proc.h> | ||
6 | #include <errno.h> | ||
7 | #include <sys/select.h> | ||
8 | #include <sys/types.h> | ||
9 | #include <sys/time.h> | ||
10 | #include <unistd.h> | ||
11 | |||
12 | #include "os_crypto/md5/md5_op.h" | ||
13 | #include "external/procps/readproc.h" | ||
14 | #include "proc_collector.h" | ||
15 | |||
16 | static struct | ||
17 | { | ||
18 | int queue_fd; | ||
19 | int proc_fd; | ||
20 | } proc_monitor = | ||
21 | { | ||
22 | .queue_fd = -1, | ||
23 | .proc_fd = -1 | ||
24 | }; | ||
25 | |||
26 | typedef struct __attribute__((aligned(NLMSG_ALIGNTO))) | ||
27 | { | ||
28 | struct nlmsghdr nl_hdr; | ||
29 | struct __attribute__((__packed__)) | ||
30 | { | ||
31 | struct cn_msg cn_msg; | ||
32 | enum proc_cn_mcast_op cn_mcast; | ||
33 | }; | ||
34 | } register_msg_t; | ||
35 | |||
36 | typedef struct __attribute__((aligned(NLMSG_ALIGNTO))) | ||
37 | { | ||
38 | struct nlmsghdr nl_hdr; | ||
39 | struct __attribute__((__packed__)) | ||
40 | { | ||
41 | struct cn_msg cn_msg; | ||
42 | struct proc_event proc_ev; | ||
43 | }; | ||
44 | } event_msg_t; | ||
45 | |||
46 | #define MAX_TEMP_PROCESS 5000 | ||
47 | #define TEMP_WAIT_TIME 1 | ||
48 | #define PROCESS_SLOT_EMPTY 0 | ||
49 | #define MAX_PATH_NAME 4096 | ||
50 | #define MAX_PIPE_WAIT_USECOND 100 | ||
51 | |||
52 | |||
53 | typedef struct | ||
54 | { | ||
55 | pid_t pid; | ||
56 | pid_t ppid; | ||
57 | time_t fork_time; | ||
58 | int status; | ||
59 | char path[MAX_PATH_NAME]; | ||
60 | os_md5 md5; | ||
61 | char parent_path[MAX_PATH_NAME]; | ||
62 | os_md5 parent_md5; | ||
63 | } process_parent_child_pair_t; | ||
64 | static process_parent_child_pair_t temp_processes[ MAX_TEMP_PROCESS ]; | ||
65 | |||
66 | |||
67 | /* | ||
68 | typedef struct | ||
69 | { | ||
70 | pid_t pid; // process id | ||
71 | char *name; // process name | ||
72 | char *state; //program running state | ||
73 | pid_t ppid; // parent process id | ||
74 | char *pname; // parent process name | ||
75 | ulong utime; // process time in user mode | ||
76 | ulong stime; // process time in kernel mode | ||
77 | char **cmd_line; // command line | ||
78 | char *real_user; // | ||
79 | char *effective_user; | ||
80 | char *saved_user; | ||
81 | char *fs_user; | ||
82 | char *real_group; | ||
83 | char *effective_group; | ||
84 | char *saved_group; | ||
85 | char *fs_group; | ||
86 | int priority; // process priority | ||
87 | int nice; // nice value | ||
88 | long size; // the toal memory | ||
89 | long vm_size; // virtual memory | ||
90 | long resident; // occupied physical memory | ||
91 | long share; // shared memory | ||
92 | time_t start_time; // process startup time | ||
93 | int pgrp; /// process group | ||
94 | int session; // session id | ||
95 | long nlwp; // number of thread | ||
96 | int tgid; // task group id | ||
97 | int tty; // control terminal | ||
98 | int processor; // cpu number last executed on | ||
99 | } proc_info_t; | ||
100 | */ | ||
101 | |||
102 | |||
103 | static void wm_proc_cleanup() | ||
104 | { | ||
105 | if ( proc_monitor.proc_fd > 0 ) | ||
106 | { | ||
107 | close( proc_monitor.proc_fd ); | ||
108 | proc_monitor.proc_fd = -1; | ||
109 | } | ||
110 | |||
111 | if ( proc_monitor.queue_fd > 0 ) | ||
112 | { | ||
113 | close( proc_monitor.queue_fd ); | ||
114 | proc_monitor.queue_fd = -1; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | |||
119 | static int wm_setup_netlink( ) | ||
120 | { | ||
121 | int rc; | ||
122 | int nl_sock; | ||
123 | struct sockaddr_nl sa_nl; | ||
124 | register_msg_t nlcn_msg; | ||
125 | |||
126 | nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); | ||
127 | if (nl_sock == -1) | ||
128 | { | ||
129 | mterror( WM_PROC_LOGTAG, "Can't open netlink socket"); | ||
130 | return -1; | ||
131 | } | ||
132 | |||
133 | sa_nl.nl_family = AF_NETLINK; | ||
134 | sa_nl.nl_groups = CN_IDX_PROC; | ||
135 | sa_nl.nl_pid = getpid(); // 向内核注册 | ||
136 | |||
137 | rc = bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl)); | ||
138 | if (rc == -1) | ||
139 | { | ||
140 | mterror( WM_PROC_LOGTAG, "Can't bind netlink socket"); | ||
141 | close(nl_sock); | ||
142 | return -1; | ||
143 | } | ||
144 | |||
145 | // create listener | ||
146 | memset(&nlcn_msg, 0, sizeof(nlcn_msg)); | ||
147 | nlcn_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg); | ||
148 | nlcn_msg.nl_hdr.nlmsg_pid = getpid(); | ||
149 | nlcn_msg.nl_hdr.nlmsg_type = NLMSG_DONE; | ||
150 | |||
151 | nlcn_msg.cn_msg.id.idx = CN_IDX_PROC; | ||
152 | nlcn_msg.cn_msg.id.val = CN_VAL_PROC; | ||
153 | nlcn_msg.cn_msg.len = sizeof(enum proc_cn_mcast_op); | ||
154 | |||
155 | nlcn_msg.cn_mcast = PROC_CN_MCAST_LISTEN ; | ||
156 | |||
157 | rc = send(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0); | ||
158 | if (rc == -1) | ||
159 | { | ||
160 | mterror(WM_PROC_LOGTAG, "can't register to netlink"); | ||
161 | close( nl_sock ); | ||
162 | return -1; | ||
163 | } | ||
164 | |||
165 | proc_monitor.proc_fd = nl_sock; | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int wm_setup_mq( wm_proc_t *proc ) | ||
170 | { | ||
171 | unsigned int indx; | ||
172 | // Connect to socket | ||
173 | for (indx = 0; indx < WM_MAX_ATTEMPTS; indx++) | ||
174 | { | ||
175 | proc_monitor.queue_fd = StartMQ(DEFAULTQPATH, WRITE); | ||
176 | if ( proc_monitor.queue_fd > 0 ) | ||
177 | { | ||
178 | break; | ||
179 | } | ||
180 | wm_delay(1000 * WM_MAX_WAIT); | ||
181 | } | ||
182 | |||
183 | if (indx == WM_MAX_ATTEMPTS) | ||
184 | { | ||
185 | mterror(WM_PROC_LOGTAG, "Can't connect to queue."); | ||
186 | pthread_exit(NULL); | ||
187 | } | ||
188 | |||
189 | // Cleanup exiting | ||
190 | atexit(wm_proc_cleanup); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | int wm_proc_linux_setup( wm_proc_t *proc ) | ||
196 | { | ||
197 | memset( temp_processes, 0, sizeof( temp_processes ) ); | ||
198 | if ( wm_setup_netlink() < 0 ) | ||
199 | { | ||
200 | return -1; | ||
201 | } | ||
202 | return wm_setup_mq(proc); | ||
203 | } | ||
204 | |||
205 | static void get_path_and_md5( pid_t pid, char *path, char *md5 ) | ||
206 | { | ||
207 | char pid_path[MAX_PATH_NAME]; | ||
208 | struct stat dir_stat; | ||
209 | |||
210 | memset( pid_path, 0, MAX_PATH_NAME); | ||
211 | snprintf( pid_path, MAX_PATH_NAME-1, "/proc/%d", pid ); | ||
212 | if ( stat( pid_path, &dir_stat ) < 0 ) | ||
213 | { | ||
214 | //mterror(WM_PROC_LOGTAG, "failed to open directory %s, errno=(%d:%m)", pid_path, errno ); | ||
215 | return; | ||
216 | } | ||
217 | |||
218 | memset( pid_path, 0, MAX_PATH_NAME); | ||
219 | snprintf( pid_path, MAX_PATH_NAME-1, "/proc/%d/exe", pid ); | ||
220 | memset( path, 0, MAX_PATH_NAME ); | ||
221 | memset( md5, 0, sizeof(os_md5)); | ||
222 | if ( readlink( pid_path, path, MAX_PATH_NAME ) < 0 ) | ||
223 | { | ||
224 | memset(pid_path, 0, MAX_PATH_NAME); | ||
225 | snprintf(pid_path, MAX_PATH_NAME - 1, "/proc/%d/comm", pid); | ||
226 | memset(path, 0, MAX_PATH_NAME); | ||
227 | FILE* fp = fopen(pid_path, "rb"); | ||
228 | if ( NULL == fp ) | ||
229 | { | ||
230 | return; | ||
231 | } | ||
232 | fread( path, MAX_PATH_NAME, 1, fp ); | ||
233 | if ( strlen( path ) > 0 ) | ||
234 | { | ||
235 | path[strlen(path)-1] = '\0'; | ||
236 | } | ||
237 | fclose( fp ); | ||
238 | return; | ||
239 | } | ||
240 | |||
241 | OS_MD5_File(path, md5, OS_BINARY); | ||
242 | |||
243 | return; | ||
244 | } | ||
245 | |||
246 | |||
247 | |||
248 | static void get_process_baseinfo( const process_parent_child_pair_t *pair, const char *location ) | ||
249 | { | ||
250 | proc_t curr_proc; | ||
251 | |||
252 | memset( &curr_proc, 0, sizeof( proc_t )); | ||
253 | |||
254 | cJSON *process = cJSON_CreateObject(); | ||
255 | if( NULL == process) | ||
256 | { | ||
257 | return; | ||
258 | } | ||
259 | cJSON_AddStringToObject(process, "type", "new process"); | ||
260 | cJSON_AddNumberToObject(process, "pid", pair->pid); | ||
261 | cJSON_AddNumberToObject(process, "eventTime", pair->fork_time); | ||
262 | cJSON_AddNumberToObject(process, "ppid", pair->ppid); | ||
263 | if (strlen(pair->path) > 0) | ||
264 | { | ||
265 | cJSON_AddStringToObject(process, "exe", pair->path); | ||
266 | } | ||
267 | if (strlen(pair->md5) > 0) | ||
268 | { | ||
269 | cJSON_AddStringToObject(process, "md5", pair->md5); | ||
270 | } | ||
271 | if (strlen(pair->parent_path) > 0) | ||
272 | { | ||
273 | cJSON_AddStringToObject(process, "parent_exe", pair->parent_path); | ||
274 | } | ||
275 | if (strlen(pair->parent_md5) > 0) | ||
276 | { | ||
277 | cJSON_AddStringToObject(process, "parent_md5", pair->parent_md5); | ||
278 | } | ||
279 | |||
280 | // get process information | ||
281 | if (NULL != get_proc_stats(pair->pid, &curr_proc)) | ||
282 | { | ||
283 | cJSON_AddStringToObject(process, "state", &curr_proc.state); | ||
284 | cJSON_AddNumberToObject(process, "utime", curr_proc.utime); | ||
285 | cJSON_AddNumberToObject(process, "stime", curr_proc.stime); | ||
286 | if (curr_proc.cmdline && curr_proc.cmdline[0]) | ||
287 | { | ||
288 | cJSON *argvs = cJSON_CreateArray(); | ||
289 | cJSON_AddStringToObject(process, "cmd", curr_proc.cmdline[0]); | ||
290 | for (int i = 1; curr_proc.cmdline[i]; i++) | ||
291 | { | ||
292 | if (!strlen(curr_proc.cmdline[i]) == 0) | ||
293 | { | ||
294 | cJSON_AddItemToArray(argvs, cJSON_CreateString(curr_proc.cmdline[i])); | ||
295 | } | ||
296 | } | ||
297 | if (cJSON_GetArraySize(argvs) > 0) | ||
298 | { | ||
299 | cJSON_AddItemToObject(process, "argvs", argvs); | ||
300 | } | ||
301 | else | ||
302 | { | ||
303 | cJSON_Delete(argvs); | ||
304 | } | ||
305 | } | ||
306 | cJSON_AddStringToObject(process, "euser", curr_proc.euser); | ||
307 | cJSON_AddStringToObject(process, "egroup", curr_proc.egroup); | ||
308 | cJSON_AddNumberToObject(process, "resident", curr_proc.resident); | ||
309 | cJSON_AddNumberToObject(process, "nlwp", curr_proc.nlwp); | ||
310 | cJSON_AddNumberToObject(process, "tty", curr_proc.tty); | ||
311 | cJSON_AddNumberToObject(process, "processor", curr_proc.processor); | ||
312 | /* | ||
313 | cJSON_AddStringToObject(process, "ruser", curr_proc.ruser); | ||
314 | cJSON_AddStringToObject(process, "suser", curr_proc.suser); | ||
315 | cJSON_AddStringToObject(process, "rgroup", curr_proc.rgroup); | ||
316 | cJSON_AddStringToObject(process, "sgroup", curr_proc.sgroup); | ||
317 | cJSON_AddStringToObject(process, "fgroup", curr_proc.fgroup); | ||
318 | cJSON_AddNumberToObject(process, "priority", curr_proc.priority); | ||
319 | cJSON_AddNumberToObject(process, "nice", curr_proc.nice); | ||
320 | cJSON_AddNumberToObject(process, "size", curr_proc.size); | ||
321 | cJSON_AddNumberToObject(process, "vm_size", curr_proc.vm_size); | ||
322 | cJSON_AddNumberToObject(process, "share", curr_proc.share); | ||
323 | cJSON_AddNumberToObject(process, "pgrp", curr_proc.pgrp); | ||
324 | cJSON_AddNumberToObject(process, "session", curr_proc.session); | ||
325 | cJSON_AddNumberToObject(process, "tgid", curr_proc.tgid); | ||
326 | */ | ||
327 | } | ||
328 | |||
329 | char *msg = cJSON_PrintUnformatted(process); | ||
330 | wm_sendmsg( MAX_PIPE_WAIT_USECOND, proc_monitor.queue_fd, msg, location, PROC_COLLECTOR_MQ ); | ||
331 | free(msg); | ||
332 | cJSON_Delete( process ); | ||
333 | |||
334 | return; | ||
335 | } | ||
336 | |||
337 | static void get_process_info( const process_parent_child_pair_t *pair, const char *location ) | ||
338 | { | ||
339 | // get process base info | ||
340 | get_process_baseinfo( pair, location ); | ||
341 | |||
342 | // get process library info | ||
343 | |||
344 | // find rootkit in user mode | ||
345 | |||
346 | // check process is a malware | ||
347 | } | ||
348 | |||
349 | static void handle_temp_process( const char *location ) | ||
350 | { | ||
351 | int i = 0; | ||
352 | for ( i = 0; i < MAX_TEMP_PROCESS; i++ ) | ||
353 | { | ||
354 | if ( ( temp_processes[i].status != PROCESS_SLOT_EMPTY ) && ( temp_processes[i].ppid != 0 ) ) | ||
355 | { | ||
356 | mtdebug1(WM_PROC_LOGTAG, "handle process: %d, parent process:%d", temp_processes[i].pid, temp_processes[i].ppid ); | ||
357 | get_process_info( &temp_processes[i], location ); | ||
358 | temp_processes[i].status = PROCESS_SLOT_EMPTY; | ||
359 | } | ||
360 | } | ||
361 | } | ||
362 | |||
363 | static void handle_process_fork( const event_msg_t *proc_msg ) | ||
364 | { | ||
365 | int i = 0; | ||
366 | for ( i = 0; i < MAX_TEMP_PROCESS; i++ ) | ||
367 | { | ||
368 | if ( temp_processes[i].status == PROCESS_SLOT_EMPTY ) | ||
369 | { | ||
370 | get_path_and_md5( proc_msg->proc_ev.event_data.fork.child_pid, temp_processes[i].path, temp_processes[i].md5 ); | ||
371 | get_path_and_md5( proc_msg->proc_ev.event_data.fork.parent_pid, temp_processes[i].parent_path, temp_processes[i].parent_md5); | ||
372 | temp_processes[i].pid = proc_msg->proc_ev.event_data.fork.child_pid; | ||
373 | temp_processes[i].ppid = proc_msg->proc_ev.event_data.fork.parent_pid; | ||
374 | temp_processes[i].fork_time = time(0); | ||
375 | temp_processes[i].status = !PROCESS_SLOT_EMPTY; | ||
376 | mtdebug1(WM_PROC_LOGTAG, "fork process: %d, parent process:%d", temp_processes[i].pid, temp_processes[i].ppid ); | ||
377 | break; | ||
378 | } | ||
379 | } | ||
380 | } | ||
381 | |||
382 | static void handle_process_exec( const event_msg_t *proc_msg, const char *location ) | ||
383 | { | ||
384 | int i = 0; | ||
385 | for ( i = 0; i < MAX_TEMP_PROCESS; i++ ) | ||
386 | { | ||
387 | if (temp_processes[i].pid == proc_msg->proc_ev.event_data.exec.process_pid | ||
388 | && temp_processes[i].status != PROCESS_SLOT_EMPTY) | ||
389 | { | ||
390 | get_path_and_md5( proc_msg->proc_ev.event_data.exec.process_pid, temp_processes[i].path, temp_processes[i].md5 ); | ||
391 | mtdebug1(WM_PROC_LOGTAG, "exec process: %d, parent process:%d", temp_processes[i].pid, temp_processes[i].ppid ); | ||
392 | get_process_info( &temp_processes[i], location ); | ||
393 | temp_processes[i].status = PROCESS_SLOT_EMPTY; | ||
394 | break; | ||
395 | } | ||
396 | } | ||
397 | } | ||
398 | |||
399 | static void handle_process_exit( const event_msg_t *proc_msg, const char* location ) | ||
400 | { | ||
401 | int i = 0; | ||
402 | for ( i = 0; i < MAX_TEMP_PROCESS; i++ ) | ||
403 | { | ||
404 | if ( ( temp_processes[i].status != PROCESS_SLOT_EMPTY ) | ||
405 | && ( proc_msg->proc_ev.event_data.exit.process_pid == temp_processes[i].pid ) | ||
406 | && ( temp_processes[i].ppid == 0 ) ) | ||
407 | { | ||
408 | temp_processes[i].status = PROCESS_SLOT_EMPTY; | ||
409 | return; | ||
410 | } | ||
411 | } | ||
412 | |||
413 | cJSON *process = cJSON_CreateObject(); | ||
414 | cJSON_AddStringToObject(process, "type", "exit"); | ||
415 | cJSON_AddNumberToObject( process, "pid", proc_msg->proc_ev.event_data.exit.process_pid ); | ||
416 | cJSON_AddNumberToObject( process, "eventTime", time(0) ); | ||
417 | cJSON_AddNumberToObject(process, "exitCode", proc_msg->proc_ev.event_data.exit.exit_code); | ||
418 | cJSON_AddNumberToObject(process, "exitSignal", (int)proc_msg->proc_ev.event_data.exit.exit_signal); | ||
419 | |||
420 | char *exit_msg = cJSON_PrintUnformatted( process ); | ||
421 | wm_sendmsg( MAX_PIPE_WAIT_USECOND, proc_monitor.queue_fd, exit_msg, location, PROC_COLLECTOR_MQ ); | ||
422 | free( exit_msg ); | ||
423 | cJSON_Delete( process ); | ||
424 | } | ||
425 | |||
426 | static time_t get_process_start_time( pid_t pid ) | ||
427 | { | ||
428 | char path[MAX_PATH_NAME]; | ||
429 | memset( path, 0, MAX_PATH_NAME); | ||
430 | |||
431 | snprintf( path, MAX_PATH_NAME-1, "/proc/%d", pid ); | ||
432 | |||
433 | struct stat dir_stat; | ||
434 | |||
435 | if ( stat( path, &dir_stat) < 0 ) | ||
436 | { | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | return dir_stat.st_mtime; | ||
441 | } | ||
442 | |||
443 | static void get_inventory_processes(const char *location) | ||
444 | { | ||
445 | DIR *proc_dir = opendir( "/proc" ); | ||
446 | if ( NULL == proc_dir ) | ||
447 | { | ||
448 | mterror( WM_PROC_LOGTAG, "failed to open /proc, errno=(%d:%m)", errno ); | ||
449 | return; | ||
450 | } | ||
451 | |||
452 | struct dirent *entry = NULL; | ||
453 | while ( NULL != ( entry = readdir( proc_dir ))) | ||
454 | { | ||
455 | if ( !strcmp( entry->d_name, "." ) || !strcmp( entry->d_name, ".." ) ) | ||
456 | { | ||
457 | continue; | ||
458 | } | ||
459 | int pid = atoi( entry->d_name ); | ||
460 | if ( 0 == pid ) | ||
461 | { | ||
462 | continue; | ||
463 | } | ||
464 | |||
465 | char pid_path[MAX_PATH_NAME]; | ||
466 | os_md5 md5; | ||
467 | memset( pid_path, 0, sizeof( MAX_PATH_NAME)); | ||
468 | memset( md5, 0, sizeof( os_md5 ) ); | ||
469 | get_path_and_md5( pid, pid_path, md5 ); | ||
470 | |||
471 | cJSON *process = cJSON_CreateObject(); | ||
472 | cJSON_AddStringToObject(process, "type", "new process"); | ||
473 | cJSON_AddNumberToObject(process, "eventTime", time(0)); | ||
474 | cJSON_AddNumberToObject(process, "pid", pid); | ||
475 | cJSON_AddNumberToObject(process, "startTime", get_process_start_time(pid)); | ||
476 | if (strlen(pid_path) > 0) | ||
477 | { | ||
478 | cJSON_AddStringToObject(process, "exe", pid_path); | ||
479 | } | ||
480 | if (strlen(md5) > 0) | ||
481 | { | ||
482 | cJSON_AddStringToObject(process, "md5", md5); | ||
483 | } | ||
484 | |||
485 | proc_t curr_proc; | ||
486 | memset( &curr_proc, 0, sizeof( proc_t )); | ||
487 | if ( NULL != get_proc_stats(pid, &curr_proc )) | ||
488 | { | ||
489 | cJSON_AddStringToObject(process, "state", &curr_proc.state); | ||
490 | cJSON_AddNumberToObject(process, "utime", curr_proc.utime); | ||
491 | cJSON_AddNumberToObject(process, "stime", curr_proc.stime); | ||
492 | cJSON_AddStringToObject(process, "euser", curr_proc.euser); | ||
493 | cJSON_AddStringToObject(process, "egroup", curr_proc.egroup); | ||
494 | cJSON_AddNumberToObject(process, "resident", curr_proc.resident); | ||
495 | cJSON_AddNumberToObject(process, "nlwp", curr_proc.nlwp); | ||
496 | cJSON_AddNumberToObject(process, "tty", curr_proc.tty); | ||
497 | cJSON_AddNumberToObject(process, "processor", curr_proc.processor); | ||
498 | /* | ||
499 | cJSON_AddStringToObject(process, "ruser", curr_proc.ruser); | ||
500 | cJSON_AddStringToObject(process, "suser", curr_proc.suser); | ||
501 | cJSON_AddStringToObject(process, "rgroup", curr_proc.rgroup); | ||
502 | cJSON_AddStringToObject(process, "sgroup", curr_proc.sgroup); | ||
503 | cJSON_AddStringToObject(process, "fgroup", curr_proc.fgroup); | ||
504 | |||
505 | cJSON_AddNumberToObject(process, "priority", curr_proc.priority); | ||
506 | cJSON_AddNumberToObject(process, "nice", curr_proc.nice); | ||
507 | cJSON_AddNumberToObject(process, "size", curr_proc.size); | ||
508 | cJSON_AddNumberToObject(process, "vm_size", curr_proc.vm_size); | ||
509 | cJSON_AddNumberToObject(process, "share", curr_proc.share); | ||
510 | cJSON_AddNumberToObject(process, "pgrp", curr_proc.pgrp); | ||
511 | cJSON_AddNumberToObject(process, "session", curr_proc.session); | ||
512 | cJSON_AddNumberToObject(process, "tgid", curr_proc.tgid); | ||
513 | */ | ||
514 | |||
515 | memset(pid_path, 0, sizeof(MAX_PATH_NAME)); | ||
516 | memset(md5, 0, sizeof(os_md5)); | ||
517 | get_path_and_md5(curr_proc.ppid, pid_path, md5); | ||
518 | if (strlen(pid_path) > 0) | ||
519 | { | ||
520 | cJSON_AddStringToObject(process, "parent_exe", pid_path); | ||
521 | } | ||
522 | if (strlen(md5) > 0) | ||
523 | { | ||
524 | cJSON_AddStringToObject(process, "parent_md5", md5); | ||
525 | } | ||
526 | } | ||
527 | |||
528 | char *msg = cJSON_PrintUnformatted(process); | ||
529 | wm_sendmsg(MAX_PIPE_WAIT_USECOND, proc_monitor.queue_fd, msg, location, PROC_COLLECTOR_MQ); | ||
530 | free(msg); | ||
531 | cJSON_Delete(process); | ||
532 | } | ||
533 | |||
534 | closedir( proc_dir); | ||
535 | } | ||
536 | |||
537 | int wm_proc_linux_process(wm_proc_t *proc, const char *location) | ||
538 | { | ||
539 | int rc; | ||
540 | event_msg_t proc_msg; | ||
541 | fd_set readfds; | ||
542 | int max_fd = proc_monitor.proc_fd + 1; | ||
543 | struct timeval tv; | ||
544 | |||
545 | if (proc->flags.enabled == 0) | ||
546 | { | ||
547 | return 0; | ||
548 | merror("process collector disabled, let us rest."); | ||
549 | } | ||
550 | |||
551 | |||
552 | merror("process collector enabled, let us work."); | ||
553 | |||
554 | get_inventory_processes(location); | ||
555 | |||
556 | tv.tv_sec = 5; | ||
557 | tv.tv_usec = 0; | ||
558 | |||
559 | while (1) | ||
560 | { | ||
561 | FD_ZERO(&readfds); | ||
562 | FD_SET(proc_monitor.proc_fd, &readfds); | ||
563 | |||
564 | rc = select(max_fd, &readfds, NULL, NULL, &tv); | ||
565 | if (0 == rc) | ||
566 | { | ||
567 | handle_temp_process(location); | ||
568 | tv.tv_sec = 5; | ||
569 | tv.tv_usec = 0; | ||
570 | continue; | ||
571 | } | ||
572 | if (-1 == rc) | ||
573 | { | ||
574 | if (errno == EINTR) | ||
575 | { | ||
576 | continue; | ||
577 | } | ||
578 | mterror(WM_PROC_LOGTAG, "failed to listen to netlink socket, errno=(%d:%m)", errno); | ||
579 | return rc; | ||
580 | } | ||
581 | if (FD_ISSET(proc_monitor.proc_fd, &readfds)) | ||
582 | { | ||
583 | rc = recv(proc_monitor.proc_fd, &proc_msg, sizeof(proc_msg), 0); | ||
584 | if (rc > 0) | ||
585 | { | ||
586 | switch (proc_msg.proc_ev.what) | ||
587 | { | ||
588 | case proc_event::PROC_EVENT_FORK: | ||
589 | handle_process_fork(&proc_msg); | ||
590 | tv.tv_sec = 1; | ||
591 | tv.tv_usec = 1000; | ||
592 | break; | ||
593 | case proc_event::PROC_EVENT_EXEC: | ||
594 | handle_process_exec(&proc_msg, location); | ||
595 | break; | ||
596 | case proc_event::PROC_EVENT_COMM: | ||
597 | break; | ||
598 | case proc_event::PROC_EVENT_EXIT: | ||
599 | handle_process_exit(&proc_msg, location); | ||
600 | break; | ||
601 | default: | ||
602 | break; | ||
603 | } | ||
604 | } | ||
605 | else if (rc == -1) | ||
606 | { | ||
607 | if (errno == EINTR) | ||
608 | { | ||
609 | continue; | ||
610 | } | ||
611 | mterror(WM_PROC_LOGTAG, "failed to received from netlink socket, errno=(%d:%m)", errno); | ||
612 | } | ||
613 | } | ||
614 | } | ||
615 | |||
616 | return 0; | ||
617 | } | ||
618 | #endif \ No newline at end of file | ||
diff --git a/connector/proc_mon_linux.cpp b/connector/proc_mon_linux.cpp new file mode 100755 index 0000000..16dd51c --- /dev/null +++ b/connector/proc_mon_linux.cpp | |||
@@ -0,0 +1,487 @@ | |||
1 | #ifndef WIN32 | ||
2 | #include <unistd.h> | ||
3 | #include <sys/socket.h> | ||
4 | #include <algorithm> | ||
5 | #include "shared.h" | ||
6 | #include "proc_mon_linux.h" | ||
7 | #include <malloc.h> | ||
8 | #include "linux_proc_baseline.h" | ||
9 | |||
10 | |||
11 | #define MAX_PIPE_WAIT_USECOND 100 | ||
12 | #define PROCESS_SCAN_ITERTIME 10 | ||
13 | const char *WM_PROC_LOCATION = "proc_collector"; | ||
14 | |||
15 | ProcMon* ProcMon::m_instance = NULL; | ||
16 | |||
17 | ProcMon& ProcMon::instance() | ||
18 | { | ||
19 | if ( m_instance == NULL ) | ||
20 | { | ||
21 | m_instance = new ProcMon; | ||
22 | } | ||
23 | |||
24 | return *m_instance; | ||
25 | } | ||
26 | |||
27 | void ProcMon::destroy() | ||
28 | { | ||
29 | delete m_instance; | ||
30 | m_instance = NULL; | ||
31 | } | ||
32 | |||
33 | int ProcMon::init( const wm_proc_t* config ) | ||
34 | { | ||
35 | pthread_mutex_init(&m_mutex, NULL); | ||
36 | setConfig( config ); | ||
37 | |||
38 | int ret = setupNetlink(); | ||
39 | if (ret != 0 ) | ||
40 | { | ||
41 | fini(); | ||
42 | return -1; | ||
43 | } | ||
44 | |||
45 | ret = setupMQ(); | ||
46 | if (ret != 0 ) | ||
47 | { | ||
48 | fini(); | ||
49 | return -1; | ||
50 | } | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | int ProcMon::working() | ||
56 | { | ||
57 | int rc; | ||
58 | event_msg_t procMsg; | ||
59 | fd_set readfds; | ||
60 | int maxfd = m_procFd + 1; | ||
61 | struct timeval tv; | ||
62 | time_t last = time(0); | ||
63 | |||
64 | if ( m_config.flags.enabled == 0 ) | ||
65 | { | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | getInventoryProcesses(); | ||
70 | |||
71 | |||
72 | while ( 1 ) | ||
73 | { | ||
74 | FD_ZERO(&readfds); | ||
75 | FD_SET( m_procFd, &readfds ); | ||
76 | tv.tv_sec = 1; | ||
77 | tv.tv_usec = 0; | ||
78 | |||
79 | if ( time(0) - last > PROCESS_SCAN_ITERTIME ) | ||
80 | { | ||
81 | // scan processes | ||
82 | scanProcesses(last); | ||
83 | last = time(0); | ||
84 | } | ||
85 | |||
86 | rc = select( maxfd, &readfds, NULL, NULL, &tv ); | ||
87 | if ( 0 == rc ) | ||
88 | { | ||
89 | continue; | ||
90 | } | ||
91 | |||
92 | if ( -1 == rc ) | ||
93 | { | ||
94 | if ( errno == EINTR ) | ||
95 | { | ||
96 | continue; | ||
97 | } | ||
98 | |||
99 | mterror(WM_PROC_LOGTAG, "failed to listen to netlink socket, errno=(%d:%m)", errno); | ||
100 | return rc; | ||
101 | } | ||
102 | |||
103 | if ( FD_ISSET( m_procFd, &readfds ) ) | ||
104 | { | ||
105 | rc = recv( m_procFd, &procMsg, sizeof(procMsg), 0 ); | ||
106 | if( rc > 0 ) | ||
107 | { | ||
108 | switch (procMsg.proc_ev.what) | ||
109 | { | ||
110 | case proc_event::PROC_EVENT_FORK: | ||
111 | handleForkMsg(procMsg); | ||
112 | break; | ||
113 | case proc_event::PROC_EVENT_EXEC: | ||
114 | handleExecMsg(procMsg); | ||
115 | break; | ||
116 | case proc_event::PROC_EVENT_COMM: | ||
117 | break; | ||
118 | case proc_event::PROC_EVENT_EXIT: | ||
119 | handleExitMsg(procMsg); | ||
120 | break; | ||
121 | default: | ||
122 | break; | ||
123 | } | ||
124 | } | ||
125 | else if (rc == -1) | ||
126 | { | ||
127 | if (errno == EINTR) | ||
128 | { | ||
129 | continue; | ||
130 | } | ||
131 | mterror(WM_PROC_LOGTAG, "failed to received from netlink socket, errno=(%d:%m)", errno); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | malloc_trim(0); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | ProcMon::ProcMon() | ||
140 | { | ||
141 | m_mutex = PTHREAD_MUTEX_INITIALIZER; | ||
142 | m_processes.clear(); | ||
143 | m_pidCache.clear(); | ||
144 | m_procFd = -1; | ||
145 | m_queueFd = -1; | ||
146 | } | ||
147 | |||
148 | ProcMon::~ProcMon() | ||
149 | { | ||
150 | fini(); | ||
151 | } | ||
152 | |||
153 | void ProcMon::setConfig( const wm_proc_t* config ) | ||
154 | { | ||
155 | m_config.flags.enabled = config->flags.enabled; | ||
156 | m_config.flags.rootcheck = config->flags.rootcheck; | ||
157 | m_config.flags.limitcheck = config->flags.limitcheck; | ||
158 | m_config.flags.environcheck = config->flags.environcheck; | ||
159 | m_config.flags.statuscheck = config->flags.statuscheck; | ||
160 | m_config.flags.threadcheck = config->flags.threadcheck; | ||
161 | m_config.flags.cgroupcheck = config->flags.cgroupcheck; | ||
162 | m_config.flags.libcheck = config->flags.libcheck; | ||
163 | m_config.flags.malwarecheck = config->flags.malwarecheck; | ||
164 | m_config.interval = config->interval; | ||
165 | } | ||
166 | |||
167 | int ProcMon::setupNetlink() | ||
168 | { | ||
169 | int rc; | ||
170 | int nl_sock; | ||
171 | struct sockaddr_nl sa_nl; | ||
172 | register_msg_t nlcn_msg; | ||
173 | |||
174 | nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); | ||
175 | if (nl_sock == -1) | ||
176 | { | ||
177 | mterror(WM_PROC_LOGTAG, "Can't open netlink socket"); | ||
178 | return -1; | ||
179 | } | ||
180 | |||
181 | sa_nl.nl_family = AF_NETLINK; | ||
182 | sa_nl.nl_groups = CN_IDX_PROC; | ||
183 | sa_nl.nl_pid = getpid(); | ||
184 | |||
185 | rc = bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl)); | ||
186 | if (rc == -1) | ||
187 | { | ||
188 | mterror(WM_PROC_LOGTAG, "Can't bind netlink socket"); | ||
189 | close(nl_sock); | ||
190 | return -1; | ||
191 | } | ||
192 | |||
193 | // create listener | ||
194 | memset(&nlcn_msg, 0, sizeof(nlcn_msg)); | ||
195 | nlcn_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg); | ||
196 | nlcn_msg.nl_hdr.nlmsg_pid = getpid(); | ||
197 | nlcn_msg.nl_hdr.nlmsg_type = NLMSG_DONE; | ||
198 | |||
199 | nlcn_msg.cn_msg.id.idx = CN_IDX_PROC; | ||
200 | nlcn_msg.cn_msg.id.val = CN_VAL_PROC; | ||
201 | nlcn_msg.cn_msg.len = sizeof(enum proc_cn_mcast_op); | ||
202 | |||
203 | nlcn_msg.cn_mcast = PROC_CN_MCAST_LISTEN; | ||
204 | |||
205 | rc = send(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0); | ||
206 | if (rc == -1) | ||
207 | { | ||
208 | mterror(WM_PROC_LOGTAG, "can't register to netlink"); | ||
209 | close(nl_sock); | ||
210 | return -1; | ||
211 | } | ||
212 | |||
213 | m_procFd = nl_sock; | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | int ProcMon::setupMQ() | ||
218 | { | ||
219 | unsigned int indx; | ||
220 | // Connect to socket | ||
221 | for (indx = 0; indx < WM_MAX_ATTEMPTS; indx++) | ||
222 | { | ||
223 | m_queueFd = StartMQ(DEFAULTQPATH, WRITE); | ||
224 | if (m_queueFd > 0) | ||
225 | { | ||
226 | break; | ||
227 | } | ||
228 | wm_delay(1000 * WM_MAX_WAIT); | ||
229 | } | ||
230 | |||
231 | if (indx == WM_MAX_ATTEMPTS) | ||
232 | { | ||
233 | mterror(WM_PROC_LOGTAG, "Can't connect to queue."); | ||
234 | pthread_exit(NULL); | ||
235 | } | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | |||
241 | void ProcMon::fini() | ||
242 | { | ||
243 | m_processes.clear(); | ||
244 | m_pidCache.clear(); | ||
245 | if (m_procFd != -1 ) | ||
246 | { | ||
247 | close( m_procFd); | ||
248 | m_procFd = -1; | ||
249 | } | ||
250 | |||
251 | if (m_queueFd != -1 ) | ||
252 | { | ||
253 | close( m_queueFd); | ||
254 | m_queueFd = -1; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | void ProcMon::getInventoryProcesses() | ||
259 | { | ||
260 | DIR *procDir = opendir( "/proc" ); | ||
261 | if ( NULL == procDir ) | ||
262 | { | ||
263 | mterror(WM_PROC_LOGTAG, "failed to open /proc, errno=(%d:%m)", errno); | ||
264 | return; | ||
265 | } | ||
266 | |||
267 | struct dirent *entry = NULL; | ||
268 | while (NULL != (entry = readdir(procDir))) | ||
269 | { | ||
270 | if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) | ||
271 | { | ||
272 | continue; | ||
273 | } | ||
274 | int pid = atoi(entry->d_name); | ||
275 | if (0 == pid) | ||
276 | { | ||
277 | continue; | ||
278 | } | ||
279 | |||
280 | Process *proc = new Process(pid); | ||
281 | if ( NULL == proc ) | ||
282 | { | ||
283 | continue; | ||
284 | } | ||
285 | if(0 != proc->init()) | ||
286 | { | ||
287 | delete proc; | ||
288 | proc = NULL; | ||
289 | continue; | ||
290 | } | ||
291 | std::pair<std::map<pid_t, Process*>::iterator,bool> ret = m_processes.insert(std::make_pair(pid, proc)); | ||
292 | if(!ret.second) | ||
293 | { | ||
294 | delete proc; | ||
295 | proc = NULL; | ||
296 | continue; | ||
297 | } | ||
298 | std::vector<std::string> events = proc->getEvents(); | ||
299 | if ( !events.empty() ) | ||
300 | { | ||
301 | reportEvents(events); | ||
302 | } | ||
303 | usleep( 500 ); | ||
304 | } | ||
305 | |||
306 | return; | ||
307 | } | ||
308 | |||
309 | void ProcMon::handleForkMsg( const event_msg_t& procMsg ) | ||
310 | { | ||
311 | pid_t pid = procMsg.proc_ev.event_data.fork.child_pid; | ||
312 | auto iter = m_pidCache.find( pid ); | ||
313 | if ( iter != m_pidCache.end() ) | ||
314 | { | ||
315 | m_pidCache.erase(iter); | ||
316 | return; | ||
317 | } | ||
318 | |||
319 | PidRelation relation; | ||
320 | relation.pid = pid; | ||
321 | relation.ppid = procMsg.proc_ev.event_data.fork.parent_pid; | ||
322 | relation.pidEvent = PidRelation::FORKEVENT; | ||
323 | relation.born = time(0); | ||
324 | |||
325 | m_pidCache.insert( std::make_pair(relation.pid, relation )); | ||
326 | } | ||
327 | |||
328 | void ProcMon::handleExecMsg( const event_msg_t& procMsg ) | ||
329 | { | ||
330 | pid_t pid = procMsg.proc_ev.event_data.exec.process_pid; | ||
331 | auto iter = m_pidCache.find( pid ); | ||
332 | if ( iter == m_pidCache.end() ) | ||
333 | { | ||
334 | return; | ||
335 | } | ||
336 | |||
337 | //mterror(WM_PROC_LOGTAG, "cache size:%lu", m_pidCache.size()); | ||
338 | Process *proc = new Process( pid, iter->second.ppid, iter->second.born ); | ||
339 | if ( NULL == proc ) | ||
340 | { | ||
341 | return; | ||
342 | } | ||
343 | // check hidden process | ||
344 | if ( 0 != proc->init() ) | ||
345 | { | ||
346 | return; | ||
347 | } | ||
348 | m_processes.insert( std::make_pair(pid, proc )); | ||
349 | std::vector<std::string> events = proc->getEvents(); | ||
350 | if (!events.empty()) | ||
351 | { | ||
352 | reportEvents(events); | ||
353 | } | ||
354 | // m_pidCache.erase(iter); | ||
355 | //mterror(WM_PROC_LOGTAG, "exec process:%d exe:%s", pid, proc.exe().c_str()); | ||
356 | } | ||
357 | |||
358 | void ProcMon::handleExitMsg( const event_msg_t& procMsg ) | ||
359 | { | ||
360 | pid_t pid = procMsg.proc_ev.event_data.exit.process_pid; | ||
361 | auto iter = m_pidCache.find( pid ); | ||
362 | if ( iter != m_pidCache.end() ) | ||
363 | { | ||
364 | m_pidCache.erase(iter); | ||
365 | } | ||
366 | |||
367 | auto procIter = m_processes.find(pid); | ||
368 | if ( procIter == m_processes.end() ) | ||
369 | { | ||
370 | return; | ||
371 | } | ||
372 | |||
373 | std::vector<int> signals{ 3, 9, 10, 12, 15,16,17,30,31}; | ||
374 | |||
375 | //if ( signals.end() == std::find( signals.begin(), signals.end(), procMsg.proc_ev.event_data.exit.exit_signal ) | ||
376 | //|| (procMsg.proc_ev.event_data.exit.exit_code != 0)) | ||
377 | { | ||
378 | // report abnormal events | ||
379 | cJSON *obj= cJSON_CreateObject(); | ||
380 | cJSON_AddStringToObject(obj, "type", "exit"); | ||
381 | cJSON_AddStringToObject(obj, "exe", procIter->second->exe().c_str()); | ||
382 | cJSON_AddNumberToObject(obj, "pid", procIter->first); | ||
383 | cJSON_AddNumberToObject(obj, "event_time", time(0)); | ||
384 | cJSON_AddNumberToObject(obj, "exit_signal", procMsg.proc_ev.event_data.exit.exit_signal); | ||
385 | cJSON_AddNumberToObject(obj, "exit_code", procMsg.proc_ev.event_data.exit.exit_code); | ||
386 | char *data = cJSON_PrintUnformatted( obj ); | ||
387 | std::string msg(data); | ||
388 | free(data); | ||
389 | reportEvent( msg ); | ||
390 | cJSON_Delete(obj); | ||
391 | //mterror(WM_PROC_LOGTAG, "%s", msg.c_str()); | ||
392 | } | ||
393 | |||
394 | delete procIter->second; | ||
395 | m_processes.erase(procIter); | ||
396 | //mterror(WM_PROC_LOGTAG, "process collection:%d", m_processes.size()); | ||
397 | } | ||
398 | |||
399 | void ProcMon::scanProcesses(time_t last) | ||
400 | { | ||
401 | time_t now = time(0); | ||
402 | // mterror(WM_PROC_LOGTAG, "pid cache size: %d , process collection size : %d", m_pidCache.size(), m_processes.size()); | ||
403 | for (auto iter = m_pidCache.begin(); iter != m_pidCache.end(); ) | ||
404 | { | ||
405 | if ( now - iter->second.born < 1 || m_processes.find(iter->second.pid) != m_processes.end()) | ||
406 | { | ||
407 | iter++; | ||
408 | } | ||
409 | else | ||
410 | { | ||
411 | Process *proc = new Process( iter->second.pid, iter->second.ppid, iter->second.born); | ||
412 | if (NULL != proc ) | ||
413 | { | ||
414 | if(0 != proc->init()) | ||
415 | { | ||
416 | delete proc; | ||
417 | proc = NULL; | ||
418 | continue; | ||
419 | } | ||
420 | std::pair<std::map<pid_t, Process*>::iterator, bool> ret = m_processes.insert(std::make_pair(iter->first, proc)); | ||
421 | if(!ret.second) | ||
422 | { | ||
423 | delete proc; | ||
424 | proc = NULL; | ||
425 | continue; | ||
426 | } | ||
427 | std::vector<std::string> events = proc->getEvents(); | ||
428 | if (!events.empty()) | ||
429 | { | ||
430 | reportEvents(events); | ||
431 | } | ||
432 | |||
433 | } | ||
434 | else | ||
435 | { | ||
436 | // hidden process found | ||
437 | cJSON *obj = cJSON_CreateObject(); | ||
438 | cJSON_AddStringToObject(obj, "type", "rootkit"); | ||
439 | cJSON_AddNumberToObject(obj, "pid", iter->first); | ||
440 | cJSON_AddNumberToObject(obj, "event_time", iter->second.born); | ||
441 | cJSON_AddNumberToObject(obj, "ppid", iter->second.ppid); | ||
442 | auto parent = m_processes.find(iter->second.ppid); | ||
443 | if (parent != m_processes.end()) | ||
444 | { | ||
445 | cJSON_AddStringToObject(obj, "parent exe", parent->second->exe().c_str()); | ||
446 | } | ||
447 | char *data = cJSON_PrintUnformatted(obj); | ||
448 | std::string msg(data); | ||
449 | free(data); | ||
450 | reportEvent(msg); | ||
451 | cJSON_Delete(obj); | ||
452 | } | ||
453 | iter = m_pidCache.erase(iter); | ||
454 | } | ||
455 | usleep( 500 ); | ||
456 | } | ||
457 | /* | ||
458 | if ( now - last < 60 ) | ||
459 | { | ||
460 | return; | ||
461 | } | ||
462 | */ | ||
463 | for (auto& procIter : m_processes ) | ||
464 | { | ||
465 | procIter.second->scan(); | ||
466 | std::vector<std::string> events = procIter.second->getEvents(); | ||
467 | if (!events.empty()) | ||
468 | { | ||
469 | reportEvents(events); | ||
470 | } | ||
471 | usleep( 5000 ); | ||
472 | } | ||
473 | } | ||
474 | |||
475 | void ProcMon::reportEvent( const std::string& event ) | ||
476 | { | ||
477 | wm_sendmsg(MAX_PIPE_WAIT_USECOND, m_queueFd, event.c_str(), WM_PROC_LOCATION, PROC_COLLECTOR_MQ); | ||
478 | } | ||
479 | |||
480 | void ProcMon::reportEvents(const std::vector<std::string> &events) | ||
481 | { | ||
482 | for (auto it : events) | ||
483 | { | ||
484 | wm_sendmsg(MAX_PIPE_WAIT_USECOND, m_queueFd, it.c_str(), WM_PROC_LOCATION, PROC_COLLECTOR_MQ); | ||
485 | } | ||
486 | } | ||
487 | #endif | ||
diff --git a/connector/test.c b/connector/test.c new file mode 100644 index 0000000..c12ad10 --- /dev/null +++ b/connector/test.c | |||
@@ -0,0 +1,64 @@ | |||
1 | #define _GNU_SOURCE | ||
2 | #include <sched.h> | ||
3 | #include <stdio.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <sys/types.h> | ||
6 | #include <sys/wait.h> | ||
7 | #include <sys/syscall.h> | ||
8 | #include <unistd.h> | ||
9 | #include <pthread.h> | ||
10 | |||
11 | #define STACK_SIZE (1024 * 1024) // 定义栈大小 | ||
12 | |||
13 | // 子任务的入口函数 | ||
14 | void *child_func(void *arg) | ||
15 | { | ||
16 | printf("子任务: PID=%ld, PPID=%ld, TID=%ld\n", (long)getpid(), | ||
17 | (long)getppid(), (long)syscall(SYS_gettid)); | ||
18 | sleep(3); | ||
19 | } | ||
20 | |||
21 | int main() | ||
22 | { | ||
23 | char *stack; // 栈的指针 | ||
24 | char *stack_top; // 栈顶的指针 | ||
25 | pid_t child_tid; | ||
26 | pid_t forkPid; | ||
27 | pid_t threadPid; | ||
28 | |||
29 | printf("主任务:我是%d\n", getpid()); | ||
30 | if ((forkPid = fork()) == 0) | ||
31 | { | ||
32 | sleep(3); | ||
33 | exit(0); | ||
34 | } | ||
35 | printf("主任务:fork子任务 %d\n", forkPid); | ||
36 | |||
37 | pthread_create(&threadPid, NULL, child_func, NULL); | ||
38 | printf("主任务:create新线程%d\n", threadPid); | ||
39 | |||
40 | // 使用 clone 创建子任务 | ||
41 | child_tid = clone(child_func, stack_top, SIGCHLD, NULL); | ||
42 | if (child_tid == -1) | ||
43 | { | ||
44 | perror("clone"); | ||
45 | free(stack); | ||
46 | exit(EXIT_FAILURE); | ||
47 | } | ||
48 | |||
49 | printf("主任务: 创建了子任务, TID=%ld\n", (long)child_tid); | ||
50 | |||
51 | // 等待子任务结束 | ||
52 | if (waitpid(child_tid, NULL, 0) == -1) | ||
53 | { | ||
54 | perror("waitpid"); | ||
55 | free(stack); | ||
56 | exit(EXIT_FAILURE); | ||
57 | } | ||
58 | |||
59 | // 释放分配的栈 | ||
60 | // free(stack); | ||
61 | |||
62 | printf("主任务: 子任务结束\n"); | ||
63 | return 0; | ||
64 | } | ||
diff --git a/src/deal.go b/src/deal.go index aaac8c5..717344c 100644 --- a/src/deal.go +++ b/src/deal.go | |||
@@ -55,18 +55,25 @@ func deal() { | |||
55 | break | 55 | break |
56 | } | 56 | } |
57 | 57 | ||
58 | // fmt.Printf("%v\n", cooked) | ||
59 | |||
58 | switch cooked.tag { | 60 | switch cooked.tag { |
59 | case NEWPID: | 61 | case NEWPID: |
60 | dealNewPid(cooked) | 62 | dealNewPid(cooked) |
61 | case EXECVE: | 63 | case EXECVE: |
64 | check(cooked) | ||
62 | dealExecve(cooked) | 65 | dealExecve(cooked) |
63 | case PIDEXIT: | 66 | case PIDEXIT: |
67 | check(cooked) | ||
64 | deletePid(cooked) | 68 | deletePid(cooked) |
65 | case FILEOPEN: | 69 | case FILEOPEN: |
70 | check(cooked) | ||
66 | fileOpen(cooked) | 71 | fileOpen(cooked) |
67 | case FILEWRITE: | 72 | case FILEWRITE: |
73 | check(cooked) | ||
68 | fileWrite(cooked) | 74 | fileWrite(cooked) |
69 | case FILECLOSE: | 75 | case FILECLOSE: |
76 | check(cooked) | ||
70 | fileClose(cooked) | 77 | fileClose(cooked) |
71 | } | 78 | } |
72 | } | 79 | } |
@@ -168,19 +175,19 @@ func dealExecve(cooked Event) { | |||
168 | }, | 175 | }, |
169 | }, | 176 | }, |
170 | }) | 177 | }) |
171 | } else { | 178 | // } else { |
172 | // 先fork抵达,插入 | 179 | // // 先fork抵达,插入 |
173 | pidCol.InsertOne(bson.M{ | 180 | // pidCol.InsertOne(bson.M{ |
174 | "ppid": cooked.ppid, | 181 | // "ppid": cooked.ppid, |
175 | "pid": cooked.pid, | 182 | // "pid": cooked.pid, |
176 | "children": []bson.M{}, | 183 | // "children": []bson.M{}, |
177 | "execve": []bson.M{ | 184 | // "execve": []bson.M{ |
178 | { | 185 | // { |
179 | "timestamp": cooked.timestamp, | 186 | // "timestamp": cooked.timestamp, |
180 | "execArgs": cooked.argv, | 187 | // "execArgs": cooked.argv, |
181 | }, | 188 | // }, |
182 | }, | 189 | // }, |
183 | }) | 190 | // }) |
184 | } | 191 | } |
185 | mongoMutex.Unlock() | 192 | mongoMutex.Unlock() |
186 | } | 193 | } |
@@ -255,3 +262,27 @@ func fileWrite(cooked Event) { | |||
255 | "close_timestamp": bson.M{"$exists": false}, | 262 | "close_timestamp": bson.M{"$exists": false}, |
256 | }, bson.M{"$push": bson.M{"written": cooked.timestamp}}) | 263 | }, bson.M{"$push": bson.M{"written": cooked.timestamp}}) |
257 | } | 264 | } |
265 | |||
266 | func check(cooked Event) { | ||
267 | // 检查进程是否需要记录 | ||
268 | // 有无父进程在观察中 | ||
269 | docRes, err = pidCol.Finddoc(bson.M{"pid": cooked.ppid}) | ||
270 | if err != nil || len(docRes) != 1 { | ||
271 | return | ||
272 | } | ||
273 | |||
274 | // 自身是否已经记录 | ||
275 | docRes, err = pidCol.Finddoc(bson.M{"pid": cooked.pid}) | ||
276 | if err != nil { | ||
277 | fmt.Printf("Err finding: %v\n", err) | ||
278 | return | ||
279 | } | ||
280 | if len(docRes) == 0 { | ||
281 | pidCol.InsertOne(bson.M{ | ||
282 | "ppid": cooked.ppid, | ||
283 | "pid": cooked.pid, | ||
284 | "children": []bson.M{}, | ||
285 | "start_timestamp": cooked.timestamp, | ||
286 | }) | ||
287 | } | ||
288 | } | ||
diff --git a/src/global.go b/src/global.go index d1c5c0f..f0f909c 100644 --- a/src/global.go +++ b/src/global.go | |||
@@ -1,8 +1,11 @@ | |||
1 | package main | 1 | package main |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "fmt" | ||
4 | "sync" | 5 | "sync" |
5 | "time" | 6 | "time" |
7 | |||
8 | "go.mongodb.org/mongo-driver/bson/primitive" | ||
6 | ) | 9 | ) |
7 | 10 | ||
8 | type eventType int | 11 | type eventType int |
@@ -12,11 +15,19 @@ const ( | |||
12 | PIDEXIT | 15 | PIDEXIT |
13 | EXECVE | 16 | EXECVE |
14 | FILEOPEN | 17 | FILEOPEN |
15 | FILEWRITE | ||
16 | FILECLOSE | 18 | FILECLOSE |
19 | FILEWRITE | ||
17 | TYPENUM | 20 | TYPENUM |
18 | ) | 21 | ) |
19 | 22 | ||
23 | func (et eventType) String() string { | ||
24 | names := []string{"NEWPID", "PIDEXIT", "EXECVE", "FILEOPEN", "FILECLOSE", "FILEWRITE", "TYPENUM"} | ||
25 | if et < NEWPID || et > TYPENUM { | ||
26 | return "Unknown" | ||
27 | } | ||
28 | return names[et] | ||
29 | } | ||
30 | |||
20 | type Event struct { | 31 | type Event struct { |
21 | tag eventType | 32 | tag eventType |
22 | timestamp time.Time | 33 | timestamp time.Time |
@@ -30,12 +41,37 @@ type Event struct { | |||
30 | pathName string | 41 | pathName string |
31 | } | 42 | } |
32 | 43 | ||
33 | func (et eventType) String() string { | 44 | func (event Event) String() string { |
34 | names := []string{"NEWPID", "PIDEXIT", "EXECVE", "FILEOPEN", "FILEWRITE", "TYPENUM"} | 45 | var res string |
35 | if et < NEWPID || et > TYPENUM { | 46 | res = fmt.Sprintf("tag: %v\ntimestamp: %v\nppid: %d\npid: %d\n", event.tag, event.timestamp.Local(), event.ppid, event.pid) |
36 | return "Unknown" | 47 | res += fmt.Sprintf("syscall: %s\nexit_code: %d\nargs: \n", syscallTable[event.syscall], event.exit_code) |
48 | for i := 0; i < len(event.argv); i++ { | ||
49 | res += fmt.Sprintf("\t\"%s\"\n", event.argv[i]) | ||
37 | } | 50 | } |
38 | return names[et] | 51 | res += "syscallParam: " |
52 | for i := 0; i < len(event.syscallParam); i++ { | ||
53 | res += fmt.Sprintf("\t\"%d\"\n", event.syscallParam[i]) | ||
54 | } | ||
55 | res += "pathName: \"" + event.pathName + "\"\n------\n" | ||
56 | return res | ||
57 | } | ||
58 | |||
59 | type pidExec struct { | ||
60 | timestamp time.Time `bson:"timestamp"` | ||
61 | execArgs []string `bson:"execArgs"` | ||
62 | } | ||
63 | |||
64 | type pid struct { | ||
65 | ID primitive.ObjectID `bson:"_id,ometempty"` | ||
66 | start_timestamp time.Time `bson:"start_timestamp"` | ||
67 | ppid int `bson:"ppid"` | ||
68 | pid int `bson:"pid"` | ||
69 | cwd string `bson:"cwd"` | ||
70 | args []string `bson:"args"` | ||
71 | execve []pidExec `bson:"execve"` | ||
72 | children []int `bson:"children"` | ||
73 | exit_timestamp time.Time `bson:"exit_timestamp"` | ||
74 | exit_code uint64 `bson:"exit_code"` | ||
39 | } | 75 | } |
40 | 76 | ||
41 | var wg sync.WaitGroup // 掌管协程 | 77 | var wg sync.WaitGroup // 掌管协程 |