Repository navigation
Apply relocs for ifuncs #1536
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
kStor2poche
wants to merge
14
commits into
cea-sec:master
Choose a base branch
from
kStor2poche:apply-relocs-for-ifuncs
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Apply relocs for ifuncs #1536
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
3c20b41
Apply relocs for ifuncs
kStor2poche 4ad7f56
Raise error for weird elf sizes
kStor2poche 6b932c1
Basic ifunc example to iterate upon
kStor2poche c1e0bd4
Add run_ifunc switch for vm_load_elf and apply_reloc_x86
kStor2poche 8330418
Switch to f-strings and tiny optimization
kStor2poche 112ad40
More accurate reloc addend and parsing of Rela relocation entries
kStor2poche 7e28ed9
Enforce base address=0 when loading non-PIE ELFs
kStor2poche 7297c8d
Cleanup ifunc reloc implementation
kStor2poche 6af66af
Better ifunc example and derived test
kStor2poche 187602d
Merge branch 'cea-sec:master' into apply-relocs-for-ifuncs
kStor2poche 69b1cb9
Improved interface for ifunc resolving and adapted example
kStor2poche 63bdc0a
Expose options for apply_reloc_x86's ifunc_jitter through a RelocOpti…
kStor2poche 2d07c11
Allow default mapping of ifunc_jitter stack after loaded ELF if in ad…
kStor2poche 545fb49
Fix example run_ifuncs and some polish
kStor2poche File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| import logging | ||
| from argparse import ArgumentParser | ||
|
|
||
| from miasm.analysis.binary import Container, ContainerELF | ||
| from miasm.analysis.machine import Machine | ||
| from miasm.core.locationdb import LocationDB | ||
| from miasm.jitter.loader.elf import RelocOptions, get_ifuncs_x86, apply_ifunc_x86 | ||
| from miasm.loader.elf import ET_EXEC | ||
|
|
||
|
|
||
| def code_sentinelle(jitter): | ||
| jitter.running = False | ||
| jitter.pc = 0 | ||
| return False | ||
|
|
||
| def prepare(run_ifuncs: bool): | ||
| loc_db = LocationDB() | ||
|
|
||
| myjit = Machine("x86_64").jitter(loc_db, args.jitter) | ||
| myjit.init_stack() | ||
|
|
||
| reloc_options = RelocOptions(run_ifuncs=run_ifuncs, ifunc_jitter_engine=args.jitter) | ||
|
|
||
| base_addr = 0x400000 | ||
| with open(args.filename, 'rb') as f: | ||
| elf: ContainerELF = Container.from_stream(f, addr=base_addr, loc_db=loc_db, vm=myjit.vm, apply_reloc=True, reloc_options=reloc_options) | ||
| assert isinstance(elf, ContainerELF) | ||
| if elf.executable.Ehdr.type == ET_EXEC: | ||
| # static executables can't be rebased | ||
| base_addr = 0 | ||
|
|
||
| return (base_addr, loc_db, elf, myjit) | ||
|
|
||
| def launch(jitter) -> str: | ||
| jitter.push_uint64_t(0x1337beef) | ||
| jitter.add_breakpoint(0x1337beef, code_sentinelle) | ||
|
|
||
| if args.verbose >= 2: | ||
| jitter.set_trace_log(True, True) | ||
| run_at = jitter.lifter.loc_db.get_name_offset("wrapper") | ||
| assert run_at is not None | ||
| jitter.run(run_at) | ||
| return jitter.get_c_str(jitter.cpu.RAX) | ||
|
|
||
| if __name__ == "__main__": | ||
| parser = ArgumentParser(description="x86 ELF ifunc relocs (e.g. `python resolve_ifunc.py -j llvm -vv ../samples/ifunc`)") | ||
| parser.add_argument("filename", help="ELF to apply (ifunc) relocs to") | ||
| parser.add_argument("-j", "--jitter", | ||
| help="Jitter engine (default is 'gcc')", | ||
| default="gcc") | ||
| parser.add_argument("--verbose", "-v", action="count", | ||
| help="Verbose mode (-v activates debug logging, -vv adds jitter tracing)", | ||
| default=0) | ||
| args = parser.parse_args() | ||
|
|
||
| # setup logging | ||
| log = logging.getLogger(__name__) | ||
| ch = logging.StreamHandler() | ||
| formatter = logging.Formatter("[%(levelname)-8s]: %(message)s") | ||
| ch.setFormatter(formatter) | ||
| if args.verbose >= 1: | ||
| log.setLevel(logging.DEBUG) | ||
| else: | ||
| log.setLevel(logging.WARNING) | ||
| log.addHandler(ch) | ||
|
|
||
|
|
||
| # 1. Run ifunc with default resolver behavior | ||
|
|
||
| _, _, _, jitter = prepare(run_ifuncs=True) | ||
| res1 = launch(jitter) | ||
| log.info(f"Default ifunc resolving returned {res1}.") | ||
| assert res1 == "zglorg" | ||
|
|
||
|
|
||
| # 2. Run ifunc with alternate resolver behavior | ||
|
|
||
| base_addr, loc_db, elf, jitter = prepare(run_ifuncs=False) | ||
|
|
||
| # The ifunc resolver in ../samples/ifunc uses .bss variable `use_func2` | ||
| # to know whether to redirect to `func1` or `func2` when we execute `func` | ||
| # which we proceed to set to `true` | ||
| # | ||
| # Note that we could've created a separate jitter to run ifuncs on (5th arg | ||
| # of apply_ifunc) if we wanted to keep our bss clean for the regular jitter | ||
| # We also could've prepared a special jitter to pass in RelocOptions to | ||
| # achieve the same goal | ||
| use_func2_addr = loc_db.get_name_offset("use_func2") | ||
|
|
||
| if use_func2_addr is None: | ||
| raise ValueError("symbol use_func2 was not found") | ||
| if not jitter.vm.is_mapped(use_func2_addr + base_addr, 1): | ||
| raise ValueError(f"use_func2 exists but doesn't seem to be loaded inside our vm ({use_func2_addr+base_addr=:x})\n{jitter.vm}") | ||
|
|
||
| jitter.vm.set_mem(use_func2_addr + base_addr, b'\x01') | ||
| log.info(f"Set symbol use_func2 (@0x{use_func2_addr + base_addr:x}) to 1") | ||
|
|
||
| # we can then run our ifunc resolver | ||
| ifunc_resolvers = get_ifuncs_x86(elf.executable, base_addr, with_syms=False) | ||
| for reloc, ifunc_resolver in ifunc_resolvers: | ||
| apply_ifunc_x86(reloc, ifunc_resolver, elf.executable, jitter) | ||
|
|
||
| res2 = launch(jitter) | ||
| log.info(f"Forcing ifunc resolving to func2 returned {res2}.") | ||
| assert res2 == "bloups" | ||
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| // Compile with gcc -fno-stack-protector -o ifunc ifunc.c | ||
|
|
||
| #include <stdbool.h> | ||
| #include <stdint.h> | ||
|
|
||
| const char *func_1() { | ||
| return "zglorg"; | ||
| } | ||
| const char *func_2() { | ||
| return "bloups"; | ||
| } | ||
|
|
||
| static bool use_func2; | ||
|
|
||
| char *func() __attribute__((ifunc("resolve_func"))); | ||
|
|
||
| // Function pointer type matching `func` prototype | ||
| typedef const char *(*func_type)(); | ||
|
|
||
| static func_type resolve_func() { | ||
| if (use_func2) { | ||
| return func_2; | ||
| } | ||
| return func_1; | ||
| } | ||
|
|
||
| char *wrapper() { | ||
| return func(); | ||
| } | ||
|
|
||
| int main() { | ||
| wrapper(); | ||
| return 0; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe clearer in the example if regrouped with the original definition of the base address ? (line 21)
Maybe it can be passed as an argument and put the if statement in the main ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm good with the first change but I'm not sure about the second since it would lead to unnecessarily duplicated code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fair