mirror of https://github.com/pwndbg/pwndbg.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
64 lines
2.0 KiB
Python
64 lines
2.0 KiB
Python
#!/usr/bin/env python
|
|
# Original file copied from https://github.com/3noch/nix-bundle-exe
|
|
# But it was modified/patched for pwndbg usecase!
|
|
|
|
# Prints resolved paths to needed libraries for an ELF executable.
|
|
# ldd also does this, but it segfaults in some odd scenarios so we avoid it.
|
|
import sys
|
|
import os
|
|
import subprocess
|
|
from typing import Any, Iterable, List
|
|
|
|
|
|
def eprint(msg: Any):
|
|
print(msg, file=sys.stderr)
|
|
|
|
|
|
def run(args: List[str]) -> str:
|
|
result = subprocess.run(args, capture_output=True)
|
|
if result.returncode != 0:
|
|
eprint(result.stderr)
|
|
eprint("Command failed with return code {}: {}".format(result.returncode, args))
|
|
sys.exit(result.returncode)
|
|
return result.stdout.decode("utf-8")
|
|
|
|
|
|
def stripped_strs(strs: Iterable[str]) -> Iterable[str]:
|
|
return (cleaned for x in strs for cleaned in [x.strip()] if cleaned != "")
|
|
|
|
|
|
def get_rpaths(exe: str) -> Iterable[str]:
|
|
return stripped_strs(run(["patchelf", "--print-rpath", exe]).split(":"))
|
|
|
|
|
|
def resolve_origin(origin: str, paths: Iterable[str]) -> Iterable[str]:
|
|
return (path.replace("$ORIGIN", origin) for path in paths)
|
|
|
|
|
|
def get_needed(exe: str) -> Iterable[str]:
|
|
return stripped_strs(run(["patchelf", "--print-needed", exe]).splitlines())
|
|
|
|
|
|
def resolve_paths(needed: Iterable[str], rpaths: List[str]) -> Iterable[str]:
|
|
existing_paths = lambda lib, paths: (
|
|
abs_path for path in paths for abs_path in [os.path.join(path, lib)]
|
|
if os.path.exists(abs_path)
|
|
)
|
|
return (
|
|
found if found is not None else eprint("Warning: can't find {} in {}".format(lib, rpaths))
|
|
for lib in needed for found in [next(existing_paths(lib, rpaths), None)]
|
|
)
|
|
|
|
|
|
def main(exe: str):
|
|
dirname = os.path.dirname(exe)
|
|
rpaths_raw = list(get_rpaths(exe))
|
|
rpaths_raw = [dirname] if rpaths_raw == [] else rpaths_raw
|
|
rpaths = list(resolve_origin(dirname, rpaths_raw))
|
|
for path in (x for x in resolve_paths(get_needed(exe), rpaths) if x is not None):
|
|
print(path)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main(*sys.argv[1:])
|