View difference between Paste ID: VThWZYeW and ccbk3bzZ
SHOW: | | - or go back to the newest paste.
1
/* load shared from memory, sort of (x) 2021 by [email protected] / https://twitter.com/vx_herm1t */
2
#include <stdio.h>
3
#include <stdint.h>
4
#include <stdlib.h>
5
#include <string.h>
6
#include <sys/mman.h>
7
#include <unistd.h>
8
#include <elf.h>
9
#include <assert.h>
10
#include <link.h>
11
#include <fcntl.h>
12
13
static int load(unsigned char *lib, int size)
14
{
15
	uint8_t *map;
16
	Elf64_Ehdr *ehdr = (Elf64_Ehdr*)lib;
17
	Elf64_Phdr *phdr = (Elf64_Phdr*)(lib + ehdr->e_phoff);
18
	Elf64_Addr lo = ~0, hi = 0, t;
19
	int i;
20
	struct elf {
21
		int relent, relpltsz, symcnt, relasz, gnuhash;
22
		char *dynstr;
23
		Elf64_Sym * dynsym;
24
		void *relplt, *rela;
25
		void *delta;
26
		void (*init)(void);
27
		uint32_t *hash;
28
	} lm, lc;
29
	bzero(&lm, sizeof(lm));
30
	bzero(&lc, sizeof(lc));
31
32
	/* get ELF size */
33
	for (i = 0; i < ehdr->e_phnum; i++)
34
		if (phdr[i].p_type == PT_LOAD) {
35
			if (phdr[i].p_vaddr < lo)
36
				lo = phdr[i].p_vaddr;
37
			t = phdr[i].p_vaddr + phdr[i].p_memsz;
38
			if (t > hi)
39
				hi = t;
40
		}
41
42
	/* allocate memory */
43
	map = mmap(NULL, hi - lo, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
44
	if (map == MAP_FAILED) {
45
		printf("failed to allocate memory\n");
46
		return 2;
47
	}
48
49
	/* copy segments and find DYNAMIC */
50
	Elf64_Dyn *dyn = NULL;
51
	int f2p(int f) {
52
		int p = PROT_READ;
53
		if (f & PF_X)
54
			p |= PROT_EXEC;
55
		if (f & PF_W)
56
			p |= PROT_WRITE;
57
		return p;
58
	}
59
	for (i = 0; i < ehdr->e_phnum; i++) {
60
		if (phdr[i].p_type == PT_LOAD) {
61
			if (phdr[i].p_offset == 0)
62
				lm.delta = map - lo;
63
			Elf64_Addr off = phdr[i].p_vaddr & 4095ULL;
64
			void *seg = phdr[i].p_vaddr - off + lm.delta;
65
			memcpy(seg + off, lib + phdr[i].p_offset, phdr[i].p_filesz);
66
			mprotect(seg, phdr[i].p_memsz + off, f2p(phdr[i].p_flags));
67
		}
68
		if (phdr[i].p_type == PT_DYNAMIC)
69
			dyn = (Elf64_Dyn*)(lm.delta + phdr[i].p_vaddr);
70
	}
71
	assert(dyn != NULL);
72
73
	/* get init(), relocations and symbols */
74
	void parse_dyn(Elf64_Dyn *dyn, struct elf *elf) {
75
#define	GET_PTR(tag, var)	if (dyn->d_tag == tag) elf->var = (void*)(dyn->d_un.d_val + elf->delta);
76
#define	GET_VAL(tag, var)	if (dyn->d_tag == tag) elf->var = dyn->d_un.d_val;
77
		for ( ; dyn->d_tag != DT_NULL; dyn++) {
78
			GET_PTR(DT_INIT, init)
79
			GET_PTR(DT_JMPREL, relplt)
80
			GET_VAL(DT_RELENT, relent)
81
			GET_VAL(DT_RELAENT, relent)
82
			GET_VAL(DT_PLTRELSZ, relpltsz)
83
			GET_PTR(DT_REL, rela)
84
			GET_PTR(DT_RELA, rela)
85
			GET_VAL(DT_RELSZ, relasz)
86
			GET_VAL(DT_RELASZ, relasz)
87
			GET_PTR(DT_SYMTAB, dynsym)
88
			GET_PTR(DT_STRTAB, dynstr)
89
			GET_PTR(DT_HASH, hash)
90
			GET_PTR(DT_GNU_HASH, hash)
91
			if (dyn->d_tag == DT_GNU_HASH)
92
				elf->gnuhash = 1;
93
		}
94
		/* get symbol count */
95
		uint32_t *hash = elf->hash;
96
		if (elf->gnuhash) {
97
			int i;
98
			uint32_t nbucket = hash[0];
99
			uint32_t base = hash[1];
100
			uint32_t bloom_size = hash[2];
101
			uint64_t *bloom = (void*)&hash[4];
102
			uint32_t *bucket = (void*)&bloom[bloom_size];
103
			uint32_t *chain = &bucket[nbucket];
104
        		unsigned int last_sym = 0;
105
        		for (i = 0; i < nbucket; i++)
106
                		if (bucket[i] > last_sym)
107
                        		last_sym = bucket[i];
108
			for (i = last_sym - base; !(chain[i] & 1); i++)
109
				last_sym++;
110
			elf->symcnt= last_sym + 1;
111
		} else
112
		if (hash) {
113
			elf->symcnt = hash[1];
114
		} else {
115
			/* it's outdated, but... */
116
			elf->symcnt = (elf->dynstr - (char*)elf->dynsym) / sizeof(Elf64_Sym);
117
		}
118
	}
119
	parse_dyn(dyn, &lm);
120
121
	/* find libc */
122
        struct link_map *l = _r_debug.r_map;
123
	for ( ; l != NULL; l = l->l_next)
124
		if (l->l_name && *l->l_name && strstr(l->l_name, "libc")) {
125
			printf("Found %s %p\n", l->l_name, l->l_ld);
126
			parse_dyn(l->l_ld, &lc);
127
			lc.delta = (void*)l->l_addr;
128
			break;
129
	}
130
	assert(lc.dynsym != NULL);
131
132
	/* relocate, sort of */
133
	void relocate(void *rela, int relasz, int relaent) {
134
		void *r;
135
		for (r = rela; (r - rela) < relasz; r += relaent) {
136
			Elf64_Rela *rela = (Elf64_Rela*)r;
137
			int index = ELF64_R_SYM(rela->r_info);
138
			void *value = 0;
139
			char *name = NULL;
140
			if (index) {
141
				if (lm.dynsym[index].st_value) {
142
					value = lm.dynsym[index].st_value + lm.delta;
143
				} else {
144
					/* FIXME: use hash, search all libraries */
145
					int found = 0;
146
					name = lm.dynsym[index].st_name + lm.dynstr;
147
					for (i = 0; i < lc.symcnt; i++)
148
						if (! strcmp(name, lc.dynsym[i].st_name + lc.dynstr)) {
149
							value = lc.dynsym[i].st_value + lc.delta;
150
							found = 1;
151
						}
152
					if (! found)
153
						printf("Failed to resolve %d %s\n", index, name);
154
				}
155
			}
156
			if (lm.relent == sizeof(Elf64_Rela))
157
				value += rela->r_addend;
158
			printf("%p (%s + %x) %p\n", rela->r_offset, name ? name : "",
159
				rela->r_addend, value - lm.delta);
160
			*(void**)(rela->r_offset + lm.delta) = value;
161
		}
162
	}
163
	relocate(lm.relplt, lm.relpltsz, lm.relent);
164
	relocate(lm.rela, lm.relasz, lm.relent);
165
166
	printf("Done! Call init\n");
167
	if (lm.init)
168
		lm.init();
169
}
170
171
int main(int argc, char **argv)
172
{
173
	int h = open(argv[1], 0);
174
	int l = lseek(h, 0, 2);
175
	lseek(h, 0, 0);
176
	unsigned char lib[l];
177
	if (h > 0 && l > 0 && read(h, lib, l) == l)
178
		load(lib, l);
179
	else
180
		printf("Failed to read %s\n", argv[1]);
181
	close(h);
182
	return 0;
183
}