From b5105a1e57bba3305d5dce93ab4d2f7faab6b34a Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Mon, 26 Aug 2024 17:45:13 +0200 Subject: Added preliminary Box32 support (#1760) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Improve the ReserveHigMemory helper function * [BOX32] Added some wrapping infrastructure * [BOX32] More wrapped 32bits lib infrastructure * [BOX32] Added callback and tls 32bits handling * [BOX32] Added more 32bits, around wrappers and elfs * [BOX32] Added the 32bits version of myalign * [BOX32] More wrapped libs and 32bits fixes and imrpovments * [BOX32] Added some 32bits tests * [BOX32] Try to enable some Box32 build and test on the CI * [BOX32] Disable Box32 testing on CI platform that use qemu * [BOX32] Another attempt to disable Box32 testing on CI platform that use qemu * [BOX32] Small fix for another attempt to disable Box32 testing on CI platform that use qemu * [BOX32] Yet another fix for another attempt to disable Box32 testing on CI platform that use qemu * [BOX32] Fixed a typo in CI script * [BOX32] Better scratch alighnment and enabled more tests * [BOX32] Added (partial) wrapped 32bits librt * [BOX32] Added mention of Box32 in README * [BOX32] Added phtread handling, and numerous fixes to 32bits handling. [ARM64_DYNAREC] Fixed access to segment with negative offset * [BOX32] Added system libs and cpp testing, plus some more fixes * [BOX32] Fix previous commit * [BOX32] Better stack adjustment for 32bits processes * [BOX32] Added getenv wrapped 32bits function and friends * [BOX32] Don't look for box86 for a Box32 build * [BOX32] Don't do 32bits cppThreads test for now on CI * [BOX32] Enabled a few more 32bits tests * [BOX32] For ld_lib_path for both CppThreads tests * [BOX32] [ANDROID] Some Fixes for Android Build * [BOX32] Still need to disable cppThread_32bits test on CI for some reason * [BOX32] [ANDROID] Don't show PreInit Array Warning (#1751) * [BOX32] [ANDROID] One More Fix for Android Build That I forgotten to … (#1752) * [BOX32] [ANDROID] One More Fix for Android Build That I forgotten to push before * [BOX32] [ANDROID] Try to Create __libc_init * [BOX32] [ANDROID] Try to disable NEEDED_LIBS for now (libdl is not wrapped) * [BOX32] Updated generated files * [BOX32] Added 32bits context functions * [BOX32] Added 32bits signal handling * [BOX32] Added some missing 32bits elfloader functions * [BOX32] Fix build on x86_64 machine * [BOX32] Better fix for x86_64 build * [BOX32] Actually added missing libs, and re-enabled cppThreads_32bits test * [BOX32] Added wrapped 32bits libdl * [BOX32] Try to re-enabled Box32 test on CI for ARM64 builds * [BOX32] fine-tuning Box32 test on CI for ARM64 builds * [BOX32] More fine-tuning to Box32 test on CI for ARM64 builds * [BOX32] Enabled Box32 test on CI for LA64 and RV64 builds too * [BOX32] re-Disabled Box32 test on CI for LA64 and RV64 builds, not working for now * [BOX32] Temporarily disabled cppThreads_32bits test on CI --------- Co-authored-by: KreitinnSoftware Co-authored-by: KreitinnSoftware <80591934+KreitinnSoftware@users.noreply.github.com> --- src/elfs/elfloader32.c | 264 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) (limited to 'src/elfs/elfloader32.c') diff --git a/src/elfs/elfloader32.c b/src/elfs/elfloader32.c index 3b30bc07..62a3918e 100644 --- a/src/elfs/elfloader32.c +++ b/src/elfs/elfloader32.c @@ -42,6 +42,12 @@ #include "x64tls.h" #include "box32.h" +ptr_t pltResolver32 = ~(ptr_t)0; + +extern void* my__IO_2_1_stderr_; +extern void* my__IO_2_1_stdin_ ; +extern void* my__IO_2_1_stdout_; + // return the index of header (-1 if it doesn't exist) static int getElfIndex(box64context_t* ctx, elfheader_t* head) { for (int i=0; ielfsize; ++i) @@ -60,6 +66,68 @@ static elfheader_t* checkElfLib(elfheader_t* h, library_t* lib) return h; } +static Elf32_Sym* ElfLocateSymbol(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt) +{ + Elf32_Sym* sym = ElfLookup32(head, symname, *ver, *vername, local, *veropt); + if(!sym) return NULL; + if(head->VerSym && !*veropt) { + int idx = ((uintptr_t)sym - (uintptr_t)head->DynSym._32)/sizeof(Elf32_Sym); + int version = ((Elf32_Half*)((uintptr_t)head->VerSym+head->delta))[idx]; + if(version!=-1) version &=0x7fff; + const char* symvername = GetSymbolVersion(head, version); + Elf32_Half flags = GetSymbolVersionFlag(head, version); + if(version>1 && *ver<2 && (flags==0)) { + *ver = version; + *vername = symvername; + *veropt = 1; + } else if(flags==0 && !*veropt && version>1 && *ver>1 && !strcmp(symvername, *vername)) { + *veropt = 1; + } + } + if(!sym->st_shndx) return NULL; + int vis = ELF32_ST_VISIBILITY(sym->st_other); + if(vis==STV_HIDDEN && !local) + return NULL; + return sym; +} + + +static void GrabX32CopyMainElfReloc(elfheader_t* head) +{ + if(head->rela) { + int cnt = head->relasz / head->relaent; + Elf32_Rela* rela = (Elf32_Rela *)(head->rela + head->delta); + printf_dump(LOG_DEBUG, "Grabbing R_386_COPY Relocation(s) in advance for %s\n", head->name); + for (int i=0; iDynSym._32[ELF32_R_SYM(rela[i].r_info)]; + const char* symname = SymName32(head, sym); + int version = head->VerSym?((Elf32_Half*)((uintptr_t)head->VerSym+head->delta))[ELF32_R_SYM(rela[i].r_info)]:-1; + if(version!=-1) version &=0x7fff; + const char* vername = GetSymbolVersion(head, version); + Elf32_Half flags = GetSymbolVersionFlag(head, version); + int veropt = flags?0:1; + uintptr_t offs = sym->st_value + head->delta; + AddUniqueSymbol(my_context->globdata, symname, offs, sym->st_size, version, vername, veropt); + } + } + } +} + +void checkHookedSymbols(elfheader_t* h); +void AddSymbols32(lib_t *maplib, elfheader_t* h) +{ + //if(box64_dump && h->hash) old_elf_hash_dump(h); + //if(box64_dump && h->gnu_hash) new_elf_hash_dump(h); + if(box64_dump && h->DynSym._32) DumpDynSym32(h); + if(h==my_context->elfs[0]) + GrabX32CopyMainElfReloc(h); + #ifndef STATICBUILD + checkHookedSymbols(h); + #endif +} + int AllocLoadElfMemory32(box64context_t* context, elfheader_t* head, int mainbin) { ptr_t offs = 0; @@ -624,3 +692,199 @@ int RelocateElf32(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, } return 0; } + +int RelocateElfPlt32(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head) +{ + int need_resolver = 0; + if(0 && (head->flags&DF_BIND_NOW) && !bindnow) { // disable for now, needs more symbol in a fow libs like gtk and nss3 + bindnow = 1; + printf_log(LOG_DEBUG, "Forcing %s to Bind Now\n", head->name); + } + if(head->pltrel) { + int cnt = head->pltsz / head->pltent; + if(head->pltrel==DT_REL) { + DumpRelTable32(head, cnt, (Elf32_Rel *)(head->jmprel + head->delta), "PLT"); + printf_log(LOG_DEBUG, "Applying %d PLT Relocation(s) for %s\n", cnt, head->name); + if(RelocateElfREL(maplib, local_maplib, bindnow, deepbind, head, cnt, (Elf32_Rel *)(head->jmprel + head->delta), &need_resolver)) + return -1; + } else if(head->pltrel==DT_RELA) { + DumpRelATable32(head, cnt, (Elf32_Rela *)(head->jmprel + head->delta), "PLT"); + printf_log(LOG_DEBUG, "Applying %d PLT Relocation(s) with Addend for %s\n", cnt, head->name); + if(RelocateElfRELA(maplib, local_maplib, bindnow, deepbind, head, cnt, (Elf32_Rela *)(head->jmprel + head->delta), &need_resolver)) + return -1; + } + if(need_resolver) { + if(pltResolver32==~(ptr_t)0) { + pltResolver32 = AddBridge(my_context->system, vFEv, PltResolver32, 0, "(PltResolver)"); + } + if(head->pltgot) { + *(ptr_t*)from_ptrv(head->pltgot+head->delta+8) = pltResolver32; + *(ptr_t*)from_ptrv(head->pltgot+head->delta+4) = to_ptrv(head); + printf_log(LOG_DEBUG, "PLT Resolver injected in plt.got at %p\n", from_ptrv(head->pltgot+head->delta+8)); + } else if(head->got) { + *(ptr_t*)from_ptrv(head->got+head->delta+8) = pltResolver32; + *(ptr_t*)from_ptrv(head->got+head->delta+4) = to_ptrv(head); + printf_log(LOG_DEBUG, "PLT Resolver injected in got at %p\n", from_ptrv(head->got+head->delta+8)); + } + } + } + return 0; +} + +void ResetSpecialCaseMainElf32(elfheader_t* h) +{ + Elf32_Sym *sym = NULL; + for (uint32_t i=0; inumDynSym; ++i) { + if(h->DynSym._32[i].st_info == 17) { + sym = h->DynSym._32+i; + const char * symname = h->DynStr+sym->st_name; + if(strcmp(symname, "_IO_2_1_stderr_")==0 && (from_ptrv(sym->st_value+h->delta))) { + memcpy(from_ptrv(sym->st_value+h->delta), stderr, sym->st_size); + my__IO_2_1_stderr_ = from_ptrv(sym->st_value+h->delta); + printf_log(LOG_DEBUG, "BOX32: Set @_IO_2_1_stderr_ to %p\n", my__IO_2_1_stderr_); + } else + if(strcmp(symname, "_IO_2_1_stdin_")==0 && (from_ptrv(sym->st_value+h->delta))) { + memcpy(from_ptrv(sym->st_value+h->delta), stdin, sym->st_size); + my__IO_2_1_stdin_ = from_ptrv(sym->st_value+h->delta); + printf_log(LOG_DEBUG, "BOX32: Set @_IO_2_1_stdin_ to %p\n", my__IO_2_1_stdin_); + } else + if(strcmp(symname, "_IO_2_1_stdout_")==0 && (from_ptrv(sym->st_value+h->delta))) { + memcpy(from_ptrv(sym->st_value+h->delta), stdout, sym->st_size); + my__IO_2_1_stdout_ = from_ptrv(sym->st_value+h->delta); + printf_log(LOG_DEBUG, "BOX32: Set @_IO_2_1_stdout_ to %p\n", my__IO_2_1_stdout_); + } else + if(strcmp(symname, "_IO_stderr_")==0 && (from_ptrv(sym->st_value+h->delta))) { + memcpy(from_ptrv(sym->st_value+h->delta), stderr, sym->st_size); + my__IO_2_1_stderr_ = from_ptrv(sym->st_value+h->delta); + printf_log(LOG_DEBUG, "BOX32: Set @_IO_stderr_ to %p\n", my__IO_2_1_stderr_); + } else + if(strcmp(symname, "_IO_stdin_")==0 && (from_ptrv(sym->st_value+h->delta))) { + memcpy(from_ptrv(sym->st_value+h->delta), stdin, sym->st_size); + my__IO_2_1_stdin_ = from_ptrv(sym->st_value+h->delta); + printf_log(LOG_DEBUG, "BOX32: Set @_IO_stdin_ to %p\n", my__IO_2_1_stdin_); + } else + if(strcmp(symname, "_IO_stdout_")==0 && (from_ptrv(sym->st_value+h->delta))) { + memcpy(from_ptrv(sym->st_value+h->delta), stdout, sym->st_size); + my__IO_2_1_stdout_ = from_ptrv(sym->st_value+h->delta); + printf_log(LOG_DEBUG, "BOX32: Set @_IO_stdout_ to %p\n", my__IO_2_1_stdout_); + } + } + } +} + +void* ElfGetLocalSymbolStartEnd32(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt) +{ + Elf32_Sym* sym = ElfLocateSymbol(head, offs, end, symname, ver, vername, local, veropt); + if(!sym) return NULL; + int bind = ELF32_ST_BIND(sym->st_info); + if(bind!=STB_LOCAL) return 0; + if(offs) *offs = sym->st_value + head->delta; + if(end) *end = sym->st_value + head->delta + sym->st_size; + return sym; +} + +void* ElfGetGlobalSymbolStartEnd32(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt) +{ + Elf32_Sym* sym = ElfLocateSymbol(head, offs, end, symname, ver, vername, local, veropt); + if(!sym) return NULL; + int bind = ELF32_ST_BIND(sym->st_info); + if(bind!=STB_GLOBAL && bind!=STB_GNU_UNIQUE) return 0; + if(offs) *offs = sym->st_value + head->delta; + if(end) *end = sym->st_value + head->delta + sym->st_size; + return sym; +} + +void* ElfGetWeakSymbolStartEnd32(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt) +{ + Elf32_Sym* sym = ElfLocateSymbol(head, offs, end, symname, ver, vername, local, veropt); + if(!sym) return NULL; + int bind = ELF32_ST_BIND(sym->st_info); + if(bind!=STB_WEAK) return 0; + if(offs) *offs = sym->st_value + head->delta; + if(end) *end = sym->st_value + head->delta + sym->st_size; + return sym; +} + +int ElfGetSymTabStartEnd32(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname) +{ + Elf32_Sym* sym = ElfSymTabLookup32(head, symname); + if(!sym) return 0; + if(!sym->st_shndx) return 0; + if(!sym->st_size) return 0; //needed? + if(offs) *offs = sym->st_value + head->delta; + if(end) *end = sym->st_value + head->delta + sym->st_size; + return 1; +} + +EXPORT void PltResolver32(x64emu_t* emu) +{ + ptr_t addr = Pop32(emu); + int slot = (int)Pop32(emu); + elfheader_t *h = (elfheader_t*)from_ptrv(addr); + library_t* lib = h->lib; + lib_t* local_maplib = GetMaplib(lib); + int deepbind = GetDeepBind(lib); + printf_dump(LOG_DEBUG, "PltResolver32: Addr=%p, Slot=%d Return=%p: elf is %s (VerSym=%p)\n", from_ptrv(addr), slot, *(ptr_t*)from_ptrv(R_ESP), h->name, h->VerSym); + + Elf32_Rel * rel = (Elf32_Rel *)(from_ptrv(h->jmprel + h->delta + slot)); + + Elf32_Sym *sym = &h->DynSym._32[ELF32_R_SYM(rel->r_info)]; + int bind = ELF32_ST_BIND(sym->st_info); + const char* symname = SymName32(h, sym); + int version = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[ELF32_R_SYM(rel->r_info)]:-1; + if(version!=-1) version &= 0x7fff; + const char* vername = GetSymbolVersion(h, version); + Elf32_Half flags = GetSymbolVersionFlag(h, version); + int veropt = flags?0:1; + ptr_t *p = (uint32_t*)from_ptrv(rel->r_offset + h->delta); + uintptr_t offs = 0; + uintptr_t end = 0; + + Elf32_Sym *elfsym = NULL; + if(bind==STB_LOCAL) { + elfsym = ElfDynSymLookup32(h, symname); + if(elfsym && elfsym->st_shndx) { + offs = elfsym->st_value + h->delta; + end = offs + elfsym->st_size; + } + if(!offs && !end && local_maplib && deepbind) + GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + if(!offs && !end) + GetLocalSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + if(!offs && !end && local_maplib && !deepbind) + GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + } else if(bind==STB_WEAK) { + if(local_maplib && deepbind) + GetGlobalWeakSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + else + GetGlobalWeakSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + if(!offs && !end && local_maplib && !deepbind) + GetGlobalWeakSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + } else { + if(!offs && !end && local_maplib && deepbind) + GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + if(!offs && !end) + GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + if(!offs && !end && local_maplib && !deepbind) + GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, veropt, (void**)&elfsym); + } + + if (!offs) { + printf_log(LOG_NONE, "Error: PltResolver32: Symbol %s(ver %d: %s%s%s) not found, cannot apply R_386_JMP_SLOT %p (%p) in %s\n", symname, version, symname, vername?"@":"", vername?vername:"", p, from_ptrv(*p), h->name); + emu->quit = 1; + return; + } else { + elfheader_t* sym_elf = FindElfSymbol(my_context, elfsym); + offs = (uintptr_t)getAlternate(from_ptrv(offs)); + + if(p) { + printf_dump(LOG_DEBUG, " Apply %s R_386_JMP_SLOT %p with sym=%s(ver %d: %s%s%s) (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, symname, version, symname, vername?"@":"", vername?vername:"",from_ptrv(*p), from_ptrv(offs), ElfName(FindElfAddress(my_context, offs))); + *p = offs; + } else { + printf_log(LOG_NONE, "PltResolver32: Warning, Symbol %s(ver %d: %s%s%s) found, but Jump Slot Offset is NULL \n", symname, version, symname, vername?"@":"", vername?vername:""); + } + } + + // jmp to function + R_EIP = offs; +} -- cgit 1.4.1