1 /*
2 http://sourceforge.net/projects/unhide/
3 */
4
5 /*
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 // Needed for unistd.h to declare getpgid() and others
21 #define _XOPEN_SOURCE 500
22
23 // Needed for sched.h to declare sched_getaffinity()
24 #define _GNU_SOURCE
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <wait.h>
31 #include <sys/resource.h>
32 #include <errno.h>
33 #include <dirent.h>
34 #include <sched.h>
35 #include <sys/types.h>
36 #include <signal.h>
37 #include <stdlib.h>
38 #include <sys/sysinfo.h>
39 #include <fcntl.h>
40 #include <pthread.h>
41 #include <sys/syscall.h>
42 #include <ctype.h>
43 #include <time.h>
44
45 #include "unhide-output.h"
46 #include "unhide-linux.h"
47
48
49 /*
50 * Check all the PID stat() see in /proc.
51 */
checkproc(void)52 void checkproc(void)
53 {
54
55 int procpids ;
56 int statusprocbefore, statusprocafter;
57 struct stat buffer;
58 char directory[100] ;
59
60 msgln(unlog, 0, "[*]Searching for Hidden processes through /proc stat scanning\n") ;
61
62 sprintf(directory,"/proc/");
63
64 for ( procpids = 1; procpids <= maxpid; procpids = procpids +1 )
65 {
66 // avoid ourselves
67 if (procpids == mypid)
68 {
69 continue;
70 }
71 sprintf(&directory[6],"%d",procpids);
72
73 statusprocbefore = stat(directory, &buffer) ;
74 if (statusprocbefore != 0)
75 {
76 continue;
77 }
78
79 if(checkps(procpids,PS_PROC | PS_THREAD))
80 {
81 continue;
82 }
83
84 statusprocafter = stat(directory, &buffer) ;
85 if (statusprocafter != 0)
86 {
87 continue;
88 }
89
90 printbadpid(procpids);
91 }
92 }
93
94 /*
95 * Check all the pid that chdir() see in /proc.
96 */
checkchdir(void)97 void checkchdir(void)
98 {
99
100 int procpids ;
101 int statusdir, backtodir;
102 char curdir[PATH_MAX], *pathpt ;
103 char directory[100] ;
104 // char scratch[PATH_MAX] ; // DEBUG
105 // int count = 0; //DEBUG
106
107 msgln(unlog, 0, "[*]Searching for Hidden processes through /proc chdir scanning\n") ;
108
109 // get the path where Unhide is ran from.
110 if (NULL == (pathpt = getcwd(curdir, PATH_MAX)))
111 {
112 warnln(verbose, unlog, "Can't get current directory, test aborted") ;
113 return;
114 }
115
116 sprintf(directory,"/proc/");
117
118 for ( procpids = 1; procpids <= maxpid; procpids = procpids +1 )
119 {
120 // avoid ourselves
121 if (procpids == mypid)
122 {
123 continue;
124 }
125
126 sprintf(&directory[6],"%d",procpids);
127 statusdir = chdir(directory) ;
128 // the directory doesn't exist continue with the next one
129 if (statusdir != 0)
130 {
131 continue;
132 }
133 if (morecheck == TRUE)
134 {
135 // find process group ID (the master thread) by reading the status file of the current dir
136 FILE* fich_tmp ;
137 int found_tgid = FALSE;
138 char line[128] ;
139 char* tmp_pids = line;
140 char* end_pid;
141 char new_directory[100];
142
143 // printf("directory = '%s'\n", directory); // DEBUG
144 // getcwd(scratch, PATH_MAX); // DEBUG
145 // printf("CWD = '%s'\n", scratch); // DEBUG
146
147 // we are in the /proc/pid directory
148 fich_tmp=fopen("status", "r") ;
149 if (NULL == fich_tmp)
150 {
151 warnln(verbose, unlog, "can't open status file for process: %d", procpids) ;
152 continue ; // next process
153 }
154 while ((FALSE == found_tgid) && (NULL != fgets (line, 128, fich_tmp)))
155 {
156 line[127] = 0;
157 if (0 == strncmp (line, "Tgid:", 5))
158 {
159 found_tgid = TRUE;
160 }
161 }
162 fclose(fich_tmp);
163
164 if (TRUE == found_tgid)
165 {
166 tmp_pids = line + 5;
167 while( ((*tmp_pids == ' ') || (*tmp_pids == '\t')) && (tmp_pids <= line+127))
168 {
169 tmp_pids++;
170 }
171 // printf("tmp_pids2 = '%s'\n", tmp_pids); // DEBUG
172 end_pid = tmp_pids;
173 while( isdigit(*end_pid) && end_pid <= line+127)
174 {
175 end_pid++;
176 }
177 *end_pid = 0; // remove \n
178 // if the number of threads is < to about 40 % of the number of processes,
179 // the next "optimising" test actually produce a slower executable.
180 // if(procpids != atoi(tmp_pids))
181 { // if the thread isn't the master thread (process)
182 // count++; // DEBUG
183 sprintf(new_directory,"/proc/%s/task/%d", tmp_pids, procpids) ;
184 // printf("new_dir = %s\n", new_directory); // DEBUG
185 statusdir = chdir(new_directory) ;
186 if (statusdir != 0)
187 {
188 // the thread is not listed in the master thread task directory
189 errno = 0 ;
190 warnln(1, unlog, "Thread %d said it's in group %s but isn't listed in %s", procpids, tmp_pids, new_directory) ;
191 }
192 }
193 }
194 else
195 {
196 errno = 0 ;
197 warnln(1, unlog, "Can't find TGID in status file for process: %d", procpids) ;
198 }
199 }
200
201 // unlock the proc directory so it can disappear if it's a transitory process
202 if (-1 == (backtodir = chdir(curdir)))
203 {
204 warnln(verbose, unlog, "Can't go back to unhide directory, test aborted") ;
205 return;
206 }
207
208 if(checkps(procpids, PS_PROC | PS_THREAD))
209 {
210 continue;
211 }
212
213 // Avoid false positive on short life process/thread
214 statusdir = chdir(directory) ;
215 if (statusdir != 0)
216 {
217 continue;
218 }
219
220 printbadpid(procpids);
221 }
222 // go back to our path
223 if (-1 == (backtodir = chdir(curdir)))
224 {
225 warnln(verbose, unlog, "Can't go back to unhide directory, test aborted") ;
226 return;
227 }
228 // printf("Passages = %d\n", count); // DEBUG
229 }
230
231 /*
232 * Check all the pid that opendir() see in /proc.
233 */
checkopendir(void)234 void checkopendir(void)
235 {
236
237 int procpids ;
238 DIR *statusdir;
239 // char curdir[PATH_MAX] ;
240 char directory[100] ;
241 // char scratch[PATH_MAX] ; // DEBUG
242 // int count = 0; //DEBUG
243
244 msgln(unlog, 0, "[*]Searching for Hidden processes through /proc opendir scanning\n") ;
245
246 sprintf(directory,"/proc/");
247
248 for ( procpids = 1; procpids <= maxpid; procpids = procpids +1 )
249 {
250 // avoid ourselves
251 if (procpids == mypid)
252 {
253 continue;
254 }
255
256 sprintf(&directory[6],"%d",procpids);
257 statusdir = opendir(directory) ;
258 // the directory doesn't exist continue with the next one
259 if (statusdir == NULL)
260 continue;
261
262 if (morecheck == TRUE)
263 {
264 // find process group ID (the master thread) by reading the status file of the current dir
265 FILE* fich_tmp ;
266 int found_tgid = FALSE;
267 char line[128] ;
268 char* tmp_pids = line;
269 char* end_pid;
270 char new_directory[100] ;
271 DIR* statdir;
272
273 // printf("directory = '%s'\n", directory); // DEBUG
274 // getcwd(scratch, PATH_MAX); // DEBUG
275 // printf("CWD = '%s'\n", scratch); // DEBUG
276
277 snprintf(line, 128, "%s/status", directory);
278 // printf("STATUS_FILE : %s\n", line);
279 fich_tmp=fopen(line, "r") ;
280 if (NULL == fich_tmp)
281 {
282 msgln(unlog, 0, "Can't open status file for process: %d", procpids) ;
283 continue ; // next process
284 }
285 while ((FALSE == found_tgid) && (NULL != fgets (line, 128, fich_tmp)))
286 {
287 line[127] = 0;
288 if (0 == strncmp (line, "Tgid:", 5))
289 {
290 found_tgid = TRUE;
291 }
292 }
293 fclose(fich_tmp);
294
295 if (TRUE == found_tgid)
296 {
297 tmp_pids = line + 5;
298 while( ((*tmp_pids == ' ') || (*tmp_pids == '\t')) && (tmp_pids <= line+127))
299 {
300 tmp_pids++;
301 }
302 // printf("tmp_pids2 = '%s'\n", tmp_pids); // DEBUG
303 end_pid = tmp_pids;
304 while( isdigit(*end_pid) && end_pid <= line+127)
305 {
306 end_pid++;
307 }
308 *end_pid = 0; // remove \n
309 // if the number of threads is < to about 40 % of the number of processes,
310 // the next "optimising" test actually produce a slower executable.
311 // if(procpids != atoi(tmp_pids))
312 { // if the thread isn't the master thread (process)
313 // count++; // DEBUG
314 sprintf(new_directory,"/proc/%s/task/%d", tmp_pids, procpids) ;
315 // printf("new_dir = %s\n", new_directory); // DEBUG
316 // errno = 0;
317 statdir = opendir(new_directory) ;
318 if (NULL == statdir)
319 {
320 // the thread is not listed in the master thread task directory
321 // printf("opendir failed : %s)\n", strerror(errno)) ;
322 errno = 0 ;
323 warnln(1, unlog, "Thread %d said it's in group %s but isn't listed in %s", procpids, tmp_pids, new_directory) ;
324 }
325 else
326 {
327 closedir(statdir);
328 }
329 }
330 }
331 else
332 {
333 errno = 0 ;
334 warnln(1, unlog, "Can't find TGID in status file for process: %d", procpids) ;
335 }
336 }
337
338 // unlock the proc directory so it can disappear if it's a transitory process
339 closedir(statusdir);
340
341 if(checkps(procpids, PS_PROC | PS_THREAD)) {
342 continue;
343 }
344
345 // Avoid false positive on short life process/thread
346 statusdir = opendir(directory) ;
347 if (statusdir == NULL) {
348 continue;
349 }
350 // unlock dir & free descriptor
351 closedir(statusdir);
352
353 printbadpid(procpids);
354 }
355 // printf("Passages = %d\n", count); // DEBUG
356 }
357
358 /*
359 * Check all the pid that readdir() see in all /proc/pid/task.
360 */
checkreaddir(void)361 void checkreaddir(void)
362 {
363
364 int procpids ;
365 DIR *procdir, *taskdir;
366 struct dirent *dir, *dirproc;
367 char task[100] ;
368
369 msgln(unlog, 0, "[*]Searching for Hidden thread through /proc/pid/task readdir scanning\n") ;
370
371 procdir = opendir("/proc");
372 if (NULL == procdir)
373 {
374 warnln(verbose, unlog, "Cannot open /proc directory ! Exiting test.") ;
375 return ;
376 }
377
378 sprintf(task, "/proc/") ;
379
380 while ((dirproc = readdir(procdir)))
381 {
382 // As of Linux kernel 2.6 :
383 // readdir directly in /proc only see process, not thread
384 // because procfs voluntary hides threads to readdir
385 char *directory ;
386
387 directory = dirproc->d_name;
388 if(!isdigit(*directory))
389 {
390 // not a process directory of /proc
391 continue;
392 }
393 // sprintf(currentproc, "%d", directory);
394
395 sprintf(&task[6], "%s/task", directory) ;
396 // printf("task : %s", task) ; // DEBUG
397 taskdir = opendir(task);
398 if (NULL == taskdir)
399 {
400 warnln(verbose, unlog, "Cannot open %s directory ! ! Skipping process %s.", task, directory) ;
401 continue ;
402 }
403
404 while ((dir = readdir(taskdir)))
405 {
406 char *tmp_d_name ;
407 tmp_d_name = dir->d_name;
408 // printf(" thread : %s\n",tmp_d_name) ; // DEBUG
409 if (!strcmp(tmp_d_name, ".") || !strcmp(tmp_d_name, "..")) // skip parent and current dir
410 continue;
411 if(!isdigit(*tmp_d_name))
412 {
413 errno = 0 ;
414 warnln(verbose, unlog, "Not a thread ID (%s) in %s.", tmp_d_name, task) ;
415 continue;
416 }
417 else if (0 != strcmp(tmp_d_name, directory)) { // thread ID is not the process ID
418 // printf("thread : %s\n",tmp_d_name) ; // DEBUG
419 procpids = atoi(tmp_d_name) ;
420 if(checkps(procpids,PS_THREAD)) {
421 continue;
422 }
423 printbadpid(atoi(tmp_d_name));
424 }
425 else {
426 // printf("process : %s\n",tmp_d_name) ; // DEBUG
427 procpids = atoi(tmp_d_name) ;
428 if(checkps(procpids,PS_PROC)) {
429 continue;
430 }
431 printbadpid(atoi(tmp_d_name));
432 }
433 }
434 closedir(taskdir);
435 }
436 closedir(procdir) ;
437 }
438
439