Skip to content

Instantly share code, notes, and snippets.

@maxdeliso
Created November 28, 2011 22:46
Show Gist options
  • Save maxdeliso/1402444 to your computer and use it in GitHub Desktop.
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
/*
* Max DeLiso <maxdeliso@gmail.com>
* 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");
}
}
# Max DeLiso <maxdeliso@gmail.com>
# 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