1/* $OpenBSD: elf_hide.c,v 1.11 2017/10/29 08:45:53 mpi 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
33#include <elf.h>
34#include <err.h>
35#include <errno.h>
36#include <fcntl.h>
37#include <unistd.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include "mangle.h"
42
43extern	int elf_mangle;
44
45void	load_strtab(Elf_Ehdr * pehdr, char *pexe);
46void	dump_strtab(void);
47char	*get_str(int indx);
48
49void	load_symtab(Elf_Ehdr * pehdr, char *pexe);
50void	dump_symtab(Elf_Shdr * symsect, Elf_Sym * symtab, int symtabsize);
51void	fprint_str(FILE * channel, int indx);
52
53void	load_shstr_tab(Elf_Ehdr * pehdr, char *pexe);
54char	*get_shstr(int indx);
55void	fprint_shstr(FILE * channel, int indx);
56
57void	hide_sym(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
58	    Elf_Sym * symtab, int symtabsize, int symtabsecnum);
59void	reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
60	    Elf_Sym * symtab, int symtabsize, int symtabsecnum);
61typedef long    Symmap;
62void	renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap,
63	    int symtabsecnum);
64void	elf_hide(int pfile, char *p);
65
66
67char           *pexe;
68
69void
70elf_hide(int pfile, char *p)
71{
72	Elf_Ehdr       *pehdr;
73#ifdef DEBUG
74	Elf_Shdr       *pshdr;
75	Elf_Phdr       *pphdr;
76	int             i;
77#endif
78
79	pexe = p;
80	pehdr = (Elf_Ehdr *) pexe;
81
82#ifdef DEBUG
83	printf("elf header\n");
84	printf("e_type %x\n", pehdr->e_type);
85	printf("e_machine %x\n", pehdr->e_machine);
86	printf("e_version %x\n", pehdr->e_version);
87	printf("e_entry %x\n", pehdr->e_entry);
88	printf("e_phoff %x\n", pehdr->e_phoff);
89	printf("e_shoff %x\n", pehdr->e_shoff);
90	printf("e_flags %x\n", pehdr->e_flags);
91	printf("e_ehsize %x\n", pehdr->e_ehsize);
92	printf("e_phentsize %x\n", pehdr->e_phentsize);
93	printf("e_phnum %x\n", pehdr->e_phnum);
94	printf("e_shentsize %x\n", pehdr->e_shentsize);
95	printf("e_shnum %x\n", pehdr->e_shnum);
96	printf("e_shstrndx %x\n", pehdr->e_shstrndx);
97#endif
98
99	load_shstr_tab(pehdr, pexe);
100#ifdef DEBUG
101	for (i = 0; i < pehdr->e_shnum; i++) {
102		pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff +
103		    (i * pehdr->e_shentsize));
104
105		printf("section header %d\n", i);
106		printf("sh_name %x ", pshdr->sh_name);
107		fprint_shstr(stdout, pshdr->sh_name);
108		printf("\n");
109		printf("sh_type %x\n", pshdr->sh_type);
110		printf("sh_flags %x\n", pshdr->sh_flags);
111		printf("sh_addr %x\n", pshdr->sh_addr);
112		printf("sh_offset %x\n", pshdr->sh_offset);
113		printf("sh_size %x\n", pshdr->sh_size);
114		printf("sh_link %x\n", pshdr->sh_link);
115		printf("sh_info %x\n", pshdr->sh_info);
116		printf("sh_addralign %x\n", pshdr->sh_addralign);
117		printf("sh_entsize %x\n", pshdr->sh_entsize);
118	}
119#endif				/* DEBUG */
120
121#ifdef DEBUG
122	for (i = 0; i < pehdr->e_phnum; i++) {
123		pshdr = (Elf_Phdr *) (pexe + pehdr->e_phoff +
124		    (i * pehdr->e_phentsize));
125
126		printf("program header %d\n", i);
127		printf("p_type %x\n", pphdr->p_type);
128		printf("p_offset %x\n", pphdr->p_offset);
129		printf("p_vaddr %x\n", pphdr->p_vaddr);
130		printf("p_paddr %x\n", pphdr->p_paddr);
131		printf("p_filesz %x\n", pphdr->p_filesz);
132		printf("p_memsz %x\n", pphdr->p_memsz);
133		printf("p_flags %x\n", pphdr->p_flags);
134		printf("p_align %x\n", pphdr->p_align);
135	}
136#endif				/* DEBUG */
137#if 0
138	for (i = 0; i < pehdr->e_shnum; i++) {
139		pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff +
140		    (i * pehdr->e_shentsize));
141		if (strcmp(".strtab", get_shstr(pshdr->sh_name)) == 0)
142			break;
143	}
144	fprint_shstr(stdout, pshdr->sh_name);
145	printf("\n");
146#endif
147
148	load_strtab(pehdr, pexe);
149	load_symtab(pehdr, pexe);
150	close(pfile);
151}
152char           *shstrtab;
153
154void
155load_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
167void
168fprint_shstr(FILE * channel, int indx)
169{
170	if (shstrtab != NULL)
171		fprintf(channel, "\"%s\"", &(shstrtab[indx]));
172}
173
174char           *
175get_shstr(int indx)
176{
177	return &(shstrtab[indx]);
178}
179
180void
181load_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
217void
218dump_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
239char           *strtab;
240int             strtabsize;
241void
242load_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
270void
271dump_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
289void
290fprint_str(FILE * channel, int indx)
291{
292	if (strtab != NULL)
293		fprintf(channel, "\"%s\"", &(strtab[indx]));
294}
295
296char *
297get_str(int indx)
298{
299	return &(strtab[indx]);
300}
301
302int             in_keep_list(char *symbol);
303
304void
305hide_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				mangle_str(get_str(psymtab->st_name));
330			}
331#ifdef DEBUG
332			printf("st_info %x\n", psymtab->st_info);
333#endif
334		}
335	}
336	reorder_syms(ehdr, symsect, symtab, symtabsize, symtabsecnum);
337}
338
339void
340reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
341    Elf_Sym * symtab, int symtabsize, int symtabsecnum)
342{
343	int             i;
344	int             nsyms;
345	int             cursym;
346	Elf_Sym        *tmpsymtab;
347	Symmap         *symmap;
348
349
350	nsyms = symtabsize / sizeof(Elf_Sym);
351
352	tmpsymtab = calloc(1, symtabsize);
353	symmap = calloc(nsyms, sizeof(Symmap));
354	if (!tmpsymtab || !symmap)
355		errc(5, ENOMEM, "calloc");
356
357	bcopy(symtab, tmpsymtab, symtabsize);
358
359	cursym = 1;
360	for (i = 1; i < nsyms; i++) {
361		if ((tmpsymtab[i].st_info & 0xf0) == 0x00) {
362#ifdef DEBUG
363			printf("copying  l o%d n%d <%s>\n", i, cursym,
364			    get_str(tmpsymtab[i].st_name));
365#endif
366			bcopy(&(tmpsymtab[i]), &(symtab[cursym]),
367			    sizeof(Elf_Sym));
368			symmap[i] = cursym;
369			cursym++;
370		}
371	}
372	symsect->sh_info = cursym;
373	for (i = 1; i < nsyms; i++) {
374		if ((tmpsymtab[i].st_info & 0xf0) != 0x00) {
375#ifdef DEBUG
376			printf("copying nl o%d n%d <%s>\n", i, cursym,
377			    get_str(tmpsymtab[i].st_name));
378#endif
379			bcopy(&(tmpsymtab[i]), &(symtab[cursym]),
380			    sizeof(Elf_Sym));
381			symmap[i] = cursym;
382			cursym++;
383		}
384	}
385	if (cursym != nsyms) {
386		printf("miscounted symbols somewhere c %d n %d \n",
387		    cursym, nsyms);
388		exit(5);
389	}
390	renum_reloc_syms(ehdr, symmap, symtabsecnum);
391	free(tmpsymtab);
392	free(symmap);
393}
394
395void
396renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap, int symtabsecnum)
397{
398	Elf_Shdr       *pshdr;
399	int             i, j;
400	int             num_reloc;
401	Elf_Rel        *prel;
402	Elf_RelA       *prela;
403	int             symnum;
404
405	for (i = 0; i < ehdr->e_shnum; i++) {
406		pshdr = (Elf_Shdr *) (pexe + ehdr->e_shoff +
407		    (i * ehdr->e_shentsize));
408		if ((pshdr->sh_type == SHT_RELA) &&
409		    pshdr->sh_link == symtabsecnum) {
410
411#ifdef DEBUG
412			printf("section %d has rela relocations in symtab\n", i);
413#endif
414			prela = (Elf_RelA *) (pexe + pshdr->sh_offset);
415			num_reloc = pshdr->sh_size / sizeof(Elf_RelA);
416			for (j = 0; j < num_reloc; j++) {
417				symnum = ELF_R_SYM(prela[j].r_info);
418#ifdef DEBUG
419				printf("sym num o %d n %d\n", symnum,
420				    symmap[symnum]);
421#endif
422				prela[j].r_info = ELF_R_INFO(symmap[symnum],
423				    ELF_R_TYPE(prela[j].r_info));
424			}
425		}
426		if ((pshdr->sh_type == SHT_REL) &&
427		    pshdr->sh_link == symtabsecnum) {
428#ifdef DEBUG
429			printf("section %d has rel relocations in symtab\n", i);
430#endif
431			prel = (Elf_Rel *) (pexe + pshdr->sh_offset);
432			num_reloc = pshdr->sh_size / sizeof(Elf_Rel);
433			for (j = 0; j < num_reloc; j++) {
434				symnum = ELF_R_SYM(prel[j].r_info);
435#ifdef DEBUG
436				printf("sym num o %d n %d\n", symnum,
437				    symmap[symnum]);
438#endif
439				prel[j].r_info = ELF_R_INFO(symmap[symnum],
440				    ELF_R_TYPE(prel[j].r_info));
441			}
442		}
443	}
444
445}
446