void load_dll_crt(uint32_t pid, const wchar_t *dll_path) { load_library_t s; memset(&s, 0, sizeof(s)); s.ldr_load_dll = resolve_symbol("ntdll", "LdrLoadDll"); s.get_last_error = resolve_symbol("ntdll", "RtlGetLastWin32Error"); s.filepath.Length = lstrlenW(dll_path) * sizeof(wchar_t); s.filepath.MaximumLength = strsizeW(dll_path); s.filepath.Buffer = write_data(pid, dll_path, strsizeW(dll_path)); void *settings_addr = write_data(pid, &s, sizeof(s)); void *shellcode_addr = write_data(pid, &load_library_worker, 0x1000); // Run LdrLoadDll(..., dll_path, ...) in the target process. uint32_t last_error = create_thread_and_wait(pid, shellcode_addr, settings_addr); if(last_error != 0) { error("[-] Error loading monitor into process: %d\n", last_error); } free_data(pid, s.filepath.Buffer, strsizeW(dll_path)); free_data(pid, settings_addr, sizeof(s)); free_data(pid, shellcode_addr, 0x1000); }
void load_dll_apc(uint32_t pid, uint32_t tid, const wchar_t *dll_path) { load_library_t s; memset(&s, 0, sizeof(s)); s.ldr_load_dll = resolve_symbol("ntdll", "LdrLoadDll"); s.get_last_error = resolve_symbol("ntdll", "RtlGetLastWin32Error"); s.filepath.Length = lstrlenW(dll_path) * sizeof(wchar_t); s.filepath.MaximumLength = strsizeW(dll_path); s.filepath.Buffer = write_data(pid, dll_path, strsizeW(dll_path)); void *settings_addr = write_data(pid, &s, sizeof(s)); void *shellcode_addr = write_data(pid, &load_library_worker, 0x1000); HANDLE thread_handle = open_thread(tid); // Add LdrLoadDll(..., dll_path, ...) to the APC queue. if(QueueUserAPC((PAPCFUNC) shellcode_addr, thread_handle, (ULONG_PTR) settings_addr) == 0) { error("[-] Error adding task to APC queue: %ld\n", GetLastError()); } // TODO Come up with a way to deallocate dll_addr. CloseHandle(thread_handle); }
static bool backtrace_test () { free (resolve_symbol (puts)); free (resolve_symbol (puts)); #if 0 for (int i = 0; i < 10; i++) make_stack (); #endif exit (0); return true; }
u64 resolve_symbol_tab(inject_ctx *ctx, char *name) { u64 sym; if (ctx->dynsym != 0 && ctx->dynstr != 0) { sym = resolve_symbol(ctx->dynsym, ctx->dynsym_sz, (char*)ctx->dynstr, name); } if (sym == 0 && ctx->symtab != 0 && ctx->strtab != 0) { sym = resolve_symbol(ctx->symtab, ctx->symtab_sz, (char*)ctx->strtab, name); } if (sym != 0) { sym += ctx->elf_base; } return sym; }
void exit_plugin(void *handle) { int (*exit)(void *); exit = resolve_symbol("cifs_idmap_exit_plugin"); if (exit) (*exit)(handle); }
/// Adds a symbol and returns its ID. Can also be used to look-up a symbol. ID add_symbol(Symbol new_symbol) { ID result = resolve_symbol(new_symbol); if (result >= 0) { // the new symbol does already exist return result; } else { // add symbol to signature VLOG(9) << "Signature: New mapping added: '" << new_symbol << "' <-> " << number_of_entries(); external_to_internal[new_symbol] = number_of_entries(); internal_to_external.push_back(new_symbol); return number_of_entries() - 1; } }
/* Change all symbols so that sh_value encodes the pointer directly. */ static int simplify_symbols(Elf32_Shdr *sechdrs, unsigned int symindex, const char *strtab) { Elf32_Sym *sym = (void *)sechdrs[symindex].sh_addr; unsigned long secbase; unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf32_Sym); int ret = 0; for (i = 1; i < n; i++) { switch (sym[i].st_shndx) { case SHN_COMMON: /* We compiled with -fno-common. These are not supposed to happen. */ printf("Common symbol: %s\n", strtab + sym[i].st_name); printf("please compile with -fno-common\n"); ret = -1; break; case SHN_ABS: /* Don't need to do anything */ debug("Absolute symbol: 0x%08lx\n", (long)sym[i].st_value); break; case SHN_UNDEF: sym[i].st_value = resolve_symbol(sechdrs, strtab + sym[i].st_name); debug("undef : %20s 0x%08x 0x%08lx\n", strtab + sym[i].st_name, sym[i].st_value); /* Ok if resolved. */ if (sym[i].st_value != 0) break; /* Ok if weak. */ if (ELF32_ST_BIND(sym[i].st_info) == STB_WEAK) break; printf("Unknown symbol %s\n", strtab + sym[i].st_name); ret = -1; break; default: secbase = sechdrs[sym[i].st_shndx].sh_addr; debug("default: %20s 0x%08x 0x%08lx\n", strtab + sym[i].st_name, sym[i].st_value, secbase); sym[i].st_value += secbase; break; } } return ret; }
static int simplify_symbols(struct secthdr *sechdrs, unsigned int symindex, const char *strtab, unsigned int versindex, unsigned int pcpuindex, struct module *mod) { struct symtab_s *sym = (void *)sechdrs[symindex].sh_addr; unsigned long secbase; unsigned int i, n = sechdrs[symindex].sh_size / sizeof(struct symtab_s); int ret = 0; const struct kernel_symbol *ksym; for (i = 1; i < n; i++) { switch (sym[i].st_shndx) { case SHN_COMMON: /* We compiled with -fno-common. These are not supposed to happen. */ kprintf("simplify_symbols: Common symbol: %s\n", strtab + sym[i].st_name); kprintf("%s: please compile with -fno-common\n", mod->name); ret = -1; break; case SHN_ABS: /* Don't need to do anything */ kprintf("simplify_symbols: Absolute symbol: 0x%08lx\n", (long)sym[i].st_value); break; case SHN_UNDEF: ksym = resolve_symbol(sechdrs, versindex, strtab + sym[i].st_name, mod); /* Ok if resolved. */ if (ksym) { sym[i].st_value = ksym->value; break; } /* Ok if weak. */ if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK) break; kprintf("simplify_symbols: Unknown symbol %s\n", strtab + sym[i].st_name); ret = -1; break; default: if (sym[i].st_shndx == pcpuindex) secbase = (unsigned long)mod->percpu; else secbase = sechdrs[sym[i].st_shndx].sh_addr; sym[i].st_value += secbase; break; } } return ret; }
int str_to_sid(void *handle, const char *name, struct cifs_sid *sid) { int (*entry)(void *, const char *, struct cifs_sid *); *(void **)(&entry) = resolve_symbol("cifs_idmap_str_to_sid"); if (!entry) { plugin_errmsg = "cifs_idmap_str_to_sid not implemented"; return -ENOSYS; } return (*entry)(handle, name, sid); }
int sid_to_str(void *handle, const struct cifs_sid *sid, char **name) { int (*entry)(void *, const struct cifs_sid *, char **); *(void **)(&entry) = resolve_symbol("cifs_idmap_sid_to_str"); if (!entry) { plugin_errmsg = "cifs_idmap_sid_to_str not implemented"; return -ENOSYS; } return (*entry)(handle, sid, name); }
int main(int argc, char** argv) { load_library(library_name); void (*selfloaded_func)() = resolve_symbol(library_name, function_name); if (!selfloaded_func) { fprintf(stderr, "failed to locate %s()\n", function_name); return 1; } fprintf(stderr, "calling %s() by programically located pointer:\n", function_name); selfloaded_func(); }
int ids_to_sids(void *handle, const struct cifs_uxid *cuxid, const size_t num, struct cifs_sid *sid) { int (*entry)(void *handle, const struct cifs_uxid *cuxid, const size_t num, struct cifs_sid *sid); *(void **)(&entry) = resolve_symbol("cifs_idmap_ids_to_sids"); if (!entry) { plugin_errmsg = "cifs_idmap_ids_to_sids not implemented"; return -ENOSYS; } return (*entry)(handle, cuxid, num, sid); }
int init_plugin(void **handle) { int ret; int (*init)(void **, const char **); ret = open_plugin(); if (ret) return ret; init = resolve_symbol("cifs_idmap_init_plugin"); if (!init) { plugin_errmsg = "cifs_idmap_init_plugin not implemented"; return -ENOSYS; } return (*init)(handle, &plugin_errmsg); }
void symbol_dump_resolved(int level, const char *symbol) { int has_value; i32 value; if(resolve_symbol(symbol, &has_value, &value)) { if(has_value) { LOG(level, ("symbol \"%s\" resolves to %d ($%04X)\n", symbol, value, value)); } else { LOG(level, ("symbol \"%s\" is defined but has no value\n", symbol)); } } else { LOG(level, ("symbol \"%s\" not found\n", symbol)); } }
uint32_t start_app(uint32_t from, const wchar_t *path, const wchar_t *arguments, const wchar_t *curdir, uint32_t *tid, int show_window) { create_process_t s; memset(&s, 0, sizeof(s)); s.si.cb = sizeof(s.si); // Emulate explorer.exe's startupinfo flags behavior. s.si.dwFlags = STARTF_USESHOWWINDOW; s.si.wShowWindow = show_window; s.create_process_w = resolve_symbol("kernel32", "CreateProcessW"); s.get_last_error = resolve_symbol("kernel32", "GetLastError"); wchar_t *cmd_line = malloc(strsizeW(path) + strsizeW(arguments) + 4 * sizeof(wchar_t)); wsprintfW(cmd_line, L"\"%s\" %s", path, arguments); s.filepath = write_data(from, path, strsizeW(path)); s.cmdline = write_data(from, cmd_line, strsizeW(cmd_line)); s.curdir = write_data(from, curdir, strsizeW(curdir)); create_process_t *settings_addr = write_data(from, &s, sizeof(s)); void *shellcode_addr = write_data(from, &create_process_worker, 0x1000); uint32_t last_error = create_thread_and_wait(from, shellcode_addr, settings_addr); if(last_error != 0) { error("[-] Error launching process: %d\n", last_error); } read_data(from, settings_addr, &s, sizeof(s)); free_data(from, s.curdir, strsizeW(curdir)); free_data(from, s.cmdline, strsizeW(cmd_line)); free_data(from, s.filepath, strsizeW(path)); free_data(from, shellcode_addr, 0x1000); free_data(from, settings_addr, sizeof(s)); free(cmd_line); HANDLE process_handle = open_process(from), object_handle; if(DuplicateHandle(process_handle, s.pi.hThread, GetCurrentProcess(), &object_handle, DUPLICATE_SAME_ACCESS, FALSE, DUPLICATE_CLOSE_SOURCE) != FALSE) { CloseHandle(object_handle); } if(DuplicateHandle(process_handle, s.pi.hProcess, GetCurrentProcess(), &object_handle, DUPLICATE_SAME_ACCESS, FALSE, DUPLICATE_CLOSE_SOURCE) != FALSE) { CloseHandle(object_handle); } CloseHandle(process_handle); if(tid != NULL) { *tid = s.pi.dwThreadId; } return s.pi.dwProcessId; }
/* Force the target to call `dlopen()'. Modify its registers and stack contents * and continue execution until a segmentation fault is caught. Return 0 on * success and -1 on failure. */ static int force_dlopen(pid_t pid, char *filename) { void *linker_addr, *dlopen_off, *dlopen_addr; regs_t regs; size_t size; int r = -1; if(resolve_symbol(LINKER_PATH, DLOPEN_NAME1, &dlopen_off) != 0 && resolve_symbol(LINKER_PATH, DLOPEN_NAME2, &dlopen_off) != 0 && resolve_symbol(LINKER_PATH, DLOPEN_NAME3, &dlopen_off) != 0) { printf("[*] Could not resolve dlopen()\n"); goto ret; } if((linker_addr = get_linker_addr(pid)) == NULL) { printf("[*] Linker not found in PID %d\n", pid); goto ret; } dlopen_addr = linker_addr + (ptrdiff_t)dlopen_off; printf("[*] Resolved dlopen() at %p\n", dlopen_addr); if(read_registers(pid, ®s) != 0) goto ret; /* Prepare `do_dlopen()' input arguments. On Android >= 7, we set the 4th * argument to a value that emulates `__builtin_return_address()', so that * our DSO is loaded in the correct namespace. */ ARG0(regs) = SP(regs) + SP_OFF; ARG1(regs) = RTLD_NOW | RTLD_GLOBAL; ARG2(regs) = 0; ARG3(regs) = PC(regs); /* We set the new PC and also set LR to force the debuggee to crash. */ #if defined(__aarch64__) LR(regs) = 0xffffffffffffffff; PC(regs) = (reg_t)dlopen_addr; #elif defined(__arm__) LR(regs) = 0xffffffff; PC(regs) = (reg_t)dlopen_addr | 1; CPSR(regs) |= 1 << 5; #endif printf("[*] Modifying target's state\n"); if(write_registers(pid, ®s) != 0) goto ret; size = strlen(filename) + 1; if(write_memory(pid, (void *)SP(regs) + SP_OFF, filename, size) != size) goto ret; printf("[*] Waiting for target to throw SIGSEGV or SIGBUS\n"); if(resume_and_wait(pid) != 0) goto ret; r = 0; ret: return r; }
static status_t relocate_rela(image_t* rootImage, image_t* image, Elf64_Rela* rel, size_t relLength, SymbolLookupCache* cache) { for (size_t i = 0; i < relLength / sizeof(Elf64_Rela); i++) { int type = ELF64_R_TYPE(rel[i].r_info); int symIndex = ELF64_R_SYM(rel[i].r_info); Elf64_Addr symAddr = 0; image_t* symbolImage = NULL; // Resolve the symbol, if any. if (symIndex != 0) { Elf64_Sym* sym = SYMBOL(image, symIndex); status_t status = resolve_symbol(rootImage, image, sym, cache, &symAddr, &symbolImage); if (status != B_OK) { TRACE(("resolve symbol \"%s\" returned: %" B_PRId32 "\n", SYMNAME(image, sym), status)); printf("resolve symbol \"%s\" returned: %" B_PRId32 "\n", SYMNAME(image, sym), status); return status; } } // Address of the relocation. Elf64_Addr relocAddr = image->regions[0].delta + rel[i].r_offset; // Calculate the relocation value. Elf64_Addr relocValue; switch(type) { case R_X86_64_NONE: continue; case R_X86_64_64: case R_X86_64_GLOB_DAT: case R_X86_64_JUMP_SLOT: relocValue = symAddr + rel[i].r_addend; break; case R_X86_64_PC32: relocValue = symAddr + rel[i].r_addend - rel[i].r_offset; break; case R_X86_64_RELATIVE: relocValue = image->regions[0].delta + rel[i].r_addend; break; case R_X86_64_DTPMOD64: relocValue = symbolImage == NULL ? image->dso_tls_id : symbolImage->dso_tls_id; break; case R_X86_64_DTPOFF32: case R_X86_64_DTPOFF64: relocValue = symAddr; break; default: TRACE(("unhandled relocation type %d\n", type)); return B_BAD_DATA; } *(Elf64_Addr *)relocAddr = relocValue; } return B_OK; }
static void load_library(const char* filename) { // Yay! Using internals of libc! Let's just cross fingers this won't change too fast :/ void* (*__libc_dlopen_mode)(const char*, int) = resolve_symbol("libc.so.6", "__libc_dlopen_mode"); __libc_dlopen_mode(filename, RTLD_NOW | RTLD_GLOBAL); }
static Dwfl_Error relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, size_t shstrndx, struct reloc_symtab_cache *reloc_symtab, Elf_Scn *scn, GElf_Shdr *shdr, Elf_Scn *tscn, bool debugscn, bool partial) { /* First, fetch the name of the section these relocations apply to. */ GElf_Shdr tshdr_mem; GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem); const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name); if (tname == NULL) return DWFL_E_LIBELF; if (unlikely (tshdr->sh_type == SHT_NOBITS) || unlikely (tshdr->sh_size == 0)) /* No contents to relocate. */ return DWFL_E_NOERROR; if (debugscn && ! ebl_debugscn_p (mod->ebl, tname)) /* This relocation section is not for a debugging section. Nothing to do here. */ return DWFL_E_NOERROR; /* Fetch the section data that needs the relocations applied. */ Elf_Data *tdata = elf_rawdata (tscn, NULL); if (tdata == NULL) return DWFL_E_LIBELF; /* Apply one relocation. Returns true for any invalid data. */ Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend, int rtype, int symndx) { /* First see if this is a reloc we can handle. If we are skipping it, don't bother resolving the symbol. */ if (unlikely (rtype == 0)) /* In some odd situations, the linker can leave R_*_NONE relocs behind. This is probably bogus ld -r behavior, but the only cases it's known to appear in are harmless: DWARF data referring to addresses in a section that has been discarded. So we just pretend it's OK without further relocation. */ return DWFL_E_NOERROR; Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype); if (unlikely (type == ELF_T_NUM)) return DWFL_E_BADRELTYPE; /* First, resolve the symbol to an absolute value. */ GElf_Addr value; if (symndx == STN_UNDEF) /* When strip removes a section symbol referring to a section moved into the debuginfo file, it replaces that symbol index in relocs with STN_UNDEF. We don't actually need the symbol, because those relocs are always references relative to the nonallocated debugging sections, which start at zero. */ value = 0; else { GElf_Sym sym; GElf_Word shndx; Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab, symndx, &sym, &shndx); if (unlikely (error != DWFL_E_NOERROR)) return error; if (shndx == SHN_UNDEF || shndx == SHN_COMMON) { /* Maybe we can figure it out anyway. */ error = resolve_symbol (mod, reloc_symtab, &sym, shndx); if (error != DWFL_E_NOERROR && !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON)) return error; } value = sym.st_value; } /* These are the types we can relocate. */ #define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \ DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \ DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword) size_t size; switch (type) { #define DO_TYPE(NAME, Name) \ case ELF_T_##NAME: \ size = sizeof (GElf_##Name); \ break TYPES; #undef DO_TYPE default: return DWFL_E_BADRELTYPE; } if (offset + size > tdata->d_size) return DWFL_E_BADRELOFF; #define DO_TYPE(NAME, Name) GElf_##Name Name; union { TYPES; } tmpbuf; #undef DO_TYPE Elf_Data tmpdata = { .d_type = type, .d_buf = &tmpbuf, .d_size = size, .d_version = EV_CURRENT, }; Elf_Data rdata = { .d_type = type, .d_buf = tdata->d_buf + offset, .d_size = size, .d_version = EV_CURRENT, }; /* XXX check for overflow? */ if (addend) { /* For the addend form, we have the value already. */ value += *addend; switch (type) { #define DO_TYPE(NAME, Name) \ case ELF_T_##NAME: \ tmpbuf.Name = value; \ break TYPES; #undef DO_TYPE default: abort (); } } else { /* Extract the original value and apply the reloc. */ Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata, ehdr->e_ident[EI_DATA]); if (d == NULL) return DWFL_E_LIBELF; assert (d == &tmpdata); switch (type) { #define DO_TYPE(NAME, Name) \ case ELF_T_##NAME: \ tmpbuf.Name += (GElf_##Name) value; \ break TYPES; #undef DO_TYPE default: abort (); } } /* Now convert the relocated datum back to the target format. This will write into rdata.d_buf, which points into the raw section data being relocated. */ Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata, ehdr->e_ident[EI_DATA]); if (s == NULL) return DWFL_E_LIBELF; assert (s == &rdata); /* We have applied this relocation! */ return DWFL_E_NOERROR; } /* Fetch the relocation section and apply each reloc in it. */ Elf_Data *reldata = elf_getdata (scn, NULL); if (reldata == NULL) return DWFL_E_LIBELF; Dwfl_Error result = DWFL_E_NOERROR; bool first_badreltype = true; inline void check_badreltype (void) { if (first_badreltype) { first_badreltype = false; if (ebl_get_elfmachine (mod->ebl) == EM_NONE) /* This might be because ebl_openbackend failed to find any libebl_CPU.so library. Diagnose that clearly. */ result = DWFL_E_UNKNOWN_MACHINE; } } size_t nrels = shdr->sh_size / shdr->sh_entsize; size_t complete = 0; if (shdr->sh_type == SHT_REL) for (size_t relidx = 0; !result && relidx < nrels; ++relidx) { GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem); if (r == NULL) return DWFL_E_LIBELF; result = relocate (r->r_offset, NULL, GELF_R_TYPE (r->r_info), GELF_R_SYM (r->r_info)); check_badreltype (); if (partial) switch (result) { case DWFL_E_NOERROR: /* We applied the relocation. Elide it. */ memset (&rel_mem, 0, sizeof rel_mem); gelf_update_rel (reldata, relidx, &rel_mem); ++complete; break; case DWFL_E_BADRELTYPE: case DWFL_E_RELUNDEF: /* We couldn't handle this relocation. Skip it. */ result = DWFL_E_NOERROR; break; default: break; } } else for (size_t relidx = 0; !result && relidx < nrels; ++relidx) { GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx, &rela_mem); if (r == NULL) return DWFL_E_LIBELF; result = relocate (r->r_offset, &r->r_addend, GELF_R_TYPE (r->r_info), GELF_R_SYM (r->r_info)); check_badreltype (); if (partial) switch (result) { case DWFL_E_NOERROR: /* We applied the relocation. Elide it. */ memset (&rela_mem, 0, sizeof rela_mem); gelf_update_rela (reldata, relidx, &rela_mem); ++complete; break; case DWFL_E_BADRELTYPE: case DWFL_E_RELUNDEF: /* We couldn't handle this relocation. Skip it. */ result = DWFL_E_NOERROR; break; default: break; } } if (likely (result == DWFL_E_NOERROR)) { if (!partial || complete == nrels) /* Mark this relocation section as being empty now that we have done its work. This affects unstrip -R, so e.g. it emits an empty .rela.debug_info along with a .debug_info that has already been fully relocated. */ nrels = 0; else if (complete != 0) { /* We handled some of the relocations but not all. We've zeroed out the ones we processed. Now remove them from the section. */ size_t next = 0; if (shdr->sh_type == SHT_REL) for (size_t relidx = 0; relidx < nrels; ++relidx) { GElf_Rel rel_mem; GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem); if (r->r_info != 0 || r->r_offset != 0) { if (next != relidx) gelf_update_rel (reldata, next, r); ++next; } } else for (size_t relidx = 0; relidx < nrels; ++relidx) { GElf_Rela rela_mem; GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem); if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0) { if (next != relidx) gelf_update_rela (reldata, next, r); ++next; } } nrels = next; } shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize; gelf_update_shdr (scn, shdr); } return result; } Dwfl_Error internal_function __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug) { assert (mod->e_type == ET_REL); GElf_Ehdr ehdr_mem; const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem); if (ehdr == NULL) return DWFL_E_LIBELF; size_t d_shstrndx; if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0) return DWFL_E_LIBELF; RELOC_SYMTAB_CACHE (reloc_symtab); /* Look at each section in the debuginfo file, and process the relocation sections for debugging sections. */ Dwfl_Error result = DWFL_E_NOERROR; Elf_Scn *scn = NULL; while (result == DWFL_E_NOERROR && (scn = elf_nextscn (debugfile, scn)) != NULL) { GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) && shdr->sh_size != 0) { /* It's a relocation section. */ Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info); if (unlikely (tscn == NULL)) result = DWFL_E_LIBELF; else result = relocate_section (mod, debugfile, ehdr, d_shstrndx, &reloc_symtab, scn, shdr, tscn, debug, !debug); } } return result; }
static int relocate_rel(image_t *rootImage, image_t *image, struct Elf32_Rel *rel, int rel_len, SymbolLookupCache* cache) { int i; addr_t S; addr_t final_val; # define P ((addr_t *)(image->regions[0].delta + rel[i].r_offset)) # define A (*(P)) # define B (image->regions[0].delta) for (i = 0; i * (int)sizeof(struct Elf32_Rel) < rel_len; i++) { unsigned type = ELF32_R_TYPE(rel[i].r_info); switch (type) { case R_386_32: case R_386_PC32: case R_386_GLOB_DAT: case R_386_JMP_SLOT: case R_386_GOTOFF: { struct Elf32_Sym *sym; status_t status; sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); status = resolve_symbol(rootImage, image, sym, cache, &S); if (status < B_OK) { TRACE(("resolve symbol \"%s\" returned: %ld\n", SYMNAME(image, sym), status)); printf("resolve symbol \"%s\" returned: %ld\n", SYMNAME(image, sym), status); return status; } } } switch (type) { case R_386_NONE: continue; case R_386_32: final_val = S + A; break; case R_386_PC32: final_val = S + A - (addr_t)P; break; #if 0 case R_386_GOT32: final_val = G + A; break; case R_386_PLT32: final_val = L + A - (addr_t)P; break; #endif case R_386_COPY: /* what ? */ continue; case R_386_GLOB_DAT: final_val = S; break; case R_386_JMP_SLOT: final_val = S; break; case R_386_RELATIVE: final_val = B + A; break; #if 0 case R_386_GOTOFF: final_val = S + A - GOT; break; case R_386_GOTPC: final_val = GOT + A - P; break; #endif default: TRACE(("unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info))); return B_NOT_ALLOWED; } *P = final_val; } # undef P # undef A # undef B return B_NO_ERROR; }
static int relocate_rela(image_t *rootImage, image_t *image, Elf32_Rela *rel, int rel_len, SymbolLookupCache* cache) { int i; addr_t S; addr_t final_val; # define P ((addr_t *)(image->regions[0].delta + rel[i].r_offset)) //# define A (*(P)) #define A ((addr_t)rel[i].r_addend) # define B (image->regions[0].delta) for (i = 0; i * (int)sizeof(Elf32_Rel) < rel_len; i++) { unsigned type = ELF32_R_TYPE(rel[i].r_info); switch (type) { case R_68K_32: case R_68K_16: case R_68K_8: case R_68K_PC32: case R_68K_PC16: case R_68K_PC8: case R_68K_GLOB_DAT: case R_68K_JMP_SLOT: { Elf32_Sym *sym; status_t status; sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); status = resolve_symbol(rootImage, image, sym, cache, &S); if (status < B_OK) { TRACE(("resolve symbol \"%s\" returned: %ld\n", SYMNAME(image, sym), status)); printf("resolve symbol \"%s\" returned: %ld\n", SYMNAME(image, sym), status); return status; } } } switch (type) { case R_68K_NONE: continue; case R_68K_32: write_32(P, S + A); break; case R_68K_16: if (write_16_check(P, S + A)) break; TRACE(("R_68K_16 overflow\n")); return B_BAD_DATA; case R_68K_8: if (write_8_check(P, S + A)) break; TRACE(("R_68K_8 overflow\n")); return B_BAD_DATA; case R_68K_PC32: write_32(P, (S + A - (addr_t)P)); break; #if 0 case R_68K_PC16: if (write_16_check(P, (S + A - P))) break; TRACE(("R_68K_PC16 overflow\n")); return B_BAD_DATA; case R_68K_PC8: if (write_8(P, (S + A - P))) break; TRACE(("R_68K_PC8 overflow\n")); return B_BAD_DATA; case R_68K_GOT32: REQUIRE_GOT; write_32(P, (G + A - P)); break; case R_68K_GOT16: REQUIRE_GOT; if (write_16_check(P, (G + A - P))) break; TRACE(("R_68K_GOT16 overflow\n")); return B_BAD_DATA; case R_68K_GOT8: REQUIRE_GOT; if (write_8_check(P, (G + A - P))) break; TRACE(("R_68K_GOT8 overflow\n")); return B_BAD_DATA; case R_68K_GOT32O: REQUIRE_GOT; write_32(P, (G + A)); break; case R_68K_GOT16O: REQUIRE_GOT; if (write_16_check(P, (G + A))) break; TRACE(("R_68K_GOT16 overflow\n")); return B_BAD_DATA; case R_68K_GOT8O: REQUIRE_GOT; if (write_8_check(P, (G + A))) break; TRACE(("R_68K_GOT8 overflow\n")); return B_BAD_DATA; case R_68K_PLT32: REQUIRE_PLT; write_32(P, (L + A - P)); break; case R_68K_PLT16: REQUIRE_PLT; if (write_16_check(P, (L + A - P))) break; TRACE(("R_68K_PLT16 overflow\n")); return B_BAD_DATA; case R_68K_PLT8: REQUIRE_PLT; if (write_8_check(P, (L + A - P))) break; TRACE(("R_68K_PLT8 overflow\n")); return B_BAD_DATA; case R_68K_PLT32O: REQUIRE_PLT; write_32(P, (L + A)); break; case R_68K_PLT16O: REQUIRE_PLT; if (write_16_check(P, (L + A))) break; TRACE(("R_68K_PLT16O overflow\n")); return B_BAD_DATA; case R_68K_PLT8O: REQUIRE_PLT; if (write_8_check(P, (L + A))) break; TRACE(("R_68K_PLT8O overflow\n")); return B_BAD_DATA; case R_386_GOT32: final_val = G + A; break; case R_386_PLT32: final_val = L + A - (addr_t)P; break; #endif case R_68K_COPY: /* what ? */ continue; case R_68K_GLOB_DAT: write_32(P, S/* + A*/); break; case R_68K_JMP_SLOT: //XXX ? write_32(P, (G + A)); write_32(P, S); break; #if 0 case R_386_JMP_SLOT: write_32(P, S); break; #endif case R_68K_RELATIVE: write_32(P, B + A); break; #if 0 case R_386_GOTOFF: final_val = S + A - GOT; break; case R_386_GOTPC: final_val = GOT + A - P; break; #endif default: TRACE(("unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info))); return B_NOT_ALLOWED; } *P = final_val; } # undef P # undef A # undef B return B_NO_ERROR; }