Created
November 28, 2011 22:46
-
-
Save maxdeliso/1402444 to your computer and use it in GitHub Desktop.
Hydra - spawns a very annoying set of processes that can't be defeated without specialized tools
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Max DeLiso <[email protected]> | |
* Hydra.c | |
*/ | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <signal.h> | |
#include <fcntl.h> | |
#include <errno.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <sys/wait.h> | |
#include <sys/ipc.h> | |
#include <sys/shm.h> | |
#include <sys/sem.h> | |
#include <sys/prctl.h> | |
typedef unsigned char bool; | |
const bool false = 0; | |
const bool true = 1; | |
union semun { | |
int val; | |
struct semid_ds *buf; | |
ushort *array; | |
}; | |
int handleCmdLine(int argc, char **argv); | |
void installSignalHandlers(); | |
void *setupShmem(int childCount); | |
int setupSem(); | |
void autoReap(int sigNum); | |
void childProcedure(int n, int count, void *shmAddr, int semId); | |
bool semaphoreP(int semId); | |
void semaphoreV(int semId); | |
int main(int argc, char **argv) | |
{ | |
int i; | |
int childCount; | |
int semId; | |
int returnCode; | |
void *shmAddr; | |
/* parse command line */ | |
childCount = handleCmdLine(argc, argv); | |
/* setup signal handlers - this wil persist after fork */ | |
installSignalHandlers(); | |
/* acquire shared memory - this will be shared by all of the children */ | |
shmAddr = setupShmem(childCount); | |
semId = setupSem(); | |
/* main forking loop */ | |
for (i = 0; i < childCount; i++) { | |
switch (returnCode = fork()) { | |
case 0: | |
childProcedure(i, childCount, shmAddr, semId); | |
exit(EXIT_SUCCESS); | |
break; | |
case -1: | |
perror("fork()"); | |
exit(EXIT_FAILURE); | |
break; | |
default: | |
((int *)shmAddr)[i] = returnCode; | |
break; | |
} | |
} | |
/*detach shmem */ | |
if (shmdt(shmAddr) == -1) { | |
perror("shmdt()"); | |
exit(1); | |
} | |
return (EXIT_SUCCESS); | |
} | |
int handleCmdLine(int argc, char **argv) | |
{ | |
int opt; | |
int childCount = -1; | |
while ((opt = getopt(argc, argv, "hvn:")) != -1) { | |
switch (opt) { | |
default: | |
case 'h': | |
printf("%s [-n count] [-h] [-v]\n", argv[0]); | |
exit(0); | |
case 'v': | |
printf("%s: version 1.0\n", argv[0]); | |
exit(0); | |
case 'n': | |
childCount = atoi(optarg); | |
break; | |
} | |
} | |
if (childCount == -1) { | |
fprintf(stderr, | |
"Fatal: you must specify a number of processes with -n\n"); | |
exit(1); | |
} | |
if (childCount <= 0) { | |
fprintf(stderr, "Fatal: n out of range\n"); | |
exit(1); | |
} | |
return childCount; | |
} | |
void installSignalHandlers() | |
{ | |
struct sigaction childAction; | |
const static int sigIgnList[] = { | |
SIGHUP, | |
SIGINT, | |
SIGQUIT, | |
SIGPIPE, | |
SIGALRM, | |
SIGTERM, | |
SIGUSR1, | |
SIGUSR2, | |
SIGTSTP, | |
SIGTTIN, | |
SIGTTOU, | |
SIGTRAP, | |
SIGILL | |
}; | |
int sigIgnListCount = sizeof(sigIgnList) / sizeof(sigIgnList[0]); | |
int i; | |
/* install autoreap signal handler */ | |
childAction.sa_handler = autoReap; | |
sigemptyset(&childAction.sa_mask); | |
childAction.sa_flags = 0; | |
if (sigaction(SIGCHLD, &childAction, NULL) == -1) { | |
perror("child: sigaction()"); | |
exit(1); | |
} | |
/* ignore signals that can be ignored */ | |
for (i = 0; i < sigIgnListCount; i++) { | |
if (signal(sigIgnList[i], SIG_IGN)) { | |
perror("child: signal()"); | |
exit(1); | |
} | |
} | |
} | |
void *setupShmem(int childCount) | |
{ | |
int shmId; | |
int i; | |
void *shmAddr; | |
/* allocate shared memory */ | |
shmId = shmget(IPC_PRIVATE, childCount * sizeof(int), S_IRWXU); | |
if (shmId == -1) { | |
perror("shmget()"); | |
exit(1); | |
} | |
/* attach to current process */ | |
shmAddr = shmat(shmId, NULL, O_RDWR); | |
if (shmAddr == (const void *)-1) { | |
perror("shmat()"); | |
exit(1); | |
} | |
/* initialize to -1 (invalid) */ | |
for (i = 0; i < childCount; i++) { | |
((int *)shmAddr)[i] = -1; | |
} | |
return shmAddr; | |
} | |
int setupSem() | |
{ | |
int semId; | |
union semun semArg; | |
/* create semaphore */ | |
semId = semget(IPC_PRIVATE, 1, S_IRWXU); | |
if (semId == -1) { | |
perror("semget()"); | |
exit(1); | |
} | |
/* initialize to 1 */ | |
semArg.val = 1; | |
if (semctl(semId, 0, SETVAL, semArg) < 0) { | |
perror("semctl()"); | |
exit(1); | |
} | |
return semId; | |
} | |
void autoReap(int sigNum) | |
{ | |
int status; | |
int pid; | |
pid = wait(&status); | |
} | |
void childProcedure(int n, int count, void *shmAddr, int semId) | |
{ | |
int i; | |
int ret; | |
char nameBuf[32]; | |
char numBuf[32]; | |
/* generate unqiue process name */ | |
strcpy(nameBuf, "hydra-"); | |
sprintf(numBuf, "%i", n); | |
strcat(nameBuf, numBuf); | |
/* set it */ | |
if (prctl(PR_SET_NAME, nameBuf)) { | |
perror("prctl(): could not set process name"); | |
exit(1); | |
} | |
/* iterate infinitely through the shared memory, pinging each peer */ | |
for (;;) | |
/* for each of the children */ | |
for (i = 0; i < count; i++) { | |
/* if the current child in shmem is not this one */ | |
if (((int *)shmAddr)[i] != -1 && getpid() != ((int *)shmAddr)[i]) { | |
/* send a signal to see if it is still living */ | |
ret = kill((pid_t) ((int *)shmAddr)[i], 0); | |
/* if it isn't... */ | |
if (ret == -1 && errno == ESRCH) { | |
/* acquire the spawn mutex */ | |
if (semaphoreP(semId)) { | |
/* fork a new process */ | |
switch (ret = fork()) { | |
case -1: | |
perror("child: fork()"); | |
exit(1); | |
case 0: | |
/* and call this function with it */ | |
((int *)shmAddr)[i] = -1; | |
childProcedure(i, count, shmAddr, semId); | |
default: | |
/* while storing it's pid in the shared memory */ | |
((int *)shmAddr)[i] = ret; | |
break; | |
} | |
/* and release the spawn mutex */ | |
semaphoreV(semId); | |
} | |
} | |
} | |
} | |
} | |
bool semaphoreP(int semId) | |
{ | |
struct sembuf semOps[1]; | |
int retCode; | |
bool result; | |
semOps[0].sem_num = 0; | |
semOps[0].sem_op = -1; | |
semOps[0].sem_flg = SEM_UNDO | IPC_NOWAIT; | |
retCode = semop(semId, semOps, 1); | |
if (retCode == 0) { | |
result = true; | |
} else if (retCode == -1 && errno == EAGAIN) { | |
result = false; | |
} else { | |
perror("child: semop() P"); | |
exit(1); | |
} | |
return result; | |
} | |
void semaphoreV(int semId) | |
{ | |
struct sembuf semOps[1]; | |
int retCode; | |
semOps[0].sem_num = 0; | |
semOps[0].sem_op = 1; | |
semOps[0].sem_flg = SEM_UNDO; | |
retCode = semop(semId, semOps, 1); | |
if (retCode == -1) { | |
perror("child: semop() V"); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Max DeLiso <[email protected]> | |
# Hydra makefile | |
hydra: | |
gcc -O2 hydra.c -o hydra | |
clean: | |
rm -f hydra |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment