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