def test_dump(self): elf = ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB, 183, ['a'], ['b'], ['libc.so', 'libm.so'], {'hello', 'world'}, {'d', 'e'}) f = StringIO() elf.dump(f) actual_output = f.getvalue() self.assertEqual( 'EI_CLASS\t32\n' 'EI_DATA\t\tLittle-Endian\n' 'E_MACHINE\tEM_AARCH64\n' 'FILE_SIZE\t0\n' 'RO_SEG_FILE_SIZE\t0\n' 'RO_SEG_MEM_SIZE\t0\n' 'RW_SEG_FILE_SIZE\t0\n' 'RW_SEG_MEM_SIZE\t0\n' 'DT_RPATH\ta\n' 'DT_RUNPATH\tb\n' 'DT_NEEDED\tlibc.so\n' 'DT_NEEDED\tlibm.so\n' 'EXP_SYMBOL\thello\n' 'EXP_SYMBOL\tworld\n' 'IMP_SYMBOL\td\n' 'IMP_SYMBOL\te\n', actual_output)
def test_dump(self): elf = ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB, 183, ['a'], ['b'], ['libc.so', 'libm.so'], {'hello', 'world'}, {'d', 'e'}) f = StringIO() elf.dump(f) actual_output = f.getvalue() self.assertEqual('EI_CLASS\t32\n' 'EI_DATA\t\tLittle-Endian\n' 'E_MACHINE\tEM_AARCH64\n' 'FILE_SIZE\t0\n' 'RO_SEG_FILE_SIZE\t0\n' 'RO_SEG_MEM_SIZE\t0\n' 'RW_SEG_FILE_SIZE\t0\n' 'RW_SEG_MEM_SIZE\t0\n' 'DT_RPATH\ta\n' 'DT_RUNPATH\tb\n' 'DT_NEEDED\tlibc.so\n' 'DT_NEEDED\tlibm.so\n' 'EXP_SYMBOL\thello\n' 'EXP_SYMBOL\tworld\n' 'IMP_SYMBOL\td\n' 'IMP_SYMBOL\te\n', actual_output)
def test_dt_rpath_runpath(self): elf = ELF() self.assertEqual(None, elf.dt_rpath) self.assertEqual(None, elf.dt_runpath) elf = ELF(None, None, 0, 'a', 'b') self.assertEqual('a', elf.dt_rpath) self.assertEqual('b', elf.dt_runpath)
def test_dt_rpath_runpath(self): elf = ELF() self.assertEqual([], elf.dt_rpath) self.assertEqual([], elf.dt_runpath) elf = ELF(None, None, 0, ['a'], ['b']) self.assertEqual(['a'], elf.dt_rpath) self.assertEqual(['b'], elf.dt_runpath)
def test_repr(self): elf = ELF() self.assertEqual(elf, eval(repr(elf))) elf = ELF(ei_class=ELF.ELFCLASS32, ei_data=ELF.ELFDATA2LSB, e_machine=183, dt_rpath=['a'], dt_runpath=['b'], dt_needed=['c', 'd'], exported_symbols={'e', 'f', 'g'}) self.assertEqual(elf, eval(repr(elf)))
def test_dump_exported_symbols(self): elf = ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB, 183, 'a', 'b', ['libc.so', 'libm.so'], ['hello', 'world']) with StringIO() as f: elf.dump_exported_symbols(f) actual_output = f.getvalue() self.assertEqual('hello\nworld\n', actual_output)
def test_class_name(self): self.assertEqual('None', ELF().elf_class_name) elf = ELF(ELF.ELFCLASS32) self.assertEqual('32', elf.elf_class_name) self.assertTrue(elf.is_32bit) self.assertFalse(elf.is_64bit) elf = ELF(ELF.ELFCLASS64) self.assertEqual('64', elf.elf_class_name) self.assertFalse(elf.is_32bit) self.assertTrue(elf.is_64bit)
def test_rewrite_apex_modules(self): graph = ELFLinker() libfoo = graph.add_lib(PT_SYSTEM, '/system/apex/foo/lib/libfoo.so', ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB)) libbar = graph.add_lib(PT_SYSTEM, '/system/apex/bar/lib/libbar.so', ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB)) graph.rewrite_apex_modules() self.assertEqual(libfoo.path, '/apex/foo/lib/libfoo.so') self.assertEqual(libbar.path, '/apex/bar/lib/libbar.so')
def test_lib_deps(self): elf = ELF(dt_needed=['libnativehelper.so']) self.assertTrue(elf.is_jni_lib()) elf = ELF(dt_needed=['libandroid_runtime.so']) self.assertTrue(elf.is_jni_lib()) elf = ELF(dt_needed=['libc.so']) self.assertFalse(elf.is_jni_lib())
def test_link_apex_modules(self): graph = ELFLinker() libfoo = graph.add_lib(PT_SYSTEM, '/system/apex/foo/lib/libfoo.so', ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB)) libbar = graph.add_lib( PT_SYSTEM, '/system/lib/libbar.so', ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB, dt_needed=['libfoo.so'])) graph.rewrite_apex_modules() graph.resolve_deps() self.assertIn(libfoo, libbar.deps_all)
def test_link_apex_bionic(self): graph = ELFLinker() libc = graph.add_lib( PT_SYSTEM, '/system/apex/com.android.runtime/lib/bionic/libc.so', ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB)) libbar = graph.add_lib( PT_SYSTEM, '/system/lib/libbar.so', ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB, dt_needed=['libc.so'])) graph.rewrite_apex_modules() graph.resolve_deps() self.assertIn(libc, libbar.deps_all)
def add_lib(self, partition, klass, name, dt_needed=[], exported_symbols=set(), imported_symbols=set(), extra_dir=None): """Create and add a shared library to ELFLinker.""" lib_dir = os.path.join('/', self._PARTITION_NAMES[partition], self._LIB_DIRS[klass]) if extra_dir: lib_dir = os.path.join(lib_dir, extra_dir) path = os.path.join(lib_dir, name + '.so') elf = ELF(klass, ELF.ELFDATA2LSB, dt_needed=dt_needed, exported_symbols=exported_symbols, imported_symbols=imported_symbols) node = self.graph.add_lib(partition, path, elf) setattr(self, name + '_' + elf.elf_class_name, node) return node
def test_parse_dump_file(self): data = ('EI_CLASS\t64\n' 'EI_DATA\t\tLittle-Endian\n' 'E_MACHINE\tEM_AARCH64\n' 'FILE_SIZE\t90\n' 'RO_SEG_FILE_SIZE\t18\n' 'RO_SEG_MEM_SIZE\t24\n' 'RW_SEG_FILE_SIZE\t42\n' 'RW_SEG_MEM_SIZE\t81\n' 'DT_RPATH\trpath_1\n' 'DT_RPATH\trpath_2\n' 'DT_RUNPATH\trunpath_1\n' 'DT_RUNPATH\trunpath_2\n' 'DT_NEEDED\tlibc.so\n' 'DT_NEEDED\tlibm.so\n' 'EXP_SYMBOL\texported_1\n' 'EXP_SYMBOL\texported_2\n' 'IMP_SYMBOL\timported_1\n' 'IMP_SYMBOL\timported_2\n') def check_parse_dump_file_result(res): self.assertEqual(ELF.ELFCLASS64, res.ei_class) self.assertEqual(ELF.ELFDATA2LSB, res.ei_data) self.assertEqual(183, res.e_machine) self.assertEqual(90, res.file_size) self.assertEqual(18, res.ro_seg_file_size) self.assertEqual(24, res.ro_seg_mem_size) self.assertEqual(42, res.rw_seg_file_size) self.assertEqual(81, res.rw_seg_mem_size) self.assertEqual(['rpath_1', 'rpath_2'], res.dt_rpath) self.assertEqual(['runpath_1', 'runpath_2'], res.dt_runpath) self.assertEqual(['libc.so', 'libm.so'], res.dt_needed) self.assertSetEqual({'exported_1', 'exported_2'}, res.exported_symbols) self.assertSetEqual({'imported_1', 'imported_2'}, res.imported_symbols) # Parse ELF dump from the string buffer. check_parse_dump_file_result(ELF.load_dumps(data)) # Parse ELF dump from the given file path. with tempfile.NamedTemporaryFile('w+') as f: f.write(data) f.flush() f.seek(0) check_parse_dump_file_result(ELF.load_dump(f.name))
def test_dump(self): elf = ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB, 183, 'a', 'b', ['libc.so', 'libm.so'], ['hello', 'world']) with StringIO() as f: elf.dump(f) actual_output = f.getvalue() self.assertEqual( 'EI_CLASS\t32\n' 'EI_DATA\t\tLittle-Endian\n' 'E_MACHINE\tEM_AARCH64\n' 'DT_RPATH\ta\n' 'DT_RUNPATH\tb\n' 'DT_NEEDED\tlibc.so\n' 'DT_NEEDED\tlibm.so\n' 'SYMBOL\t\thello\n' 'SYMBOL\t\tworld\n', actual_output)
def test_get_e_machine_from_name(self): self.assertEqual(0, ELF.get_e_machine_from_name('EM_NONE')) self.assertEqual(3, ELF.get_e_machine_from_name('EM_386')) self.assertEqual(8, ELF.get_e_machine_from_name('EM_MIPS')) self.assertEqual(40, ELF.get_e_machine_from_name('EM_ARM')) self.assertEqual(62, ELF.get_e_machine_from_name('EM_X86_64')) self.assertEqual(183, ELF.get_e_machine_from_name('EM_AARCH64'))
def test_machine_name(self): self.assertEqual('EM_NONE', ELF(e_machine=0).elf_machine_name) self.assertEqual('EM_386', ELF(e_machine=3).elf_machine_name) self.assertEqual('EM_MIPS', ELF(e_machine=8).elf_machine_name) self.assertEqual('EM_ARM', ELF(e_machine=40).elf_machine_name) self.assertEqual('EM_X86_64', ELF(e_machine=62).elf_machine_name) self.assertEqual('EM_AARCH64', ELF(e_machine=183).elf_machine_name)
def add_lib(self, partition, klass, name, dt_needed, exported_symbols, imported_symbols): """Create and add a shared library to ELFLinker.""" elf = ELF(klass, ELF.ELFDATA2LSB, dt_needed=dt_needed, exported_symbols=exported_symbols, imported_symbols=imported_symbols) setattr(self, 'elf' + elf.elf_class_name + '_' + name, elf) path = os.path.join('/', self._PARTITION_NAMES[partition], self._LIB_DIRS[klass], name + '.so') self.graph.add(partition, path, elf)
def test_get_ei_class_from_name(self): self.assertEqual(ELF.ELFCLASS32, ELF.get_ei_class_from_name('32')) self.assertEqual(ELF.ELFCLASS64, ELF.get_ei_class_from_name('64'))
def test_endianness(self): self.assertEqual('None', ELF().elf_data_name) self.assertEqual('Little-Endian', ELF(None, ELF.ELFDATA2LSB).elf_data_name) self.assertEqual('Big-Endian', ELF(None, ELF.ELFDATA2MSB).elf_data_name)
def setUp(self): # 32-bit libraries on the system partition. self.elf_libdl_32 = ELF( ELF.ELFCLASS32, ELF.ELFDATA2LSB, exported_symbols=['dlclose', 'dlopen', 'dlsym']) self.elf_libm_32 = ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB, exported_symbols=['cos', 'sin']) self.elf_libc_32 = ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB, dt_needed=['libdl.so', 'libm.so'], exported_symbols=['fclose', 'fopen', 'fread']) self.elf_libRS_32 = ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB, dt_needed=['libdl.so'], exported_symbols=['rsContextCreate']) self.elf_libcutils_32 = ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB, dt_needed=['libc.so', 'libdl.so']) # 64-bit libraries on the system partition. self.elf_libdl_64 = ELF( ELF.ELFCLASS64, ELF.ELFDATA2LSB, exported_symbols=['dlclose', 'dlopen', 'dlsym']) self.elf_libm_64 = ELF(ELF.ELFCLASS64, ELF.ELFDATA2LSB, exported_symbols=['cos', 'sin']) self.elf_libc_64 = ELF(ELF.ELFCLASS64, ELF.ELFDATA2LSB, dt_needed=['libdl.so', 'libm.so'], exported_symbols=['fclose', 'fopen', 'fread']) self.elf_libRS_64 = ELF(ELF.ELFCLASS64, ELF.ELFDATA2LSB, dt_needed=['libdl.so'], exported_symbols=['rsContextCreate']) self.elf_libcutils_64 = ELF(ELF.ELFCLASS64, ELF.ELFDATA2LSB, dt_needed=['libc.so', 'libdl.so']) # 32-bit libraries on the vendor partition. self.elf_libEGL_32 = ELF( ELF.ELFCLASS32, ELF.ELFDATA2LSB, dt_needed=['libc.so', 'libcutils.so', 'libdl.so'], exported_symbols=['eglGetDisplay']) # 64-bit libraries on the vendor partition. self.elf_libEGL_64 = ELF( ELF.ELFCLASS64, ELF.ELFDATA2LSB, dt_needed=['libc.so', 'libcutils.so', 'libdl.so'], exported_symbols=['eglGetDisplay']) # Build the linker. g = Graph() g.add(PT_SYSTEM, '/system/lib/libc.so', self.elf_libc_32) g.add(PT_SYSTEM, '/system/lib/libcutils.so', self.elf_libcutils_32) g.add(PT_SYSTEM, '/system/lib/libdl.so', self.elf_libdl_32) g.add(PT_SYSTEM, '/system/lib/libm.so', self.elf_libm_32) g.add(PT_SYSTEM, '/system/lib/libRS.so', self.elf_libRS_32) g.add(PT_SYSTEM, '/system/lib64/libc.so', self.elf_libc_64) g.add(PT_SYSTEM, '/system/lib64/libcutils.so', self.elf_libcutils_64) g.add(PT_SYSTEM, '/system/lib64/libdl.so', self.elf_libdl_64) g.add(PT_SYSTEM, '/system/lib64/libm.so', self.elf_libm_64) g.add(PT_SYSTEM, '/system/lib64/libRS.so', self.elf_libRS_64) g.add(PT_VENDOR, '/vendor/lib/libEGL.so', self.elf_libEGL_32) g.add(PT_VENDOR, '/vendor/lib64/libEGL.so', self.elf_libEGL_64) g.resolve_deps() self.graph = g
def test_get_ei_data_from_name(self): self.assertEqual(ELF.ELFDATA2LSB, ELF.get_ei_data_from_name('Little-Endian')) self.assertEqual(ELF.ELFDATA2MSB, ELF.get_ei_data_from_name('Big-Endian'))
def test_jni_symbols(self): elf = ELF(imported_symbols={'JNI_CreateJavaVM'}) self.assertTrue(elf.is_jni_lib()) elf = ELF(exported_symbols={'JNI_CreateJavaVM'}) self.assertTrue(elf.is_jni_lib()) elf = ELF(imported_symbols={'Java_com_example_Example_test'}) self.assertTrue(elf.is_jni_lib()) elf = ELF(exported_symbols={'Java_com_example_Example_test'}) self.assertTrue(elf.is_jni_lib()) elf = ELF(imported_symbols={'printf'}) self.assertFalse(elf.is_jni_lib()) elf = ELF(exported_symbols={'printf'}) self.assertFalse(elf.is_jni_lib())