xref: /openbsd-src/usr.sbin/crunchgen/elf_hide.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /* $OpenBSD: elf_hide.c,v 1.3 2008/11/24 17:23:26 drahn Exp $ */
2 
3 /*
4  * Copyright (c) 1997 Dale Rahn.
5  * All rights reserved.
6  *
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/types.h>
30 #include <sys/mman.h>
31 #include <sys/stat.h>
32 #include <err.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/exec.h>
40 #ifdef _NLIST_DO_ELF
41 #include <sys/exec_elf.h>
42 
43 extern	int elf_mangle;
44 
45 void	load_strtab(Elf_Ehdr * pehdr, char *pexe);
46 void	dump_strtab();
47 char	*get_str(int indx);
48 
49 void	load_symtab(Elf_Ehdr * pehdr, char *pexe);
50 void	dump_symtab();
51 
52 void	load_shstr_tab(Elf_Ehdr * pehdr, char *pexe);
53 char	*get_shstr(int indx);
54 void	fprint_shstr(FILE * channel, int indx);
55 
56 void	hide_sym();
57 void	reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
58 	    Elf_Sym * symtab, int symtabsize, int symtabsecnum);
59 typedef long    Symmap;
60 void	renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap,
61 	    int symtabsecnum);
62 
63 
64 char           *pexe;
65 
66 void
67 elf_hide(int pfile, char *p)
68 {
69 	Elf_Ehdr       *pehdr;
70 #ifdef DEBUG
71 	Elf_Shdr       *pshdr;
72 	Elf_Phdr       *pphdr;
73 	int             i;
74 #endif
75 	struct stat     sb;
76 
77 	pexe = p;
78 	pehdr = (Elf_Ehdr *) pexe;
79 
80 #ifdef DEBUG
81 	printf("elf header\n");
82 	printf("e_type %x\n", pehdr->e_type);
83 	printf("e_machine %x\n", pehdr->e_machine);
84 	printf("e_version %x\n", pehdr->e_version);
85 	printf("e_entry %x\n", pehdr->e_entry);
86 	printf("e_phoff %x\n", pehdr->e_phoff);
87 	printf("e_shoff %x\n", pehdr->e_shoff);
88 	printf("e_flags %x\n", pehdr->e_flags);
89 	printf("e_ehsize %x\n", pehdr->e_ehsize);
90 	printf("e_phentsize %x\n", pehdr->e_phentsize);
91 	printf("e_phnum %x\n", pehdr->e_phnum);
92 	printf("e_shentsize %x\n", pehdr->e_shentsize);
93 	printf("e_shnum %x\n", pehdr->e_shnum);
94 	printf("e_shstrndx %x\n", pehdr->e_shstrndx);
95 #endif
96 
97 	load_shstr_tab(pehdr, pexe);
98 #ifdef DEBUG
99 	for (i = 0; i < pehdr->e_shnum; i++) {
100 		pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff +
101 		    (i * pehdr->e_shentsize));
102 
103 		printf("section header %d\n", i);
104 		printf("sh_name %x ", pshdr->sh_name);
105 		fprint_shstr(stdout, pshdr->sh_name);
106 		printf("\n");
107 		printf("sh_type %x\n", pshdr->sh_type);
108 		printf("sh_flags %x\n", pshdr->sh_flags);
109 		printf("sh_addr %x\n", pshdr->sh_addr);
110 		printf("sh_offset %x\n", pshdr->sh_offset);
111 		printf("sh_size %x\n", pshdr->sh_size);
112 		printf("sh_link %x\n", pshdr->sh_link);
113 		printf("sh_info %x\n", pshdr->sh_info);
114 		printf("sh_addralign %x\n", pshdr->sh_addralign);
115 		printf("sh_entsize %x\n", pshdr->sh_entsize);
116 	}
117 #endif				/* DEBUG */
118 
119 #ifdef DEBUG
120 	for (i = 0; i < pehdr->e_phnum; i++) {
121 		pshdr = (Elf_Phdr *) (pexe + pehdr->e_phoff +
122 		    (i * pehdr->e_phentsize));
123 
124 		printf("program header %d\n", i);
125 		printf("p_type %x\n", pphdr->p_type);
126 		printf("p_offset %x\n", pphdr->p_offset);
127 		printf("p_vaddr %x\n", pphdr->p_vaddr);
128 		printf("p_paddr %x\n", pphdr->p_paddr);
129 		printf("p_filesz %x\n", pphdr->p_filesz);
130 		printf("p_memsz %x\n", pphdr->p_memsz);
131 		printf("p_flags %x\n", pphdr->p_flags);
132 		printf("p_align %x\n", pphdr->p_align);
133 	}
134 #endif				/* DEBUG */
135 #if 0
136 	for (i = 0; i < pehdr->e_shnum; i++) {
137 		pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff +
138 		    (i * pehdr->e_shentsize));
139 		if (strcmp(".strtab", get_shstr(pshdr->sh_name)) == 0)
140 			break;
141 	}
142 	fprint_shstr(stdout, pshdr->sh_name);
143 	printf("\n");
144 #endif
145 
146 	load_strtab(pehdr, pexe);
147 	load_symtab(pehdr, pexe);
148 
149 	munmap(pexe, sb.st_size);
150 	close(pfile);
151 }
152 char           *shstrtab;
153 
154 void
155 load_shstr_tab(Elf_Ehdr * pehdr, char *pexe)
156 {
157 	Elf_Shdr       *pshdr;
158 	shstrtab = NULL;
159 	if (pehdr->e_shstrndx == 0)
160 		return;
161 	pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
162 	    (pehdr->e_shstrndx * pehdr->e_shentsize));
163 
164 	shstrtab = (char *) (pexe + pshdr->sh_offset);
165 }
166 
167 void
168 fprint_shstr(FILE * channel, int indx)
169 {
170 	if (shstrtab != NULL)
171 		fprintf(channel, "\"%s\"", &(shstrtab[indx]));
172 }
173 
174 char           *
175 get_shstr(int indx)
176 {
177 	return &(shstrtab[indx]);
178 }
179 
180 void
181 load_symtab(Elf_Ehdr * pehdr, char *pexe)
182 {
183 	Elf_Sym        *symtab;
184 	Elf_Shdr       *symsect;
185 	int             symtabsize;
186 	Elf_Shdr       *psymshdr;
187 	Elf_Shdr       *pshdr;
188 #ifdef DEBUG
189 	char           *shname;
190 #endif
191 	int             i;
192 
193 	symtab = NULL;
194 	for (i = 0; i < pehdr->e_shnum; i++) {
195 		pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
196 		    (i * pehdr->e_shentsize));
197 		if (SHT_REL != pshdr->sh_type && SHT_RELA != pshdr->sh_type)
198 			continue;
199 		psymshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
200 		    (pshdr->sh_link * pehdr->e_shentsize));
201 #ifdef DEBUG
202 		fprint_shstr(stdout, pshdr->sh_name);
203 		printf("\n");
204 #endif
205 		symtab = (Elf_Sym *) (pexe + psymshdr->sh_offset);
206 		symsect = psymshdr;
207 		symtabsize = psymshdr->sh_size;
208 
209 #ifdef DEBUG
210 		dump_symtab(symsect, symtab, symtabsize);
211 #endif
212 		hide_sym(pehdr, symsect, symtab, symtabsize, pshdr->sh_link);
213 	}
214 
215 }
216 
217 void
218 dump_symtab(Elf_Shdr * symsect, Elf_Sym * symtab, int symtabsize)
219 {
220 	int             i;
221 	Elf_Sym        *psymtab;
222 
223 	for (i = 0; i < (symtabsize / sizeof(Elf_Sym)); i++) {
224 		psymtab = &(symtab[i]);
225 		if ((psymtab->st_info & 0xf0) == 0x10 &&
226 		    (psymtab->st_shndx != SHN_UNDEF)) {
227 			printf("symbol %d:\n", i);
228 			printf("st_name %x \"%s\"\n", psymtab->st_name,
229 			    get_str(psymtab->st_name));
230 			printf("st_value %llx\n", (unsigned long long)psymtab->st_value);
231 			printf("st_size %llx\n", (unsigned long long)psymtab->st_size);
232 			printf("st_info %x\n", psymtab->st_info);
233 			printf("st_other %x\n", psymtab->st_other);
234 			printf("st_shndx %x\n", psymtab->st_shndx);
235 		}
236 	}
237 }
238 
239 char           *strtab;
240 int             strtabsize;
241 void
242 load_strtab(Elf_Ehdr * pehdr, char *pexe)
243 {
244 	Elf_Shdr       *pshdr = NULL;
245 	char           *shname;
246 	int             i;
247 	strtab = NULL;
248 	for (i = 0; i < pehdr->e_shnum; i++) {
249 		pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
250 		    (i * pehdr->e_shentsize));
251 
252 		shname = get_shstr(pshdr->sh_name);
253 		if (strcmp(".strtab", shname) == 0)
254 			break;
255 	}
256 #ifdef DEBUG
257 	fprint_shstr(stdout, pshdr->sh_name);
258 	printf("\n");
259 #endif
260 
261 	strtab = (char *) (pexe + pshdr->sh_offset);
262 
263 	strtabsize = pshdr->sh_size;
264 
265 #ifdef DEBUG
266 	dump_strtab();
267 #endif
268 }
269 
270 void
271 dump_strtab()
272 {
273 	int             index;
274 	char           *pstr;
275 	char           *pnstr;
276 	int             i = 0;
277 	index = 0;
278 	pstr = strtab;
279 	while (index < strtabsize) {
280 		printf("string %x: \"%s\"\n", i, pstr);
281 		pnstr = pstr + strlen(pstr) + 1;
282 		index = pnstr - strtab;
283 		pstr = pnstr;
284 		i++;
285 	}
286 
287 }
288 
289 void
290 fprint_str(FILE * channel, int indx)
291 {
292 	if (strtab != NULL)
293 		fprintf(channel, "\"%s\"", &(strtab[indx]));
294 }
295 
296 char *
297 get_str(int indx)
298 {
299 	return &(strtab[indx]);
300 }
301 
302 int             in_keep_list(char *symbol);
303 
304 void
305 hide_sym(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
306     Elf_Sym * symtab, int symtabsize, int symtabsecnum)
307 {
308 	int             i;
309 	unsigned char   info;
310 	Elf_Sym        *psymtab;
311 
312 	for (i = 0; i < (symtabsize / sizeof(Elf_Sym)); i++) {
313 		psymtab = &(symtab[i]);
314 		if ((psymtab->st_info & 0xf0) == 0x10 &&
315 		    (psymtab->st_shndx != SHN_UNDEF)) {
316 			if (in_keep_list(get_str(psymtab->st_name)))
317 				continue;
318 #ifdef DEBUG
319 			printf("symbol %d:\n", i);
320 			printf("st_name %x \"%s\"\n", psymtab->st_name,
321 			    get_str(psymtab->st_name));
322 			printf("st_info %x\n", psymtab->st_info);
323 #endif
324 			if (!elf_mangle) {
325 				info = psymtab->st_info;
326 				info = info & 0xf;
327 				psymtab->st_info = info;
328 			} else {
329 				/*
330 				 * XXX This is a small ugly hack to be able to
331 				 * XXX use chrunchide with MIPS.
332 				 * XXX Because MIPS needs global symbols to stay
333 				 * XXX global (has to do with GOT), we mess
334 				 * XXX around with the symbol names instead.
335 				 * XXX For most uses this will be no problem,
336 				 * XXX symbols are stripped anyway.
337 				 * XXX However, if many one character
338 				 * XXX symbols exist, names may clash.
339 				 */
340 				char *p;
341 				u_int32_t n, z;
342 				u_int32_t f;
343 				f = arc4random();
344 
345 				z = f++;
346 				p = get_str(psymtab->st_name);
347 				n = strlen(p);
348 				if (n > 4)
349 					n = 4;
350 				while (n--) {
351 					p[n] = z;
352 					z >>= 8;
353 					while (p[n] == 0)
354 						p[n] += arc4random();
355 				}
356 			}
357 #ifdef DEBUG
358 			printf("st_info %x\n", psymtab->st_info);
359 #endif
360 		}
361 	}
362 	reorder_syms(ehdr, symsect, symtab, symtabsize, symtabsecnum);
363 }
364 
365 void
366 reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
367     Elf_Sym * symtab, int symtabsize, int symtabsecnum)
368 {
369 	int             i;
370 	int             nsyms;
371 	int             cursym;
372 	Elf_Sym        *tmpsymtab;
373 	Symmap         *symmap;
374 
375 
376 	nsyms = symtabsize / sizeof(Elf_Sym);
377 
378 	tmpsymtab = (Elf_Sym *) calloc(1, symtabsize);
379 	symmap = (Symmap *) calloc(nsyms, sizeof(Symmap));
380 	if (!tmpsymtab || !symmap)
381 		errx(5, "calloc: %s", strerror(ENOMEM));
382 
383 	bcopy(symtab, tmpsymtab, symtabsize);
384 
385 	cursym = 1;
386 	for (i = 1; i < nsyms; i++) {
387 		if ((tmpsymtab[i].st_info & 0xf0) == 0x00) {
388 #ifdef DEBUG
389 			printf("copying  l o%d n%d <%s>\n", i, cursym,
390 			    get_str(tmpsymtab[i].st_name));
391 #endif
392 			bcopy(&(tmpsymtab[i]), &(symtab[cursym]),
393 			    sizeof(Elf_Sym));
394 			symmap[i] = cursym;
395 			cursym++;
396 		}
397 	}
398 	symsect->sh_info = cursym;
399 	for (i = 1; i < nsyms; i++) {
400 		if ((tmpsymtab[i].st_info & 0xf0) != 0x00) {
401 #ifdef DEBUG
402 			printf("copying nl o%d n%d <%s>\n", i, cursym,
403 			    get_str(tmpsymtab[i].st_name));
404 #endif
405 			bcopy(&(tmpsymtab[i]), &(symtab[cursym]),
406 			    sizeof(Elf_Sym));
407 			symmap[i] = cursym;
408 			cursym++;
409 		}
410 	}
411 	if (cursym != nsyms) {
412 		printf("miscounted symbols somewhere c %d n %d \n",
413 		    cursym, nsyms);
414 		exit(5);
415 	}
416 	renum_reloc_syms(ehdr, symmap, symtabsecnum);
417 	free(tmpsymtab);
418 	free(symmap);
419 }
420 
421 void
422 renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap, int symtabsecnum)
423 {
424 	Elf_Shdr       *pshdr;
425 	int             i, j;
426 	int             num_reloc;
427 	Elf_Rel        *prel;
428 	Elf_RelA       *prela;
429 	int             symnum;
430 
431 	for (i = 0; i < ehdr->e_shnum; i++) {
432 		pshdr = (Elf_Shdr *) (pexe + ehdr->e_shoff +
433 		    (i * ehdr->e_shentsize));
434 		if ((pshdr->sh_type == SHT_RELA) &&
435 		    pshdr->sh_link == symtabsecnum) {
436 
437 #ifdef DEBUG
438 			printf("section %d has rela relocations in symtab\n", i);
439 #endif
440 			prela = (Elf_RelA *) (pexe + pshdr->sh_offset);
441 			num_reloc = pshdr->sh_size / sizeof(Elf_RelA);
442 			for (j = 0; j < num_reloc; j++) {
443 				symnum = ELF_R_SYM(prela[j].r_info);
444 #ifdef DEBUG
445 				printf("sym num o %d n %d\n", symnum,
446 				    symmap[symnum]);
447 #endif
448 				prela[j].r_info = ELF_R_INFO(symmap[symnum],
449 				    ELF_R_TYPE(prela[j].r_info));
450 			}
451 		}
452 		if ((pshdr->sh_type == SHT_REL) &&
453 		    pshdr->sh_link == symtabsecnum) {
454 #ifdef DEBUG
455 			printf("section %d has rel relocations in symtab\n", i);
456 #endif
457 			prel = (Elf_Rel *) (pexe + pshdr->sh_offset);
458 			num_reloc = pshdr->sh_size / sizeof(Elf_Rel);
459 			for (j = 0; j < num_reloc; j++) {
460 				symnum = ELF_R_SYM(prel[j].r_info);
461 #ifdef DEBUG
462 				printf("sym num o %d n %d\n", symnum,
463 				    symmap[symnum]);
464 #endif
465 				prel[j].r_info = ELF_R_INFO(symmap[symnum],
466 				    ELF_R_TYPE(prel[j].r_info));
467 			}
468 		}
469 	}
470 
471 }
472 #endif				/* _NLIST_DO_ELF */
473