diff --git a/README.md b/README.md index 88bacd2..ba946dd 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ PoC by Shiz, bugfixing and 64-bit version by PoroCYon. ```sh ./smol.py -lfoo -lbar input.o... smol-output.asm -nasm -I src/ [-DUSE_NX] [-DUSE_DL_FINI] -o nasm-output.o smol-output.asm +nasm -I src/ [-DUSE_INTERP] [-DALIGN_STACK] [-DUSE_NX] [-DUSE_DL_FINI] \ + -o nasm-output.o smol-output.asm +# -DALIGN_STACK: 64-bit only. ld -T ld/link.ld -o binary nasm-output.o input.o... ``` diff --git a/smol.py b/smol.py index c9eb7ca..324a164 100755 --- a/smol.py +++ b/smol.py @@ -52,13 +52,13 @@ def main(): libs = list(find_libs(spaths, libnames)) symbols = {} - for symbol in syms: + for symbol, reloc in syms: library = find_symbol(args.scanelf, libs, libnames, symbol) if not library: eprintf("could not find symbol: {}".format(symbol)) sys.exit(1) symbols.setdefault(library, []) - symbols[library].append(symbol) + symbols[library].append((symbol, reloc)) output(arch, symbols, args.output) diff --git a/smolemit.py b/smolemit.py index 8c5111a..190bbab 100644 --- a/smolemit.py +++ b/smolemit.py @@ -15,11 +15,20 @@ def output_x86(libraries, outf): outf.write('dd (_symbols.{} - _symbols)\n'.format(shorts[library])) outf.write('.dynamic.end:\n') +# if needgot: +# outf.write('global _GLOBAL_OFFSET_TABLE_\n') +# outf.write('_GLOBAL_OFFSET_TABLE_:\n') +# outf.write('dd dynamic\n') outf.write('_symbols:\n') - for library, symbols in libraries.items(): + for library, symrels in libraries.items(): outf.write('\t_symbols.{}: db "{}",0\n'.format(shorts[library], library)) - for sym in symbols: + for sym, reloc in symrels: + # meh + if reloc != 'R_386_PC32': + eprintf('Relocation type ' + reloc + ' of symbol ' + sym + ' unsupported!') + sys.exit(1) + hash = hash_djb2(sym) outf.write(""" \t\tglobal {name} @@ -46,11 +55,25 @@ def output_amd64(libraries, outf): outf.write('dynamic.end:\n') outf.write('[section .data.smolgot]\n') +# if needgot: +# outf.write('global _GLOBAL_OFFSET_TABLE_\n') +# outf.write('_GLOBAL_OFFSET_TABLE_:\n') +# outf.write('dq dynamic\n') outf.write('_symbols:\n') - for library, symbols in libraries.items(): + for library, symrels in libraries.items(): outf.write('\t_symbols.{}: db "{}",0\n'.format(shorts[library], library)) - for sym in symbols: + for sym, reloc in symrels: + if reloc != 'R_X86_64_PLT32' and reloc != 'R_X86_64_GOTPCRELX': + eprintf('Relocation type ' + reloc + ' of symbol ' + sym + ' unsupported!') + sys.exit(1) + + if reloc == 'R_X86_64_GOTPCRELX': + outf.write(""" +global {name} +{name}: +""".format(name=sym).lstrip('\n')) + hash = hash_djb2(sym) outf.write('\t\t_symbols.{lib}.{name}: dq 0x{hash:x}\n'\ .format(lib=shorts[library],name=sym,hash=hash)) @@ -60,9 +83,10 @@ def output_amd64(libraries, outf): outf.write('_symbols.end:\n') outf.write('_smolplt:\n') - for library, symbols in libraries.items(): - for sym in symbols: - outf.write(""" + for library, symrels in libraries.items(): + for sym, reloc in symrels: + if reloc == 'R_X86_64_PLT32': + outf.write(""" [section .text.smolplt.{name}] global {name} {name}: diff --git a/smolparse.py b/smolparse.py index 43f1cd4..ab6048e 100644 --- a/smolparse.py +++ b/smolparse.py @@ -31,18 +31,45 @@ def decide_arch(inpfiles): return archmagic[archn] +def build_reloc_typ_table(reo): + relocs = dict({}) + + for s in reo.decode('utf-8').splitlines(): + stuff = s.split() + + # prolly a 'header' line + if len(stuff) < 5: + continue + + # yes, we're assuming every reference to the same symbol will use the + # same relocation type. if this isn't the case, your compiler flags are + # stupid + relocs[stuff[4]] = stuff[2] + + return relocs + def get_needed_syms(readelf_bin, inpfiles): output = subprocess.check_output([readelf_bin, '-s', '-W']+inpfiles, stderr=subprocess.DEVNULL) + outrel = subprocess.check_output([readelf_bin, '-r', '-W']+inpfiles, + stderr=subprocess.DEVNULL) + + relocs = build_reloc_typ_table(outrel) syms=set({}) for entry in output.decode('utf-8').splitlines(): stuff = entry.split() if len(stuff)<8: continue - if stuff[4] == "GLOBAL" and stuff[6] == "UND" and len(stuff[7])>0: - syms.add(stuff[7]) + if stuff[4] == "GLOBAL" and stuff[6] == "UND" and len(stuff[7])>0 \ + and stuff[7] in relocs: + syms.add((stuff[7], relocs[stuff[7]])) - return syms + #needgot = False + #if "_GLOBAL_OFFSET_TABLE_" in syms: + # needgot = True + # syms.remove("_GLOBAL_OFFSET_TABLE_") + + return syms#, needgot def get_cc_paths(cc_bin): output = subprocess.check_output([cc_bin, '-print-search-dirs'], diff --git a/src/loader64.asm b/src/loader64.asm index ad955ee..7a6b125 100644 --- a/src/loader64.asm +++ b/src/loader64.asm @@ -44,7 +44,7 @@ _smol_start: sub rsi, LF_ENTRY_OFF+8 xchg rbx, rsi - mov rsi, _symbols + mov esi, _symbols ; for (rsi = (uint8_t*)_symbols; *rsi; ++rsi) { .next_needed: @@ -159,7 +159,9 @@ _smol_start: .needed_end: ;xor rbp, rbp ; still 0 from _dl_start_user mov rdi, rsp +%ifdef ALIGN_STACK push rax +%endif %ifdef USE_DL_FINI xchg rsi, r13 ; _dl_fini %endif