-
Notifications
You must be signed in to change notification settings - Fork 49
/
set_target_pid.c
181 lines (137 loc) · 4.1 KB
/
set_target_pid.c
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/***********************************************************************************************************************
*
* set_target_pid
*
* 2014-10-09
*
* emptymonkey's tool for process pid alignment.
*
*
* Purpose:
* This tool will exhaust pids until the current pids being issued are at (or near) your target.
* This is very handy when combined with the mimic tool for covert execution, as it will bury the mimiced process
* in an otherwise unlooked range.
*
* Notes:
* The linux kernel reserves the first three-hundered pids for kernel threads. If you target below that,
* set_target_pid will get you as close as possible to the boundary.
*
**********************************************************************************************************************/
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
/*
* The strategy here is to have an original parent process that holds the foreground for the user.
* There will then be a loop parent, who is the child of the original parent. The loop parent is
* responsible for fork()ing children and tracking state. Those children immediately exit.
*
* Child death is fairly lightweight. Parent death is not. This is why we put the burden of death
* on the children and not the parents.
*
* Unfortunately, some systems seem to have a "maximum number of forks per process" of some
* sort. Because of this, the loop parent will only spawn off MAX_FORKS number of children before
* killing itself and letting the next child become the new loop parent (thus resetting the max
* forks possible).
*
* Until I find a way of determining this setting dynamically at runtime, it is for now a CPP #define.
*
*/
#define MAX_FORKS 1000
int sig_found;
void signal_handler(int signal){
sig_found = signal;
}
int main(int argc, char **argv){
char *short_name;
pid_t target, current, last;
int flag;
int count;
char pid_max_buffer[64];
int pid_max_fd;
pid_t pid_max;
pid_t original_parent;
struct sigaction act;
if((short_name = strrchr(argv[0], '/')) == NULL){
short_name = argv[0];
}else{
short_name++;
}
if(argc != 2){
fprintf(stderr, "\n%s usage: %s TARGET\n", short_name, argv[0]);
fprintf(stderr, "\tFork proceses until TARGET pid is reached. Happily loops through pid rollover.\n\n");
exit(-1);
}
memset(pid_max_buffer, 0, 64);
if((pid_max_fd = open("/proc/sys/kernel/pid_max", O_RDONLY)) == -1){
error(-1, errno, "open(\"/proc/sys/kernel/pid_max\")");
}
if(read(pid_max_fd, pid_max_buffer, sizeof(pid_max_buffer)) == -1){
error(-1, errno, "read(%d, %p, %d)", pid_max_fd, pid_max_buffer, (int) sizeof(pid_max_buffer));
}
close(pid_max_fd);
pid_max = (pid_t) strtol(pid_max_buffer, NULL, 10);
target = (pid_t) strtol(argv[1], NULL, 10);
// The target the user is asking for should be the next pid available for them. Let's decrement
// target now, so we don't step on it later.
target--;
if(target > pid_max){
error(-1, 0, "error: target is greater than pid_max! Quitting.");
}
sig_found = 0;
memset(&act, 0, sizeof(act));
act.sa_handler = signal_handler;
if(sigaction(SIGUSR1, &act, NULL) == -1){
error(-1, errno, "sigaction(%d, %p, NULL)", SIGUSR1, &act);
}
original_parent = getpid();
if((current = fork()) == -1){
error(-1, errno, "fork()");
}else if(current){
pause();
if(sig_found == SIGUSR1){
exit(0);
}else{
error(-1, errno, "pause()");
}
}
flag = 0;
last = 0;
current = getpid();
count = 0;
if(current < target){
flag = 1;
}
while((flag && (current < target)) || (!flag && (target < current))){
last = current;
if(count == MAX_FORKS){
if((current = fork()) == -1){
error(-1, errno, "fork()");
}else if(current){
exit(1);
}
count = 0;
current = getpid();
}else{
if(!(current = fork())){
exit(2);
}
}
if(current < last){
if(current == -1){
printf("error: last pid: %d\n", last);
exit(-1);
}
flag = 1;
}
count++;
}
kill(original_parent, SIGUSR1);
return(0);
}