Skip to content

Instantly share code, notes, and snippets.

@dreness
Forked from pudquick/symfind.py
Last active September 13, 2017 20:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dreness/390ce576ac754f07b4f8c0616381fd7c to your computer and use it in GitHub Desktop.
Save dreness/390ce576ac754f07b4f8c0616381fd7c to your computer and use it in GitHub Desktop.
Automatic symbol definition discovery for OS X binaries and their linked shared libraries
#!/usr/bin/python
"""Usage: symfind BINARY_PATH SEARCH_STR
symfind automates the usage of otool and nm to attempt to find out which
binary a symbol is defined in that's used within BINARY_PATH's code.
"""
import subprocess, os.path, sys, getopt
def find_symbol(binary_path, symbol_str):
print "At path: {}".format(binary_path)
# Check the binary itself first
symbols_raw = subprocess.check_output(['/usr/bin/nm', '-a', binary_path])
symbols = [x for x in symbols_raw.splitlines() if not ' u ' in x.lower()]
symbols = [x for x in symbols if symbol_str.lower() in x.lower()]
if symbols:
print "\nFOUND:", binary_path
for x in symbols:
print x
# Root linked images
root_images_raw = subprocess.check_output(['/usr/bin/otool', '-L', binary_path])
root_images = [x for x in root_images_raw.splitlines() if x[0] == '\t']
root_images = [x for x in root_images if ' (compatibility version' in x]
root_images = [x.split('\t',1)[-1].split(' (compatibility version', 1)[0] for x in root_images]
for image in root_images:
# normalize @rpath and @executable_path linkage to an absolute path
if "@rpath" in image:
rPathPrefix = binary_path.partition(image.split("/")[1])[0]
image = image.replace("@rpath", rPathPrefix)
if "@executable_path" in image:
image = image.replace("@executable_path", os.path.dirname(binary_path))
symbols_raw = subprocess.check_output(['/usr/bin/nm', '-a', image])
symbols = [x for x in symbols_raw.splitlines() if not ' u ' in x.lower()]
symbols = [x for x in symbols if symbol_str.lower() in x.lower()]
if symbols:
print "\nFOUND:", image
for x in symbols:
print x
def usage():
print __doc__
sys.exit()
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
except getopt.GetoptError, err:
print str(err)
usage()
for o, a in opts:
usage()
if len(args) != 2:
usage()
binary_path = args[0]
symbol_str = args[1]
if not os.path.exists(binary_path):
usage()
find_symbol(binary_path, symbol_str)
sys.exit(0)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment