Created
April 3, 2016 09:20
-
-
Save michalbednarski/c225c968765d22affdd88f224d5ff266 to your computer and use it in GitHub Desktop.
Find conflicts with PRoot loader, termux/termux-packages#189
This file contains 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
from elftools.elf.elffile import ELFFile | |
# Expected architecture for ELFs | |
EXPECTED_MACHINE = "EM_ARM" | |
# Paths | |
LOADER_FILE = "loader" # point to "~/termux/proot/src/src/loader/loader" | |
LINKER_FILE = "linker" # copy from "/system/bin/linker" possibly check with multiple devices | |
# TODO: glob + try-except NotInterestingElfException | |
EXEC_FILES = [ | |
"/data/data/com.termux/files/usr/bin/php", | |
"/data/data/com.termux/files/usr/libexec/gcc/arm-linux-androideabi/5.3.0/cc1plus" | |
] | |
# From arch.h | |
EXEC_PIC_ADDRESS = 0x0f000000 | |
INTERP_PIC_ADDRESS = 0x1f000000 | |
# From execve/enter.c | |
PAGE_SIZE = 4096 | |
PAGE_MASK = ~(PAGE_SIZE - 1) | |
class NotInterestingElfException(Exception): | |
""" | |
Exception raised by getElfPages when ELF file appears to be not interesting for us | |
(Not for ARM or not executable) | |
""" | |
pass | |
def getElfPages(path, picOffset): | |
""" | |
Get used pages for given ELF file | |
""" | |
usedPages = set() | |
with open(path, "rb") as fi: | |
elf = ELFFile(fi) | |
if elf.header["e_machine"] != EXPECTED_MACHINE: | |
raise NotInterestingElfException("Not matching e_machine %s in %s" % (elf.header["e_machine"], path)) | |
# Check if this is PIC executable | |
# (This is required for use with Android linker anyway, | |
# but static executables can be non-PIC) | |
if elf.header["e_type"] == "ET_DYN": | |
if picOffset < 0: | |
raise Exception("PIC executable but no picOffset specified for %s" % path) | |
offset = picOffset | |
elif elf.header["e_type"] == "ET_EXEC": | |
offset = 0 | |
else: | |
raise NotInterestingElfException("Unexpected e_type %s in %s" % (elf.header["e_type"], path)) | |
# Iterate over segments | |
for seg in elf.iter_segments(): | |
segHeader = seg.header | |
if segHeader["p_type"] == "PT_LOAD": | |
# print(segHeader) | |
assert segHeader["p_memsz"] >= segHeader["p_filesz"] | |
start_address = segHeader["p_vaddr"] & PAGE_MASK | |
end_address = (segHeader["p_vaddr"] + segHeader["p_memsz"] + PAGE_SIZE) & PAGE_MASK | |
start_address += offset | |
end_address += offset | |
usedPages |= set(range(start_address / PAGE_SIZE, end_address / PAGE_SIZE)) | |
return frozenset(usedPages) | |
if __name__ == "__main__": | |
linkerPages = getElfPages(LINKER_FILE, INTERP_PIC_ADDRESS) | |
loaderPages = getElfPages(LOADER_FILE, -1) # Must be non-PIC | |
if not loaderPages.isdisjoint(linkerPages): | |
print("Loader overlaps linker") | |
for execFile in EXEC_FILES: | |
execPages = getElfPages(execFile, EXEC_PIC_ADDRESS) | |
if not loaderPages.isdisjoint(execPages): | |
print("Loader overlaps executable in " + execFile) | |
if not linkerPages.isdisjoint(execPages): | |
print("Linker overlaps executable in " + execFile) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment