summaryrefslogtreecommitdiffstats
path: root/src/modules.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/modules.cpp99
1 files changed, 99 insertions, 0 deletions
diff --git a/src/modules.cpp b/src/modules.cpp
index 70e2dff..b832694 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -1,5 +1,7 @@
1// modules.cpp — /proc/self/maps parsing and module discovery 1// modules.cpp — /proc/self/maps parsing and module discovery
2#include "hl2h.h" 2#include "hl2h.h"
3#include <elf.h>
4#include <vector>
3 5
4static bool basename_is(const char *path, const char *base) { 6static bool basename_is(const char *path, const char *base) {
5 size_t pl = strlen(path), bl = strlen(base); 7 size_t pl = strlen(path), bl = strlen(base);
@@ -70,3 +72,100 @@ void find_modules() {
70 } 72 }
71 fclose(f); 73 fclose(f);
72} 74}
75
76// ---------------------------------------------------------------------------
77// ELF relocation lookup
78// ---------------------------------------------------------------------------
79//
80// The server RandomSeed hook used to hardcode the GOT offset measured on one
81// server.so build. The anniversary branch ships a different server.so
82// (hl2_complete/bin/server.so) whose slot moved, so the patch silently landed
83// on unrelated data and No spread stopped working. Read the loaded module's
84// ELF relocation table instead: find the R_386_JMP_SLOT for a symbol and
85// return its virtual address plus the load bias implied by the first PT_LOAD.
86bool module_jump_slot(const char *path, const char *name, uintptr_t *out_vaddr,
87 uintptr_t *out_bias) {
88 if (!path || !*path || !name)
89 return false;
90 FILE *f = fopen(path, "rb");
91 if (!f)
92 return false;
93 if (fseek(f, 0, SEEK_END) != 0) {
94 fclose(f);
95 return false;
96 }
97 long sz = ftell(f);
98 if (sz < (long)sizeof(Elf32_Ehdr) || fseek(f, 0, SEEK_SET) != 0) {
99 fclose(f);
100 return false;
101 }
102 std::vector<unsigned char> buf((size_t)sz);
103 size_t got = fread(buf.data(), 1, buf.size(), f);
104 fclose(f);
105 if (got != buf.size())
106 return false;
107 if (buf.size() < sizeof(Elf32_Ehdr))
108 return false;
109
110 const Elf32_Ehdr *eh = (const Elf32_Ehdr *)buf.data();
111 if (memcmp(eh->e_ident, ELFMAG, SELFMAG) != 0 ||
112 eh->e_ident[EI_CLASS] != ELFCLASS32)
113 return false;
114 if (eh->e_shoff == 0 || eh->e_shentsize != sizeof(Elf32_Shdr))
115 return false;
116 if ((uint64_t)eh->e_shoff + (uint64_t)eh->e_shnum * sizeof(Elf32_Shdr) >
117 buf.size())
118 return false;
119 const Elf32_Shdr *sh = (const Elf32_Shdr *)(buf.data() + eh->e_shoff);
120
121 uintptr_t bias = 0;
122 if (eh->e_phoff && eh->e_phnum &&
123 eh->e_phentsize == sizeof(Elf32_Phdr) &&
124 (uint64_t)eh->e_phoff + (uint64_t)eh->e_phnum * sizeof(Elf32_Phdr) <=
125 buf.size()) {
126 const Elf32_Phdr *ph = (const Elf32_Phdr *)(buf.data() + eh->e_phoff);
127 for (int i = 0; i < eh->e_phnum; i++) {
128 if (ph[i].p_type == PT_LOAD) {
129 bias = ph[i].p_vaddr;
130 break;
131 }
132 }
133 }
134
135 for (int s = 0; s < eh->e_shnum; s++) {
136 if (sh[s].sh_type != SHT_REL || sh[s].sh_link >= eh->e_shnum)
137 continue;
138 if ((uint64_t)sh[s].sh_offset + (uint64_t)sh[s].sh_size > buf.size())
139 continue;
140 const Elf32_Shdr &symsh = sh[sh[s].sh_link];
141 if (symsh.sh_link >= eh->e_shnum)
142 continue;
143 const Elf32_Shdr &strsh = sh[symsh.sh_link];
144 if ((uint64_t)symsh.sh_offset + (uint64_t)symsh.sh_size > buf.size() ||
145 (uint64_t)strsh.sh_offset + (uint64_t)strsh.sh_size > buf.size())
146 continue;
147 const Elf32_Rel *rels = (const Elf32_Rel *)(buf.data() + sh[s].sh_offset);
148 size_t nrels = sh[s].sh_size / sizeof(Elf32_Rel);
149 const Elf32_Sym *syms = (const Elf32_Sym *)(buf.data() + symsh.sh_offset);
150 size_t nsyms = symsh.sh_size / sizeof(Elf32_Sym);
151 const char *strs = (const char *)(buf.data() + strsh.sh_offset);
152 size_t strn = strsh.sh_size;
153 for (size_t r = 0; r < nrels; r++) {
154 unsigned type = ELF32_R_TYPE(rels[r].r_info);
155 unsigned sym = ELF32_R_SYM(rels[r].r_info);
156 if (type != R_386_JMP_SLOT || sym >= nsyms)
157 continue;
158 if (syms[sym].st_name >= strn)
159 continue;
160 const char *sn = strs + syms[sym].st_name;
161 if (strcmp(sn, name) != 0)
162 continue;
163 if (out_vaddr)
164 *out_vaddr = rels[r].r_offset;
165 if (out_bias)
166 *out_bias = bias;
167 return true;
168 }
169 }
170 return false;
171}