├── .gitignore ├── DextractorException.py ├── Dextripador.py ├── FileFormats ├── DEX.py ├── OAT.py └── VDEX.py ├── FileWork.py ├── LICENSE ├── README.md ├── __init__.py ├── elfparser_e ├── Makefile ├── headers │ ├── elf_generic_types.h │ ├── elf_parser.h │ ├── file_management.h │ └── memory_management.h ├── main.c ├── python_binding │ └── elf.py └── src │ ├── elf_data_access.c │ ├── elf_parser.c │ ├── file_management.c │ └── memory_management.c └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # JSON files 10 | *.json 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | pip-wheel-metadata/ 27 | share/python-wheels/ 28 | *.egg-info/ 29 | .installed.cfg 30 | *.egg 31 | MANIFEST 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | 43 | # Unit test / coverage reports 44 | htmlcov/ 45 | .tox/ 46 | .nox/ 47 | .coverage 48 | .coverage.* 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | *.cover 53 | *.py,cover 54 | .hypothesis/ 55 | .pytest_cache/ 56 | cover/ 57 | 58 | # Translations 59 | *.mo 60 | *.pot 61 | 62 | # Django stuff: 63 | *.log 64 | local_settings.py 65 | db.sqlite3 66 | db.sqlite3-journal 67 | 68 | # Flask stuff: 69 | instance/ 70 | .webassets-cache 71 | 72 | # Scrapy stuff: 73 | .scrapy 74 | 75 | # Sphinx documentation 76 | docs/_build/ 77 | 78 | # PyBuilder 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | config.ini 88 | # pyenv 89 | # For a library or package, you might want to ignore these files since the code is 90 | # intended to run in multiple environments; otherwise, check them in: 91 | # .python-version 92 | 93 | # pipenv 94 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 95 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 96 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 97 | # install all needed dependencies. 98 | #Pipfile.lock 99 | 100 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 101 | __pypackages__/ 102 | 103 | # Celery stuff 104 | celerybeat-schedule 105 | celerybeat.pid 106 | 107 | # SageMath parsed files 108 | *.sage.py 109 | 110 | # Environments 111 | .env 112 | .venv 113 | env/ 114 | venv/ 115 | ENV/ 116 | env.bak/ 117 | venv.bak/ 118 | 119 | # Spyder project settings 120 | .spyderproject 121 | .spyproject 122 | 123 | # Rope project settings 124 | .ropeproject 125 | 126 | # mkdocs documentation 127 | /site 128 | 129 | # mypy 130 | .mypy_cache/ 131 | .dmypy.json 132 | dmypy.json 133 | 134 | # Pyre type checker 135 | .pyre/ 136 | 137 | # pytype static type analyzer 138 | .pytype/ 139 | 140 | # Cython debug symbols 141 | cython_debug/ 142 | 143 | # configuration file -- paths are machine dependent 144 | config.ini 145 | 146 | # PDF files 147 | *.pdf 148 | 149 | # visual studio code 150 | .vscode/ 151 | 152 | # elfparser 153 | obj-files/ 154 | out/ 155 | 156 | # test folder with apks 157 | test/ 158 | -------------------------------------------------------------------------------- /DextractorException.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | #-*- coding: utf-8 -*- 3 | 4 | ###################################################### 5 | # Dextripador 6 | # File: DextractorException.py 7 | # Version: 0.7 8 | ###################################################### 9 | 10 | class IncorrectMagicException(Exception): 11 | pass 12 | 13 | class OffsetOutOfBoundException(Exception): 14 | pass 15 | 16 | class OatdataNotFoundException(Exception): 17 | pass 18 | 19 | class DexOutOfFoundException(Exception): 20 | pass 21 | 22 | class NotElfFileException(Exception): 23 | pass 24 | 25 | class NotOatFileException(Exception): 26 | pass 27 | 28 | class UnsupportedOatVersion(Exception): 29 | pass 30 | 31 | class OATClassHeaderIncorrectStatusException(Exception): 32 | pass 33 | 34 | class OATClassHeaderIncorrectTypeException(Exception): 35 | pass 36 | 37 | class DecompressionException(Exception): 38 | pass 39 | -------------------------------------------------------------------------------- /Dextripador.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | ###################################################### 5 | # Dextripador 6 | # File: Dextripador.py 7 | # Version: 0.7 8 | ###################################################### 9 | 10 | import os 11 | import sys 12 | import ntpath 13 | import argparse 14 | import zlib 15 | import tempfile 16 | import lzma 17 | import gzip 18 | 19 | USE_LIEF = False 20 | USE_OWN_PARSER = False 21 | 22 | try: 23 | import lief.ELF 24 | USE_LIEF = True 25 | except: 26 | from elfparser_e.python_binding.elf import * 27 | USE_OWN_PARSER = True 28 | 29 | 30 | from FileWork import * 31 | from utils import * 32 | from DextractorException import * 33 | from FileFormats.OAT import OATHeader 34 | from struct import pack 35 | 36 | 37 | class Extractor(): 38 | DYNAMIC_SYMBOL_NAME = "oatdata" 39 | 40 | def __init__(self, path_to_odex=""): 41 | self.path_to_odex = path_to_odex 42 | self.oatdata_offset = None 43 | self.oatdata_size = None 44 | self.oatdata = None 45 | self.oat_file = None 46 | self.number_of_dex_files = 0 47 | self.number_of_optimized_methods = 0 48 | self.oat_file = None 49 | self.not_an_elf = False 50 | 51 | # Handle compressed odex files 52 | if self.path_to_odex.endswith('.xz'): 53 | fd, fpath = tempfile.mkstemp(suffix='.odex', prefix='dextripador_', dir='/tmp') 54 | with lzma.open(self.path_to_odex, 'rb') as odexfile: 55 | written = os.write(fd, odexfile.read()) 56 | if written == 0: 57 | raise DecompressionException('Cannot decompress file {}'.format(self.path_to_odex)) 58 | self.path_to_odex = fpath 59 | elif self.path_to_odex.endswith('.gz'): 60 | fd, fpath = tempfile.mkstemp(suffix='.odex', prefix='dextripador_', dir='/tmp') 61 | with gzip.open(self.path_to_odex, 'rb') as odexfile: 62 | written = os.write(fd, odexfile.read()) 63 | if written == 0: 64 | raise DecompressionException('Cannot decompress file {}'.format(self.path_to_odex)) 65 | self.path_to_odex = fpath 66 | 67 | 68 | def __parse_elf(self, path_to_elf): 69 | Printer.verbose1("Analyzing file %s searching oatdata symbol" % (path_to_elf)) 70 | 71 | Printer.verbose2("Checking existence of the file %s" % (path_to_elf)) 72 | if not os.path.exists(path_to_elf): 73 | Printer.verbose2("File %s does not exist" % (path_to_elf)) 74 | raise FileNotFoundError("File %s doesn't exist or is not correct" % (path_to_elf)) 75 | 76 | if USE_LIEF: 77 | elf_binary = lief.ELF.parse(path_to_elf) 78 | 79 | if elf_binary is None: 80 | raise NotElfFileException("Provided file %s is not an ELF" % (path_to_elf)) 81 | 82 | for symbol in list(elf_binary.symbols): 83 | if symbol.name == Extractor.DYNAMIC_SYMBOL_NAME: 84 | Printer.verbose2("%s Found in %s" % (Extractor.DYNAMIC_SYMBOL_NAME, path_to_elf)) 85 | self.oatdata_offset = symbol.value 86 | self.oatdata_size = symbol.size 87 | break 88 | elif USE_OWN_PARSER: 89 | elf_binary = Elf(path_to_elf) 90 | 91 | if not elf_binary.is_elf(): 92 | raise NotElfFileException("Provided file %s is not an ELF" % (path_to_elf)) 93 | 94 | for symbol in elf_binary.elf_sym: 95 | if symbol.st_name == Extractor.DYNAMIC_SYMBOL_NAME: 96 | Printer.verbose2("%s Found in %s" % (Extractor.DYNAMIC_SYMBOL_NAME, path_to_elf)) 97 | self.oatdata_offset = symbol.st_value 98 | self.oatdata_size = symbol.st_size 99 | break 100 | 101 | if self.oatdata_offset is None or self.oatdata_size is None: 102 | raise OatdataNotFoundException("Error, oatdata symbol not found in ELF (maybe not odex file)") 103 | 104 | Printer.verbose1("Oatdata offset %x - Oatdata size: %x" % (self.oatdata_offset, self.oatdata_size)) 105 | 106 | def __parse_oat(self, path_to_oat): 107 | Printer.verbose1("Analyzing file %s searching oatdata header" % (path_to_oat)) 108 | 109 | if not os.path.exists(path_to_oat): 110 | Printer.verbose2("File %s does not exist" % (path_to_oat)) 111 | raise FileNotFoundError("File %s doesn't exist or is not correct" % (path_to_oat)) 112 | 113 | magic_header = [] 114 | file_size = os.stat(path_to_oat).st_size 115 | 116 | if file_size < len(OATHeader.MAGIC_VALUE): 117 | raise NotOatFileException("File is not an oat file") 118 | 119 | with open(path_to_oat, 'rb') as oat_binary: 120 | magic_header = oat_binary.read(4) 121 | 122 | if magic_header == OATHeader.MAGIC_VALUE: 123 | self.oatdata_offset = 0 124 | self.oatdata_size = file_size 125 | 126 | if self.oatdata_offset is None or self.oatdata_size is None: 127 | raise OatdataNotFoundException("Error, oatdata header not found in oat file (maybe not oat file)") 128 | 129 | 130 | def load(self): 131 | Printer.print("Starting analysis of odex file") 132 | 133 | try: 134 | self.__parse_elf(self.path_to_odex) 135 | except NotElfFileException: 136 | self.not_an_elf = True 137 | 138 | if self.not_an_elf: 139 | self.__parse_oat(self.path_to_odex) 140 | 141 | self.oat_file = open(self.path_to_odex, 'rb') 142 | 143 | self.oat_file.seek(self.oatdata_offset, FILE_BEGIN) 144 | 145 | self.oatdata = OATHeader(self.oat_file) 146 | 147 | self.oatdata.parse_header(self.oatdata_offset, os.path.getsize(self.path_to_odex)) 148 | 149 | self.number_of_dex_files = self.oatdata.dex_file_count.value 150 | 151 | for i in range(len(self.oatdata.OATDexFileHeaders)): 152 | for key,oatclass_header in self.oatdata.OATDexFileHeaders[i].OATClassHeader.items(): 153 | self.number_of_optimized_methods += oatclass_header.compiled_methods 154 | 155 | Printer.print("Analysis done correctly") 156 | 157 | if self.path_to_odex.startswith('/tmp/dextripador_') and \ 158 | self.path_to_odex.endswith('.odex'): 159 | # Remove files that were decompressed 160 | os.remove(self.path_to_odex) 161 | 162 | def get_dex_files(self): 163 | 164 | Printer.print("Returning dex files") 165 | dex_files = [] 166 | for i in range(self.number_of_dex_files): 167 | actual_oatdexfile = self.oatdata.OATDexFileHeaders[i] 168 | dex_files.append(actual_oatdexfile.dex_file) 169 | 170 | return dex_files 171 | 172 | def get_dex_names(self): 173 | 174 | Printer.print("Returning dex file names") 175 | dex_names = [] 176 | for i in range(self.number_of_dex_files): 177 | actual_oatdexfile = self.oatdata.OATDexFileHeaders[i] 178 | 179 | path_name = "" 180 | for i in range(actual_oatdexfile.dex_file_location_size.value): 181 | path_name += chr(actual_oatdexfile.dex_file_location_data[i]) 182 | file_name = ntpath.basename(path_name) 183 | 184 | if '.apk' in file_name: 185 | file_name = file_name.replace('.apk', '.dex') 186 | else: 187 | file_name = file_name + '.dex' 188 | 189 | dex_names.append(file_name) 190 | 191 | return dex_names 192 | 193 | def extract_all_dex(self, recalculate_dex_checksum = False): 194 | 195 | Printer.print("Extracting all the dex files") 196 | for i in range(self.number_of_dex_files): 197 | actual_oatdexfile = self.oatdata.OATDexFileHeaders[i] 198 | 199 | actual_dex_file = actual_oatdexfile.dex_file 200 | 201 | # Get the name to extract 202 | path_name = "" 203 | for i in range(actual_oatdexfile.dex_file_location_size.value): 204 | path_name += chr(actual_oatdexfile.dex_file_location_data[i]) 205 | file_name = ntpath.basename(path_name) 206 | 207 | if '.apk' in file_name: 208 | file_name = file_name.replace('.apk', '.dex') 209 | else: 210 | file_name = file_name + '.dex' 211 | 212 | # get the offset and size of the dex 213 | dex_offset = actual_oatdexfile.dex_file_pointer.value + self.oatdata.oatdata_offset 214 | dex_size = actual_dex_file.file_size.value 215 | 216 | self.oat_file.seek(dex_offset, FILE_BEGIN) 217 | 218 | dex_file_bytes = self.oat_file.read(dex_size) 219 | 220 | output_file = open(file_name, 'wb') 221 | 222 | 223 | calculated_dex_checksum = zlib.adler32(dex_file_bytes[12:]) 224 | 225 | Printer.verbose1("Calculated dex checksum: 0x%08X - Dex file checksum: 0x%08X" % 226 | (calculated_dex_checksum, c_uint(actual_dex_file.checksum.value).value)) 227 | 228 | if recalculate_dex_checksum and calculated_dex_checksum != c_uint(actual_dex_file.checksum.value).value: 229 | Printer.verbose1("Replacing the checksum") 230 | dex_file_bytes = dex_file_bytes[:8] + pack('I',calculated_dex_checksum) + dex_file_bytes[12:] 231 | Printer.verbose1("Replaced the checksum") 232 | 233 | output_file.write(dex_file_bytes) 234 | output_file.close() 235 | 236 | return True 237 | 238 | def extract_dex(self, dex_number, output_name = "", recalculate_dex_checksum = False): 239 | 240 | Printer.print("Extracting dex file %d" % dex_number) 241 | if dex_number >= self.number_of_dex_files or dex_number < 0: 242 | raise DexOutOfFoundException("Selected Dex (%d) doesn't exists" % (dex_number)) 243 | 244 | actual_oatdexfile = self.oatdata.OATDexFileHeaders[dex_number] 245 | 246 | actual_dex_file = actual_oatdexfile.dex_file 247 | 248 | # Get the name to extract 249 | if output_name == "": 250 | # Get the name to extract 251 | path_name = "" 252 | for i in range(actual_oatdexfile.dex_file_location_size.value): 253 | path_name += chr(actual_oatdexfile.dex_file_location_data[i]) 254 | file_name = ntpath.basename(path_name) 255 | if '.apk' in file_name: 256 | file_name = file_name.replace('.apk', '.dex') 257 | else: 258 | file_name = file_name + '.dex' 259 | else: 260 | file_name = output_name 261 | 262 | # get the offset and size of the dex 263 | dex_offset = actual_oatdexfile.dex_file_pointer.value + self.oatdata.oatdata_offset 264 | dex_size = actual_dex_file.file_size.value 265 | 266 | self.oat_file.seek(dex_offset, FILE_BEGIN) 267 | 268 | dex_file_bytes = self.oat_file.read(dex_size) 269 | 270 | output_file = open(file_name, 'wb') 271 | 272 | calculated_dex_checksum = zlib.adler32(dex_file_bytes[12:]) 273 | 274 | Printer.verbose1("Calculated dex checksum: 0x%08X - Dex file checksum: 0x%08X" % ( 275 | calculated_dex_checksum, c_uint(actual_dex_file.checksum.value).value)) 276 | 277 | if recalculate_dex_checksum and calculated_dex_checksum != c_uint(actual_dex_file.checksum.value).value: 278 | Printer.verbose1("Replacing the checksum") 279 | dex_file_bytes = dex_file_bytes[:8] + pack('I', calculated_dex_checksum) + dex_file_bytes[12:] 280 | Printer.verbose1("Replaced the checksum") 281 | 282 | output_file.write(dex_file_bytes) 283 | output_file.close() 284 | 285 | return True 286 | 287 | def print_all_headers(self): 288 | Printer.print("Printing all the oatdata headers") 289 | self.oatdata.print_header() 290 | 291 | def print_all_dex(self): 292 | Printer.print("Printing all dex file headers\n\n") 293 | for i in range(self.number_of_dex_files): 294 | actual_oatdexfile = self.oatdata.OATDexFileHeaders[i] 295 | 296 | actual_dex_file = actual_oatdexfile.dex_file 297 | 298 | actual_dex_file.print_header(num=i) 299 | 300 | verbosity_message = ''' 301 | Verbosity level: 302 | -1: no messages 303 | 0: only necessary messages (by default) 304 | 1: verbose level 1 305 | 2: verbose level 2 306 | 3: verbose level 3" 307 | ''' 308 | 309 | def main(): 310 | extractor = None 311 | 312 | if "--show-credits" in sys.argv: 313 | print("%s" % credits) 314 | sys.exit(0) 315 | 316 | 317 | parser = argparse.ArgumentParser( 318 | description="'Dextripador' tool for pasing Odex files and extract dex files from them.\nResearch From UC3M-COSEC & IMDEA Networks.") 319 | parser.add_argument("-i", "--input", type=str, help="APK to analyze", required=True) 320 | parser.add_argument("-v", "--verbosity", type=int, help=verbosity_message) 321 | parser.add_argument("-o", "--output", type=str, help="Output name for the file, by default is extracted from OAT header") 322 | parser.add_argument("--dextripar", type=int, help="Extract one of the dex files given by index", default=-1) 323 | parser.add_argument("--dextripar-all", action="store_true", help="Extract all the dex from the file") 324 | parser.add_argument("--replace-checksum", action="store_true", help="If selected any dextripar option, replace dex checksum for calculated one") 325 | parser.add_argument("--print-headers", action="store_true", help="Show all the OAT headers (including dex headers)") 326 | parser.add_argument("--list-dexs", action="store_true", help="List all the internal dex files") 327 | parser.add_argument("--show-credits", action="store_true", help="Show credits of the tool") 328 | args = parser.parse_args() 329 | 330 | SET_COMMAND_FLAG(True) 331 | 332 | if args.verbosity == -1: 333 | SET_COMMAND_FLAG (False) 334 | elif args.verbosity == 1: 335 | SET_VERBOSE1(True) 336 | elif args.verbosity == 2: 337 | SET_VERBOSE1(True) 338 | SET_VERBOSE2(True) 339 | elif args.verbosity == 3: 340 | SET_VERBOSE1(True) 341 | SET_VERBOSE2(True) 342 | SET_VERBOSE3(True) 343 | 344 | extractor = Extractor(args.input) 345 | extractor.load() 346 | 347 | if args.print_headers: 348 | extractor.print_all_headers() 349 | 350 | if args.list_dexs: 351 | extractor.print_all_dex() 352 | 353 | if args.dextripar_all: 354 | if args.replace_checksum: 355 | extractor.extract_all_dex(True) 356 | else: 357 | extractor.extract_all_dex() 358 | 359 | if args.dextripar >= 0: 360 | try: 361 | if args.output: 362 | extractor.extract_dex(args.dextripar, args.output) 363 | else: 364 | extractor.extract_dex(args.dextripar, "") 365 | except DexOutOfFoundException as dofe: 366 | Printer.print("Error extracting dex: %s" % (str(dofe))) 367 | 368 | 369 | if __name__ == '__main__': 370 | main() 371 | -------------------------------------------------------------------------------- /FileFormats/DEX.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | #-*- coding: utf-8 -*- 3 | 4 | ###################################################### 5 | # Dextripador 6 | # File: FileFormats/DEX.py 7 | # Version: 0.7 8 | ###################################################### 9 | 10 | import os 11 | import sys 12 | 13 | from FileWork import * 14 | from DextractorException import * 15 | 16 | DEX_MAGIC_TYPE = c_ubyte * 8 17 | DEX_SIGNATURE_TYPE = c_ubyte * 20 18 | 19 | class DEXHeader(): 20 | ''' 21 | Header of Dex file, it has the next structure: 22 | DexfileHeader{ 23 | ubyte[8] magic, 24 | int checksum, 25 | ubyte[20] signature, 26 | uint file_size, 27 | uint header_size, 28 | uint endian_tag, 29 | uint link_size, 30 | uint link_off, 31 | uint map_off, 32 | uint string_ids_size, 33 | uint string_ids_off, 34 | uint type_ids_size, 35 | uint type_ids_off, 36 | uint proto_ids_size, 37 | uint proto_ids_off, 38 | uint field_ids_size, 39 | uint field_ids_off, 40 | uint method_ids_size, 41 | uint method_ids_off, 42 | uint class_defs_size, 43 | uint class_defs_off, 44 | uint data_size, 45 | uint data_off 46 | } 47 | ''' 48 | 49 | def __init__(self, file_pointer): 50 | ''' 51 | Initializer of DEX header parser, we will use 52 | ctypes instead of using python types so we will 53 | have fixed size types. 54 | 55 | :param file_pointer: integer specifying pointer offset within opened file. 56 | ''' 57 | self.file_p = file_pointer 58 | 59 | self.magic = DEX_MAGIC_TYPE() 60 | self.checksum = c_int() 61 | self.signature = DEX_SIGNATURE_TYPE() 62 | self.file_size = c_uint() 63 | self.header_size = c_uint() 64 | self.endian_tag = c_uint() 65 | 66 | self.link_size = c_uint() 67 | self.link_off = c_uint() 68 | 69 | self.map_off = c_uint() 70 | 71 | self.string_ids_size = c_uint() 72 | self.string_ids_off = c_uint() 73 | 74 | self.type_ids_size = c_uint() 75 | self.type_ids_off = c_uint() 76 | 77 | self.proto_ids_size = c_uint() 78 | self.proto_ids_off = c_uint() 79 | 80 | self.field_ids_size = c_uint() 81 | self.field_ids_off = c_uint() 82 | 83 | self.method_ids_size = c_uint() 84 | self.method_ids_off = c_uint() 85 | 86 | self.class_defs_size = c_uint() 87 | self.class_defs_off = c_uint() 88 | 89 | self.data_size = c_uint() 90 | self.data_off = c_uint() 91 | 92 | self.header_initialized = False 93 | 94 | def print_header(self, num = None): 95 | ''' 96 | Print the parsed DEX header, as different 97 | DEX files can be within an OAT file, a number 98 | can be given to specify which one is being printed. 99 | 100 | :param num: DEX header that is being printed. 101 | ''' 102 | if not self.header_initialized: 103 | return 104 | 105 | print("\n==================================") 106 | if num is None: 107 | print("DEX Header") 108 | else: 109 | print("Dex Header [%d]" % (num)) 110 | print("==================================") 111 | 112 | sys.stdout.write("\nMagic: ") 113 | for i in range(ctypes.sizeof(DEX_MAGIC_TYPE)): 114 | sys.stdout.write("%02X " % self.magic[i]) 115 | 116 | sys.stdout.write("(%s)" % ctypes.cast(self.magic, ctypes.c_char_p).value) 117 | 118 | sys.stdout.write("\nChecksum: %d(0x%08X)" % (self.checksum.value, self.checksum.value)) 119 | 120 | sys.stdout.write("\nSignature: ") 121 | for i in range(ctypes.sizeof(DEX_SIGNATURE_TYPE)): 122 | sys.stdout.write("%02X " % self.signature[i]) 123 | 124 | sys.stdout.write("\nFile Size: %d" % self.file_size.value) 125 | sys.stdout.write("\nHeader Size: %d" % self.header_size.value) 126 | sys.stdout.write("\nEndian Tag: %d(0x%08X)" % (self.endian_tag.value, self.endian_tag.value)) 127 | sys.stdout.write("\nLink Size: %d" % (self.link_size.value)) 128 | sys.stdout.write("\nLink Offset: 0x%08X" % (self.link_off.value)) 129 | sys.stdout.write("\nMap Offset: 0x%08X" % (self.map_off.value)) 130 | sys.stdout.write("\nString IDS Size: %d" % (self.string_ids_size.value)) 131 | sys.stdout.write("\nString IDS Offset: 0x%08X" % (self.string_ids_off.value)) 132 | sys.stdout.write("\nType IDS Size: %d" % (self.type_ids_size.value)) 133 | sys.stdout.write("\nType IDS Offset: 0x%08X" % (self.type_ids_off.value)) 134 | sys.stdout.write("\nProto IDS Size: %d" % (self.proto_ids_size.value)) 135 | sys.stdout.write("\nProto IDS Offset: 0x%08X" % (self.proto_ids_off.value)) 136 | sys.stdout.write("\nField IDS Size: %d" % (self.field_ids_size.value)) 137 | sys.stdout.write("\nField IDS Offset: 0x%08X" % (self.field_ids_off.value)) 138 | sys.stdout.write("\nMethod IDS Size: %d" % (self.method_ids_size.value)) 139 | sys.stdout.write("\nMethod IDS Offset: 0x%08X" % (self.method_ids_off.value)) 140 | sys.stdout.write("\nClass Defs Size: %d" % (self.class_defs_size.value)) 141 | sys.stdout.write("\nClass Defs Offset: 0x%08X" % (self.class_defs_off.value)) 142 | sys.stdout.write("\nData Size: %d" % (self.data_size.value)) 143 | sys.stdout.write("\nData Offset: 0x%08X\n" % (self.data_off.value)) 144 | 145 | def parse_header(self, offset, file_size): 146 | ''' 147 | Parsing method for DEX header, checks are done 148 | in order to detech if some offsets are out of bound 149 | of the current file. 150 | 151 | :param offset: offset where to start parsing the DEX header. 152 | :param file_size: file size used for checking offset bounds. 153 | ''' 154 | self.file_p.seek(offset, 0) 155 | 156 | for i in range(ctypes.sizeof(DEX_MAGIC_TYPE)): 157 | self.magic[i] = read_file_le(self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 158 | 159 | self.checksum = read_file_le(self.file_p, INTEGER, INTEGER_SIZE, self.file_p.tell()) 160 | 161 | for i in range(ctypes.sizeof(DEX_SIGNATURE_TYPE)): 162 | self.signature[i] = read_file_le(self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 163 | 164 | self.file_size = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 165 | self.header_size = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 166 | self.endian_tag = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 167 | self.link_size = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 168 | self.link_off = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 169 | if self.link_off.value > file_size: 170 | raise OffsetOutOfBoundException("Error, link offset (0x%08X) is out of bound of the file" % self.link_off.value) 171 | 172 | self.map_off = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 173 | if self.map_off.value > file_size: 174 | raise OffsetOutOfBoundException("Error, map offset (0x%08X) is out of bound of the file" % self.map_off.value) 175 | 176 | self.string_ids_size = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 177 | self.string_ids_off = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 178 | if self.string_ids_off.value > file_size: 179 | raise OffsetOutOfBoundException("Error, string ids offset (0x%08X) is out of bound of the file" % self.string_ids_off.value) 180 | 181 | self.type_ids_size = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 182 | self.type_ids_off = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 183 | if self.type_ids_off.value > file_size: 184 | raise OffsetOutOfBoundException("Error, type ids offset (0x%08X) is out of bound of the file" % self.type_ids_off.value) 185 | 186 | self.proto_ids_size = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 187 | self.proto_ids_off = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 188 | if self.proto_ids_off.value > file_size: 189 | raise OffsetOutOfBoundException("Error, proto ids offset (0x%08X) is out of bound of the file" % self.proto_ids_off.value) 190 | 191 | self.field_ids_size = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 192 | self.field_ids_off = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 193 | if self.field_ids_off.value > file_size: 194 | raise OffsetOutOfBoundException("Error, field ids offset (0x%08X) is out of bound of the file" % self.field_ids_off.value) 195 | 196 | self.method_ids_size = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 197 | self.method_ids_off = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 198 | if self.method_ids_off.value > file_size: 199 | raise OffsetOutOfBoundException("Error, method ids offset (0x%08X) is out of bound of the file" % self.method_ids_off.value) 200 | 201 | self.class_defs_size = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 202 | self.class_defs_off = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 203 | if self.class_defs_off.value > file_size: 204 | raise OffsetOutOfBoundException("Error, class defs offset (0x%08X) is out of bound of the file" % self.class_defs_off.value) 205 | 206 | self.data_size = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 207 | self.data_off = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 208 | if self.data_off.value > file_size: 209 | raise OffsetOutOfBoundException("Error, data offset (0x%08X) is out of bound of the file" % self.data_off.value) 210 | 211 | self.header_initialized = True -------------------------------------------------------------------------------- /FileFormats/OAT.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | ###################################################### 5 | # Dextripador 6 | # File: FileFormats/OAT.py 7 | # Version: 0.7 8 | ###################################################### 9 | 10 | import os 11 | import sys 12 | 13 | from FileWork import * 14 | from DextractorException import * 15 | from FileFormats.DEX import DEXHeader 16 | from utils import * 17 | 18 | OAT_MAGIC_TYPE = c_ubyte * 4 19 | OAT_VERSION_TYPE = c_ubyte * 4 20 | 21 | 22 | class OATClassHeader(): 23 | ''' 24 | Parser for OAT Class Header, here we will have the number 25 | of compiled methods 26 | 27 | OATClassHeader { 28 | uint16 status, 29 | uint16 type, 30 | uint32 bitmap_size, 31 | ubyte[bitmap_size] bitmap, 32 | uint32[variable] methods_offsets 33 | } 34 | ''' 35 | 36 | kOatClassAllCompiled = 0 37 | kOatClassSomeCompiled = 1 38 | kOatClassNoneCompiled = 2 39 | 40 | ''' 41 | Constants, thanks to Lief project by @rh0main 42 | ''' 43 | STATUS_RETIRED = -2 # Retired, should not be used. Use the newly cloned one instead. 44 | STATUS_ERROR = -1 45 | STATUS_NOTREADY = 0 46 | # Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_. 47 | STATUS_IDX = 1 48 | STATUS_LOADED = 2 # DEX idx values resolved. 49 | STATUS_RESOLVING = 3 # Just cloned from temporary class object. 50 | STATUS_RESOLVED = 4 # Part of linking. 51 | STATUS_VERIFYING = 5 # In the process of being verified. 52 | # Compile time verification failed, retry at runtime. 53 | STATUS_RETRY_VERIFICATION_AT_RUNTIME = 6 54 | STATUS_VERIFYING_AT_RUNTIME = 7 # Retrying verification at runtime. 55 | STATUS_VERIFIED = 8 # Logically part of linking; done pre-init. 56 | STATUS_INITIALIZING = 9 # Class init in progress. 57 | STATUS_INITIALIZED = 10 # Ready to go. 58 | 59 | def __init__(self, file_pointer): 60 | ''' 61 | Initializer of OAT header parser, here 62 | we will initialize used variables, we will 63 | use ctypes instead of python types to have 64 | fixed size types. 65 | 66 | :param file_pointer: integer specifying pointer offset within opened file. 67 | ''' 68 | self.file_p = file_pointer 69 | 70 | self.status = c_ushort() 71 | self.type = c_ushort() 72 | self.bitmap_size = c_uint() 73 | self.bitmap = None 74 | self.methods_offsets = None 75 | 76 | self.compiled_methods = 0 77 | 78 | self.header_initialized = False 79 | 80 | def parse_header(self, offset, file_size): 81 | self.file_p.seek(offset, FILE_BEGIN) 82 | 83 | self.status = read_file_le( 84 | self.file_p, USHORT, USHORT_SIZE, self.file_p.tell()) 85 | 86 | if self.status.value > OATClassHeader.STATUS_INITIALIZED: 87 | raise OATClassHeaderIncorrectStatusException( 88 | "OATClassHeader status incorrect (%d)" % (self.status.value)) 89 | 90 | self.type = read_file_le( 91 | self.file_p, USHORT, USHORT_SIZE, self.file_p.tell()) 92 | 93 | if self.type.value > OATClassHeader.kOatClassNoneCompiled: 94 | raise OATClassHeaderIncorrectTypeException( 95 | "OATClassHeader type incorrect (%d)" % (self.type.value)) 96 | 97 | ''' 98 | The bitmap field represents the compiled methods, each bit of 99 | the bitmap starting from the least significant bit to the most 100 | significant bit. 101 | If type is kOatClassAllCompiled there's no bitmap as all the 102 | methods have been optimized. 103 | If type is kOatClassNoneCompiled there's no bitmap, as there aren't 104 | compiled methods. 105 | ''' 106 | if self.type.value == OATClassHeader.kOatClassSomeCompiled: 107 | self.bitmap_size = read_file_le( 108 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 109 | self.bitmap = (c_ubyte * self.bitmap_size.value)() 110 | for i in range(self.bitmap_size.value): 111 | self.bitmap[i] = read_file_le( 112 | self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 113 | 114 | # check each byte for compiled methods 115 | for shifter in range(8): 116 | if (1 << shifter) & self.bitmap[i]: 117 | self.compiled_methods += 1 118 | 119 | self.methods_offsets = (c_uint * self.compiled_methods)() 120 | 121 | for i in range(self.compiled_methods): 122 | self.methods_offsets[i] = read_file_le( 123 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 124 | if self.methods_offsets[i] > file_size: 125 | raise OffsetOutOfBoundException( 126 | "Error, methods_offset[%d] (0x%08X) is out of bound of the file" % (i, self.methods_offsets[i])) 127 | 128 | self.header_initialized = True 129 | 130 | def print_header(self): 131 | 132 | if not self.header_initialized: 133 | return 134 | 135 | print("\n\t==================================") 136 | print("\tOAT Class Header") 137 | print("\t==================================") 138 | 139 | sys.stdout.write("\tStatus: %d (0x%08X)" % 140 | (self.status.value, self.status.value)) 141 | 142 | if self.status.value == OATClassHeader.STATUS_RETIRED: 143 | sys.stdout.write("(STATUS_RETIRED)") 144 | elif self.status.value == OATClassHeader.STATUS_ERROR: 145 | sys.stdout.write("(STATUS_ERROR)") 146 | elif self.status.value == OATClassHeader.STATUS_NOTREADY: 147 | sys.stdout.write("(STATUS_NOTREADY)") 148 | elif self.status.value == OATClassHeader.STATUS_IDX: 149 | sys.stdout.write("(STATUS_IDX)") 150 | elif self.status.value == OATClassHeader.STATUS_LOADED: 151 | sys.stdout.write("(STATUS_LOADED)") 152 | elif self.status.value == OATClassHeader.STATUS_RESOLVING: 153 | sys.stdout.write("(STATUS_RESOLVING)") 154 | elif self.status.value == OATClassHeader.STATUS_RESOLVED: 155 | sys.stdout.write("(STATUS_RESOLVED)") 156 | elif self.status.value == OATClassHeader.STATUS_VERIFYING: 157 | sys.stdout.write("(STATUS_VERIFYING)") 158 | elif self.status.value == OATClassHeader.STATUS_RETRY_VERIFICATION_AT_RUNTIME: 159 | sys.stdout.write("(STATUS_RETRY_VERIFICATION_AT_RUNTIME)") 160 | elif self.status.value == OATClassHeader.STATUS_VERIFYING_AT_RUNTIME: 161 | sys.stdout.write("(STATUS_VERIFYING_AT_RUNTIME)") 162 | elif self.status.value == OATClassHeader.STATUS_VERIFIED: 163 | sys.stdout.write("(STATUS_VERIFIED)") 164 | elif self.status.value == OATClassHeader.STATUS_INITIALIZING: 165 | sys.stdout.write("(STATUS_INITIALIZING)") 166 | elif self.status.value == OATClassHeader.STATUS_INITIALIZED: 167 | sys.stdout.write("(STATUS_INITIALIZED)") 168 | 169 | sys.stdout.write('\n') 170 | sys.stdout.write("\tType: %d" % (self.type.value)) 171 | 172 | if self.type.value == OATClassHeader.kOatClassSomeCompiled: 173 | sys.stdout.write("(kOatClassSomeCompiled)") 174 | 175 | print("\n\tBitmap size: %d" % self.bitmap_size.value) 176 | 177 | sys.stdout.write("\tBitmap (in bits): ") 178 | for i in range(self.bitmap_size.value): 179 | sys.stdout.write( 180 | '%s' % (bin(self.bitmap[self.bitmap_size.value - 1 - i])[2:].zfill(8))) 181 | 182 | elif self.type.value == OATClassHeader.kOatClassAllCompiled: 183 | sys.stdout.write("(kOatClassAllCompiled)") 184 | 185 | elif self.type.value == OATClassHeader.kOatClassNoneCompiled: 186 | sys.stdout.write("(kOatClassNoneCompiled)") 187 | 188 | sys.stdout.write("\n") 189 | 190 | sys.stdout.write("\tMethods offsets: ") 191 | for i in range(self.compiled_methods): 192 | sys.stdout.write("0x%08X " % self.methods_offsets[i]) 193 | 194 | sys.stdout.write('\n') 195 | 196 | 197 | class OATDexFileHeader(): 198 | ''' 199 | Parser for OAT Dex File Header, this will contain a header 200 | of the class DEXHeader 201 | 202 | OATDexFileHeader { 203 | uint32 dex_file_location_size, 204 | ubyte[dex_file_location_size] dex_file_location_data, 205 | uint32 dex_file_location_checksum, 206 | uint32 dex_file_pointer, 207 | uint32[DEXHeader.class_defs_size] classes_offsets 208 | } 209 | 210 | This class can be an array if more than one Dex is inside of the 211 | oat file, but the array is not sequencial as the next structure 212 | is stored inside of the second classes_offsets. 213 | ''' 214 | 215 | def __init__(self, file_pointer): 216 | self.file_p = file_pointer 217 | self.oat_dex_file_header_offset = file_pointer.tell() 218 | self.dex_file_location_size = c_uint() 219 | self.dex_file_location_data = None 220 | self.dex_file_location_checksum = c_uint() 221 | self.dex_file_pointer = c_uint() 222 | self.classes_offsets = None 223 | 224 | self.OATClassHeader = {} 225 | 226 | self.header_initialized = False 227 | 228 | self.dex_file = None 229 | 230 | def print_header(self): 231 | if not self.header_initialized: 232 | return 233 | 234 | print("\n==================================") 235 | print("OAT Dex File Header") 236 | print("==================================") 237 | 238 | sys.stdout.write("\nDex File Location Size: %d" % 239 | self.dex_file_location_size.value) 240 | sys.stdout.write("\nDex File Location Data: ") 241 | 242 | dex_file_location_data_str = "" 243 | 244 | for i in range(self.dex_file_location_size.value): 245 | sys.stdout.write("%02X " % self.dex_file_location_data[i]) 246 | dex_file_location_data_str += chr(self.dex_file_location_data[i]) 247 | 248 | sys.stdout.write("(%s)" % dex_file_location_data_str) 249 | sys.stdout.write("\nDex File Location Checksum: %d(0x%08X)" % ( 250 | self.dex_file_location_checksum.value, self.dex_file_location_checksum.value)) 251 | sys.stdout.write("\nDex File Pointer: 0x%08X" % 252 | (self.dex_file_pointer.value)) 253 | 254 | for i in range(self.dex_file.class_defs_size.value): 255 | sys.stdout.write("\nClass Number: %d\tClass offset: 0x%08X\n" % ( 256 | i, self.classes_offsets[i])) 257 | 258 | if self.classes_offsets[i] in self.OATClassHeader: 259 | self.OATClassHeader[self.classes_offsets[i]].print_header() 260 | 261 | sys.stdout.write("\n") 262 | 263 | self.dex_file.print_header() 264 | 265 | def parse_header(self, offset, file_size, oatdata_offset, oat_header_version): 266 | self.file_p.seek(offset, FILE_BEGIN) 267 | 268 | self.dex_file_location_size = read_file_le( 269 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 270 | 271 | # create the data 272 | self.dex_file_location_data = ( 273 | c_ubyte * self.dex_file_location_size.value)() 274 | 275 | # read it 276 | for i in range(self.dex_file_location_size.value): 277 | self.dex_file_location_data[i] = read_file_le( 278 | self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 279 | 280 | self.dex_file_location_checksum = read_file_le( 281 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 282 | 283 | self.dex_file_pointer = read_file_le( 284 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 285 | 286 | if self.dex_file_pointer.value > file_size or (oatdata_offset + self.dex_file_pointer.value) > file_size: 287 | raise OffsetOutOfBoundException( 288 | "Error, dex file pointer (0x%08X) is out of bound of the file" % self.dex_file_pointer.value) 289 | 290 | auxiliar_offset = self.file_p.tell() 291 | 292 | ############################################################ 293 | # now point to dex header 294 | self.file_p.seek(oatdata_offset + 295 | self.dex_file_pointer.value, FILE_BEGIN) 296 | self.dex_file = DEXHeader(self.file_p) 297 | 298 | self.dex_file.parse_header(self.file_p.tell(), file_size) 299 | ############################################################ 300 | 301 | # again move to auxiliar offset 302 | self.file_p.seek(auxiliar_offset, FILE_BEGIN) 303 | 304 | # Now as we have the class_defs_size 305 | self.classes_offsets = (c_uint * self.dex_file.class_defs_size.value)() 306 | 307 | next_header = self.file_p.tell() + 8 308 | 309 | for i in range(self.dex_file.class_defs_size.value): 310 | self.classes_offsets[i] = read_file_le( 311 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 312 | 313 | if self.classes_offsets[i] > file_size or (oatdata_offset + self.classes_offsets[i]) > file_size: 314 | continue 315 | 316 | # from dextra 317 | # if ( getOATVer() != '970' && getOATVer() != '570' && getOATVer() != '880' && getOATVer() != '411' ) 318 | if oat_header_version != b"079" and oat_header_version != b"075" and oat_header_version != b"088" and oat_header_version != b"114": 319 | oatclassheader = OATClassHeader(self.file_p) 320 | auxiliar_offset = self.file_p.tell() 321 | try: 322 | oatclassheader.parse_header( 323 | (oatdata_offset + self.classes_offsets[i]), file_size) 324 | # if everything was okay, set as class header 325 | self.OATClassHeader[self.classes_offsets[i] 326 | ] = oatclassheader 327 | except OATClassHeaderIncorrectStatusException as status_exception: 328 | Printer.verbose2( 329 | "Exception in status parsing OatClassHeader (%s)" % (str(status_exception))) 330 | except OATClassHeaderIncorrectTypeException as type_exception: 331 | Printer.verbose2( 332 | "Exception in type parsing OatClassHeader (%s)" % (str(type_exception))) 333 | 334 | # always set previous offset 335 | self.file_p.seek(auxiliar_offset, FILE_BEGIN) 336 | 337 | self.file_p.seek(next_header, FILE_BEGIN) 338 | self.header_initialized = True 339 | 340 | 341 | class OATHeader(): 342 | ''' 343 | Parser for the oatdata section header, this will be used 344 | to extract parse the headers and finally extract the dex 345 | file. 346 | 347 | OATFileHeader { 348 | ubyte[4] magic, 349 | ubyte[4] version, 350 | uint32 adler32_checksum, 351 | uint32 instruction_set, 352 | uint32 instruction_set_features, 353 | uint32 dex_file_count, 354 | uint32 oat_dex_files_offset, # starting from OAT 131 355 | uint32 executable_offset, 356 | uint32 interpreter_to_interpreter_bridge_offset, 357 | uint32 interpreter_to_compiled_code_bridge_offset, 358 | uint32 jni_dlsym_lookup_offset_, 359 | uint32 portable_imt_conflict_trampoline_offset, 360 | uint32 portable_resolution_trampoline_offset, 361 | uint32 portable_to_interpreter_bridge_offset, 362 | uint32 quick_generic_jni_trampoline_offset, 363 | uint32 quick_imt_conflict_trampoline_offset, 364 | uint32 quick_resolution_trampoline_offset, 365 | uint32 quick_to_interpreter_bridge_offset, 366 | int32 image_patch_delta, 367 | uint32 image_file_location_oat_checksum, 368 | uint32 image_file_location_oat_data_begin, 369 | uint32 key_value_store_size, 370 | ubyte[key_value_store_size] key_value_store 371 | } 372 | ''' 373 | 374 | # CONSTANTS 375 | KNONE = 0 376 | KARM = 1 377 | KARM64 = 2 378 | KTHUMB2 = 3 379 | KX86 = 4 380 | X86_64 = 5 381 | KMIPS = 6 382 | KMIPS64 = 7 383 | 384 | MAGIC_VALUE = b'oat\n' 385 | 386 | VERSION_1 = [b'039', b'045'] 387 | VERSION_2 = [b'062', b'063', b'064', b'075', b'077'] 388 | VERSION_3 = [b'079', b'088', b'114', b'124'] 389 | VERSION_4 = [b'131'] 390 | VERSION_5 = [b'170'] 391 | 392 | def __init__(self, file_pointer): 393 | self.file_p = file_pointer 394 | self.oatdata_offset = self.file_p.tell() 395 | self.header_initialized = False 396 | 397 | self.magic = OAT_MAGIC_TYPE() 398 | self.version = OAT_VERSION_TYPE() 399 | self.adler32_checksum = c_uint() 400 | self.instruction_set = c_uint() 401 | self.instruction_set_features = c_uint() 402 | self.dex_file_count = c_uint() 403 | self.oat_dex_files_offset = c_uint() 404 | self.executable_offset = c_uint() 405 | self.interpreter_to_interpreter_bridge_offset = c_uint() 406 | self.interpreter_to_compiled_code_bridge_offset = c_uint() 407 | self.jni_dlsym_lookup_offset_ = c_uint() 408 | self.portable_imt_conflict_trampoline_offset = c_uint() 409 | self.portable_resolution_trampoline_offset = c_uint() 410 | self.portable_to_interpreter_bridge_offset = c_uint() 411 | self.quick_generic_jni_trampoline_offset = c_uint() 412 | self.quick_imt_conflict_trampoline_offset = c_uint() 413 | self.quick_resolution_trampoline_offset = c_uint() 414 | self.quick_to_interpreter_bridge_offset = c_uint() 415 | self.image_patch_delta = c_int() 416 | self.image_file_location_oat_checksum = c_uint() 417 | self.image_file_location_oat_data_begin = c_uint() 418 | self.key_value_store_size = c_uint() 419 | self.key_value_store = None # Necessary to initialize with key_value_store_size 420 | 421 | self.OATDexFileHeaders = [] 422 | 423 | def print_header(self): 424 | 425 | if not self.header_initialized: 426 | return 427 | 428 | print("\n==================================") 429 | print("OAT Header") 430 | print("==================================") 431 | 432 | sys.stdout.write("\nMagic: ") 433 | for i in range(ctypes.sizeof(OAT_MAGIC_TYPE)): 434 | sys.stdout.write("%02X " % self.magic[i]) 435 | 436 | sys.stdout.write("(%s)\n" % ctypes.cast( 437 | self.magic, ctypes.c_char_p).value) 438 | 439 | sys.stdout.write("Version: ") 440 | for i in range(ctypes.sizeof(OAT_VERSION_TYPE)): 441 | sys.stdout.write("%02X " % self.version[i]) 442 | 443 | sys.stdout.write("(%s)" % ctypes.cast( 444 | self.version, ctypes.c_char_p).value) 445 | 446 | sys.stdout.write("\nAdler32_checksum: %d(0x%08X)" % ( 447 | self.adler32_checksum.value, self.adler32_checksum.value)) 448 | sys.stdout.write("\nInstruction set: %d" % 449 | (self.instruction_set.value)) 450 | sys.stdout.write("\nInstruction set features: %d" % 451 | (self.instruction_set_features.value)) 452 | sys.stdout.write("\nDex file count: %d" % (self.dex_file_count.value)) 453 | sys.stdout.write("\nOat dex file offset: 0x%08X" % 454 | (self.oat_dex_files_offset.value)) 455 | sys.stdout.write("\nExecutable offset: 0x%08X" % 456 | (self.executable_offset.value)) 457 | sys.stdout.write("\nInterpreter to interpreter bridge offset: 0x%08X" % ( 458 | self.interpreter_to_interpreter_bridge_offset.value)) 459 | sys.stdout.write("\nInterpreter to compiled code bridge offset: 0x%08X" % ( 460 | self.interpreter_to_compiled_code_bridge_offset.value)) 461 | sys.stdout.write("\njni dlsym lookup offset: 0x%08X" % 462 | (self.jni_dlsym_lookup_offset_.value)) 463 | sys.stdout.write( 464 | "\nportable imt conflict trampoline offset: 0x%08X" % (self.portable_imt_conflict_trampoline_offset.value)) 465 | sys.stdout.write( 466 | "\nportable resolution trampoline offset: 0x%08X" % (self.portable_resolution_trampoline_offset.value)) 467 | sys.stdout.write( 468 | "\nportable to interpreter bridge offset: 0x%08X" % (self.portable_to_interpreter_bridge_offset.value)) 469 | sys.stdout.write( 470 | "\nquick generic jni trampoline offset: 0x%08X" % (self.quick_generic_jni_trampoline_offset.value)) 471 | sys.stdout.write( 472 | "\nquick imt conflict trampoline offset: 0x%08X" % (self.quick_imt_conflict_trampoline_offset.value)) 473 | sys.stdout.write( 474 | "\nquick resolution trampoline offset: 0x%08X" % (self.quick_resolution_trampoline_offset.value)) 475 | sys.stdout.write( 476 | "\nquick to interpreter bridge offset: 0x%08X" % (self.quick_to_interpreter_bridge_offset.value)) 477 | 478 | sys.stdout.write("\nimage patch delta: 0x%08X" % 479 | (self.image_patch_delta.value)) 480 | sys.stdout.write("\nimage file location oat checksum: 0x%08X" % 481 | (self.image_file_location_oat_checksum.value)) 482 | sys.stdout.write( 483 | "\nimage file location oat data begin: 0x%08X" % (self.image_file_location_oat_data_begin.value)) 484 | 485 | sys.stdout.write("\nkey value store size: %d" % 486 | (self.key_value_store_size.value)) 487 | 488 | key_value_store_s = "" 489 | for i in range(self.key_value_store_size.value): 490 | if (self.key_value_store[i] == 0x00 and i != (self.key_value_store_size.value - 1)): 491 | key_value_store_s += " " 492 | else: 493 | key_value_store_s += chr(self.key_value_store[i]) 494 | sys.stdout.write("\nkey value store: %s\n" % (key_value_store_s)) 495 | 496 | for i in range(len(self.OATDexFileHeaders)): 497 | self.OATDexFileHeaders[i].print_header() 498 | 499 | def _parse_v1(self, offset, file_size): 500 | ''' 501 | Parse the OAT versions [045, 039] 502 | :param offset: offset where to start the analysis 503 | :param file_size: size if it's necessary for offset checks 504 | :return: 505 | ''' 506 | self.file_p.seek(offset, FILE_BEGIN) 507 | 508 | self.adler32_checksum = read_file_le( 509 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 510 | self.instruction_set = read_file_le( 511 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 512 | self.instruction_set_features = read_file_le( 513 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 514 | self.dex_file_count = read_file_le( 515 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 516 | # below OAT 131 oat_dex_files_offset = 0 517 | self.oat_dex_files_offset = c_uint(0) 518 | self.executable_offset = read_file_le( 519 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 520 | if self.executable_offset.value > file_size or (self.executable_offset.value + self.oatdata_offset) > file_size: 521 | raise OffsetOutOfBoundException( 522 | "Error, executable_offset (0x%08X) is out of bound of the file" % self.executable_offset.value) 523 | 524 | self.interpreter_to_interpreter_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 525 | self.file_p.tell()) 526 | self.interpreter_to_compiled_code_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 527 | self.file_p.tell()) 528 | self.jni_dlsym_lookup_offset_ = read_file_le( 529 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 530 | 531 | self.portable_imt_conflict_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 532 | self.file_p.tell()) 533 | self.portable_resolution_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 534 | self.file_p.tell()) 535 | self.portable_to_interpreter_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 536 | self.file_p.tell()) 537 | 538 | self.quick_generic_jni_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 539 | self.file_p.tell()) 540 | self.quick_imt_conflict_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 541 | self.file_p.tell()) 542 | self.quick_resolution_trampoline_offset = read_file_le( 543 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 544 | self.quick_to_interpreter_bridge_offset = read_file_le( 545 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 546 | 547 | self.image_patch_delta = read_file_le( 548 | self.file_p, INTEGER, INTEGER_SIZE, self.file_p.tell()) 549 | self.image_file_location_oat_checksum = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 550 | self.file_p.tell()) 551 | self.image_file_location_oat_data_begin = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 552 | self.file_p.tell()) 553 | 554 | self.key_value_store_size = read_file_le( 555 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 556 | self.key_value_store = (c_ubyte * self.key_value_store_size.value)() 557 | 558 | for i in range(self.key_value_store_size.value): 559 | self.key_value_store[i] = read_file_le( 560 | self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 561 | 562 | def _parse_v2(self, offset, file_size): 563 | ''' 564 | Parse the OAT versions [077, 075, 063, 064, 062] 565 | :param offset: offset where to start the analysis 566 | :param file_size: size if it's necessary for offset checks 567 | :return: 568 | ''' 569 | self.file_p.seek(offset, FILE_BEGIN) 570 | 571 | self.adler32_checksum = read_file_le( 572 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 573 | self.instruction_set = read_file_le( 574 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 575 | self.instruction_set_features = read_file_le( 576 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 577 | self.dex_file_count = read_file_le( 578 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 579 | # below OAT 131 oat_dex_files_offset = 0 580 | self.oat_dex_files_offset = c_uint(0) 581 | self.executable_offset = read_file_le( 582 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 583 | if self.executable_offset.value > file_size or (self.executable_offset.value + self.oatdata_offset) > file_size: 584 | raise OffsetOutOfBoundException( 585 | "Error, executable_offset (0x%08X) is out of bound of the file" % self.executable_offset.value) 586 | 587 | self.interpreter_to_interpreter_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 588 | self.file_p.tell()) 589 | self.interpreter_to_compiled_code_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 590 | self.file_p.tell()) 591 | self.jni_dlsym_lookup_offset_ = read_file_le( 592 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 593 | 594 | self.portable_imt_conflict_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 595 | self.file_p.tell()) 596 | self.portable_resolution_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 597 | self.file_p.tell()) 598 | self.portable_to_interpreter_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 599 | self.file_p.tell()) 600 | 601 | self.quick_generic_jni_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 602 | self.file_p.tell()) 603 | self.quick_imt_conflict_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 604 | self.file_p.tell()) 605 | self.quick_resolution_trampoline_offset = read_file_le( 606 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 607 | self.quick_to_interpreter_bridge_offset = read_file_le( 608 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 609 | 610 | self.key_value_store_size = read_file_le( 611 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 612 | self.key_value_store = (c_ubyte * self.key_value_store_size.value)() 613 | 614 | for i in range(self.key_value_store_size.value): 615 | self.key_value_store[i] = read_file_le( 616 | self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 617 | 618 | def _parse_v3(self, offset, file_size): 619 | ''' 620 | Parse the OAT versions [079, 088, 114] 621 | :param offset: offset where to start the analysis 622 | :param file_size: size if it's necessary for offset checks 623 | :return: 624 | ''' 625 | self.file_p.seek(offset, FILE_BEGIN) 626 | 627 | self.adler32_checksum = read_file_le( 628 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 629 | self.instruction_set = read_file_le( 630 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 631 | self.instruction_set_features = read_file_le( 632 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 633 | self.dex_file_count = read_file_le( 634 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 635 | # below OAT 131 oat_dex_files_offset = 0 636 | self.oat_dex_files_offset = c_uint(0) 637 | self.executable_offset = read_file_le( 638 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 639 | if self.executable_offset.value > file_size or (self.executable_offset.value + self.oatdata_offset) > file_size: 640 | raise OffsetOutOfBoundException( 641 | "Error, executable_offset (0x%08X) is out of bound of the file" % self.executable_offset.value) 642 | 643 | self.interpreter_to_interpreter_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 644 | self.file_p.tell()) 645 | self.interpreter_to_compiled_code_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 646 | self.file_p.tell()) 647 | self.jni_dlsym_lookup_offset_ = read_file_le( 648 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 649 | 650 | self.portable_imt_conflict_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 651 | self.file_p.tell()) 652 | self.portable_resolution_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 653 | self.file_p.tell()) 654 | self.portable_to_interpreter_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 655 | self.file_p.tell()) 656 | 657 | self.quick_generic_jni_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 658 | self.file_p.tell()) 659 | self.quick_imt_conflict_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 660 | self.file_p.tell()) 661 | 662 | self.image_file_location_oat_checksum = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 663 | self.file_p.tell()) 664 | self.image_file_location_oat_data_begin = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 665 | self.file_p.tell()) 666 | 667 | self.key_value_store_size = read_file_le( 668 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 669 | self.key_value_store = (c_ubyte * self.key_value_store_size.value)() 670 | 671 | for i in range(self.key_value_store_size.value): 672 | self.key_value_store[i] = read_file_le( 673 | self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 674 | 675 | def _parse_v4(self, offset, file_size): 676 | ''' 677 | Parse the OAT versions [131] 678 | :param offset: offset where to start the analysis 679 | :param file_size: size if it's necessary for offset checks 680 | :return: 681 | ''' 682 | self.file_p.seek(offset, FILE_BEGIN) 683 | 684 | self.adler32_checksum = read_file_le( 685 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 686 | self.instruction_set = read_file_le( 687 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 688 | self.instruction_set_features = read_file_le( 689 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 690 | self.dex_file_count = read_file_le( 691 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 692 | self.oat_dex_files_offset = read_file_le( 693 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 694 | if self.oat_dex_files_offset.value > file_size: 695 | raise OffsetOutOfBoundException( 696 | "Error, oat_dex_files_offset (0x%08X) is out of bound of the file" % self.oat_dex_files_offset.value) 697 | self.executable_offset = read_file_le( 698 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 699 | if self.executable_offset.value > file_size or (self.executable_offset.value + self.oatdata_offset) > file_size: 700 | raise OffsetOutOfBoundException( 701 | "Error, executable_offset (0x%08X) is out of bound of the file" % self.executable_offset.value) 702 | self.interpreter_to_interpreter_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 703 | self.file_p.tell()) 704 | self.interpreter_to_compiled_code_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 705 | self.file_p.tell()) 706 | self.jni_dlsym_lookup_offset_ = read_file_le( 707 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 708 | 709 | self.quick_generic_jni_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 710 | self.file_p.tell()) 711 | self.quick_imt_conflict_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 712 | self.file_p.tell()) 713 | 714 | self.quick_resolution_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 715 | self.file_p.tell()) 716 | 717 | self.quick_to_interpreter_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 718 | self.file_p.tell()) 719 | 720 | self.image_patch_delta = read_file_le( 721 | self.file_p, INTEGER, INTEGER_SIZE, self.file_p.tell()) 722 | 723 | self.image_file_location_oat_checksum = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 724 | self.file_p.tell()) 725 | self.image_file_location_oat_data_begin = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 726 | self.file_p.tell()) 727 | 728 | self.key_value_store_size = read_file_le( 729 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 730 | 731 | print("key value store size: %d" % (self.key_value_store_size.value)) 732 | 733 | self.key_value_store = (c_ubyte * self.key_value_store_size.value)() 734 | 735 | for i in range(self.key_value_store_size.value): 736 | self.key_value_store[i] = read_file_le( 737 | self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 738 | 739 | def _parse_v5(self, offset, file_size): 740 | ''' 741 | Parse the OAT versions [170] 742 | :param offset: offset where to start the analysis 743 | :param file_size: size if it's necessary for offset checks 744 | :return: 745 | ''' 746 | self.file_p.seek(offset, FILE_BEGIN) 747 | 748 | self.adler32_checksum = read_file_le( 749 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 750 | self.instruction_set = read_file_le( 751 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 752 | self.instruction_set_features = read_file_le( 753 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 754 | self.dex_file_count = read_file_le( 755 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 756 | self.oat_dex_files_offset = read_file_le( 757 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 758 | if self.oat_dex_files_offset.value > file_size: 759 | raise OffsetOutOfBoundException( 760 | "Error, oat_dex_files_offset (0x%08X) is out of bound of the file" % self.oat_dex_files_offset.value) 761 | self.executable_offset = read_file_le( 762 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 763 | if self.executable_offset.value > file_size or (self.executable_offset.value + self.oatdata_offset) > file_size: 764 | raise OffsetOutOfBoundException( 765 | "Error, executable_offset (0x%08X) is out of bound of the file" % self.executable_offset.value) 766 | self.jni_dlsym_lookup_offset_ = read_file_le( 767 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 768 | 769 | self.quick_generic_jni_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 770 | self.file_p.tell()) 771 | self.quick_imt_conflict_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 772 | self.file_p.tell()) 773 | 774 | self.quick_resolution_trampoline_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 775 | self.file_p.tell()) 776 | 777 | self.quick_to_interpreter_bridge_offset = read_file_le(self.file_p, UINTEGER, UINTEGER_SIZE, 778 | self.file_p.tell()) 779 | 780 | self.key_value_store_size = read_file_le( 781 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 782 | 783 | self.key_value_store = (c_ubyte * self.key_value_store_size.value)() 784 | 785 | for i in range(self.key_value_store_size.value): 786 | self.key_value_store[i] = read_file_le( 787 | self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 788 | 789 | def parse_header(self, offset, file_size): 790 | self.file_p.seek(offset, FILE_BEGIN) 791 | 792 | for i in range(ctypes.sizeof(OAT_MAGIC_TYPE)): 793 | self.magic[i] = read_file_le( 794 | self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 795 | 796 | if ctypes.cast(self.magic, ctypes.c_char_p).value != OATHeader.MAGIC_VALUE: 797 | raise IncorrectMagicException( 798 | "Error, magic header doesn't match expected header %s" % (OATHeader.MAGIC_VALUE)) 799 | 800 | for i in range(ctypes.sizeof(OAT_VERSION_TYPE)): 801 | self.version[i] = read_file_le( 802 | self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 803 | 804 | # [045, 039] 805 | if ctypes.cast(self.version, ctypes.c_char_p).value in OATHeader.VERSION_1: 806 | self._parse_v1(self.file_p.tell(), file_size) 807 | 808 | # [077, 075, 063, 064, 062] 809 | elif ctypes.cast(self.version, ctypes.c_char_p).value in OATHeader.VERSION_2: 810 | self._parse_v2(self.file_p.tell(), file_size) 811 | 812 | # [079, 088, 114] 813 | elif ctypes.cast(self.version, ctypes.c_char_p).value in OATHeader.VERSION_3: 814 | self._parse_v3(self.file_p.tell(), file_size) 815 | 816 | # [131]: 817 | elif ctypes.cast(self.version, ctypes.c_char_p).value in OATHeader.VERSION_4: 818 | self._parse_v4(self.file_p.tell(), file_size) 819 | 820 | # [170]: 821 | elif ctypes.cast(self.version, ctypes.c_char_p).value in OATHeader.VERSION_5: 822 | self._parse_v5(self.file_p.tell(), file_size) 823 | 824 | else: 825 | raise UnsupportedOatVersion("OAT Version analyzed (%s) not supported" % ctypes.cast( 826 | self.version, ctypes.c_char_p).value) 827 | 828 | # since version 131 oat_dex_file_offset 829 | # this was introduced inversion android-8.1.0_r1 830 | if self.oat_dex_files_offset.value != 0: 831 | OatDexFile = offset + self.oat_dex_files_offset.value 832 | self.file_p.seek(OatDexFile, FILE_BEGIN) 833 | 834 | for i in range(self.dex_file_count.value): 835 | oatdexfileheader_aux = OATDexFileHeader(self.file_p) 836 | oatdexfileheader_aux.parse_header(self.file_p.tell( 837 | ), file_size, offset, ctypes.cast(self.version, ctypes.c_char_p).value) 838 | self.OATDexFileHeaders.append(oatdexfileheader_aux) 839 | 840 | self.header_initialized = True 841 | -------------------------------------------------------------------------------- /FileFormats/VDEX.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | ###################################################### 5 | # Dextripador 6 | # File: FileFormats/VDEX.py 7 | # Version: 0.7 8 | ###################################################### 9 | 10 | import os 11 | import sys 12 | 13 | from FileWork import * 14 | from DextractorException import * 15 | from FileFormats.DEX import DEXHeader 16 | 17 | VDEX_MAGIC_TYPE = c_ubyte * 4 18 | VDEX_VERIFIER_DEPS_VERSION_TYPE = c_ubyte * 4 19 | VDEX_DEX_SECTION_VERSION_TYPE = c_ubyte * 4 20 | 21 | 22 | class VDEXFile(): 23 | ''' 24 | Parser for VDEX File Header, in this file 25 | we will find the DEX files after OAT version 26 | 124 (Android 8.0). 27 | 28 | VDEXFile { 29 | uint8_t magic_[4] 30 | uint8_t verifier_deps_version_[4] 31 | uint8_t dex_section_version_[4] 32 | uint32_t number_of_dex_files_ 33 | uint32_t verifier_deps_size_ 34 | uint32_t bootclasspath_checksums_size_ 35 | uint32_t class_loader_context_size_ 36 | } 37 | ''' 38 | 39 | def __init__(self, file_pointer): 40 | self.file_p = file_pointer 41 | self.header_initialized = False 42 | self.dex_file = None 43 | 44 | self.magic = VDEX_MAGIC_TYPE() 45 | self.verifier_deps_version = VDEX_VERIFIER_DEPS_VERSION_TYPE() 46 | self.dex_section_version = VDEX_DEX_SECTION_VERSION_TYPE() 47 | self.number_of_dex_files = c_uint() 48 | self.verifier_deps_size = c_uint() 49 | self.bootclasspath_checksums_size = c_uint() 50 | self.class_loader_context_size = c_uint() 51 | 52 | def print_header(self): 53 | if not self.header_initialized: 54 | return 55 | 56 | print("\n==================================") 57 | print("VEX File Header") 58 | print("==================================") 59 | 60 | sys.stdout.write("\nVDEX Magic: ") 61 | 62 | for i in range(ctypes.sizeof(VDEX_MAGIC_TYPE)): 63 | sys.stdout.write("%02X " % (self.magic[i])) 64 | 65 | sys.stdout.write("(%s)\n" % ctypes.cast( 66 | self.magic, ctypes.c_char_p).value) 67 | 68 | sys.stdout.write("\nVerifier Deps Version: ") 69 | 70 | for i in range(ctypes.sizeof(VDEX_VERIFIER_DEPS_VERSION_TYPE)): 71 | sys.stdout.write("%02X " % (self.verifier_deps_version[i])) 72 | 73 | sys.stdout.write("(%s)\n" % ctypes.cast( 74 | self.verifier_deps_version, ctypes.c_char_p).value) 75 | 76 | sys.stdout.write("\nDEX Section Version: ") 77 | 78 | for i in range(ctypes.sizeof(VDEX_DEX_SECTION_VERSION_TYPE)): 79 | sys.stdout.write("%02X " % (self.dex_section_version[i])) 80 | 81 | sys.stdout.write("(%s)" % ctypes.cast( 82 | self.dex_section_version, ctypes.c_char_p).value) 83 | 84 | sys.stdout.write("\nNumber of DEX files: %d" % 85 | (self.number_of_dex_files.value)) 86 | 87 | sys.stdout.write("\nVerifier Deps Size: %d" % 88 | (self.verifier_deps_size.value)) 89 | 90 | sys.stdout.write("\nBootclasspath checksums size: %d" % 91 | (self.bootclasspath_checksums_size.value)) 92 | 93 | sys.stdout.write("\nClass Loader Context Size: %d" % 94 | (self.class_loader_context_size.value)) 95 | 96 | def parse_header(self, offset, file_size): 97 | self.file_p.seek(offset, FILE_BEGIN) 98 | 99 | for i in range(ctypes.sizeof(VDEX_MAGIC_TYPE)): 100 | self.magic[i] = read_file_le( 101 | self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 102 | 103 | for i in range(ctypes.sizeof(VDEX_VERIFIER_DEPS_VERSION_TYPE)): 104 | self.verifier_deps_version[i] = read_file_le( 105 | self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 106 | 107 | for i in range(ctypes.sizeof(VDEX_DEX_SECTION_VERSION_TYPE)): 108 | self.dex_section_version[i] = read_file_le( 109 | self.file_p, BYTE, BYTE_SIZE, self.file_p.tell()) 110 | 111 | self.number_of_dex_files = read_file_le( 112 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 113 | 114 | self.verifier_deps_size = read_file_le( 115 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 116 | 117 | self.bootclasspath_checksums_size = read_file_le( 118 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) 119 | 120 | self.class_loader_context_size = read_file_le( 121 | self.file_p, UINTEGER, UINTEGER_SIZE, self.file_p.tell()) -------------------------------------------------------------------------------- /FileWork.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | #-*- coding: utf-8 -*- 3 | 4 | ###################################################### 5 | # Dextripador 6 | # File: FileWork.py 7 | # Version: 0.7 8 | ###################################################### 9 | 10 | import ctypes 11 | from ctypes import c_int 12 | from ctypes import c_uint 13 | from ctypes import c_short 14 | from ctypes import c_ushort 15 | from ctypes import c_byte 16 | from ctypes import c_ubyte 17 | from ctypes import c_float 18 | from ctypes import c_long 19 | from ctypes import c_double 20 | import struct 21 | 22 | 23 | FILE_BEGIN = 0 24 | FILE_CURRENT = 1 25 | FILE_END = 2 26 | 27 | # FORMATS AND SIZES 28 | INTEGER = "i" 29 | INTEGER_SIZE = ctypes.sizeof(c_int()) 30 | 31 | UINTEGER = "I" 32 | UINTEGER_SIZE = ctypes.sizeof(c_uint()) 33 | 34 | SHORT = "h" 35 | SHORT_SIZE = ctypes.sizeof(c_short()) 36 | 37 | USHORT = "H" 38 | USHORT_SIZE = ctypes.sizeof(c_ushort()) 39 | 40 | BYTE = "B" 41 | BYTE_SIZE = ctypes.sizeof(c_ubyte()) 42 | 43 | FLOAT = "f" 44 | FLOAT_SIZE = ctypes.sizeof(c_float()) 45 | 46 | LONG = "l" 47 | LONG_SIZE = ctypes.sizeof(c_long()) 48 | 49 | DOUBLE = "d" 50 | DOUBLE_SIZE = ctypes.sizeof(c_double()) 51 | 52 | def read_file(file_p, format, size, offset, endianess = '>'): 53 | little_endian_format = endianess + format 54 | file_p.seek(offset, FILE_BEGIN) 55 | 56 | buf = file_p.read(size) 57 | value = struct.unpack(little_endian_format, buf)[0] 58 | 59 | if format == INTEGER: 60 | return c_int(value) 61 | elif format == UINTEGER: 62 | return c_uint(value) 63 | elif format == SHORT: 64 | return c_short(value) 65 | elif format == USHORT: 66 | return c_ushort(value) 67 | elif format == BYTE: 68 | return c_ubyte(value) 69 | elif format == FLOAT: 70 | return c_float(value) 71 | elif format == LONG: 72 | return c_long(value) 73 | elif format == DOUBLE: 74 | return c_double(value) 75 | 76 | 77 | def read_file_le(file_p, format, size, offset): 78 | return read_file(file_p, format, size, offset, endianess='<') 79 | 80 | def read_file_be(file_p, format, size, offset): 81 | return read_file(file_p, format, size, offset, endianess='>') 82 | 83 | def read_string_no_modify_offset(file_p, offset): 84 | previous_offset = file_p.tell() 85 | return_string = "" 86 | 87 | file_p.seek(offset, 0) 88 | 89 | string_length = file_p.read(1) 90 | 91 | 92 | for i in range(string_length[0]): 93 | byte_value = file_p.read(1) 94 | return_string += chr(byte_value[0]) 95 | 96 | 97 | file_p.seek(previous_offset, 0) 98 | 99 | return return_string 100 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Android Observatory 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dextripador 2 | A tool to extract the DEX file from ODEX compiled ahead of time version. 3 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Android-Observatory/DEXtripador/c459742c700fa8a59577d584f87584b3e31237f0/__init__.py -------------------------------------------------------------------------------- /elfparser_e/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | AR=ar 3 | CFLAGS=-c -g -Wall 4 | OBJ=obj-files/ 5 | OUT=out/ 6 | BIN_NAME=elf_parser 7 | STATIC_LIB_NAME=elf_parser.a 8 | SHARED_LIB_NAME=elf_parser.so 9 | HDR=headers/ 10 | SRC=src/ 11 | PYB=python_binding/ 12 | 13 | .PHONY: clean remove install 14 | 15 | all: dirs $(OUT)$(BIN_NAME) $(OUT)$(STATIC_LIB_NAME) $(OUT)$(SHARED_LIB_NAME) 16 | 17 | dirs: 18 | mkdir -p $(OBJ) 19 | mkdir -p $(OUT) 20 | 21 | $(OUT)$(BIN_NAME): $(OBJ)file_management.o $(OBJ)memory_management.o $(OBJ)elf_parser.o $(OBJ)elf_data_access.o $(OBJ)main.o 22 | $(CC) -I $(HDR) -o $@ $^ 23 | 24 | $(OBJ)file_management.o: $(SRC)file_management.c 25 | $(CC) -I $(HDR) $(CFLAGS) -o $@ $< 26 | 27 | $(OBJ)memory_management.o: $(SRC)memory_management.c 28 | $(CC) -I $(HDR) $(CFLAGS) -o $@ $< 29 | 30 | $(OBJ)elf_parser.o: $(SRC)elf_parser.c 31 | $(CC) -I $(HDR) $(CFLAGS) -Wformat=0 -o $@ $< 32 | 33 | $(OBJ)elf_data_access.o: $(SRC)elf_data_access.c 34 | $(CC) -I $(HDR) $(CFLAGS) -o $@ $< 35 | 36 | $(OBJ)main.o: main.c 37 | $(CC) -I $(HDR) $(CFLAGS) -o $@ $< 38 | 39 | $(OUT)$(STATIC_LIB_NAME): $(OBJ)file_management.o $(OBJ)memory_management.o $(OBJ)elf_parser.o $(OBJ)elf_data_access.o 40 | $(AR) -crv $@ $^ 41 | 42 | $(OUT)$(SHARED_LIB_NAME): $(SRC)file_management.c $(SRC)memory_management.c $(SRC)elf_parser.c $(SRC)elf_data_access.c 43 | $(CC) -Wl,-soname=$(SHARED_LIB_NAME) -fpic -shared -Wformat=0 -I $(HDR) -o $@ $^ 44 | @cp $(OUT)$(SHARED_LIB_NAME) $(PYB) 45 | 46 | ######################################################## 47 | clean: 48 | rm -rf $(OBJ) 49 | rm -rf $(OUT) 50 | rm $(PYB)$(SHARED_LIB_NAME) 51 | 52 | ######################################################## 53 | remove: 54 | rm -rf $(OBJ) 55 | rm -rf $(OUT) 56 | rm $(PYB)$(SHARED_LIB_NAME) 57 | sudo rm -f /usr/bin/$(BIN_NAME) 58 | 59 | install: dirs $(OUT)$(BIN_NAME) 60 | @cd $(OUT) 61 | @echo "Creating symbolic link to $(PWD)/$(OUT)$(BIN_NAME) in /usr/bin (you need to be root)" 62 | sudo rm -f /usr/bin/$(BIN_NAME) 63 | sudo ln -s "$(PWD)/$(OUT)$(BIN_NAME)" /usr/bin/$(BIN_NAME) 64 | @echo "Done" -------------------------------------------------------------------------------- /elfparser_e/headers/elf_generic_types.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef ELF_GENERIC_TYPES_H 4 | #define ELF_GENERIC_TYPES_H 5 | 6 | typedef struct elf_ehdr 7 | { 8 | unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ 9 | Elf64_Half e_type; 10 | Elf64_Half e_machine; 11 | Elf64_Word e_version; 12 | Elf64_Addr e_entry; /* Entry point virtual address */ 13 | Elf64_Off e_phoff; /* Program header table file offset */ 14 | Elf64_Off e_shoff; /* Section header table file offset */ 15 | Elf64_Word e_flags; 16 | Elf64_Half e_ehsize; 17 | Elf64_Half e_phentsize; 18 | Elf64_Half e_phnum; 19 | Elf64_Half e_shentsize; 20 | Elf64_Half e_shnum; 21 | Elf64_Half e_shstrndx; 22 | } Elf_Ehdr; 23 | 24 | typedef struct elf_phdr 25 | { 26 | uint32_t p_type; /* Segment type */ 27 | uint32_t p_flags; /* Segment flags, I.E execute|read|write */ 28 | Elf64_Off p_offset; /* Segment offset */ 29 | Elf64_Addr p_vaddr; /* Segment virtual address */ 30 | Elf64_Addr p_paddr; /* Segment physical address */ 31 | uint64_t p_filesz; /* Size of segment in the file */ 32 | uint64_t p_memsz; /* Size of segment in memory */ 33 | uint64_t p_align; /* Segment alignment in memory */ 34 | } Elf_Phdr; 35 | 36 | typedef struct elf_shdr 37 | { 38 | uint32_t sh_name; /* offset into shdr string table for shdr name */ 39 | uint32_t sh_type; /* shdr type I.E SHT_PROGBITS */ 40 | uint64_t sh_flags; /* shdr flags I.E SHT_WRITE|SHT_ALLOC */ 41 | Elf64_Addr sh_addr; /* address of where section begins */ 42 | Elf64_Off sh_offset; /* offset of shdr from beginning of file */ 43 | uint64_t sh_size; /* size that section takes up on disk */ 44 | uint32_t sh_link; /* points to another section (depends on the type) */ 45 | uint32_t sh_info; /* interpretation depends on section type */ 46 | uint64_t sh_addralign;/* alignment for address of section */ 47 | uint64_t sh_entsize; /* size of each certain entries that may be in section */ 48 | } Elf_Shdr; 49 | 50 | typedef struct elf_sym 51 | { 52 | uint32_t st_name; 53 | unsigned char st_info; 54 | unsigned char st_other; 55 | uint16_t st_shndx; 56 | Elf64_Addr st_value; 57 | uint64_t st_size; 58 | } Elf_Sym; 59 | 60 | typedef struct elf_rel 61 | { 62 | Elf64_Addr r_offset; 63 | uint64_t r_info; 64 | } Elf_Rel; 65 | 66 | typedef struct elf_rela 67 | { 68 | Elf64_Addr r_offset; 69 | uint64_t r_info; 70 | int64_t r_addend; 71 | } Elf_Rela; 72 | 73 | typedef struct elf_dyn 74 | { 75 | Elf64_Sxword d_tag; 76 | union { 77 | Elf64_Xword d_val; 78 | Elf64_Addr d_ptr; 79 | } d_un; 80 | } Elf_Dyn; 81 | 82 | #endif -------------------------------------------------------------------------------- /elfparser_e/headers/elf_parser.h: -------------------------------------------------------------------------------- 1 | #include "elf_generic_types.h" 2 | #include 3 | #include 4 | #include "memory_management.h" 5 | #include "file_management.h" 6 | 7 | #ifndef ELF_PARSER_H 8 | #define ELF_PARSER_H 9 | 10 | 11 | // Some lost defines 12 | 13 | // .note.gnu.property notes sections. 14 | #ifndef PT_GNU_PROPERTY 15 | #define PT_GNU_PROPERTY 0x6474e553 16 | #endif 17 | 18 | // Fill with random data. 19 | #ifndef PT_OPENBSD_RANDOMIZE 20 | #define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 21 | #endif 22 | 23 | // Program does W^X violations. 24 | #ifndef PT_OPENBSD_WXNEEDED 25 | #define PT_OPENBSD_WXNEEDED 0x65a3dbe7 26 | #endif 27 | 28 | // Section for boot arguments. 29 | #ifndef PT_OPENBSD_BOOTDATA 30 | #define PT_OPENBSD_BOOTDATA 0x65a41be6 31 | #endif 32 | 33 | // ARM program header types. 34 | // Platform architecture compatibility info 35 | #ifndef PT_ARM_ARCHEXT 36 | #define PT_ARM_ARCHEXT 0x70000000 37 | #endif 38 | 39 | 40 | int parse_elf(const char *pathname); 41 | 42 | /*** 43 | * Elf header parsing, useful functions 44 | * and printing 45 | */ 46 | int parse_elf_ehdr(uint8_t *buf_ptr, size_t file_size); 47 | int is_32_bit_binary(); 48 | int is_64_bit_binary(); 49 | const Elf_Ehdr *get_elf_ehdr_read(); 50 | void print_elf_ehdr(); 51 | 52 | /*** 53 | * Elf header 54 | * Interesting functions for python 55 | * binding. 56 | */ 57 | int is_magic_elf(); 58 | unsigned char e_ident(size_t nident); 59 | Elf64_Addr e_type(); 60 | Elf64_Half e_machine(); 61 | Elf64_Word e_version(); 62 | Elf64_Addr e_entry(); 63 | Elf64_Off e_phoff(); 64 | Elf64_Off e_shoff(); 65 | Elf64_Word e_flags(); 66 | Elf64_Half e_ehsize(); 67 | Elf64_Half e_phentsize(); 68 | Elf64_Half e_phnum(); 69 | Elf64_Half e_shentsize(); 70 | Elf64_Half e_shnum(); 71 | Elf64_Half e_shstrndx(); 72 | 73 | /*** 74 | * Program header parsing and printing 75 | */ 76 | int parse_elf_phdr(uint8_t *buf_ptr, size_t file_size); 77 | void print_elf_phdr(); 78 | 79 | /*** 80 | * Elf program header 81 | * Interesting functions for python 82 | * binding. 83 | */ 84 | uint32_t p_type(size_t header); 85 | uint32_t p_flags(size_t header); 86 | Elf64_Off p_offset(size_t header); 87 | Elf64_Addr p_vaddr(size_t header); 88 | Elf64_Addr p_paddr(size_t header); 89 | uint64_t p_filesz(size_t header); 90 | uint64_t p_memsz(size_t header); 91 | uint64_t p_align(size_t header); 92 | 93 | /*** 94 | * Section header parsing and printing 95 | */ 96 | int parse_elf_shdr(uint8_t *buf_ptr, size_t file_size); 97 | void print_elf_shdr(); 98 | 99 | /*** 100 | * Elf section header 101 | * Interesting functions for python 102 | * binding. 103 | */ 104 | uint32_t sh_name(size_t header); 105 | const char* sh_name_s(size_t header); 106 | uint32_t sh_type(size_t header); 107 | uint64_t sh_flags(size_t header); 108 | Elf64_Addr sh_addr(size_t header); 109 | Elf64_Off sh_offset(size_t header); 110 | uint64_t sh_size(size_t header); 111 | uint32_t sh_link(size_t header); 112 | uint32_t sh_info(size_t header); 113 | uint64_t sh_addralign(size_t header); 114 | uint64_t sh_entsize(size_t header); 115 | 116 | /*** 117 | * Symbols header parsing and printing 118 | */ 119 | int parse_elf_sym(uint8_t *buf_ptr); 120 | void print_elf_sym(); 121 | 122 | /*** 123 | * Elf Dynamic Symbol header 124 | * Interesting functions for python 125 | * binding 126 | */ 127 | size_t dynamic_sym_length(); 128 | uint32_t dynamic_st_name(size_t header); 129 | const char* dynamic_st_name_s(size_t header); 130 | unsigned char dynamic_st_info(size_t header); 131 | unsigned char dynamic_st_other(size_t header); 132 | uint16_t dynamic_st_shndx(size_t header); 133 | Elf64_Addr dynamic_st_value(size_t header); 134 | uint64_t dynamic_st_size(size_t header); 135 | 136 | /*** 137 | * Elf Symtab Symbol header 138 | * Interesting functions for python 139 | * binding 140 | */ 141 | size_t symtab_sym_length(); 142 | uint32_t symtab_st_name(size_t header); 143 | const char* symtab_st_name_s(size_t header); 144 | unsigned char symtab_st_info(size_t header); 145 | unsigned char symtab_st_other(size_t header); 146 | uint16_t symtab_st_shndx(size_t header); 147 | Elf64_Addr symtab_st_value(size_t header); 148 | uint64_t symtab_st_size(size_t header); 149 | 150 | /*** 151 | * Relocation header parsing and printing 152 | */ 153 | int parse_elf_rel_a(uint8_t *buf_ptr, size_t file_size); 154 | void print_elf_rel_a(); 155 | 156 | /*** 157 | * Elf Rel header 158 | * Interesting functions for python 159 | * binding 160 | */ 161 | Elf64_Addr rel_r_offset(size_t header, size_t index); 162 | uint64_t rel_r_info(size_t header, size_t index); 163 | 164 | size_t rel_32_size(); 165 | size_t rel_64_size(); 166 | 167 | /*** 168 | * Elf Rela header 169 | * Interesting functions for python 170 | * binding 171 | */ 172 | Elf64_Addr rela_r_offset(size_t header, size_t index); 173 | uint64_t rela_r_info(size_t header, size_t index); 174 | int64_t rela_r_addend(size_t header, size_t index); 175 | 176 | size_t rela_32_size(); 177 | size_t rela_64_size(); 178 | 179 | /*** 180 | * DYNAMIC Program header parsing and printing 181 | */ 182 | int parse_elf_dynamic(uint8_t *buf_ptr, size_t file_size); 183 | void print_elf_dynamic(); 184 | 185 | /*** 186 | * Printer functions, good for analsts 187 | */ 188 | void print_imported_libraries(); 189 | void print_imported_functions(); 190 | 191 | void print_exported_libraries(); 192 | void print_exported_functions(); 193 | 194 | 195 | void close_everything(); 196 | 197 | #endif -------------------------------------------------------------------------------- /elfparser_e/headers/file_management.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | #ifndef FILE_MANAGEMENT_H 8 | #define FILE_MANAGEMENT_H 9 | 10 | #ifndef INVALID_FILE_DESCRIPTOR 11 | #define INVALID_FILE_DESCRIPTOR -1 12 | #endif 13 | 14 | int open_file(const char *pathname, int flags); 15 | int open_file_reading(const char *pathname); 16 | int open_file_writing(const char *pathname); 17 | int open_file_read_write(const char *pathname); 18 | 19 | ssize_t get_file_size(int fd); 20 | 21 | 22 | int close_file(int fd); 23 | 24 | 25 | #endif 26 | 27 | -------------------------------------------------------------------------------- /elfparser_e/headers/memory_management.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifndef MEMORY_MANAGEMENT_H 6 | #define MEMORY_MANAGEMENT_H 7 | 8 | void* allocate_memory(size_t size); 9 | void* realloc_memory(void* ptr, size_t size); 10 | void* mmap_file_read(size_t length, int fd); 11 | void* mmap_file_write(size_t length, int fd); 12 | void* mmap_file_read_write(size_t length, int fd); 13 | 14 | int free_memory(void *ptr); 15 | int munmap_memory(void* ptr, size_t size); 16 | 17 | #endif -------------------------------------------------------------------------------- /elfparser_e/main.c: -------------------------------------------------------------------------------- 1 | #include "elf_parser.h" 2 | #include 3 | 4 | int 5 | main(int argc, char *argv[]) 6 | { 7 | int c; 8 | 9 | if (argc < 2) 10 | { 11 | printf("usage: elfparser [-a/-h/-l/-S/-s/-r/-L/-i/-e] \n"); 12 | printf("\t-a: all the flags\n"); 13 | printf("\t-h: print elf header\n"); 14 | printf("\t-l: print program header\n"); 15 | printf("\t-S: print section header\n"); 16 | printf("\t-s: print symbols header\n"); 17 | printf("\t-r: print reloc headers\n"); 18 | printf("\t-D: print dynamic program headers\n"); 19 | printf("\t-L: print imported libraries\n"); 20 | printf("\t-i: print imported functions\n"); 21 | printf("\t-e: print exported libraries\n"); 22 | printf("\t-f: print exported functions\n"); 23 | printf("Badly written by: Fare9\n"); 24 | printf("\n\n"); 25 | exit(0); 26 | } 27 | 28 | if (parse_elf(argv[argc-1]) < 0) 29 | exit(-1); 30 | 31 | while ((c = getopt(argc, argv, "ahlSsrDLief:")) != -1) 32 | { 33 | switch(c) 34 | { 35 | case 'a': 36 | print_elf_ehdr(); 37 | printf("\n"); 38 | print_elf_phdr(); 39 | printf("\n"); 40 | print_elf_shdr(); 41 | printf("\n"); 42 | print_elf_sym(); 43 | printf("\n"); 44 | print_elf_rel_a(); 45 | printf("\n"); 46 | print_elf_dynamic(); 47 | printf("\n"); 48 | print_imported_libraries(); 49 | printf("\n"); 50 | print_imported_functions(); 51 | printf("\n"); 52 | print_exported_libraries(); 53 | printf("\n"); 54 | print_exported_functions(); 55 | printf("\n"); 56 | break; 57 | case 'h': 58 | print_elf_ehdr(); 59 | printf("\n"); 60 | break; 61 | case 'l': 62 | print_elf_phdr(); 63 | printf("\n"); 64 | break; 65 | case 'S': 66 | print_elf_shdr(); 67 | printf("\n"); 68 | break; 69 | case 's': 70 | print_elf_sym(); 71 | printf("\n"); 72 | break; 73 | case 'r': 74 | print_elf_rel_a(); 75 | printf("\n"); 76 | break; 77 | case 'D': 78 | print_elf_dynamic(); 79 | printf("\n"); 80 | break; 81 | case 'L': 82 | print_imported_libraries(); 83 | printf("\n"); 84 | break; 85 | case 'i': 86 | print_imported_functions(); 87 | printf("\n"); 88 | break; 89 | case 'e': 90 | print_exported_libraries(); 91 | printf("\n"); 92 | break; 93 | case 'f': 94 | print_exported_functions(); 95 | printf("\n"); 96 | break; 97 | default: 98 | break; 99 | } 100 | } 101 | 102 | // free memory 103 | close_everything(); 104 | } -------------------------------------------------------------------------------- /elfparser_e/python_binding/elf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | ################################################## 5 | # elf_parser python binding 6 | # File: elf.py 7 | ################################################## 8 | 9 | import sys 10 | import os 11 | from ctypes import * 12 | from enum import Enum 13 | 14 | ELF_LIB_NAME = os.path.dirname(__file__) + "/elf_parser.so" 15 | 16 | 17 | if not os.path.isfile(ELF_LIB_NAME): 18 | raise FileNotFoundError("%s doesn't exist, did you compile elfparser_e project with make?" % ELF_LIB_NAME) 19 | 20 | ELF_LIB = CDLL(ELF_LIB_NAME) 21 | 22 | 23 | class Elf_Ehdr(): 24 | 25 | def __init__(self, e_ident, e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, e_flags, e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx): 26 | self.e_ident = e_ident 27 | self.e_type = e_type 28 | self.e_machine = e_machine 29 | self.e_version = e_version 30 | self.e_entry = e_entry 31 | self.e_phoff = e_phoff 32 | self.e_shoff = e_shoff 33 | self.e_flags = e_flags 34 | self.e_ehsize = e_ehsize 35 | self.e_phentsize = e_phentsize 36 | self.e_phnum = e_phnum 37 | self.e_shentsize = e_shentsize 38 | self.e_shnum = e_shnum 39 | self.e_shstrndx = e_shstrndx 40 | 41 | 42 | class Elf_Phdr(): 43 | 44 | def __init__(self, p_type, p_flags, p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, p_align): 45 | self.p_type = p_type 46 | self.p_flags = p_flags 47 | self.p_offset = p_offset 48 | self.p_vaddr = p_vaddr 49 | self.p_paddr = p_paddr 50 | self.p_filesz = p_filesz 51 | self.p_memsz = p_memsz 52 | self.p_align = p_align 53 | 54 | 55 | class Elf_Shdr(): 56 | 57 | def __init__(self, sh_name_offset, sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size, sh_link, sh_info, sh_addralign, sh_entsize): 58 | self.sh_name_offset = sh_name_offset 59 | self.sh_name = sh_name 60 | self.sh_type = sh_type 61 | self.sh_flags = sh_flags 62 | self.sh_addr = sh_addr 63 | self.sh_offset = sh_offset 64 | self.sh_size = sh_size 65 | self.sh_link = sh_link 66 | self.sh_info = sh_info 67 | self.sh_addralign = sh_addralign 68 | self.sh_entsize = sh_entsize 69 | 70 | 71 | class Elf_Sym(): 72 | 73 | def __init__(self, st_name_offset, st_name, st_info, st_other, st_shndx, st_value, st_size): 74 | self.st_name_offset = st_name_offset 75 | self.st_name = st_name 76 | self.st_info = st_info 77 | self.st_other = st_other 78 | self.st_shndx = st_shndx 79 | self.st_value = st_value 80 | self.st_size = st_size 81 | 82 | 83 | class Elf_Rel(): 84 | 85 | def __init__(self, r_offset, r_info): 86 | self.r_offset = r_offset 87 | self.r_info = r_info 88 | 89 | 90 | class Elf_Rela(): 91 | 92 | def __init__(self, r_offset, r_info, r_addend): 93 | self.r_offset = r_offset 94 | self.r_info = r_info 95 | self.r_addend = r_addend 96 | 97 | 98 | class Elf(): 99 | 100 | # OS ABI CONSTANTS 101 | class OSABI(): 102 | ELFOSABI_SYSV = 0 103 | ELFOSABI_HPUX = 1 104 | ELFOSABI_NETBSD = 2 105 | ELFOSABI_GNU = 3 106 | ELFOSABI_LINUX = ELFOSABI_GNU 107 | ELFOSABI_SOLARIS = 6 108 | ELFOSABI_AIX = 7 109 | ELFOSABI_IRIX = 8 110 | ELFOSABI_FREEBSD = 9 111 | ELFOSABI_TRU64 = 10 112 | ELFOSABI_MODESTO = 11 113 | ELFOSABI_OPENBSD = 12 114 | ELFOSABI_ARM_AEABI = 64 115 | ELFOSABI_ARM = 97 116 | ELFOSABI_STANDALONE = 255 117 | 118 | # Machine 119 | class Machine(): 120 | EM_NONE = 0 121 | EM_M32 = 1 122 | EM_SPARC = 2 123 | EM_386 = 3 124 | EM_68K = 4 125 | EM_88K = 5 126 | EM_IAMCU = 6 127 | EM_860 = 7 128 | EM_MIPS = 8 129 | EM_S370 = 9 130 | EM_MIPS_RS3_LE = 10 131 | EM_PARISC = 15 132 | EM_VPP500 = 17 133 | EM_SPARC32PLUS = 18 134 | EM_960 = 19 135 | EM_PPC = 20 136 | EM_PPC64 = 21 137 | EM_S390 = 22 138 | EM_SPU = 23 139 | EM_V800 = 36 140 | EM_FR20 = 37 141 | EM_RH32 = 38 142 | EM_RCE = 39 143 | EM_ARM = 40 144 | EM_FAKE_ALPHA = 41 145 | EM_SH = 42 146 | EM_SPARCV9 = 43 147 | EM_TRICORE = 44 148 | EM_ARC = 45 149 | EM_H8_300 = 46 150 | EM_H8_300H = 47 151 | EM_H8S = 48 152 | EM_H8_500 = 49 153 | EM_IA_64 = 50 154 | EM_MIPS_X = 51 155 | EM_COLDFIRE = 52 156 | EM_68HC12 = 53 157 | EM_MMA = 54 158 | EM_PCP = 55 159 | EM_NCPU = 56 160 | EM_NDR1 = 57 161 | EM_STARCORE = 58 162 | EM_ME16 = 59 163 | EM_ST100 = 60 164 | EM_TINYJ = 61 165 | EM_X86_64 = 62 166 | EM_PDSP = 63 167 | EM_PDP10 = 64 168 | EM_PDP11 = 65 169 | EM_FX66 = 66 170 | EM_ST9PLUS = 67 171 | EM_ST7 = 68 172 | EM_68HC16 = 69 173 | EM_68HC11 = 70 174 | EM_68HC08 = 71 175 | EM_68HC05 = 72 176 | EM_SVX = 73 177 | EM_ST19 = 74 178 | EM_VAX = 75 179 | EM_CRIS = 76 180 | EM_JAVELIN = 77 181 | EM_FIREPATH = 78 182 | EM_ZSP = 79 183 | EM_MMIX = 80 184 | EM_HUANY = 81 185 | EM_PRISM = 82 186 | EM_AVR = 83 187 | EM_FR30 = 84 188 | EM_D10V = 85 189 | EM_D30V = 86 190 | EM_V850 = 87 191 | EM_M32R = 88 192 | EM_MN10300 = 89 193 | EM_MN10200 = 90 194 | EM_PJ = 91 195 | EM_OPENRISC = 92 196 | EM_ARC_COMPACT = 93 197 | EM_XTENSA = 94 198 | EM_VIDEOCORE = 95 199 | EM_TMM_GPP = 96 200 | EM_NS32K = 97 201 | EM_TPC = 98 202 | EM_SNP1K = 99 203 | EM_ST200 = 100 204 | EM_IP2K = 101 205 | EM_MAX = 102 206 | EM_CR = 103 207 | EM_F2MC16 = 104 208 | EM_MSP430 = 105 209 | EM_BLACKFIN = 106 210 | EM_SE_C33 = 107 211 | EM_SEP = 108 212 | EM_ARCA = 109 213 | EM_UNICORE = 110 214 | EM_EXCESS = 111 215 | EM_DXP = 112 216 | EM_ALTERA_NIOS2 = 113 217 | EM_CRX = 114 218 | EM_XGATE = 115 219 | EM_C166 = 116 220 | EM_M16C = 117 221 | EM_DSPIC30F = 118 222 | EM_CE = 119 223 | EM_M32C = 120 224 | EM_TSK3000 = 131 225 | EM_RS08 = 132 226 | EM_SHARC = 133 227 | EM_ECOG2 = 134 228 | EM_SCORE7 = 135 229 | EM_DSP24 = 136 230 | EM_VIDEOCORE3 = 137 231 | EM_LATTICEMICO32= 138 232 | EM_SE_C17 = 139 233 | EM_TI_C6000 = 140 234 | EM_TI_C2000 = 141 235 | EM_TI_C5500 = 142 236 | EM_TI_ARP32 = 143 237 | EM_TI_PRU = 144 238 | EM_MMDSP_PLUS = 160 239 | EM_CYPRESS_M8C = 161 240 | EM_R32C = 162 241 | EM_TRIMEDIA = 163 242 | EM_QDSP6 = 164 243 | EM_8051 = 165 244 | EM_STXP7X = 166 245 | EM_NDS32 = 167 246 | EM_ECOG1X = 168 247 | EM_MAXQ30 = 169 248 | EM_XIMO16 = 170 249 | EM_MANIK = 171 250 | EM_CRAYNV2 = 172 251 | EM_RX = 173 252 | EM_METAG = 174 253 | EM_MCST_ELBRUS = 175 254 | EM_ECOG16 = 176 255 | EM_CR16 = 177 256 | EM_ETPU = 178 257 | EM_SLE9X = 179 258 | EM_L10M = 180 259 | EM_K10M = 181 260 | EM_AARCH64 = 183 261 | EM_AVR32 = 185 262 | EM_STM8 = 186 263 | EM_TILE64 = 187 264 | EM_TILEPRO = 188 265 | EM_MICROBLAZE = 189 266 | EM_CUDA = 190 267 | EM_TILEGX = 191 268 | EM_CLOUDSHIELD = 192 269 | EM_COREA_1ST = 193 270 | EM_COREA_2ND = 194 271 | EM_ARC_COMPACT2 = 195 272 | EM_OPEN8 = 196 273 | EM_RL78 = 197 274 | EM_VIDEOCORE5 = 198 275 | EM_78KOR = 199 276 | EM_56800EX = 200 277 | EM_BA1 = 201 278 | EM_BA2 = 202 279 | EM_XCORE = 203 280 | EM_MCHP_PIC = 204 281 | EM_KM32 = 210 282 | EM_KMX32 = 211 283 | EM_EMX16 = 212 284 | EM_EMX8 = 213 285 | EM_KVARC = 214 286 | EM_CDP = 215 287 | EM_COGE = 216 288 | EM_COOL = 217 289 | EM_NORC = 218 290 | EM_CSR_KALIMBA = 219 291 | EM_Z80 = 220 292 | EM_VISIUM = 221 293 | EM_FT32 = 222 294 | EM_MOXIE = 223 295 | EM_AMDGPU = 224 296 | EM_RISCV = 243 297 | EM_BPF = 247 298 | EM_NUM = 248 299 | EM_ARC_A5 = EM_ARC_COMPACT 300 | EM_ALPHA = 0x9026 301 | 302 | class PhdrType(): 303 | PT_NULL = 0 304 | PT_LOAD = 1 305 | PT_DYNAMIC = 2 306 | PT_INTERP = 3 307 | PT_NOTE = 4 308 | PT_SHLIB = 5 309 | PT_PHDR = 6 310 | PT_TLS = 7 311 | PT_NUM = 8 312 | PT_LOOS = 0x60000000 313 | PT_GNU_EH_FRAME = 0x6474e550 314 | PT_GNU_STACK = 0x6474e551 315 | PT_GNU_RELRO = 0x6474e552 316 | PT_LOSUNW = 0x6ffffffa 317 | PT_SUNWBSS = 0x6ffffffa 318 | PT_SUNWSTACK = 0x6ffffffb 319 | PT_HISUNW = 0x6fffffff 320 | PT_HIOS = 0x6fffffff 321 | PT_LOPROC = 0x70000000 322 | PT_HIPROC = 0x7fffffff 323 | 324 | class ShdrType(): 325 | SHT_NULL = 0 326 | SHT_PROGBITS = 1 327 | SHT_SYMTAB = 2 328 | SHT_STRTAB = 3 329 | SHT_RELA = 4 330 | SHT_HASH = 5 331 | SHT_DYNAMIC = 6 332 | SHT_NOTE = 7 333 | SHT_NOBITS = 8 334 | SHT_REL = 9 335 | SHT_SHLIB = 10 336 | SHT_DYNSYM = 11 337 | SHT_INIT_ARRAY = 14 338 | SHT_FINI_ARRAY = 15 339 | SHT_PREINIT_ARRAY = 16 340 | SHT_GROUP = 17 341 | SHT_SYMTAB_SHNDX = 18 342 | SHT_NUM = 19 343 | SHT_LOOS = 0x60000000 344 | SHT_GNU_ATTRIBUTES = 0x6ffffff5 345 | SHT_GNU_HASH = 0x6ffffff6 346 | SHT_GNU_LIBLIST = 0x6ffffff7 347 | SHT_CHECKSUM = 0x6ffffff8 348 | SHT_LOSUNW = 0x6ffffffa 349 | SHT_SUNW_move = 0x6ffffffa 350 | SHT_SUNW_COMDAT = 0x6ffffffb 351 | SHT_SUNW_syminfo = 0x6ffffffc 352 | SHT_GNU_verdef = 0x6ffffffd 353 | SHT_GNU_verneed = 0x6ffffffe 354 | SHT_GNU_versym = 0x6fffffff 355 | SHT_HISUNW = 0x6fffffff 356 | SHT_HIOS = 0x6fffffff 357 | SHT_LOPROC = 0x70000000 358 | SHT_HIPROC = 0x7fffffff 359 | SHT_LOUSER = 0x80000000 360 | SHT_HIUSER = 0x8fffffff 361 | 362 | class ShdrFlag(): 363 | SHF_WRITE = (1 << 0) 364 | SHF_ALLOC = (1 << 1) 365 | SHF_EXECINSTR = (1 << 2) 366 | SHF_MERGE = (1 << 4) 367 | SHF_STRINGS = (1 << 5) 368 | SHF_INFO_LINK = (1 << 6) 369 | SHF_LINK_ORDER = (1 << 7) 370 | SHF_OS_NONCONFORMING = (1 << 8) 371 | SHF_GROUP = (1 << 9) 372 | SHF_TLS = (1 << 10) 373 | SHF_COMPRESSED = (1 << 11) 374 | SHF_MASKOS = 0x0ff00000 375 | SHF_MASKPROC = 0xf0000000 376 | SHF_ORDERED = (1 << 30) 377 | SHF_EXCLUDE = (1 << 31) 378 | 379 | class SymVisibility(): 380 | STV_DEFAULT = 0 381 | STV_INTERNAL = 1 382 | STV_HIDDEN = 2 383 | STV_PROTECTED = 3 384 | 385 | class SymSection(): 386 | SHN_ABS = 0xfff1 387 | SHN_UNDEF = 0 388 | SHN_BEFORE = 0xff00 389 | SHN_AFTER = 0xff01 390 | 391 | def __init__(self, path_to_elf): 392 | self.is_elf_ = False 393 | self.analyzed = False 394 | self.is_32_bit_ = False 395 | self.is_64_bit_ = False 396 | 397 | self.elf_ehdr = None 398 | self.elf_phdr = [] 399 | self.elf_shdr = [] 400 | self.elf_sym = [] 401 | self.elf_rel = [] 402 | self.elf_rela = [] 403 | 404 | self.path_to_elf = path_to_elf 405 | 406 | self.__parse() 407 | 408 | def __del__(self): 409 | if self.analyzed: 410 | ELF_LIB.close_everything() 411 | 412 | def __parse(self): 413 | rel_index = 0 414 | rela_index = 0 415 | 416 | if not os.path.isfile(self.path_to_elf): 417 | return 418 | 419 | if ELF_LIB.parse_elf(self.path_to_elf.encode()) == -1: 420 | return 421 | 422 | self.analyzed = True 423 | 424 | e_ident = [] 425 | for i in range(16): 426 | e_ident.append(ELF_LIB.e_ident(i)) 427 | 428 | self.elf_ehdr = Elf_Ehdr( 429 | e_ident, 430 | ELF_LIB.e_type(), 431 | ELF_LIB.e_machine(), 432 | ELF_LIB.e_version(), 433 | ELF_LIB.e_entry(), 434 | ELF_LIB.e_phoff(), 435 | ELF_LIB.e_shoff(), 436 | ELF_LIB.e_flags(), 437 | ELF_LIB.e_ehsize(), 438 | ELF_LIB.e_phentsize(), 439 | ELF_LIB.e_phnum(), 440 | ELF_LIB.e_shentsize(), 441 | ELF_LIB.e_shnum(), 442 | ELF_LIB.e_shstrndx() 443 | ) 444 | 445 | if ELF_LIB.is_32_bit_binary() == 1: 446 | self.is_32_bit_ = True 447 | elif ELF_LIB.is_64_bit_binary() == 1: 448 | self.is_64_bit_ = True 449 | 450 | for i in range(self.elf_ehdr.e_phnum): 451 | self.elf_phdr.append( 452 | Elf_Phdr( 453 | ELF_LIB.p_type(i), 454 | ELF_LIB.p_flags(i), 455 | ELF_LIB.p_offset(i), 456 | ELF_LIB.p_vaddr(i), 457 | ELF_LIB.p_paddr(i), 458 | ELF_LIB.p_filesz(i), 459 | ELF_LIB.p_memsz(i), 460 | ELF_LIB.p_align(i) 461 | ) 462 | ) 463 | 464 | ELF_LIB.sh_name_s.restype = c_char_p 465 | 466 | for i in range(self.elf_ehdr.e_shnum): 467 | self.elf_shdr.append( 468 | Elf_Shdr( 469 | ELF_LIB.sh_name(i), 470 | ELF_LIB.sh_name_s(i).decode(), 471 | ELF_LIB.sh_type(i), 472 | ELF_LIB.sh_flags(i), 473 | ELF_LIB.sh_addr(i), 474 | ELF_LIB.sh_offset(i), 475 | ELF_LIB.sh_size(i), 476 | ELF_LIB.sh_link(i), 477 | ELF_LIB.sh_info(i), 478 | ELF_LIB.sh_addralign(i), 479 | ELF_LIB.sh_entsize(i) 480 | ) 481 | ) 482 | 483 | ELF_LIB.dynamic_st_name_s.restype = c_char_p 484 | ELF_LIB.symtab_st_name_s.restype = c_char_p 485 | 486 | for i in range(ELF_LIB.dynamic_sym_length()): 487 | self.elf_sym.append( 488 | Elf_Sym( 489 | ELF_LIB.dynamic_st_name(i), 490 | ELF_LIB.dynamic_st_name_s(i).decode(), 491 | ELF_LIB.dynamic_st_info(i), 492 | ELF_LIB.dynamic_st_other(i), 493 | ELF_LIB.dynamic_st_shndx(i), 494 | ELF_LIB.dynamic_st_value(i), 495 | ELF_LIB.dynamic_st_size(i) 496 | ) 497 | ) 498 | 499 | for i in range(ELF_LIB.symtab_sym_length()): 500 | self.elf_sym.append( 501 | Elf_Sym( 502 | ELF_LIB.symtab_st_name(i), 503 | ELF_LIB.symtab_st_name_s(i).decode(), 504 | ELF_LIB.symtab_st_info(i), 505 | ELF_LIB.symtab_st_other(i), 506 | ELF_LIB.symtab_st_shndx(i), 507 | ELF_LIB.symtab_st_value(i), 508 | ELF_LIB.symtab_st_size(i) 509 | ) 510 | ) 511 | 512 | for i in range(self.elf_ehdr.e_shnum): 513 | 514 | if self.elf_shdr[i].sh_type == Elf.ShdrType.SHT_REL: 515 | n_of_rels = 0 516 | relocs = [] 517 | if self.is_32_bit: 518 | n_of_rels = int(self.elf_shdr[i].sh_size / ELF_LIB.rel_32_size()) 519 | elif self.is_64_bit: 520 | n_of_rels = int(self.elf_shdr[i].sh_size / ELF_LIB.rel_64_size()) 521 | 522 | for j in range(n_of_rels): 523 | relocs.append( 524 | Elf_Rel(ELF_LIB.rel_r_offset(rel_index,j), 525 | ELF_LIB.rel_r_info(rel_index,j)) 526 | ) 527 | rel_index += 1 528 | 529 | if len(relocs) > 0: 530 | self.elf_rel.append(relocs) 531 | 532 | if self.elf_shdr[i].sh_type == Elf.ShdrType.SHT_RELA: 533 | n_of_relas = 0 534 | relocs = [] 535 | if self.is_32_bit: 536 | n_of_relas = int(self.elf_shdr[i].sh_size / ELF_LIB.rela_32_size()) 537 | elif self.is_64_bit: 538 | n_of_relas = int(self.elf_shdr[i].sh_size / ELF_LIB.rela_64_size()) 539 | 540 | for j in range(n_of_relas): 541 | relocs.append( 542 | Elf_Rela(ELF_LIB.rela_r_offset(rela_index,j), 543 | ELF_LIB.rela_r_info(rela_index,j), 544 | ELF_LIB.rela_r_addend(rela_index, j)) 545 | ) 546 | rela_index += 1 547 | 548 | if len(relocs) > 0: 549 | self.elf_rela.append(relocs) 550 | 551 | if not self.is_32_bit_ and not self.is_64_bit_: 552 | return 553 | 554 | self.is_elf_ = True 555 | 556 | def is_elf(self): 557 | return self.is_elf_ 558 | 559 | def is_32_bit(self): 560 | return self.is_32_bit_ 561 | 562 | def is_64_bit(self): 563 | return self.is_64_bit_ 564 | 565 | def print_elf_header(self): 566 | ELF_LIB.print_elf_ehdr() 567 | 568 | def print_elf_program_header(self): 569 | ELF_LIB.print_elf_phdr() 570 | 571 | def print_elf_section_header(self): 572 | ELF_LIB.print_elf_shdr() 573 | 574 | def print_elf_symbols_header(self): 575 | ELF_LIB.print_elf_sym() 576 | 577 | def print_elf_relocs_header(self): 578 | ELF_LIB.print_elf_rel_a() 579 | 580 | if __name__ == '__main__': 581 | if len(sys.argv) != 2: 582 | print("USAGE: %s " % sys.argv[0]) 583 | sys.exit(0) 584 | 585 | elf = Elf(sys.argv[1]) 586 | print("Is elf? ",elf.is_elf()) 587 | 588 | if not elf.is_elf(): 589 | sys.exit(-1) 590 | 591 | elf.print_elf_header() 592 | elf.print_elf_program_header() 593 | elf.print_elf_section_header() 594 | print(elf.elf_shdr[1].sh_name) 595 | elf.print_elf_symbols_header() 596 | elf.print_elf_relocs_header() 597 | 598 | print("Number of rel: %d" % len(elf.elf_rel)) 599 | 600 | for i in range(len(elf.elf_rel)): 601 | print("\tInternal rel: %d" % len(elf.elf_rel[i])) 602 | 603 | print("Number of rela: %d" % len(elf.elf_rela)) 604 | 605 | for i in range(len(elf.elf_rela)): 606 | print("\tInternal rela: %d" % len(elf.elf_rela[i])) -------------------------------------------------------------------------------- /elfparser_e/src/elf_data_access.c: -------------------------------------------------------------------------------- 1 | #include "elf_parser.h" 2 | 3 | extern Elf_Ehdr *elf_ehdr; 4 | extern Elf_Phdr *elf_phdr; 5 | extern Elf_Shdr *elf_shdr; 6 | extern Elf_Sym *elf_dynsym; 7 | extern Elf_Sym *elf_symtab; 8 | extern Elf_Rel **elf_rel; 9 | extern Elf_Rela **elf_rela; 10 | extern char *StringTable; 11 | extern char *SymbolStringTable; 12 | extern char *DynSymbolStringTable; 13 | 14 | extern uint64_t dynsym_num; 15 | extern uint64_t symtab_num; 16 | extern size_t rel_sections; 17 | extern size_t rela_sections; 18 | /*** 19 | * Elf header 20 | * Interesting functions for python 21 | * binding. 22 | */ 23 | int 24 | is_magic_elf() 25 | { 26 | if (elf_ehdr == NULL) 27 | { 28 | return (-1); 29 | } 30 | 31 | if (elf_ehdr->e_ident[EI_MAG0] != ELFMAG0 || 32 | elf_ehdr->e_ident[EI_MAG1] != ELFMAG1 || 33 | elf_ehdr->e_ident[EI_MAG2] != ELFMAG2 || 34 | elf_ehdr->e_ident[EI_MAG3] != ELFMAG3) 35 | { 36 | return (0); 37 | } 38 | 39 | return (1); 40 | } 41 | 42 | unsigned char 43 | e_ident(size_t nident) 44 | { 45 | if (elf_ehdr == NULL || nident >= EI_NIDENT) 46 | { 47 | return (unsigned char)(-1); 48 | } 49 | 50 | return (elf_ehdr->e_ident[nident]); 51 | } 52 | 53 | Elf64_Addr 54 | e_type() 55 | { 56 | if (elf_ehdr == NULL) 57 | { 58 | return (Elf64_Addr)(-1); 59 | } 60 | 61 | return (elf_ehdr->e_type); 62 | } 63 | 64 | Elf64_Half 65 | e_machine() 66 | { 67 | if (elf_ehdr == NULL) 68 | { 69 | return (Elf64_Half)(-1); 70 | } 71 | 72 | return (elf_ehdr->e_machine); 73 | } 74 | 75 | Elf64_Word 76 | e_version() 77 | { 78 | if (elf_ehdr == NULL) 79 | { 80 | return (Elf64_Word)(-1); 81 | } 82 | 83 | return (elf_ehdr->e_version); 84 | } 85 | 86 | Elf64_Addr 87 | e_entry() 88 | { 89 | if (elf_ehdr == NULL) 90 | { 91 | return (Elf64_Addr)(-1); 92 | } 93 | 94 | return (elf_ehdr->e_entry); 95 | } 96 | 97 | Elf64_Off 98 | e_phoff() 99 | { 100 | if (elf_ehdr == NULL) 101 | { 102 | return (Elf64_Off)(-1); 103 | } 104 | 105 | return (elf_ehdr->e_phoff); 106 | } 107 | 108 | Elf64_Off 109 | e_shoff() 110 | { 111 | if (elf_ehdr == NULL) 112 | { 113 | return (Elf64_Off)(-1); 114 | } 115 | 116 | return (elf_ehdr->e_shoff); 117 | } 118 | 119 | Elf64_Word 120 | e_flags() 121 | { 122 | if (elf_ehdr == NULL) 123 | { 124 | return (Elf64_Word)(-1); 125 | } 126 | 127 | return (elf_ehdr->e_flags); 128 | } 129 | 130 | Elf64_Half 131 | e_ehsize() 132 | { 133 | if (elf_ehdr == NULL) 134 | { 135 | return (Elf64_Half)(-1); 136 | } 137 | 138 | return (elf_ehdr->e_ehsize); 139 | } 140 | 141 | Elf64_Half 142 | e_phentsize() 143 | { 144 | if (elf_ehdr == NULL) 145 | { 146 | return (Elf64_Half)(-1); 147 | } 148 | 149 | return (elf_ehdr->e_phentsize); 150 | } 151 | 152 | Elf64_Half 153 | e_phnum() 154 | { 155 | if (elf_ehdr == NULL) 156 | { 157 | return (Elf64_Half)(-1); 158 | } 159 | 160 | return (elf_ehdr->e_phnum); 161 | } 162 | 163 | Elf64_Half 164 | e_shentsize() 165 | { 166 | if (elf_ehdr == NULL) 167 | { 168 | return (Elf64_Half)(-1); 169 | } 170 | 171 | return (elf_ehdr->e_shentsize); 172 | } 173 | 174 | Elf64_Half 175 | e_shnum() 176 | { 177 | if (elf_ehdr == NULL) 178 | { 179 | return (Elf64_Half)(-1); 180 | } 181 | 182 | return (elf_ehdr->e_shnum); 183 | } 184 | 185 | Elf64_Half 186 | e_shstrndx() 187 | { 188 | if (elf_ehdr == NULL) 189 | { 190 | return (Elf64_Half)(-1); 191 | } 192 | 193 | return (elf_ehdr->e_shstrndx); 194 | } 195 | 196 | 197 | /*** 198 | * Elf program header 199 | * Interesting functions for python 200 | * binding. 201 | */ 202 | uint32_t 203 | p_type(size_t header) 204 | { 205 | if (elf_ehdr == NULL || 206 | elf_phdr == NULL || 207 | header >= elf_ehdr->e_phnum) 208 | { 209 | return (uint32_t)(-1); 210 | } 211 | 212 | return (elf_phdr[header].p_type); 213 | } 214 | 215 | uint32_t 216 | p_flags(size_t header) 217 | { 218 | if (elf_ehdr == NULL || 219 | elf_phdr == NULL || 220 | header >= elf_ehdr->e_phnum) 221 | { 222 | return (uint32_t)(-1); 223 | } 224 | 225 | return (elf_phdr[header].p_flags); 226 | } 227 | 228 | Elf64_Off 229 | p_offset(size_t header) 230 | { 231 | if (elf_ehdr == NULL || 232 | elf_phdr == NULL || 233 | header >= elf_ehdr->e_phnum) 234 | { 235 | return (Elf64_Off)(-1); 236 | } 237 | 238 | return (elf_phdr[header].p_offset); 239 | } 240 | 241 | Elf64_Addr 242 | p_vaddr(size_t header) 243 | { 244 | if (elf_ehdr == NULL || 245 | elf_phdr == NULL || 246 | header >= elf_ehdr->e_phnum) 247 | { 248 | return (Elf64_Addr)(-1); 249 | } 250 | 251 | return (elf_phdr[header].p_vaddr); 252 | } 253 | 254 | Elf64_Addr 255 | p_paddr(size_t header) 256 | { 257 | if (elf_ehdr == NULL || 258 | elf_phdr == NULL || 259 | header >= elf_ehdr->e_phnum) 260 | { 261 | return (Elf64_Addr)(-1); 262 | } 263 | 264 | return (elf_phdr[header].p_paddr); 265 | } 266 | 267 | uint64_t 268 | p_filesz(size_t header) 269 | { 270 | if (elf_ehdr == NULL || 271 | elf_phdr == NULL || 272 | header >= elf_ehdr->e_phnum) 273 | { 274 | return (uint64_t)(-1); 275 | } 276 | 277 | return (elf_phdr[header].p_filesz); 278 | } 279 | 280 | uint64_t 281 | p_memsz(size_t header) 282 | { 283 | if (elf_ehdr == NULL || 284 | elf_phdr == NULL || 285 | header >= elf_ehdr->e_phnum) 286 | { 287 | return (uint64_t)(-1); 288 | } 289 | 290 | return (elf_phdr[header].p_memsz); 291 | } 292 | 293 | uint64_t 294 | p_align(size_t header) 295 | { 296 | if (elf_ehdr == NULL || 297 | elf_phdr == NULL || 298 | header >= elf_ehdr->e_phnum) 299 | { 300 | return (uint64_t)(-1); 301 | } 302 | 303 | return (elf_phdr[header].p_align); 304 | } 305 | 306 | /*** 307 | * Elf section header 308 | * Interesting functions for python 309 | * binding. 310 | */ 311 | uint32_t 312 | sh_name(size_t header) 313 | { 314 | if (elf_ehdr == NULL || 315 | elf_shdr == NULL || 316 | header >= elf_ehdr->e_shnum) 317 | { 318 | return (uint32_t)(-1); 319 | } 320 | 321 | return (elf_shdr[header].sh_name); 322 | } 323 | 324 | const char* 325 | sh_name_s(size_t header) 326 | { 327 | if (elf_ehdr == NULL || 328 | elf_shdr == NULL || 329 | StringTable == NULL || 330 | header >= elf_ehdr->e_shnum) 331 | { 332 | return (const char *)(NULL); 333 | } 334 | 335 | return (&StringTable[elf_shdr[header].sh_name]); 336 | } 337 | 338 | uint32_t 339 | sh_type(size_t header) 340 | { 341 | if (elf_ehdr == NULL || 342 | elf_shdr == NULL || 343 | header >= elf_ehdr->e_shnum) 344 | { 345 | return (uint32_t)(-1); 346 | } 347 | 348 | return (elf_shdr[header].sh_type); 349 | } 350 | 351 | uint64_t 352 | sh_flags(size_t header) 353 | { 354 | if (elf_ehdr == NULL || 355 | elf_shdr == NULL || 356 | header >= elf_ehdr->e_shnum) 357 | { 358 | return (uint64_t)(-1); 359 | } 360 | 361 | return (elf_shdr[header].sh_flags); 362 | } 363 | 364 | Elf64_Addr 365 | sh_addr(size_t header) 366 | { 367 | if (elf_ehdr == NULL || 368 | elf_shdr == NULL || 369 | header >= elf_ehdr->e_shnum) 370 | { 371 | return (Elf64_Addr)(-1); 372 | } 373 | 374 | return (elf_shdr[header].sh_addr); 375 | } 376 | 377 | Elf64_Off 378 | sh_offset(size_t header) 379 | { 380 | if (elf_ehdr == NULL || 381 | elf_shdr == NULL || 382 | header >= elf_ehdr->e_shnum) 383 | { 384 | return (Elf64_Off)(-1); 385 | } 386 | 387 | return (elf_shdr[header].sh_offset); 388 | } 389 | 390 | uint64_t 391 | sh_size(size_t header) 392 | { 393 | if (elf_ehdr == NULL || 394 | elf_shdr == NULL || 395 | header >= elf_ehdr->e_shnum) 396 | { 397 | return (uint64_t)(-1); 398 | } 399 | 400 | return (elf_shdr[header].sh_size); 401 | } 402 | 403 | uint32_t 404 | sh_link(size_t header) 405 | { 406 | if (elf_ehdr == NULL || 407 | elf_shdr == NULL || 408 | header >= elf_ehdr->e_shnum) 409 | { 410 | return (uint32_t)(-1); 411 | } 412 | 413 | return (elf_shdr[header].sh_link); 414 | } 415 | 416 | uint32_t 417 | sh_info(size_t header) 418 | { 419 | if (elf_ehdr == NULL || 420 | elf_shdr == NULL || 421 | header >= elf_ehdr->e_shnum) 422 | { 423 | return (uint32_t)(-1); 424 | } 425 | 426 | return (elf_shdr[header].sh_info); 427 | } 428 | 429 | uint64_t 430 | sh_addralign(size_t header) 431 | { 432 | if (elf_ehdr == NULL || 433 | elf_shdr == NULL || 434 | header >= elf_ehdr->e_shnum) 435 | { 436 | return (uint64_t)(-1); 437 | } 438 | 439 | return (elf_shdr[header].sh_addralign); 440 | } 441 | 442 | uint64_t 443 | sh_entsize(size_t header) 444 | { 445 | if (elf_ehdr == NULL || 446 | elf_shdr == NULL || 447 | header >= elf_ehdr->e_shnum) 448 | { 449 | return (uint64_t)(-1); 450 | } 451 | 452 | return (elf_shdr[header].sh_entsize); 453 | } 454 | 455 | 456 | /*** 457 | * Elf Dynamic Symbol header 458 | * Interesting functions for python 459 | * binding 460 | */ 461 | size_t 462 | dynamic_sym_length() 463 | { 464 | return (dynsym_num); 465 | } 466 | 467 | uint32_t 468 | dynamic_st_name(size_t header) 469 | { 470 | if (elf_dynsym == NULL || 471 | header >= dynsym_num) 472 | { 473 | return (uint32_t)(-1); 474 | } 475 | 476 | return (elf_dynsym[header].st_name); 477 | } 478 | 479 | const char* 480 | dynamic_st_name_s(size_t header) 481 | { 482 | if (elf_dynsym == NULL || 483 | DynSymbolStringTable == NULL || 484 | header >= dynsym_num) 485 | { 486 | return (const char*)(NULL); 487 | } 488 | 489 | return (&DynSymbolStringTable[elf_dynsym[header].st_name]); 490 | } 491 | 492 | unsigned char 493 | dynamic_st_info(size_t header) 494 | { 495 | if (elf_dynsym == NULL || 496 | header >= dynsym_num) 497 | { 498 | return (unsigned char)(-1); 499 | } 500 | 501 | return (elf_dynsym[header].st_info); 502 | } 503 | 504 | unsigned char 505 | dynamic_st_other(size_t header) 506 | { 507 | if (elf_dynsym == NULL || 508 | header >= dynsym_num) 509 | { 510 | return (unsigned char)(-1); 511 | } 512 | 513 | return (elf_dynsym[header].st_other); 514 | } 515 | 516 | uint16_t 517 | dynamic_st_shndx(size_t header) 518 | { 519 | if (elf_dynsym == NULL || 520 | header >= dynsym_num) 521 | { 522 | return (uint16_t)(-1); 523 | } 524 | 525 | return (elf_dynsym[header].st_shndx); 526 | } 527 | 528 | Elf64_Addr 529 | dynamic_st_value(size_t header) 530 | { 531 | if (elf_dynsym == NULL || 532 | header >= dynsym_num) 533 | { 534 | return (Elf64_Addr)(-1); 535 | } 536 | 537 | return (elf_dynsym[header].st_value); 538 | } 539 | 540 | uint64_t 541 | dynamic_st_size(size_t header) 542 | { 543 | if (elf_dynsym == NULL || 544 | header >= dynsym_num) 545 | { 546 | return (uint64_t)(-1); 547 | } 548 | 549 | return (elf_dynsym[header].st_size); 550 | } 551 | 552 | 553 | /*** 554 | * Elf Symtab Symbol header 555 | * Interesting functions for python 556 | * binding 557 | */ 558 | 559 | size_t 560 | symtab_sym_length() 561 | { 562 | return (symtab_num); 563 | } 564 | 565 | uint32_t 566 | symtab_st_name(size_t header) 567 | { 568 | if (elf_symtab == NULL || 569 | header >= symtab_num) 570 | { 571 | return (uint32_t)(-1); 572 | } 573 | 574 | return (elf_symtab[header].st_name); 575 | } 576 | 577 | const char* 578 | symtab_st_name_s(size_t header) 579 | { 580 | if (elf_symtab == NULL || 581 | SymbolStringTable == NULL || 582 | header >= symtab_num) 583 | { 584 | return (const char*)(NULL); 585 | } 586 | 587 | return (&SymbolStringTable[elf_symtab[header].st_name]); 588 | } 589 | 590 | unsigned char 591 | symtab_st_info(size_t header) 592 | { 593 | if (elf_symtab == NULL || 594 | header >= symtab_num) 595 | { 596 | return (unsigned char)(-1); 597 | } 598 | 599 | return (elf_symtab[header].st_info); 600 | } 601 | 602 | unsigned char 603 | symtab_st_other(size_t header) 604 | { 605 | if (elf_symtab == NULL || 606 | header >= symtab_num) 607 | { 608 | return (unsigned char)(-1); 609 | } 610 | 611 | return (elf_symtab[header].st_other); 612 | } 613 | 614 | uint16_t 615 | symtab_st_shndx(size_t header) 616 | { 617 | if (elf_symtab == NULL || 618 | header >= symtab_num) 619 | { 620 | return (uint16_t)(-1); 621 | } 622 | 623 | return (elf_symtab[header].st_shndx); 624 | } 625 | 626 | Elf64_Addr 627 | symtab_st_value(size_t header) 628 | { 629 | if (elf_symtab == NULL || 630 | header >= symtab_num) 631 | { 632 | return (Elf64_Addr)(-1); 633 | } 634 | 635 | return (elf_symtab[header].st_value); 636 | } 637 | 638 | uint64_t 639 | symtab_st_size(size_t header) 640 | { 641 | if (elf_symtab == NULL || 642 | header >= symtab_num) 643 | { 644 | return (uint64_t)(-1); 645 | } 646 | 647 | return (elf_symtab[header].st_size); 648 | } 649 | 650 | 651 | Elf64_Addr 652 | rel_r_offset(size_t header, size_t index) 653 | { 654 | size_t i; 655 | Elf_Shdr* rel_section = NULL; 656 | size_t section_relocs_i; 657 | size_t header_aux = header; 658 | 659 | if (elf_rel == NULL || 660 | elf_shdr == NULL || 661 | header >= rel_sections) 662 | { 663 | return (Elf64_Addr)(-1); 664 | } 665 | 666 | for ( i = 0; i < elf_ehdr->e_shnum; i++ ) 667 | { 668 | if (elf_shdr[i].sh_type == SHT_REL) 669 | { 670 | if (header_aux == 0) 671 | { 672 | rel_section = &elf_shdr[i]; 673 | break; 674 | } 675 | 676 | header_aux -= 1; 677 | } 678 | } 679 | 680 | if (is_32_bit_binary()) 681 | { 682 | section_relocs_i = rel_section->sh_size / sizeof(Elf32_Rel); 683 | } 684 | else if (is_64_bit_binary()) 685 | { 686 | section_relocs_i = rel_section->sh_size / sizeof(Elf64_Rel); 687 | } 688 | 689 | if (rel_section == NULL || 690 | index >= section_relocs_i) 691 | { 692 | return (Elf64_Addr)(-1); 693 | } 694 | 695 | return (elf_rel[header][index].r_offset); 696 | } 697 | 698 | 699 | uint64_t 700 | rel_r_info(size_t header, size_t index) 701 | { 702 | size_t i; 703 | Elf_Shdr* rel_section = NULL; 704 | size_t section_relocs_i; 705 | size_t header_aux = header; 706 | 707 | if (elf_rel == NULL || 708 | elf_shdr == NULL || 709 | header >= rel_sections) 710 | { 711 | return (uint64_t)(-1); 712 | } 713 | 714 | for ( i = 0; i < elf_ehdr->e_shnum; i++ ) 715 | { 716 | if (elf_shdr[i].sh_type == SHT_REL) 717 | { 718 | if (header_aux == 0) 719 | { 720 | rel_section = &elf_shdr[i]; 721 | break; 722 | } 723 | 724 | header_aux -= 1; 725 | } 726 | } 727 | 728 | if (is_32_bit_binary()) 729 | { 730 | section_relocs_i = rel_section->sh_size / sizeof(Elf32_Rel); 731 | } 732 | else if (is_64_bit_binary()) 733 | { 734 | section_relocs_i = rel_section->sh_size / sizeof(Elf64_Rel); 735 | } 736 | 737 | if (rel_section == NULL || 738 | index >= section_relocs_i) 739 | { 740 | return (uint64_t)(-1); 741 | } 742 | 743 | return (elf_rel[header][index].r_info); 744 | } 745 | 746 | 747 | size_t 748 | rel_32_size() 749 | { 750 | return sizeof(Elf32_Rel); 751 | } 752 | 753 | size_t 754 | rel_64_size() 755 | { 756 | return sizeof(Elf64_Rel); 757 | } 758 | 759 | 760 | Elf64_Addr rela_r_offset(size_t header, size_t index) 761 | { 762 | size_t i; 763 | Elf_Shdr* rela_section = NULL; 764 | size_t section_relocs_i; 765 | size_t header_aux = header; 766 | 767 | if (elf_rela == NULL || 768 | elf_shdr == NULL || 769 | header >= rela_sections) 770 | { 771 | return (Elf64_Addr)(-1); 772 | } 773 | 774 | for ( i = 0; i < elf_ehdr->e_shnum; i++ ) 775 | { 776 | if (elf_shdr[i].sh_type == SHT_RELA) 777 | { 778 | if (header_aux == 0) 779 | { 780 | rela_section = &elf_shdr[i]; 781 | break; 782 | } 783 | 784 | header_aux -= 1; 785 | } 786 | } 787 | 788 | if (is_32_bit_binary()) 789 | { 790 | section_relocs_i = rela_section->sh_size / sizeof(Elf32_Rela); 791 | } 792 | else if (is_64_bit_binary()) 793 | { 794 | section_relocs_i = rela_section->sh_size / sizeof(Elf64_Rela); 795 | } 796 | 797 | if (rela_section == NULL || 798 | index >= section_relocs_i) 799 | { 800 | return (Elf64_Addr)(-1); 801 | } 802 | 803 | return (elf_rela[header][index].r_offset); 804 | } 805 | 806 | uint64_t 807 | rela_r_info(size_t header, size_t index) 808 | { 809 | size_t i; 810 | Elf_Shdr* rela_section = NULL; 811 | size_t section_relocs_i; 812 | size_t header_aux = header; 813 | 814 | if (elf_rela == NULL || 815 | elf_shdr == NULL || 816 | header >= rela_sections) 817 | { 818 | return (uint64_t)(-1); 819 | } 820 | 821 | for ( i = 0; i < elf_ehdr->e_shnum; i++ ) 822 | { 823 | if (elf_shdr[i].sh_type == SHT_RELA) 824 | { 825 | if (header_aux == 0) 826 | { 827 | rela_section = &elf_shdr[i]; 828 | break; 829 | } 830 | 831 | header_aux -= 1; 832 | } 833 | } 834 | 835 | if (is_32_bit_binary()) 836 | { 837 | section_relocs_i = rela_section->sh_size / sizeof(Elf32_Rela); 838 | } 839 | else if (is_64_bit_binary()) 840 | { 841 | section_relocs_i = rela_section->sh_size / sizeof(Elf64_Rela); 842 | } 843 | 844 | if (rela_section == NULL || 845 | index >= section_relocs_i) 846 | { 847 | return (uint64_t)(-1); 848 | } 849 | 850 | return (elf_rela[header][index].r_info); 851 | } 852 | 853 | int64_t 854 | rela_r_addend(size_t header, size_t index) 855 | { 856 | size_t i; 857 | Elf_Shdr* rela_section = NULL; 858 | size_t section_relocs_i; 859 | size_t header_aux = header; 860 | 861 | if (elf_rela == NULL || 862 | elf_shdr == NULL || 863 | header >= rela_sections) 864 | { 865 | return (int64_t)(-1); 866 | } 867 | 868 | for ( i = 0; i < elf_ehdr->e_shnum; i++ ) 869 | { 870 | if (elf_shdr[i].sh_type == SHT_RELA) 871 | { 872 | if (header_aux == 0) 873 | { 874 | rela_section = &elf_shdr[i]; 875 | break; 876 | } 877 | 878 | header_aux -= 1; 879 | } 880 | } 881 | 882 | if (is_32_bit_binary()) 883 | { 884 | section_relocs_i = rela_section->sh_size / sizeof(Elf32_Rela); 885 | } 886 | else if (is_64_bit_binary()) 887 | { 888 | section_relocs_i = rela_section->sh_size / sizeof(Elf64_Rela); 889 | } 890 | 891 | if (rela_section == NULL || 892 | index >= section_relocs_i) 893 | { 894 | return (int64_t)(-1); 895 | } 896 | 897 | return (elf_rela[header][index].r_addend); 898 | } 899 | 900 | size_t 901 | rela_32_size() 902 | { 903 | return sizeof(Elf32_Rela); 904 | } 905 | 906 | size_t 907 | rela_64_size() 908 | { 909 | return sizeof(Elf64_Rela); 910 | } -------------------------------------------------------------------------------- /elfparser_e/src/elf_parser.c: -------------------------------------------------------------------------------- 1 | #include "elf_parser.h" 2 | 3 | Elf_Ehdr *elf_ehdr = NULL; 4 | Elf_Phdr *elf_phdr = NULL; 5 | Elf_Shdr *elf_shdr = NULL; 6 | Elf_Sym *elf_dynsym = NULL; 7 | Elf_Sym *elf_symtab = NULL; 8 | Elf_Rel **elf_rel = NULL; 9 | Elf_Rela **elf_rela = NULL; 10 | Elf_Dyn *elf_dyn = NULL; 11 | 12 | uint8_t *buf_ptr = NULL; 13 | size_t buf_ptr_size = 0; 14 | char *Interpreter = NULL; 15 | char *StringTable = NULL; 16 | char *SymbolStringTable = NULL; 17 | char *DynSymbolStringTable = NULL; 18 | uint64_t dynsym_num = 0, symtab_num = 0; 19 | size_t rel_sections, rela_sections; 20 | size_t dynamic_headers = 0; 21 | 22 | int parse_elf(const char *pathname) 23 | { 24 | int fd; 25 | 26 | ssize_t file_size; 27 | 28 | if ((fd = open_file_reading(pathname)) < 0) 29 | return (-1); 30 | 31 | if ((file_size = get_file_size(fd)) < 0) 32 | return (-1); 33 | 34 | buf_ptr_size = file_size; 35 | 36 | if ((buf_ptr = mmap_file_read((size_t)file_size, fd)) == NULL) 37 | { 38 | close_file(fd); 39 | return (-1); 40 | } 41 | 42 | if (parse_elf_ehdr(buf_ptr, (size_t)file_size) < 0) 43 | { 44 | close_file(fd); 45 | munmap_memory(buf_ptr, (size_t)file_size); 46 | return (-1); 47 | } 48 | 49 | if (parse_elf_phdr(buf_ptr, (size_t)file_size) < 0) 50 | { 51 | close_file(fd); 52 | munmap_memory(buf_ptr, (size_t)file_size); 53 | return (-1); 54 | } 55 | 56 | if (parse_elf_shdr(buf_ptr, (size_t)file_size) < 0) 57 | { 58 | close_file(fd); 59 | munmap_memory(buf_ptr, (size_t)file_size); 60 | return (-1); 61 | } 62 | 63 | if (parse_elf_sym(buf_ptr) < 0) 64 | { 65 | close_file(fd); 66 | munmap_memory(buf_ptr, (size_t)file_size); 67 | return (-1); 68 | } 69 | 70 | if (parse_elf_rel_a(buf_ptr, (size_t)file_size) < 0) 71 | { 72 | close_file(fd); 73 | munmap_memory(buf_ptr, (size_t)file_size); 74 | return (-1); 75 | } 76 | 77 | if (parse_elf_dynamic(buf_ptr, (size_t)file_size) < 0) 78 | { 79 | close_file(fd); 80 | munmap_memory(buf_ptr, (size_t)file_size); 81 | return (-1); 82 | } 83 | 84 | close_file(fd); 85 | 86 | return (0); 87 | } 88 | 89 | /*** 90 | * Elf header parsing, useful functions 91 | * and printing 92 | */ 93 | int parse_elf_ehdr(uint8_t *buf_ptr, size_t file_size) 94 | { 95 | Elf32_Ehdr *elf32_ehdr; 96 | Elf64_Ehdr *elf64_ehdr; 97 | char *e_ident; 98 | 99 | if (buf_ptr == NULL) 100 | { 101 | fprintf(stderr, "parse_elf_hdr: cannot parse null buffer\n"); 102 | return (-1); 103 | } 104 | 105 | if (file_size < EI_NIDENT) 106 | { 107 | fprintf(stderr, "parse_elf_hdr: file size incorrect for parsing, invalid elf file\n"); 108 | return (-1); 109 | } 110 | // point to buffer and do checks 111 | e_ident = (char *)buf_ptr; 112 | 113 | if (e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 || e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3) 114 | { 115 | fprintf(stderr, "parse_elf_hdr: elf incorrect header\n"); 116 | return (-1); 117 | } 118 | 119 | if (elf_ehdr != NULL) 120 | { 121 | free_memory(elf_ehdr); 122 | elf_ehdr = NULL; 123 | } 124 | 125 | elf_ehdr = allocate_memory(sizeof(Elf_Ehdr)); 126 | 127 | if (e_ident[EI_CLASS] == ELFCLASS32) // if 32 bit binary 128 | { 129 | 130 | if (file_size < sizeof(Elf32_Ehdr)) 131 | { 132 | fprintf(stderr, "parse_elf_ehdr: file size incorrect for parsing, invalid elf file\n"); 133 | return (-1); 134 | } 135 | 136 | elf32_ehdr = (Elf32_Ehdr *)buf_ptr; 137 | 138 | memcpy(elf_ehdr->e_ident, elf32_ehdr->e_ident, EI_NIDENT); 139 | elf_ehdr->e_type = elf32_ehdr->e_type; 140 | elf_ehdr->e_machine = elf32_ehdr->e_machine; 141 | elf_ehdr->e_version = elf32_ehdr->e_version; 142 | elf_ehdr->e_entry = elf32_ehdr->e_entry; 143 | elf_ehdr->e_phoff = elf32_ehdr->e_phoff; 144 | elf_ehdr->e_shoff = elf32_ehdr->e_shoff; 145 | elf_ehdr->e_flags = elf32_ehdr->e_flags; 146 | elf_ehdr->e_ehsize = elf32_ehdr->e_ehsize; 147 | elf_ehdr->e_phentsize = elf32_ehdr->e_phentsize; 148 | elf_ehdr->e_phnum = elf32_ehdr->e_phnum; 149 | elf_ehdr->e_shentsize = elf32_ehdr->e_shentsize; 150 | elf_ehdr->e_shnum = elf32_ehdr->e_shnum; 151 | elf_ehdr->e_shstrndx = elf32_ehdr->e_shstrndx; 152 | } 153 | else if (e_ident[EI_CLASS] == ELFCLASS64) // if 64 bit binary 154 | { 155 | if (file_size < sizeof(Elf64_Ehdr)) 156 | { 157 | fprintf(stderr, "parse_elf_ehdr: file size incorrect for parsing, invalid elf file\n"); 158 | return (-1); 159 | } 160 | 161 | elf64_ehdr = (Elf64_Ehdr *)buf_ptr; 162 | 163 | memcpy(elf_ehdr->e_ident, elf64_ehdr->e_ident, EI_NIDENT); 164 | elf_ehdr->e_type = elf64_ehdr->e_type; 165 | elf_ehdr->e_machine = elf64_ehdr->e_machine; 166 | elf_ehdr->e_version = elf64_ehdr->e_version; 167 | elf_ehdr->e_entry = elf64_ehdr->e_entry; 168 | elf_ehdr->e_phoff = elf64_ehdr->e_phoff; 169 | elf_ehdr->e_shoff = elf64_ehdr->e_shoff; 170 | elf_ehdr->e_flags = elf64_ehdr->e_flags; 171 | elf_ehdr->e_ehsize = elf64_ehdr->e_ehsize; 172 | elf_ehdr->e_phentsize = elf64_ehdr->e_phentsize; 173 | elf_ehdr->e_phnum = elf64_ehdr->e_phnum; 174 | elf_ehdr->e_shentsize = elf64_ehdr->e_shentsize; 175 | elf_ehdr->e_shnum = elf64_ehdr->e_shnum; 176 | elf_ehdr->e_shstrndx = elf64_ehdr->e_shstrndx; 177 | } 178 | else 179 | { 180 | fprintf(stderr, "parse_elf_ehdr: elf type (%d) not supported\n", (int)e_ident[4]); 181 | return (-1); 182 | } 183 | 184 | if (elf_ehdr->e_ehsize > file_size) 185 | { 186 | fprintf(stderr, "parse_elf_ehdr: elf header out of file bound\n"); 187 | return (-1); 188 | } 189 | 190 | if (elf_ehdr->e_phoff > file_size || (elf_ehdr->e_phoff + (elf_ehdr->e_phentsize * elf_ehdr->e_phnum)) > file_size) 191 | { 192 | fprintf(stderr, "parse_elf_ehdr: program header out of file bound\n"); 193 | return (-1); 194 | } 195 | 196 | if (elf_ehdr->e_shoff > file_size || (elf_ehdr->e_shoff + (elf_ehdr->e_shentsize * elf_ehdr->e_shnum)) > file_size) 197 | { 198 | fprintf(stderr, "parse_elf_ehdr: section header out of file bound\n"); 199 | return (-1); 200 | } 201 | 202 | return (0); 203 | } 204 | 205 | int is_32_bit_binary() 206 | { 207 | if (elf_ehdr == NULL) 208 | return (-1); 209 | 210 | if (elf_ehdr->e_ident[EI_CLASS] == ELFCLASS32) 211 | return (1); 212 | else 213 | return (0); 214 | } 215 | 216 | int is_64_bit_binary() 217 | { 218 | if (elf_ehdr == NULL) 219 | return (-1); 220 | 221 | if (elf_ehdr->e_ident[EI_CLASS] == ELFCLASS64) 222 | return (1); 223 | else 224 | return (0); 225 | } 226 | 227 | const Elf_Ehdr * 228 | get_elf_ehdr_read() 229 | { 230 | return elf_ehdr; 231 | } 232 | 233 | /* 234 | * Auxiliar methods to print names instead of simple 235 | * numbers from the ElfN_Ehdr header 236 | */ 237 | static void 238 | print_elf_class(unsigned char e_ident) 239 | { 240 | char *class; 241 | 242 | if (e_ident == ELFCLASSNONE) 243 | class = "ELFCLASSNONE"; 244 | else if (e_ident == ELFCLASS32) 245 | class = "ELFCLASS32"; 246 | else if (e_ident == ELFCLASS64) 247 | class = "ELFCLASS64"; 248 | else 249 | { 250 | printf("ELF_CLASS: %x\n", e_ident); 251 | return; 252 | } 253 | 254 | printf("ELF_CLASS: %s\n", class); 255 | } 256 | 257 | static void 258 | print_elf_data(unsigned char e_data) 259 | { 260 | char *data; 261 | 262 | if (e_data == ELFDATANONE) 263 | data = "ELFDATANONE"; 264 | else if (e_data == ELFDATA2LSB) 265 | data = "ELFDATA2LSB (Two's complement, little-endian)"; 266 | else if (e_data == ELFDATA2MSB) 267 | data = "ELFDATA2MSB (Two's complement, big-endian)"; 268 | else 269 | { 270 | printf("ELF_DATA: %x (No fucking idea)\n", e_data); 271 | return; 272 | } 273 | 274 | printf("ELF_DATA: %s\n", data); 275 | } 276 | 277 | static void 278 | print_elf_version(unsigned char e_version) 279 | { 280 | char *version; 281 | 282 | if (e_version == EV_NONE) 283 | version = "EV_NONE"; 284 | else if (e_version == EV_CURRENT) 285 | version = "EV_CURRENT"; 286 | else 287 | { 288 | printf("ELF_VERSION: %x\n", e_version); 289 | return; 290 | } 291 | 292 | printf("ELF_VERSION: %s\n", version); 293 | } 294 | 295 | static void 296 | print_elf_osabi(unsigned char e_osabi) 297 | { 298 | char *osabi; 299 | 300 | switch (e_osabi) 301 | { 302 | case ELFOSABI_SYSV: 303 | osabi = "ELFOSABI_SYSV"; 304 | break; 305 | case ELFOSABI_HPUX: 306 | osabi = "ELFOSABI_HPUX"; 307 | break; 308 | case ELFOSABI_NETBSD: 309 | osabi = "ELFOSABI_NETBSD"; 310 | break; 311 | case ELFOSABI_LINUX: 312 | osabi = "ELFOSABI_LINUX"; 313 | break; 314 | case ELFOSABI_SOLARIS: 315 | osabi = "ELFOSABI_SOLARIS"; 316 | break; 317 | case ELFOSABI_AIX: 318 | osabi = "ELFOSABI_AIX"; 319 | break; 320 | case ELFOSABI_IRIX: 321 | osabi = "ELFOSABI_IRIX"; 322 | break; 323 | case ELFOSABI_FREEBSD: 324 | osabi = "ELFOSABI_FREEBSD"; 325 | break; 326 | case ELFOSABI_TRU64: 327 | osabi = "ELFOSABI_TRU64"; 328 | break; 329 | case ELFOSABI_MODESTO: 330 | osabi = "ELFOSABI_MODESTO"; 331 | break; 332 | case ELFOSABI_OPENBSD: 333 | osabi = "ELFOSABI_OPENBSD"; 334 | break; 335 | case ELFOSABI_ARM_AEABI: 336 | osabi = "ELFOSABI_ARM_AEABI"; 337 | break; 338 | case ELFOSABI_ARM: 339 | osabi = "ELFOSABI_ARM"; 340 | break; 341 | case ELFOSABI_STANDALONE: 342 | osabi = "ELFOSABI_STANDALONE"; 343 | break; 344 | default: 345 | printf("ELF_OSABI: %x\n", e_osabi); 346 | return; 347 | } 348 | 349 | printf("ELF_OSABI: %s\n", osabi); 350 | } 351 | 352 | static void 353 | print_emachine(unsigned char machine) 354 | { 355 | printf("Machine:%32s", " "); 356 | switch (machine) 357 | { 358 | case EM_NONE: 359 | printf("No machine\n"); 360 | break; 361 | case EM_M32: 362 | printf("AT&T WE 32100\n"); 363 | break; 364 | case EM_SPARC: 365 | printf("Sun Microsystems SPARC\n"); 366 | break; 367 | case EM_386: 368 | printf("Intel 80386\n"); 369 | break; 370 | case EM_68K: 371 | printf("Motorola 68000 family\n"); 372 | break; 373 | case EM_88K: 374 | printf("Motorola 88000 family\n"); 375 | break; 376 | case EM_860: 377 | printf("Intel 80860\n"); 378 | break; 379 | case EM_MIPS: 380 | printf("MIPS RS3000 (big-endian only)\n"); 381 | break; 382 | case EM_S370: 383 | printf("IBM System/370\n"); 384 | break; 385 | case EM_MIPS_RS3_LE: 386 | printf("MIPS R3000 little-endian\n"); 387 | break; 388 | case EM_PARISC: 389 | printf("HP/PA\n"); 390 | break; 391 | case EM_VPP500: 392 | printf("Fujitsu VPP500\n"); 393 | break; 394 | case EM_SPARC32PLUS: 395 | printf("SPARC with enhanced instruction set (Sun's \"v8plus\")\n"); 396 | break; 397 | case EM_960: 398 | printf("Intel 80960\n"); 399 | break; 400 | case EM_PPC: 401 | printf("PowerPC\n"); 402 | break; 403 | case EM_PPC64: 404 | printf("PowerPC 64-bit\n"); 405 | break; 406 | case EM_S390: 407 | printf("IBM S/390\n"); 408 | break; 409 | case EM_V800: 410 | printf("NEC V800 series\n"); 411 | break; 412 | case EM_FR20: 413 | printf("Fujitsu FR20\n"); 414 | break; 415 | case EM_RH32: 416 | printf("TRW RH-32\n"); 417 | break; 418 | case EM_RCE: 419 | printf("Motorola RCE\n"); 420 | break; 421 | case EM_ARM: 422 | printf("Advanced RISC Machines\n"); 423 | break; 424 | case EM_FAKE_ALPHA: 425 | printf("Digital Alpha\n"); 426 | break; 427 | case EM_SH: 428 | printf("Renesas SuperH (formerly Hitachi SH)\n"); 429 | break; 430 | case EM_SPARCV9: 431 | printf("SPARC v9 64-bit\n"); 432 | break; 433 | case EM_TRICORE: 434 | printf("Siemens Tricore\n"); 435 | break; 436 | case EM_ARC: 437 | printf("Argonaut RISC Core\n"); 438 | break; 439 | case EM_H8_300: 440 | printf("Hitachi H8/300\n"); 441 | break; 442 | case EM_H8_300H: 443 | printf("Hitachi H8/300H\n"); 444 | break; 445 | case EM_H8S: 446 | printf("Hitachi H8S\n"); 447 | break; 448 | case EM_H8_500: 449 | printf("Hitachi H8/500\n"); 450 | break; 451 | case EM_IA_64: 452 | printf("Intel Itanium (Merced)\n"); 453 | break; 454 | case EM_MIPS_X: 455 | printf("Stanford MIPS-X\n"); 456 | break; 457 | case EM_COLDFIRE: 458 | printf("Motorola Coldfire\n"); 459 | break; 460 | case EM_68HC12: 461 | printf("Motorola M68HC12\n"); 462 | break; 463 | case EM_MMA: 464 | printf("Fujitsu MMA Multimedia Accelerator\n"); 465 | break; 466 | case EM_PCP: 467 | printf("Siemens PCP\n"); 468 | break; 469 | case EM_NCPU: 470 | printf("Sony nCPU embeeded RISC\n"); 471 | break; 472 | case EM_NDR1: 473 | printf("Denso NDR1 microprocessor\n"); 474 | break; 475 | case EM_STARCORE: 476 | printf("Motorola Start*Core processor\n"); 477 | break; 478 | case EM_ME16: 479 | printf("Toyota ME16 processor\n"); 480 | break; 481 | case EM_ST100: 482 | printf("STMicroelectronic ST100 processor\n"); 483 | break; 484 | case EM_TINYJ: 485 | printf("Advanced Logic Corp. Tinyj emb.fam\n"); 486 | break; 487 | case EM_X86_64: 488 | printf("AMD x86-64\n"); 489 | break; 490 | case EM_PDSP: 491 | printf("Sony DSP Processor\n"); 492 | break; 493 | case EM_FX66: 494 | printf("Siemens FX66 microcontroller\n"); 495 | break; 496 | case EM_ST9PLUS: 497 | printf("STMicroelectronics ST9+ 8/16 mc\n"); 498 | break; 499 | case EM_ST7: 500 | printf("STmicroelectronics ST7 8 bit mc\n"); 501 | break; 502 | case EM_68HC16: 503 | printf("Motorola MC68HC16 microcontroller\n"); 504 | break; 505 | case EM_68HC11: 506 | printf("Motorola MC68HC11 microcontroller\n"); 507 | break; 508 | case EM_68HC08: 509 | printf("Motorola MC68HC08 microcontroller\n"); 510 | break; 511 | case EM_68HC05: 512 | printf("Motorola MC68HC05 microcontroller\n"); 513 | break; 514 | case EM_SVX: 515 | printf("Silicon Graphics SVx\n"); 516 | break; 517 | case EM_ST19: 518 | printf("STMicroelectronics ST19 8 bit mc\n"); 519 | break; 520 | case EM_VAX: 521 | printf("DEC Vax\n"); 522 | break; 523 | case EM_CRIS: 524 | printf("Axis Communications 32-bit embedded processor\n"); 525 | break; 526 | case EM_JAVELIN: 527 | printf("Infineon Technologies 32-bit embedded processor\n"); 528 | break; 529 | case EM_FIREPATH: 530 | printf("Element 14 64-bit DSP Processor\n"); 531 | break; 532 | case EM_ZSP: 533 | printf("LSI Logic 16-bit DSP Processor\n"); 534 | break; 535 | case EM_MMIX: 536 | printf("Donald Knuth's educational 64-bit processor\n"); 537 | break; 538 | case EM_HUANY: 539 | printf("Harvard University machine-independent object files\n"); 540 | break; 541 | case EM_PRISM: 542 | printf("SiTera Prism\n"); 543 | break; 544 | case EM_AVR: 545 | printf("Atmel AVR 8-bit microcontroller\n"); 546 | break; 547 | case EM_FR30: 548 | printf("Fujitsu FR30\n"); 549 | break; 550 | case EM_D10V: 551 | printf("Mitsubishi D10V\n"); 552 | break; 553 | case EM_D30V: 554 | printf("Mitsubishi D30V\n"); 555 | break; 556 | case EM_V850: 557 | printf("NEC v850\n"); 558 | break; 559 | case EM_M32R: 560 | printf("Mitsubishi M32R\n"); 561 | break; 562 | case EM_MN10300: 563 | printf("Matsushita MN10300\n"); 564 | break; 565 | case EM_MN10200: 566 | printf("Matsushita MN10200\n"); 567 | break; 568 | case EM_PJ: 569 | printf("picoJava\n"); 570 | break; 571 | case EM_OPENRISC: 572 | printf("OpenRISC 32-bit embedded processor\n"); 573 | break; 574 | case EM_ARC_A5: 575 | printf("ARC Cores Tangent-A5\n"); 576 | break; 577 | case EM_XTENSA: 578 | printf("Tensilica Xtensa Architecture\n"); 579 | break; 580 | case EM_ALTERA_NIOS2: 581 | printf("Altera Nios II\n"); 582 | break; 583 | case EM_AARCH64: 584 | printf("ARM AARCH64\n"); 585 | break; 586 | case EM_TILEPRO: 587 | printf("Tilera TILEPro\n"); 588 | break; 589 | case EM_MICROBLAZE: 590 | printf("Xilinx MicroBlaze\n"); 591 | break; 592 | case EM_TILEGX: 593 | printf("Tilera TILE-Gx\n"); 594 | break; 595 | default: 596 | printf("Make me do my job properly\n"); 597 | //printf("An unknown machine\n"); 598 | break; 599 | } 600 | } 601 | 602 | void print_elf_ehdr() 603 | { 604 | int i; 605 | printf("\nElf Header\n"); 606 | 607 | printf("Elf magic: "); 608 | for (i = 0; i < EI_NIDENT; i++) 609 | { 610 | if (i >= EI_MAG1 && i <= EI_MAG3) 611 | printf("%c ", elf_ehdr->e_ident[i]); 612 | else 613 | printf("%x ", elf_ehdr->e_ident[i]); 614 | } 615 | printf("\n"); 616 | 617 | print_elf_class(elf_ehdr->e_ident[EI_CLASS]); 618 | print_elf_data(elf_ehdr->e_ident[EI_DATA]); 619 | 620 | print_elf_version(elf_ehdr->e_ident[EI_VERSION]); 621 | print_elf_osabi(elf_ehdr->e_ident[EI_OSABI]); 622 | 623 | printf("Elf ABI Version: %d\n", elf_ehdr->e_ident[EI_ABIVERSION]); 624 | 625 | printf("Elf type: "); 626 | if (elf_ehdr->e_type == ET_NONE) 627 | printf("Unknown type\n"); 628 | else if (elf_ehdr->e_type == ET_REL) 629 | printf("REL (Relocatable file)\n"); 630 | else if (elf_ehdr->e_type == ET_EXEC) 631 | printf("EXEC (Executable file)\n"); 632 | else if (elf_ehdr->e_type == ET_DYN) 633 | printf("DYN (Shared object file)\n"); 634 | else if (elf_ehdr->e_type == ET_CORE) 635 | printf("CORE (Core file file)\n"); 636 | 637 | print_emachine(elf_ehdr->e_machine); 638 | 639 | printf("Elf File Version: %d", elf_ehdr->e_version); 640 | if (elf_ehdr->e_version == EV_NONE) 641 | printf(" (Invalid Version)\n"); 642 | else if (elf_ehdr->e_version == EV_CURRENT) 643 | printf(" (Current)\n"); 644 | else 645 | printf(" (No fucking idea)\n"); 646 | 647 | printf("Elf Program entry point: 0x%llx\n", (long long unsigned int)elf_ehdr->e_entry); 648 | printf("Elf Program header Offset: %lld (raw offset bytes)\n", (long long unsigned int)elf_ehdr->e_phoff); 649 | printf("Elf Section header Offset: %lld (raw offset bytes)\n", (long long unsigned int)elf_ehdr->e_shoff); 650 | printf("Elf processor flags: %lld\n", (long long unsigned int)elf_ehdr->e_flags); 651 | printf("Elf header's size: %lld (bytes)\n", (long long unsigned int)elf_ehdr->e_ehsize); 652 | printf("Elf program header entry size: %lld (bytes)\n", (long long unsigned int)elf_ehdr->e_phentsize); 653 | printf("Elf program header number of entries: %lld\n", (long long unsigned int)elf_ehdr->e_phnum); 654 | printf("Elf section header's size: %lld (bytes)\n", (long long unsigned int)elf_ehdr->e_shentsize); 655 | printf("Elf section header number of entries: %lld\n", (long long unsigned int)elf_ehdr->e_shnum); 656 | printf("Elf section header string table index: %lld\n", (long long unsigned int)elf_ehdr->e_shstrndx); 657 | } 658 | 659 | /*** 660 | * Program header parsing and printing 661 | */ 662 | int parse_elf_phdr(uint8_t *buf_ptr, size_t file_size) 663 | { 664 | int i; 665 | Elf32_Phdr *elf32_phdr; 666 | Elf64_Phdr *elf64_phdr; 667 | 668 | if (buf_ptr == NULL) 669 | { 670 | fprintf(stderr, "parse_elf_phdr: cannot parse null buffer\n"); 671 | return (-1); 672 | } 673 | 674 | if (elf_ehdr == NULL) 675 | { 676 | fprintf(stderr, "parse_elf_phdr: cannot parse program header without elf header\n"); 677 | return (-1); 678 | } 679 | 680 | if (elf_phdr != NULL) 681 | { 682 | free_memory(elf_phdr); 683 | elf_phdr = NULL; 684 | } 685 | 686 | elf_phdr = allocate_memory(sizeof(Elf_Phdr) * elf_ehdr->e_phnum); 687 | 688 | if (is_32_bit_binary()) 689 | { 690 | elf32_phdr = (Elf32_Phdr *)&buf_ptr[elf_ehdr->e_phoff]; 691 | 692 | for (i = 0; i < elf_ehdr->e_phnum; i++) 693 | { 694 | elf_phdr[i].p_type = elf32_phdr[i].p_type; 695 | elf_phdr[i].p_flags = elf32_phdr[i].p_flags; 696 | elf_phdr[i].p_offset = elf32_phdr[i].p_offset; 697 | elf_phdr[i].p_vaddr = elf32_phdr[i].p_vaddr; 698 | elf_phdr[i].p_paddr = elf32_phdr[i].p_paddr; 699 | elf_phdr[i].p_filesz = elf32_phdr[i].p_filesz; 700 | elf_phdr[i].p_memsz = elf32_phdr[i].p_memsz; 701 | elf_phdr[i].p_align = elf32_phdr[i].p_align; 702 | } 703 | } 704 | else if (is_64_bit_binary()) 705 | { 706 | elf64_phdr = (Elf64_Phdr *)&buf_ptr[elf_ehdr->e_phoff]; 707 | 708 | for (i = 0; i < elf_ehdr->e_phnum; i++) 709 | { 710 | elf_phdr[i].p_type = elf64_phdr[i].p_type; 711 | elf_phdr[i].p_flags = elf64_phdr[i].p_flags; 712 | elf_phdr[i].p_offset = elf64_phdr[i].p_offset; 713 | elf_phdr[i].p_vaddr = elf64_phdr[i].p_vaddr; 714 | elf_phdr[i].p_paddr = elf64_phdr[i].p_paddr; 715 | elf_phdr[i].p_filesz = elf64_phdr[i].p_filesz; 716 | elf_phdr[i].p_memsz = elf64_phdr[i].p_memsz; 717 | elf_phdr[i].p_align = elf64_phdr[i].p_align; 718 | } 719 | } 720 | else 721 | { 722 | return (-1); 723 | } 724 | 725 | for (i = 0; i < elf_ehdr->e_phnum; i++) 726 | { 727 | if (elf_phdr[i].p_offset > file_size || (elf_phdr[i].p_offset + elf_phdr[i].p_filesz) > file_size) 728 | { 729 | fprintf(stderr, "parse_elf_phdr: program header %d is out of file bound\n", i); 730 | return (-1); 731 | } 732 | 733 | if (elf_phdr[i].p_type == PT_INTERP) 734 | { 735 | Interpreter = strdup((char *)&buf_ptr[elf_phdr[i].p_offset]); 736 | } 737 | } 738 | 739 | return (0); 740 | } 741 | 742 | static void 743 | print_phdr_type(uint32_t type) 744 | { 745 | switch (type) 746 | { 747 | case PT_NULL: // unused other members values are undefined 748 | printf("NULL\t\t"); 749 | break; 750 | case PT_LOAD: // loadable segment described by p_filesz and p_memsz 751 | printf("LOAD\t\t"); 752 | break; 753 | case PT_DYNAMIC: // dynamic linking information 754 | printf("DYNAMIC\t\t"); 755 | break; 756 | case PT_INTERP: // location and size of null-terminated pathname to itnerpreter 757 | printf("INTERP\t\t"); 758 | break; 759 | case PT_NOTE: 760 | printf("NOTE\t\t"); 761 | break; 762 | case PT_SHLIB: 763 | printf("SHLIB\t\t"); 764 | break; 765 | case PT_PHDR: // location and size of program header table 766 | printf("PHDR\t\t"); 767 | break; 768 | case PT_LOPROC: 769 | printf("LOPROC\t\t"); 770 | break; 771 | case PT_HIPROC: 772 | printf("HIPROC\t\t"); 773 | break; 774 | case PT_GNU_EH_FRAME: 775 | printf("GNU_EH_FRAME\t"); 776 | break; 777 | case PT_GNU_RELRO: 778 | printf("GNU_RELRO\t"); 779 | break; 780 | case PT_GNU_STACK: 781 | printf("GNU_STACK\t"); 782 | break; 783 | case PT_GNU_PROPERTY: 784 | printf("GNU_PROPERTY\t"); 785 | break; 786 | case PT_OPENBSD_RANDOMIZE: 787 | printf("OPENBSD_RANDOMIZE\t"); 788 | break; 789 | case PT_OPENBSD_WXNEEDED: 790 | printf("OPENBSD_WXNEEDED\t"); 791 | break; 792 | case PT_OPENBSD_BOOTDATA: 793 | printf("OPENBSD_BOOTDATA\t"); 794 | break; 795 | default: 796 | printf("%X\t\t", type); 797 | break; 798 | } 799 | } 800 | 801 | void print_elf_phdr() 802 | { 803 | int i, j; 804 | 805 | printf("Elf Program Header:\n"); 806 | 807 | printf("%s %s%018s%018s\n%018s%018s%018s%018s\n\n", "TYPE", "FLAGS", "Offset", "V.Addr", "P.Addr", "F.Size", "M.Size", "Align"); 808 | 809 | for (i = 0; i < elf_ehdr->e_phnum; i++) 810 | { 811 | print_phdr_type(elf_phdr[i].p_type); 812 | 813 | if (PF_R & elf_phdr[i].p_flags) 814 | printf("R"); 815 | else 816 | printf(" "); 817 | 818 | if (PF_W & elf_phdr[i].p_flags) 819 | printf("W"); 820 | else 821 | printf(" "); 822 | 823 | if (PF_X & elf_phdr[i].p_flags) 824 | printf("X"); 825 | else 826 | printf(" "); 827 | 828 | printf(" 0x%016llx 0x%016llx\n\t 0x%016llx 0x%016llx 0x%016llx 0x%llx", 829 | (long long unsigned int)elf_phdr[i].p_offset, 830 | (long long unsigned int)elf_phdr[i].p_vaddr, 831 | (long long unsigned int)elf_phdr[i].p_paddr, 832 | (long long unsigned int)elf_phdr[i].p_filesz, 833 | (long long unsigned int)elf_phdr[i].p_memsz, 834 | (long long unsigned int)elf_phdr[i].p_align); 835 | 836 | if (elf_phdr[i].p_type == PT_INTERP) 837 | { 838 | if (Interpreter) 839 | { 840 | printf("\n\t[Program Interpreter: %s]\n\n", Interpreter); 841 | free_memory(Interpreter); 842 | } 843 | } 844 | else if (elf_phdr[i].p_type == PT_LOAD) 845 | { 846 | if (PF_X & elf_phdr[i].p_flags) 847 | { 848 | printf("\t(TEXT)\n\n"); 849 | } 850 | else 851 | { 852 | printf("\t(DATA)\n\n"); 853 | } 854 | } 855 | else 856 | { 857 | printf("\n\n"); 858 | } 859 | } 860 | 861 | printf("Mapping from section to segment: \n"); 862 | printf("SEGMENT: SECTIONS\n"); 863 | 864 | for (i = 0; i < elf_ehdr->e_phnum; i++) 865 | { 866 | printf(" %5d: ", i); 867 | 868 | for (j = 0; j < elf_ehdr->e_shnum; j++) 869 | { 870 | if (elf_shdr[j].sh_offset >= elf_phdr[i].p_offset && elf_shdr[j].sh_offset < (elf_phdr[i].p_offset + elf_phdr[i].p_filesz)) 871 | { 872 | // if section is inside, just print name 873 | if (StringTable[elf_shdr[j].sh_name]) 874 | { 875 | printf("%s ", &StringTable[elf_shdr[j].sh_name]); 876 | } 877 | } 878 | } 879 | 880 | printf("\n"); 881 | } 882 | } 883 | 884 | /*** 885 | * Section header parsing and printing 886 | */ 887 | int parse_elf_shdr(uint8_t *buf_ptr, size_t file_size) 888 | { 889 | int i; 890 | Elf32_Shdr *elf32_shdr; 891 | Elf64_Shdr *elf64_shdr; 892 | 893 | if (buf_ptr == NULL) 894 | { 895 | fprintf(stderr, "parse_elf_shdr: cannot parse null buffer\n"); 896 | return (-1); 897 | } 898 | 899 | if (elf_ehdr == NULL) 900 | { 901 | fprintf(stderr, "parse_elf_shdr: cannot parse section header without elf header\n"); 902 | return (-1); 903 | } 904 | 905 | if (elf_shdr != NULL) 906 | { 907 | free_memory(elf_shdr); 908 | elf_shdr = NULL; 909 | } 910 | 911 | elf_shdr = allocate_memory(sizeof(Elf_Shdr) * elf_ehdr->e_shnum); 912 | 913 | if (is_32_bit_binary()) 914 | { 915 | elf32_shdr = (Elf32_Shdr *)&buf_ptr[elf_ehdr->e_shoff]; 916 | 917 | for (i = 0; i < elf_ehdr->e_shnum; i++) 918 | { 919 | elf_shdr[i].sh_name = elf32_shdr[i].sh_name; 920 | elf_shdr[i].sh_type = elf32_shdr[i].sh_type; 921 | elf_shdr[i].sh_flags = elf32_shdr[i].sh_flags; 922 | elf_shdr[i].sh_addr = elf32_shdr[i].sh_addr; 923 | elf_shdr[i].sh_offset = elf32_shdr[i].sh_offset; 924 | elf_shdr[i].sh_size = elf32_shdr[i].sh_size; 925 | elf_shdr[i].sh_link = elf32_shdr[i].sh_link; 926 | elf_shdr[i].sh_info = elf32_shdr[i].sh_info; 927 | elf_shdr[i].sh_addralign = elf32_shdr[i].sh_addralign; 928 | elf_shdr[i].sh_entsize = elf32_shdr[i].sh_entsize; 929 | } 930 | } 931 | else if (is_64_bit_binary()) 932 | { 933 | elf64_shdr = (Elf64_Shdr *)&buf_ptr[elf_ehdr->e_shoff]; 934 | 935 | for (i = 0; i < elf_ehdr->e_shnum; i++) 936 | { 937 | elf_shdr[i].sh_name = elf64_shdr[i].sh_name; 938 | elf_shdr[i].sh_type = elf64_shdr[i].sh_type; 939 | elf_shdr[i].sh_flags = elf64_shdr[i].sh_flags; 940 | elf_shdr[i].sh_addr = elf64_shdr[i].sh_addr; 941 | elf_shdr[i].sh_offset = elf64_shdr[i].sh_offset; 942 | elf_shdr[i].sh_size = elf64_shdr[i].sh_size; 943 | elf_shdr[i].sh_link = elf64_shdr[i].sh_link; 944 | elf_shdr[i].sh_info = elf64_shdr[i].sh_info; 945 | elf_shdr[i].sh_addralign = elf64_shdr[i].sh_addralign; 946 | elf_shdr[i].sh_entsize = elf64_shdr[i].sh_entsize; 947 | } 948 | } 949 | else 950 | { 951 | return (-1); 952 | } 953 | 954 | for (i = 0; i < elf_ehdr->e_shnum; i++) 955 | { 956 | // only if section is present on disk 957 | //if ((elf_shdr[i].sh_type == SHT_PROGBITS) && 958 | if ((elf_shdr[i].sh_type != SHT_NOBITS) && 959 | ((elf_shdr[i].sh_offset > file_size) || ((elf_shdr[i].sh_offset + elf_shdr[i].sh_size) > file_size))) 960 | { 961 | fprintf(stderr, "parse_elf_shdr: section header %d is out of file bound\n", i); 962 | return (-1); 963 | } 964 | } 965 | 966 | // does anyone remember that e_shstrndx value? Is used for this 967 | if (elf_ehdr->e_shnum > elf_ehdr->e_shstrndx) 968 | StringTable = (char *)&buf_ptr[elf_shdr[elf_ehdr->e_shstrndx].sh_offset]; 969 | 970 | return (0); 971 | } 972 | 973 | static void 974 | print_16_str(char *string) 975 | { 976 | int j; 977 | size_t string_length = strlen(string); 978 | 979 | for (j = 0; j < 16; j++) 980 | { 981 | if (j < string_length) 982 | printf("%c", string[j]); 983 | else 984 | printf(" "); 985 | } 986 | printf(" "); 987 | } 988 | 989 | static void 990 | printf_shdr_type(uint32_t type) 991 | { 992 | switch (type) 993 | { 994 | case SHT_NULL: 995 | print_16_str("NULL"); 996 | break; 997 | case SHT_PROGBITS: 998 | print_16_str("PROGBITS"); 999 | break; 1000 | case SHT_SYMTAB: 1001 | print_16_str("SYMTAB"); 1002 | break; 1003 | case SHT_STRTAB: 1004 | print_16_str("STRTAB"); 1005 | break; 1006 | case SHT_RELA: 1007 | print_16_str("RELA"); 1008 | break; 1009 | case SHT_HASH: 1010 | print_16_str("HASH"); 1011 | break; 1012 | case SHT_DYNAMIC: 1013 | print_16_str("DYNAMIC"); 1014 | break; 1015 | case SHT_NOTE: 1016 | print_16_str("NOTE"); 1017 | break; 1018 | case SHT_NOBITS: 1019 | print_16_str("NOBITS"); 1020 | break; 1021 | case SHT_REL: 1022 | print_16_str("REL"); 1023 | break; 1024 | case SHT_SHLIB: 1025 | print_16_str("SHLIB"); 1026 | break; 1027 | case SHT_DYNSYM: 1028 | print_16_str("DYNSYM"); 1029 | break; 1030 | case SHT_LOPROC: 1031 | print_16_str("LOPROC"); 1032 | break; 1033 | case SHT_HIPROC: 1034 | print_16_str("HIPROC"); 1035 | break; 1036 | case SHT_LOUSER: 1037 | print_16_str("LOUSER"); 1038 | break; 1039 | case SHT_HIUSER: 1040 | print_16_str("HIUSER"); 1041 | break; 1042 | case SHT_GNU_ATTRIBUTES: 1043 | print_16_str("GNU_ATTRIBUTES"); 1044 | break; 1045 | case SHT_GNU_HASH: 1046 | print_16_str("GNU_HASH"); 1047 | break; 1048 | case SHT_GNU_LIBLIST: 1049 | print_16_str("GNU_LIBLIST"); 1050 | break; 1051 | case SHT_GNU_verdef: 1052 | print_16_str("VERDEF"); 1053 | break; 1054 | case SHT_GNU_verneed: 1055 | print_16_str("VERNEED"); 1056 | break; 1057 | case SHT_GNU_versym: 1058 | print_16_str("VERSYM"); 1059 | break; 1060 | case SHT_INIT_ARRAY: 1061 | print_16_str("INIT_ARRAY"); 1062 | break; 1063 | case SHT_FINI_ARRAY: 1064 | print_16_str("FINI_ARRAY"); 1065 | break; 1066 | case SHT_IA_64_UNWIND: 1067 | print_16_str("IA_64_UNWIND"); 1068 | break; 1069 | default: 1070 | printf("%016x", type); 1071 | break; 1072 | } 1073 | } 1074 | 1075 | static void 1076 | printf_shdr_flags(uint64_t flags) 1077 | { 1078 | size_t i; 1079 | int max = 16; 1080 | 1081 | if (flags & SHF_WRITE) 1082 | { 1083 | printf("W"); 1084 | max--; 1085 | } 1086 | 1087 | if (flags & SHF_ALLOC) 1088 | { 1089 | printf("A"); 1090 | max--; 1091 | } 1092 | 1093 | if (flags & SHF_EXECINSTR) 1094 | { 1095 | printf("X"); 1096 | max--; 1097 | } 1098 | 1099 | if (flags & SHF_MERGE) 1100 | { 1101 | printf("M"); 1102 | max--; 1103 | } 1104 | 1105 | if (flags & SHF_STRINGS) 1106 | { 1107 | printf("S"); 1108 | max--; 1109 | } 1110 | 1111 | if (flags & SHF_INFO_LINK) 1112 | { 1113 | printf("I"); 1114 | max--; 1115 | } 1116 | 1117 | if (flags & SHF_LINK_ORDER) 1118 | { 1119 | printf("L"); 1120 | max--; 1121 | } 1122 | 1123 | if (flags & SHF_OS_NONCONFORMING) 1124 | { 1125 | printf("O"); 1126 | max--; 1127 | } 1128 | 1129 | if (flags & SHF_GROUP) 1130 | { 1131 | printf("G"); 1132 | max--; 1133 | } 1134 | 1135 | if (flags & SHF_TLS) 1136 | { 1137 | printf("T"); 1138 | max--; 1139 | } 1140 | 1141 | if (flags & SHF_EXCLUDE) 1142 | { 1143 | printf("E"); 1144 | } 1145 | 1146 | if (flags & SHF_COMPRESSED) 1147 | { 1148 | printf("C"); 1149 | } 1150 | 1151 | for (i = 0; i < max; i++) 1152 | { 1153 | printf("-"); 1154 | } 1155 | } 1156 | 1157 | void print_elf_shdr() 1158 | { 1159 | int i; 1160 | 1161 | printf("Elf Section header:\n"); 1162 | 1163 | printf("[ID] %07s%018s%18s%018s%018s\n%016s%018s%018s%018s%18s\n\n", 1164 | "NAME", "TYPE", "FLAGS", "ADDRESS", "OFFSET", 1165 | "SIZE", "LINK", "INFO", "ADDRALIGN", "ENTSIZE"); 1166 | 1167 | for (i = 0; i < elf_ehdr->e_shnum; i++) 1168 | { 1169 | printf("[%02d] ", i); 1170 | if (StringTable[elf_shdr[i].sh_name]) 1171 | { 1172 | print_16_str(&StringTable[elf_shdr[i].sh_name]); 1173 | } 1174 | else 1175 | { 1176 | print_16_str(""); 1177 | } 1178 | printf(" "); 1179 | printf_shdr_type(elf_shdr[i].sh_type); 1180 | printf(" "); 1181 | printf_shdr_flags(elf_shdr[i].sh_flags); 1182 | printf(" "); 1183 | printf("%016x ", elf_shdr[i].sh_addr); 1184 | printf("%016x ", elf_shdr[i].sh_offset); 1185 | printf("\n%07s", " "); 1186 | printf("%016x ", elf_shdr[i].sh_size); 1187 | printf("%016x ", elf_shdr[i].sh_link); 1188 | printf("%016x ", elf_shdr[i].sh_info); 1189 | printf("%016x ", elf_shdr[i].sh_addralign); 1190 | printf("%016x ", elf_shdr[i].sh_entsize); 1191 | 1192 | printf("\n\n"); 1193 | } 1194 | } 1195 | 1196 | /*** 1197 | * Symbols header parsing and printing 1198 | */ 1199 | int parse_elf_sym(uint8_t *buf_ptr) 1200 | { 1201 | Elf32_Sym *elf32_sym; 1202 | Elf64_Sym *elf64_sym; 1203 | Elf_Shdr *dynsym_sh = NULL; 1204 | Elf_Shdr *symtab_sh = NULL; 1205 | int i; 1206 | 1207 | if (buf_ptr == NULL) 1208 | { 1209 | fprintf(stderr, "parse_elf_sym: cannot parse null buffer\n"); 1210 | return (-1); 1211 | } 1212 | 1213 | if (elf_ehdr == NULL) 1214 | { 1215 | fprintf(stderr, "parse_elf_sym: cannot parse symbol header without elf header\n"); 1216 | return (-1); 1217 | } 1218 | 1219 | if (elf_shdr == NULL) 1220 | { 1221 | fprintf(stderr, "parse_elf_sym: cannot parse symbol header without section header\n"); 1222 | return (-1); 1223 | } 1224 | 1225 | // get the section headers for symbols 1226 | for (i = 0; i < elf_ehdr->e_shnum; i++) 1227 | { 1228 | if (elf_shdr[i].sh_type == SHT_DYNSYM) 1229 | { 1230 | dynsym_sh = &elf_shdr[i]; 1231 | 1232 | /* 1233 | * The sh_link value of SHT_DYNSYM 1234 | * section points to the section 1235 | * of the strings for dynamic symbols. 1236 | */ 1237 | if (elf_shdr[i].sh_link) 1238 | { 1239 | DynSymbolStringTable = (char *)&buf_ptr[elf_shdr[elf_shdr[i].sh_link].sh_offset]; 1240 | } 1241 | } 1242 | 1243 | if (elf_shdr[i].sh_type == SHT_SYMTAB) 1244 | { 1245 | symtab_sh = &elf_shdr[i]; 1246 | 1247 | /* 1248 | * The sh_link value of SHT_SYMTAB 1249 | * section points to the section 1250 | * of the strings for symbols. 1251 | */ 1252 | if (elf_shdr[i].sh_link) 1253 | { 1254 | SymbolStringTable = (char *)&buf_ptr[elf_shdr[elf_shdr[i].sh_link].sh_offset]; 1255 | } 1256 | } 1257 | } 1258 | 1259 | // check if symbols contain something 1260 | // in that case free memory 1261 | if (elf_dynsym != NULL) 1262 | { 1263 | free_memory(elf_dynsym); 1264 | elf_dynsym = NULL; 1265 | } 1266 | 1267 | if (elf_symtab != NULL) 1268 | { 1269 | free_memory(elf_symtab); 1270 | elf_symtab = NULL; 1271 | } 1272 | 1273 | // .dynsym This section holds the dynamic linking symbol table. 1274 | if (dynsym_sh) 1275 | { 1276 | if (is_32_bit_binary()) 1277 | { 1278 | dynsym_num = dynsym_sh->sh_size / sizeof(Elf32_Sym); 1279 | 1280 | elf_dynsym = (Elf_Sym *)allocate_memory(dynsym_num * sizeof(Elf_Sym)); 1281 | elf32_sym = (Elf32_Sym *)&buf_ptr[dynsym_sh->sh_offset]; 1282 | 1283 | for (i = 0; i < dynsym_num; i++) 1284 | { 1285 | elf_dynsym[i].st_name = elf32_sym[i].st_name; 1286 | elf_dynsym[i].st_info = elf32_sym[i].st_info; 1287 | elf_dynsym[i].st_other = elf32_sym[i].st_other; 1288 | elf_dynsym[i].st_shndx = elf32_sym[i].st_shndx; 1289 | elf_dynsym[i].st_value = elf32_sym[i].st_value; 1290 | elf_dynsym[i].st_size = elf32_sym[i].st_size; 1291 | } 1292 | } 1293 | else if (is_64_bit_binary()) 1294 | { 1295 | dynsym_num = dynsym_sh->sh_size / sizeof(Elf64_Sym); 1296 | 1297 | elf_dynsym = (Elf_Sym *)allocate_memory(dynsym_num * sizeof(Elf_Sym)); 1298 | elf64_sym = (Elf64_Sym *)&buf_ptr[dynsym_sh->sh_offset]; 1299 | 1300 | for (i = 0; i < dynsym_num; i++) 1301 | { 1302 | elf_dynsym[i].st_name = elf64_sym[i].st_name; 1303 | elf_dynsym[i].st_info = elf64_sym[i].st_info; 1304 | elf_dynsym[i].st_other = elf64_sym[i].st_other; 1305 | elf_dynsym[i].st_shndx = elf64_sym[i].st_shndx; 1306 | elf_dynsym[i].st_value = elf64_sym[i].st_value; 1307 | elf_dynsym[i].st_size = elf64_sym[i].st_size; 1308 | } 1309 | } 1310 | else 1311 | { 1312 | return (-1); 1313 | } 1314 | } 1315 | 1316 | // .symtab This section holds a symbol table. 1317 | if (symtab_sh) 1318 | { 1319 | if (is_32_bit_binary()) 1320 | { 1321 | symtab_num = symtab_sh->sh_size / sizeof(Elf32_Sym); 1322 | 1323 | elf_symtab = (Elf_Sym *)allocate_memory(symtab_num * sizeof(Elf_Sym)); 1324 | elf32_sym = (Elf32_Sym *)&buf_ptr[symtab_sh->sh_offset]; 1325 | 1326 | for (i = 0; i < symtab_num; i++) 1327 | { 1328 | elf_symtab[i].st_name = elf32_sym[i].st_name; 1329 | elf_symtab[i].st_info = elf32_sym[i].st_info; 1330 | elf_symtab[i].st_other = elf32_sym[i].st_other; 1331 | elf_symtab[i].st_shndx = elf32_sym[i].st_shndx; 1332 | elf_symtab[i].st_value = elf32_sym[i].st_value; 1333 | elf_symtab[i].st_size = elf32_sym[i].st_size; 1334 | } 1335 | } 1336 | else if (is_64_bit_binary()) 1337 | { 1338 | symtab_num = symtab_sh->sh_size / sizeof(Elf64_Sym); 1339 | 1340 | elf_symtab = (Elf_Sym *)allocate_memory(symtab_num * sizeof(Elf_Sym)); 1341 | elf64_sym = (Elf64_Sym *)&buf_ptr[symtab_sh->sh_offset]; 1342 | 1343 | for (i = 0; i < symtab_num; i++) 1344 | { 1345 | elf_symtab[i].st_name = elf64_sym[i].st_name; 1346 | elf_symtab[i].st_info = elf64_sym[i].st_info; 1347 | elf_symtab[i].st_other = elf64_sym[i].st_other; 1348 | elf_symtab[i].st_shndx = elf64_sym[i].st_shndx; 1349 | elf_symtab[i].st_value = elf64_sym[i].st_value; 1350 | elf_symtab[i].st_size = elf64_sym[i].st_size; 1351 | } 1352 | } 1353 | else 1354 | { 1355 | return (-1); 1356 | } 1357 | } 1358 | 1359 | return (0); 1360 | } 1361 | 1362 | static void 1363 | print_info(unsigned char st_info) 1364 | { 1365 | uint64_t type, bind; 1366 | 1367 | if (is_32_bit_binary()) 1368 | { 1369 | type = ELF32_ST_TYPE(st_info); 1370 | bind = ELF32_ST_BIND(st_info); 1371 | } 1372 | else if (is_64_bit_binary()) 1373 | { 1374 | type = ELF64_ST_TYPE(st_info); 1375 | bind = ELF64_ST_BIND(st_info); 1376 | } 1377 | 1378 | switch (type) 1379 | { 1380 | /* 1381 | * Type not specified 1382 | */ 1383 | case STT_NOTYPE: 1384 | printf("NOTYPE "); 1385 | break; 1386 | /* 1387 | * Symbol associated with a data object (variable, array, etc). 1388 | */ 1389 | case STT_OBJECT: 1390 | printf("OBJECT "); 1391 | break; 1392 | /* 1393 | * Symbol is associated with function or other executable 1394 | * code 1395 | */ 1396 | case STT_FUNC: 1397 | printf("FUNC "); 1398 | break; 1399 | /* 1400 | * Symbol associated with a section. Symbol table entries of 1401 | * this type exist for relocation and normally have STB_LOCAL 1402 | * binding 1403 | */ 1404 | case STT_SECTION: 1405 | printf("SECTION"); 1406 | break; 1407 | /* 1408 | * File symbol has STB_LOCAL binding, section index is SHN_ABS 1409 | * it precedes other STB_LOCAL symbol for file. 1410 | */ 1411 | case STT_FILE: 1412 | printf("FILE "); 1413 | break; 1414 | case STT_LOPROC: 1415 | printf("LOPROC "); 1416 | break; 1417 | case STT_HIPROC: 1418 | printf("HIPROC "); 1419 | break; 1420 | default: 1421 | printf("%08x", type); 1422 | break; 1423 | } 1424 | printf(" "); 1425 | 1426 | switch (bind) 1427 | { 1428 | /* 1429 | * local symbol, not visible outside object file containing definition, 1430 | * local symbols of same name can exist in multiple files without interfering 1431 | * with each other. 1432 | */ 1433 | case STB_LOCAL: 1434 | printf("LOCAL "); 1435 | break; 1436 | /* 1437 | * Global symbols visible to all object files combined. One file's definition 1438 | * of a global symbol will satisfy another file's undefined reference to same 1439 | * global symbol. 1440 | */ 1441 | case STB_GLOBAL: 1442 | printf("GLOBAL "); 1443 | break; 1444 | /* 1445 | * Resemble global symbols, but definitions have lower precedence 1446 | */ 1447 | case STB_WEAK: 1448 | printf("WEAK "); 1449 | break; 1450 | default: 1451 | printf("%08x", bind); 1452 | break; 1453 | } 1454 | printf(" "); 1455 | } 1456 | 1457 | static void 1458 | print_visibility(unsigned char st_other) 1459 | { 1460 | uint64_t visibility; 1461 | 1462 | if (is_32_bit_binary()) 1463 | visibility = ELF32_ST_VISIBILITY(st_other); 1464 | else if (is_64_bit_binary()) 1465 | visibility = ELF64_ST_VISIBILITY(st_other); 1466 | 1467 | switch (visibility) 1468 | { 1469 | case STV_DEFAULT: 1470 | printf("DEFAULT "); 1471 | break; 1472 | case STV_INTERNAL: 1473 | printf("INTERNAL "); 1474 | break; 1475 | case STV_HIDDEN: 1476 | printf("HIDDEN "); 1477 | break; 1478 | case STV_PROTECTED: 1479 | printf("PROTECTED"); 1480 | break; 1481 | default: 1482 | printf("%08x ", visibility); 1483 | break; 1484 | } 1485 | printf(" "); 1486 | } 1487 | 1488 | static void 1489 | print_section(uint16_t section) 1490 | { 1491 | /* 1492 | * Symbol has absolute value, will not change 1493 | * because of relocation. 1494 | */ 1495 | if (section == SHN_ABS) 1496 | printf("%2sABS", " "); 1497 | /* 1498 | * Symbol undefined, link editor combines this 1499 | * object file with another that defines 1500 | * indicated symbol, file's references to symbol 1501 | * will be linked to actual definition 1502 | */ 1503 | else if (section == SHN_UNDEF) 1504 | printf("%2sUND", " "); 1505 | else if (section == SHN_BEFORE) 1506 | printf("%2sBEF", " "); 1507 | else if (section == SHN_AFTER) 1508 | printf("%2sAFT", " "); 1509 | else 1510 | printf("%5d", section); 1511 | 1512 | printf(" "); 1513 | } 1514 | 1515 | void print_elf_sym() 1516 | { 1517 | int i; 1518 | 1519 | printf("Elf symbol headers:\n"); 1520 | 1521 | if (elf_dynsym) 1522 | { 1523 | printf("Found .dynsym section symbols with %d symbols\n", dynsym_num); 1524 | 1525 | printf(" %s: %s %s %s %s %s %s %s\n", 1526 | "ID", "Value", "Size", "TYPE", "UNION", "VIS", "Section", "NAME"); 1527 | 1528 | for (i = 0; i < dynsym_num; i++) 1529 | { 1530 | printf(" %4d: %016x %016x ", i, elf_dynsym[i].st_value, elf_dynsym[i].st_size); 1531 | print_info(elf_dynsym[i].st_info); 1532 | print_visibility(elf_dynsym[i].st_other); 1533 | print_section(elf_dynsym[i].st_shndx); 1534 | if (elf_dynsym[i].st_name != 0) 1535 | { 1536 | if (&DynSymbolStringTable[elf_dynsym[i].st_name]) 1537 | printf("%s", &DynSymbolStringTable[elf_dynsym[i].st_name]); 1538 | } 1539 | printf("\n"); 1540 | } 1541 | } 1542 | 1543 | if (elf_symtab) 1544 | { 1545 | printf("Found .symtab section symbols with %d symbols\n", symtab_num); 1546 | 1547 | printf(" %s: %s %s %s %s %s %s %s\n", 1548 | "ID", "Value", "Size", "TYPE", "UNION", "VIS", "Section", "NAME"); 1549 | 1550 | for (i = 0; i < symtab_num; i++) 1551 | { 1552 | printf(" %4d: %016x %016x ", i, elf_symtab[i].st_value, elf_symtab[i].st_size); 1553 | print_info(elf_symtab[i].st_info); 1554 | print_visibility(elf_symtab[i].st_other); 1555 | print_section(elf_symtab[i].st_shndx); 1556 | if (elf_symtab[i].st_name != 0) 1557 | { 1558 | if (&SymbolStringTable[elf_symtab[i].st_name]) 1559 | printf("%s", &SymbolStringTable[elf_symtab[i].st_name]); 1560 | } 1561 | printf("\n"); 1562 | } 1563 | } 1564 | } 1565 | 1566 | /*** 1567 | * Relocation header parsing and printing 1568 | */ 1569 | 1570 | int parse_elf_rel_a(uint8_t *buf_ptr, size_t file_size) 1571 | { 1572 | size_t section_relocs_i; 1573 | int i, j; 1574 | size_t rel_index = 0, rela_index = 0; 1575 | 1576 | Elf32_Rel *elf32_rel; 1577 | Elf64_Rel *elf64_rel; 1578 | Elf32_Rela *elf32_rela; 1579 | Elf64_Rela *elf64_rela; 1580 | 1581 | if (buf_ptr == NULL) 1582 | { 1583 | fprintf(stderr, "parse_elf_rel_a: cannot parse null buffer\n"); 1584 | return (-1); 1585 | } 1586 | 1587 | if (elf_ehdr == NULL) 1588 | { 1589 | fprintf(stderr, "parse_elf_rel_a: cannot parse reloc header without elf header\n"); 1590 | return (-1); 1591 | } 1592 | 1593 | if (elf_shdr == NULL) 1594 | { 1595 | fprintf(stderr, "parse_elf_rel_a: cannot parse reloc header without section header\n"); 1596 | return (-1); 1597 | } 1598 | 1599 | // first let's see if there are REL and RELA sections already 1600 | if (elf_rel != NULL) 1601 | { 1602 | for (i = 0; i < rel_sections; i++) 1603 | { 1604 | free_memory(elf_rel[i]); 1605 | elf_rel[i] = NULL; 1606 | } 1607 | free_memory(elf_rel); 1608 | elf_rel = NULL; 1609 | 1610 | rel_sections = 0; 1611 | } 1612 | 1613 | if (elf_rela != NULL) 1614 | { 1615 | for (i = 0; i < rela_sections; i++) 1616 | { 1617 | free_memory(elf_rela[i]); 1618 | elf_rela[i] = NULL; 1619 | } 1620 | free_memory(elf_rela); 1621 | elf_rela = NULL; 1622 | 1623 | rela_sections = 0; 1624 | } 1625 | 1626 | // Now count again number of rel and rela sections 1627 | for (i = 0; i < elf_ehdr->e_shnum; i++) 1628 | { 1629 | if (elf_shdr[i].sh_type == SHT_REL) 1630 | rel_sections++; 1631 | else if (elf_shdr[i].sh_type == SHT_RELA) 1632 | rela_sections++; 1633 | } 1634 | 1635 | if (rel_sections) 1636 | elf_rel = allocate_memory(rel_sections * sizeof(Elf_Rel *)); 1637 | 1638 | if (rela_sections) 1639 | elf_rela = allocate_memory(rela_sections * sizeof(Elf_Rela *)); 1640 | 1641 | for (i = 0; i < elf_ehdr->e_shnum; i++) 1642 | { 1643 | if (elf_shdr[i].sh_type == SHT_REL) 1644 | { 1645 | if (is_32_bit_binary()) 1646 | { 1647 | elf32_rel = (Elf32_Rel *)&buf_ptr[elf_shdr[i].sh_offset]; 1648 | 1649 | section_relocs_i = elf_shdr[i].sh_size / sizeof(Elf32_Rel); 1650 | 1651 | if (section_relocs_i) 1652 | elf_rel[rel_index] = allocate_memory(section_relocs_i * sizeof(Elf_Rel)); 1653 | 1654 | for (j = 0; j < section_relocs_i; j++) 1655 | { 1656 | elf_rel[rel_index][j].r_info = elf32_rel[j].r_info; 1657 | elf_rel[rel_index][j].r_offset = elf32_rel[j].r_offset; 1658 | } 1659 | } 1660 | else if (is_64_bit_binary()) 1661 | { 1662 | elf64_rel = (Elf64_Rel *)&buf_ptr[elf_shdr[i].sh_offset]; 1663 | 1664 | section_relocs_i = elf_shdr[i].sh_size / sizeof(Elf64_Rel); 1665 | 1666 | if (section_relocs_i) 1667 | elf_rel[rel_index] = allocate_memory(section_relocs_i * sizeof(Elf_Rel)); 1668 | 1669 | for (j = 0; j < section_relocs_i; j++) 1670 | { 1671 | elf_rel[rel_index][j].r_info = elf64_rel[j].r_info; 1672 | elf_rel[rel_index][j].r_offset = elf64_rel[j].r_offset; 1673 | } 1674 | } 1675 | rel_index++; 1676 | } 1677 | 1678 | if (elf_shdr[i].sh_type == SHT_RELA) 1679 | { 1680 | if (is_32_bit_binary()) 1681 | { 1682 | elf32_rela = (Elf32_Rela *)&buf_ptr[elf_shdr[i].sh_offset]; 1683 | 1684 | section_relocs_i = elf_shdr[i].sh_size / sizeof(Elf32_Rela); 1685 | 1686 | if (section_relocs_i) 1687 | elf_rela[rela_index] = allocate_memory(section_relocs_i * sizeof(Elf_Rela)); 1688 | 1689 | for (j = 0; j < section_relocs_i; j++) 1690 | { 1691 | elf_rela[rela_index][j].r_info = elf32_rela[j].r_info; 1692 | elf_rela[rela_index][j].r_offset = elf32_rela[j].r_offset; 1693 | elf_rela[rela_index][j].r_addend = elf32_rela[j].r_addend; 1694 | } 1695 | } 1696 | else if (is_64_bit_binary()) 1697 | { 1698 | elf64_rela = (Elf64_Rela *)&buf_ptr[elf_shdr[i].sh_offset]; 1699 | 1700 | section_relocs_i = elf_shdr[i].sh_size / sizeof(Elf64_Rela); 1701 | 1702 | if (section_relocs_i) 1703 | elf_rela[rela_index] = allocate_memory(section_relocs_i * sizeof(Elf_Rela)); 1704 | 1705 | for (j = 0; j < section_relocs_i; j++) 1706 | { 1707 | elf_rela[rela_index][j].r_info = elf64_rela[j].r_info; 1708 | elf_rela[rela_index][j].r_offset = elf64_rela[j].r_offset; 1709 | elf_rela[rela_index][j].r_addend = elf64_rela[j].r_addend; 1710 | } 1711 | } 1712 | 1713 | rela_index++; 1714 | } 1715 | } 1716 | 1717 | return (0); 1718 | } 1719 | 1720 | static void 1721 | print_rel_info_32_bit(uint64_t r_info, Elf_Sym *associated_symbol, char *str_table) 1722 | { 1723 | uint64_t sym = ELF32_R_SYM(r_info); 1724 | uint64_t type = ELF32_R_TYPE(r_info); 1725 | 1726 | printf(" "); 1727 | 1728 | switch (type) 1729 | { 1730 | case R_386_NONE: 1731 | printf("%-18s", "R_386_NONE"); 1732 | break; 1733 | case R_386_32: 1734 | printf("%-18s", "R_386_32"); 1735 | break; 1736 | case R_386_PC32: 1737 | printf("%-18s", "R_386_PC32"); 1738 | break; 1739 | case R_386_GOT32: 1740 | printf("%-18s", "R_386_GOT32"); 1741 | break; 1742 | case R_386_PLT32: 1743 | printf("%-18s", "R_386_PLT32"); 1744 | break; 1745 | case R_386_COPY: 1746 | printf("%-18s", "R_386_COPY"); 1747 | break; 1748 | case R_386_GLOB_DAT: 1749 | printf("%-18s", "R_386_GLOB_DAT"); 1750 | break; 1751 | case R_386_JMP_SLOT: 1752 | printf("%-18s", "R_386_JMP_SLOT"); 1753 | break; 1754 | case R_386_RELATIVE: 1755 | printf("%-18s", "R_386_RELATIVE"); 1756 | break; 1757 | case R_386_GOTOFF: 1758 | printf("%-18s", "R_386_GOTOFF"); 1759 | break; 1760 | case R_386_GOTPC: 1761 | printf("%-18s", "R_386_GOTPC"); 1762 | break; 1763 | case R_386_32PLT: 1764 | printf("%-18s", "R_386_32PLT"); 1765 | break; 1766 | case R_386_TLS_TPOFF: 1767 | printf("%-18s", "R_386_TLS_TPOFF"); 1768 | break; 1769 | case R_386_TLS_IE: 1770 | printf("%-18s", "R_386_TLS_IE"); 1771 | break; 1772 | case R_386_TLS_GOTIE: 1773 | printf("%-18s", "R_386_TLS_GOTIE"); 1774 | break; 1775 | case R_386_TLS_LE: 1776 | printf("%-18s", "R_386_TLS_LE"); 1777 | break; 1778 | case R_386_TLS_GD: 1779 | printf("%-18s", "R_386_TLS_GD"); 1780 | break; 1781 | case R_386_TLS_LDM: 1782 | printf("%-18s", "R_386_TLS_LDM"); 1783 | break; 1784 | case R_386_16: 1785 | printf("%-18s", "R_386_16"); 1786 | break; 1787 | case R_386_PC16: 1788 | printf("%-18s", "R_386_PC16"); 1789 | break; 1790 | case R_386_8: 1791 | printf("%-18s", "R_386_8"); 1792 | break; 1793 | case R_386_PC8: 1794 | printf("%-18s", "R_386_PC8"); 1795 | break; 1796 | case R_386_TLS_GD_32: 1797 | printf("%-18s", "R_386_TLS_GD_32"); 1798 | break; 1799 | case R_386_TLS_GD_PUSH: 1800 | printf("%-18s", "R_386_TLS_GD_PUSH"); 1801 | break; 1802 | case R_386_TLS_GD_CALL: 1803 | printf("%-18s", "R_386_TLS_GD_CALL"); 1804 | break; 1805 | case R_386_TLS_GD_POP: 1806 | printf("%-18s", "R_386_TLS_GD_POP"); 1807 | break; 1808 | case R_386_TLS_LDM_32: 1809 | printf("%-18s", "R_386_TLS_LDM_32"); 1810 | break; 1811 | case R_386_TLS_LDM_PUSH: 1812 | printf("%-18s", "R_386_TLS_LDM_PUSH"); 1813 | break; 1814 | case R_386_TLS_LDM_CALL: 1815 | printf("%-18s", "R_386_TLS_LDM_CALL"); 1816 | break; 1817 | case R_386_TLS_LDM_POP: 1818 | printf("%-18s", "R_386_TLS_LDM_POP"); 1819 | break; 1820 | case R_386_TLS_LDO_32: 1821 | printf("%-18s", "R_386_TLS_LDO_32"); 1822 | break; 1823 | case R_386_TLS_IE_32: 1824 | printf("%-18s", "R_386_TLS_IE_32"); 1825 | break; 1826 | case R_386_TLS_LE_32: 1827 | printf("%-18s", "R_386_TLS_LE_32"); 1828 | break; 1829 | case R_386_TLS_DTPMOD32: 1830 | printf("%-18s", "R_386_TLS_DTPMOD32"); 1831 | break; 1832 | case R_386_TLS_DTPOFF32: 1833 | printf("%-18s", "R_386_TLS_DTPOFF32"); 1834 | break; 1835 | case R_386_TLS_TPOFF32: 1836 | printf("%-18s", "R_386_TLS_TPOFF32"); 1837 | break; 1838 | case R_386_SIZE32: 1839 | printf("%-18s", "R_386_SIZE32"); 1840 | break; 1841 | case R_386_TLS_GOTDESC: 1842 | printf("%-18s", "R_386_TLS_GOTDESC"); 1843 | break; 1844 | case R_386_TLS_DESC_CALL: 1845 | printf("%-18s", "R_386_TLS_DESC_CALL"); 1846 | break; 1847 | case R_386_TLS_DESC: 1848 | printf("%-18s", "R_386_TLS_DESC"); 1849 | break; 1850 | case R_386_IRELATIVE: 1851 | printf("%-18s", "R_386_IRELATIVE"); 1852 | break; 1853 | case R_386_GOT32X: 1854 | printf("%-18s", "R_386_GOT32X"); 1855 | break; 1856 | case R_386_NUM: 1857 | printf("%-18s", "R_386_NUM"); 1858 | break; 1859 | default: 1860 | printf("%016x", type); 1861 | break; 1862 | } 1863 | 1864 | if (associated_symbol[sym].st_name && &str_table[associated_symbol[sym].st_name]) 1865 | printf(" %016x %s", associated_symbol[sym].st_value, &str_table[associated_symbol[sym].st_name]); 1866 | else 1867 | printf(" %016x", associated_symbol[sym].st_value); 1868 | } 1869 | 1870 | static void 1871 | print_rel_info_64_bit(uint64_t r_info, Elf_Sym *associated_symbol, char *str_table) 1872 | { 1873 | uint64_t sym = ELF64_R_SYM(r_info); 1874 | uint64_t type = ELF64_R_TYPE(r_info); 1875 | 1876 | printf(" "); 1877 | 1878 | switch (type) 1879 | { 1880 | case R_X86_64_NONE: 1881 | printf("%-18s", "R_X86_64_NONE"); 1882 | break; 1883 | case R_X86_64_64: 1884 | printf("%-18s", "R_X86_64_64"); 1885 | break; 1886 | case R_X86_64_PC32: 1887 | printf("%-18s", "R_X86_64_PC32"); 1888 | break; 1889 | case R_X86_64_GOT32: 1890 | printf("%-18s", "R_X86_64_GOT32"); 1891 | break; 1892 | case R_X86_64_PLT32: 1893 | printf("%-18s", "R_X86_64_PLT32"); 1894 | break; 1895 | case R_X86_64_COPY: 1896 | printf("%-18s", "R_X86_64_COPY"); 1897 | break; 1898 | case R_X86_64_GLOB_DAT: 1899 | printf("%-18s", "R_X86_64_GLOB_DAT"); 1900 | break; 1901 | case R_X86_64_JUMP_SLOT: 1902 | printf("%-18s", "R_X86_64_JUMP_SLOT"); 1903 | break; 1904 | case R_X86_64_RELATIVE: 1905 | printf("%-18s", "R_X86_64_RELATIVE"); 1906 | break; 1907 | case R_X86_64_GOTPCREL: 1908 | printf("%-18s", "R_X86_64_GOTPCREL"); 1909 | break; 1910 | case R_X86_64_32: 1911 | printf("%-18s", "R_X86_64_32"); 1912 | break; 1913 | case R_X86_64_32S: 1914 | printf("%-18s", "R_X86_64_32S"); 1915 | break; 1916 | case R_X86_64_16: 1917 | printf("%-18s", "R_X86_64_16"); 1918 | break; 1919 | case R_X86_64_PC16: 1920 | printf("%-18s", "R_X86_64_PC16"); 1921 | break; 1922 | case R_X86_64_8: 1923 | printf("%-18s", "R_X86_64_8"); 1924 | break; 1925 | case R_X86_64_PC8: 1926 | printf("%-18s", "R_X86_64_PC8"); 1927 | break; 1928 | case R_X86_64_DTPMOD64: 1929 | printf("%-18s", "R_X86_64_DTPMOD64"); 1930 | break; 1931 | case R_X86_64_DTPOFF64: 1932 | printf("%-18s", "R_X86_64_DTPOFF64"); 1933 | break; 1934 | case R_X86_64_TPOFF64: 1935 | printf("%-18s", "R_X86_64_TPOFF64"); 1936 | break; 1937 | case R_X86_64_TLSGD: 1938 | printf("%-18s", "R_X86_64_TLSGD"); 1939 | break; 1940 | case R_X86_64_TLSLD: 1941 | printf("%-18s", "R_X86_64_TLSLD"); 1942 | break; 1943 | case R_X86_64_DTPOFF32: 1944 | printf("%-18s", "R_X86_64_DTPOFF32"); 1945 | break; 1946 | case R_X86_64_GOTTPOFF: 1947 | printf("%-18s", "R_X86_64_GOTTPOFF"); 1948 | break; 1949 | case R_X86_64_TPOFF32: 1950 | printf("%-18s", "R_X86_64_TPOFF32"); 1951 | break; 1952 | case R_X86_64_PC64: 1953 | printf("%-18s", "R_X86_64_PC64"); 1954 | break; 1955 | case R_X86_64_GOTOFF64: 1956 | printf("%-18s", "R_X86_64_GOTOFF64"); 1957 | break; 1958 | case R_X86_64_GOTPC32: 1959 | printf("%-18s", "R_X86_64_GOTPC32"); 1960 | break; 1961 | case R_X86_64_GOT64: 1962 | printf("%-18s", "R_X86_64_GOT64"); 1963 | break; 1964 | case R_X86_64_GOTPCREL64: 1965 | printf("%-18s", "R_X86_64_GOTPCREL64"); 1966 | break; 1967 | case R_X86_64_GOTPC64: 1968 | printf("%-18s", "R_X86_64_GOTPC64"); 1969 | break; 1970 | case R_X86_64_GOTPLT64: 1971 | printf("%-18s", "R_X86_64_GOTPLT64"); 1972 | break; 1973 | case R_X86_64_PLTOFF64: 1974 | printf("%-18s", "R_X86_64_PLTOFF64"); 1975 | break; 1976 | case R_X86_64_SIZE32: 1977 | printf("%-18s", "R_X86_64_SIZE32"); 1978 | break; 1979 | case R_X86_64_SIZE64: 1980 | printf("%-18s", "R_X86_64_SIZE64"); 1981 | break; 1982 | case R_X86_64_GOTPC32_TLSDESC: 1983 | printf("%-18s", "R_X86_64_GOTPC32_TLSDESC"); 1984 | break; 1985 | case R_X86_64_TLSDESC_CALL: 1986 | printf("%-18s", "R_X86_64_TLSDESC_CALL"); 1987 | break; 1988 | case R_X86_64_TLSDESC: 1989 | printf("%-18s", "R_X86_64_TLSDESC"); 1990 | break; 1991 | case R_X86_64_IRELATIVE: 1992 | printf("%-18s", "R_X86_64_IRELATIVE"); 1993 | break; 1994 | case R_X86_64_RELATIVE64: 1995 | printf("%-18s", "R_X86_64_RELATIVE64"); 1996 | break; 1997 | case R_X86_64_GOTPCRELX: 1998 | printf("%-18s", "R_X86_64_GOTPCRELX"); 1999 | break; 2000 | case R_X86_64_REX_GOTPCRELX: 2001 | printf("%-18s", "R_X86_64_REX_GOTPCRELX"); 2002 | break; 2003 | case R_X86_64_NUM: 2004 | printf("%-18s", "R_X86_64_NUM"); 2005 | break; 2006 | default: 2007 | printf("%016x", type); 2008 | break; 2009 | } 2010 | 2011 | if (associated_symbol[sym].st_name && &str_table[associated_symbol[sym].st_name]) 2012 | printf(" %016x %s", associated_symbol[sym].st_value, &str_table[associated_symbol[sym].st_name]); 2013 | else 2014 | printf(" %016x", associated_symbol[sym].st_value); 2015 | } 2016 | 2017 | static void 2018 | print_rel_info(uint64_t r_info, Elf_Sym *associated_symbol, char *str_table) 2019 | { 2020 | if (is_32_bit_binary()) 2021 | { 2022 | print_rel_info_32_bit(r_info, associated_symbol, str_table); 2023 | } 2024 | else if (is_64_bit_binary()) 2025 | { 2026 | print_rel_info_64_bit(r_info, associated_symbol, str_table); 2027 | } 2028 | else 2029 | { 2030 | printf(" (not supported binary architecture)"); 2031 | } 2032 | } 2033 | 2034 | void print_elf_rel_a() 2035 | { 2036 | int i, j; 2037 | size_t rel_index = 0, rela_index = 0; 2038 | size_t section_relocs_i; 2039 | Elf_Sym *associated_symbol; 2040 | char *str_table; 2041 | 2042 | printf("Elf reloc headers:\n"); 2043 | for (i = 0; i < elf_ehdr->e_shnum; i++) 2044 | { 2045 | if (elf_shdr[i].sh_type == SHT_REL) 2046 | { 2047 | if (is_32_bit_binary()) 2048 | { 2049 | section_relocs_i = elf_shdr[i].sh_size / sizeof(Elf32_Rel); 2050 | } 2051 | else if (is_64_bit_binary()) 2052 | { 2053 | section_relocs_i = elf_shdr[i].sh_size / sizeof(Elf64_Rel); 2054 | } 2055 | 2056 | if (StringTable[elf_shdr[i].sh_name]) 2057 | printf("Found reloc section %s, relocs (%d):\n\n", &StringTable[elf_shdr[i].sh_name], section_relocs_i); 2058 | else 2059 | printf("Found reloc section %s, relocs (%d):\n\n", "NONE", section_relocs_i); 2060 | 2061 | printf("[%3s] %8s %16s %17s %19s %17s\n", "ID", "OFFSET", "INFO", "REL. TYPE", "SYM. VALUE", "Symbol Name"); 2062 | 2063 | if (elf_shdr[elf_shdr[i].sh_link].sh_type == SHT_DYNSYM) 2064 | { 2065 | associated_symbol = elf_dynsym; 2066 | str_table = DynSymbolStringTable; 2067 | } 2068 | else if (elf_shdr[elf_shdr[i].sh_link].sh_type == SHT_SYMTAB) 2069 | { 2070 | associated_symbol = elf_symtab; 2071 | str_table = SymbolStringTable; 2072 | } 2073 | 2074 | for (j = 0; j < section_relocs_i; j++) 2075 | { 2076 | printf("[%3d] %016x %016x", j, elf_rel[rel_index][j].r_offset, elf_rel[rel_index][j].r_info); 2077 | print_rel_info(elf_rel[rel_index][j].r_info, associated_symbol, str_table); 2078 | printf("\n"); 2079 | } 2080 | 2081 | rel_index++; 2082 | printf("\n"); 2083 | } 2084 | 2085 | if (elf_shdr[i].sh_type == SHT_RELA) 2086 | { 2087 | if (is_32_bit_binary()) 2088 | { 2089 | section_relocs_i = elf_shdr[i].sh_size / sizeof(Elf32_Rela); 2090 | } 2091 | else if (is_64_bit_binary()) 2092 | { 2093 | section_relocs_i = elf_shdr[i].sh_size / sizeof(Elf64_Rela); 2094 | } 2095 | 2096 | if (StringTable[elf_shdr[i].sh_name]) 2097 | printf("Found reloc section %s, relocs (%d):\n\n", &StringTable[elf_shdr[i].sh_name], section_relocs_i); 2098 | else 2099 | printf("Found reloc section %s, relocs (%d):\n\n", "NONE", section_relocs_i); 2100 | 2101 | printf("[%3s] %8s %16s %16s %17s %19s %17s\n", "ID", "OFFSET", "INFO", "ADDEND", "REL. TYPE", "SYM. VALUE", "Symbol Name"); 2102 | 2103 | if (elf_shdr[elf_shdr[i].sh_link].sh_type == SHT_DYNSYM) 2104 | { 2105 | associated_symbol = elf_dynsym; 2106 | str_table = DynSymbolStringTable; 2107 | } 2108 | else if (elf_shdr[elf_shdr[i].sh_link].sh_type == SHT_SYMTAB) 2109 | { 2110 | associated_symbol = elf_symtab; 2111 | str_table = SymbolStringTable; 2112 | } 2113 | 2114 | for (j = 0; j < section_relocs_i; j++) 2115 | { 2116 | printf("[%3d] %016x %016x %016x", j, elf_rela[rela_index][j].r_offset, elf_rela[rela_index][j].r_info, elf_rela[rela_index][j].r_addend); 2117 | print_rel_info(elf_rela[rela_index][j].r_info, associated_symbol, str_table); 2118 | printf("\n"); 2119 | } 2120 | 2121 | rela_index++; 2122 | printf("\n"); 2123 | } 2124 | } 2125 | } 2126 | 2127 | /*** 2128 | * Dynamic program header parsing and printing 2129 | */ 2130 | int parse_elf_dynamic(uint8_t *buf_ptr, size_t file_size) 2131 | { 2132 | int i; 2133 | 2134 | Elf32_Dyn *elf32_dyn; 2135 | Elf64_Dyn *elf64_dyn; 2136 | 2137 | Elf_Phdr *dynamic; 2138 | 2139 | if (buf_ptr == NULL) 2140 | { 2141 | fprintf(stderr, "parse_elf_dynamic: cannot parse null buffer\n"); 2142 | return (-1); 2143 | } 2144 | 2145 | if (elf_ehdr == NULL) 2146 | { 2147 | fprintf(stderr, "parse_elf_dynamic: cannot parse dynamic program header without elf header\n"); 2148 | return (-1); 2149 | } 2150 | 2151 | if (elf_phdr == NULL) 2152 | { 2153 | fprintf(stderr, "parse_elf_dynamic: cannot parse dynamic program header without elf program header\n"); 2154 | return (-1); 2155 | } 2156 | 2157 | // first let's see if there are dynamic headers already 2158 | if (elf_dyn != NULL) 2159 | { 2160 | free_memory(elf_dyn); 2161 | elf_dyn = NULL; 2162 | 2163 | dynamic_headers = 0; 2164 | } 2165 | // Now get number of dynamic headers 2166 | for (i = 0; i < elf_ehdr->e_phnum; i++) 2167 | { 2168 | if (elf_phdr[i].p_type == PT_DYNAMIC) 2169 | { 2170 | if (is_32_bit_binary()) 2171 | { 2172 | dynamic_headers = elf_phdr[i].p_filesz / sizeof(Elf32_Dyn); 2173 | } 2174 | else if (is_64_bit_binary()) 2175 | { 2176 | dynamic_headers = elf_phdr[i].p_filesz / sizeof(Elf64_Dyn); 2177 | } 2178 | 2179 | dynamic = &elf_phdr[i]; 2180 | 2181 | break; 2182 | } 2183 | } 2184 | 2185 | if (dynamic_headers) 2186 | { 2187 | elf_dyn = allocate_memory(dynamic_headers * sizeof(Elf_Dyn)); 2188 | } 2189 | 2190 | if (is_32_bit_binary()) 2191 | { 2192 | elf32_dyn = (Elf32_Dyn *)&buf_ptr[dynamic->p_offset]; 2193 | } 2194 | else if (is_64_bit_binary()) 2195 | { 2196 | elf64_dyn = (Elf64_Dyn *)&buf_ptr[dynamic->p_offset]; 2197 | } 2198 | 2199 | for (i = 0; i < dynamic_headers; i++) 2200 | { 2201 | if (is_32_bit_binary()) 2202 | { 2203 | elf_dyn[i].d_tag = elf32_dyn[i].d_tag; 2204 | elf_dyn[i].d_un.d_ptr = elf32_dyn[i].d_un.d_ptr; 2205 | } 2206 | else if (is_64_bit_binary()) 2207 | { 2208 | elf_dyn[i].d_tag = elf64_dyn[i].d_tag; 2209 | elf_dyn[i].d_un.d_ptr = elf64_dyn[i].d_un.d_ptr; 2210 | } 2211 | } 2212 | 2213 | return (0); 2214 | } 2215 | 2216 | static char * 2217 | print_tag(Elf64_Sxword d_tag) 2218 | { 2219 | char *ret_value; 2220 | switch (d_tag) 2221 | { 2222 | case DT_NULL: 2223 | ret_value = "DT_NULL"; 2224 | break; 2225 | case DT_NEEDED: 2226 | ret_value = "DT_NEEDED"; 2227 | break; 2228 | case DT_PLTRELSZ: 2229 | ret_value = "DT_PLTRELSZ"; 2230 | break; 2231 | case DT_PLTGOT: 2232 | ret_value = "DT_PLTGOT"; 2233 | break; 2234 | case DT_HASH: 2235 | ret_value = "DT_HASH"; 2236 | break; 2237 | case DT_STRTAB: 2238 | ret_value = "DT_STRTAB"; 2239 | break; 2240 | case DT_SYMTAB: 2241 | ret_value = "DT_SYMTAB"; 2242 | break; 2243 | case DT_RELA: 2244 | ret_value = "DT_RELA"; 2245 | break; 2246 | case DT_RELASZ: 2247 | ret_value = "DT_RELASZ"; 2248 | break; 2249 | case DT_RELAENT: 2250 | ret_value = "DT_RELAENT"; 2251 | break; 2252 | case DT_STRSZ: 2253 | ret_value = "DT_STRSZ"; 2254 | break; 2255 | case DT_SYMENT: 2256 | ret_value = "DT_SYMENT"; 2257 | break; 2258 | case DT_INIT: 2259 | ret_value = "DT_INIT"; 2260 | break; 2261 | case DT_FINI: 2262 | ret_value = "DT_FINI"; 2263 | break; 2264 | case DT_SONAME: 2265 | ret_value = "DT_SONAME"; 2266 | break; 2267 | case DT_RPATH: 2268 | ret_value = "DT_RPATH"; 2269 | break; 2270 | case DT_SYMBOLIC: 2271 | ret_value = "DT_SYMBOLIC"; 2272 | break; 2273 | case DT_REL: 2274 | ret_value = "DT_REL"; 2275 | break; 2276 | case DT_RELSZ: 2277 | ret_value = "DT_RELSZ"; 2278 | break; 2279 | case DT_RELENT: 2280 | ret_value = "DT_RELENT"; 2281 | break; 2282 | case DT_PLTREL: 2283 | ret_value = "DT_PLTREL"; 2284 | break; 2285 | case DT_DEBUG: 2286 | ret_value = "DT_DEBUG"; 2287 | break; 2288 | case DT_TEXTREL: 2289 | ret_value = "DT_TEXTREL"; 2290 | break; 2291 | case DT_JMPREL: 2292 | ret_value = "DT_JMPREL"; 2293 | break; 2294 | case DT_BIND_NOW: 2295 | ret_value = "DT_BIND_NOW"; 2296 | break; 2297 | case DT_INIT_ARRAY: 2298 | ret_value = "DT_INIT_ARRAY"; 2299 | break; 2300 | case DT_FINI_ARRAY: 2301 | ret_value = "DT_FINI_ARRAY"; 2302 | break; 2303 | case DT_INIT_ARRAYSZ: 2304 | ret_value = "DT_INIT_ARRAYSZ"; 2305 | break; 2306 | case DT_FINI_ARRAYSZ: 2307 | ret_value = "DT_FINI_ARRAYSZ"; 2308 | break; 2309 | case DT_RUNPATH: 2310 | ret_value = "DT_RUNPATH"; 2311 | break; 2312 | case DT_FLAGS: 2313 | ret_value = "DT_FLAGS"; 2314 | break; 2315 | case DT_ENCODING: 2316 | ret_value = "DT_ENCODING"; 2317 | break; 2318 | case DT_PREINIT_ARRAYSZ: 2319 | ret_value = "DT_PREINIT_ARRAYSZ"; 2320 | break; 2321 | case DT_SYMTAB_SHNDX: 2322 | ret_value = "DT_SYMTAB_SHNDX"; 2323 | break; 2324 | case DT_NUM: 2325 | ret_value = "DT_NUM"; 2326 | break; 2327 | case DT_LOOS: 2328 | ret_value = "DT_LOOS"; 2329 | break; 2330 | case DT_HIOS: 2331 | ret_value = "DT_HIOS"; 2332 | break; 2333 | case DT_LOPROC: 2334 | ret_value = "DT_LOPROC"; 2335 | break; 2336 | case DT_HIPROC: 2337 | ret_value = "DT_HIPROC"; 2338 | break; 2339 | case DT_VALRNGLO: 2340 | ret_value = "DT_VALRNGLO"; 2341 | break; 2342 | case DT_GNU_PRELINKED: 2343 | ret_value = "DT_GNU_PRELINKED"; 2344 | break; 2345 | case DT_GNU_CONFLICTSZ: 2346 | ret_value = "DT_GNU_CONFLICTSZ"; 2347 | break; 2348 | case DT_GNU_LIBLISTSZ: 2349 | ret_value = "DT_GNU_LIBLISTSZ"; 2350 | break; 2351 | case DT_CHECKSUM: 2352 | ret_value = "DT_CHECKSUM"; 2353 | break; 2354 | case DT_PLTPADSZ: 2355 | ret_value = "DT_PLTPADSZ"; 2356 | break; 2357 | case DT_MOVEENT: 2358 | ret_value = "DT_MOVEENT"; 2359 | break; 2360 | case DT_MOVESZ: 2361 | ret_value = "DT_MOVESZ"; 2362 | break; 2363 | case DT_FEATURE_1: 2364 | ret_value = "DT_FEATURE_1"; 2365 | break; 2366 | case DT_POSFLAG_1: 2367 | ret_value = "DT_POSFLAG_1"; 2368 | break; 2369 | case DT_SYMINSZ: 2370 | ret_value = "DT_SYMINSZ"; 2371 | break; 2372 | case DT_SYMINENT: 2373 | ret_value = "DT_SYMINENT"; 2374 | break; 2375 | case DT_ADDRRNGLO: 2376 | ret_value = "DT_ADDRRNGLO"; 2377 | break; 2378 | case DT_GNU_HASH: 2379 | ret_value = "DT_GNU_HASH"; 2380 | break; 2381 | case DT_TLSDESC_PLT: 2382 | ret_value = "DT_TLSDESC_PLT"; 2383 | break; 2384 | case DT_TLSDESC_GOT: 2385 | ret_value = "DT_TLSDESC_GOT"; 2386 | break; 2387 | case DT_GNU_CONFLICT: 2388 | ret_value = "DT_GNU_CONFLICT"; 2389 | break; 2390 | case DT_GNU_LIBLIST: 2391 | ret_value = "DT_GNU_LIBLIST"; 2392 | break; 2393 | case DT_CONFIG: 2394 | ret_value = "DT_CONFIG"; 2395 | break; 2396 | case DT_DEPAUDIT: 2397 | ret_value = "DT_DEPAUDIT"; 2398 | break; 2399 | case DT_AUDIT: 2400 | ret_value = "DT_AUDIT"; 2401 | break; 2402 | case DT_PLTPAD: 2403 | ret_value = "DT_PLTPAD"; 2404 | break; 2405 | case DT_MOVETAB: 2406 | ret_value = "DT_MOVETAB"; 2407 | break; 2408 | case DT_SYMINFO: 2409 | ret_value = "DT_SYMINFO"; 2410 | break; 2411 | case DT_VERSYM: 2412 | ret_value = "DT_VERSYM"; 2413 | break; 2414 | case DT_RELACOUNT: 2415 | ret_value = "DT_RELACOUNT"; 2416 | break; 2417 | case DT_RELCOUNT: 2418 | ret_value = "DT_RELCOUNT"; 2419 | break; 2420 | case DT_FLAGS_1: 2421 | ret_value = "DT_FLAGS_1"; 2422 | break; 2423 | case DT_VERDEF: 2424 | ret_value = "DT_VERDEF"; 2425 | break; 2426 | case DT_VERDEFNUM: 2427 | ret_value = "DT_VERDEFNUM"; 2428 | break; 2429 | case DT_VERNEED: 2430 | ret_value = "DT_VERNEED"; 2431 | break; 2432 | case DT_VERNEEDNUM: 2433 | ret_value = "DT_VERNEEDNUM"; 2434 | break; 2435 | case DT_AUXILIARY: 2436 | ret_value = "DT_AUXILIARY"; 2437 | break; 2438 | default: 2439 | ret_value = NULL; 2440 | break; 2441 | } 2442 | 2443 | return ret_value; 2444 | } 2445 | 2446 | void print_elf_dynamic() 2447 | { 2448 | int i; 2449 | 2450 | printf("Elf Dynamic Program Header:\n"); 2451 | 2452 | printf(" %s: %016s %s %09s %016s\n", 2453 | "ID", "TAG", "TAG STR", "", "Val/Ptr"); 2454 | for (i = 0; i < dynamic_headers; i++) 2455 | { 2456 | char *tag = print_tag(elf_dyn[i].d_tag); 2457 | 2458 | if (tag == NULL) 2459 | printf(" %4d: %016x %016s %016x", i, elf_dyn[i].d_tag, " ", elf_dyn[i].d_un.d_ptr); 2460 | else 2461 | printf(" %4d: %016x %-016s %016x", i, elf_dyn[i].d_tag, tag, elf_dyn[i].d_un.d_ptr); 2462 | 2463 | if (elf_dyn[i].d_tag == DT_NEEDED) 2464 | { 2465 | if ((Interpreter != NULL) && (strcmp(Interpreter, &DynSymbolStringTable[elf_dyn[i].d_un.d_val]) == 0)) 2466 | printf(" [Program Interpreter: %s]", &DynSymbolStringTable[elf_dyn[i].d_un.d_val]); 2467 | else 2468 | printf(" [Shared Lib: %s]", &DynSymbolStringTable[elf_dyn[i].d_un.d_val]); 2469 | } 2470 | else if (elf_dyn[i].d_tag == DT_SONAME) 2471 | { 2472 | printf(" [Exported Library: %s]", &DynSymbolStringTable[elf_dyn[i].d_un.d_val]); 2473 | } 2474 | 2475 | printf("\n"); 2476 | } 2477 | } 2478 | 2479 | void 2480 | print_imported_libraries() 2481 | { 2482 | int i, j = 0; 2483 | 2484 | printf("Elf binary imported libraries:\n"); 2485 | 2486 | printf(" %s: %s\n", 2487 | "ID", "Name"); 2488 | 2489 | for (i = 0; i < dynamic_headers; i++) 2490 | { 2491 | if (elf_dyn[i].d_tag == DT_NEEDED) 2492 | { 2493 | if (!Interpreter || strcmp(Interpreter, &DynSymbolStringTable[elf_dyn[i].d_un.d_val]) != 0) 2494 | printf(" %4d: %s\n", j++, &DynSymbolStringTable[elf_dyn[i].d_un.d_val]); 2495 | } 2496 | } 2497 | 2498 | return; 2499 | } 2500 | 2501 | void 2502 | print_imported_functions() 2503 | { 2504 | int i, j = 0; 2505 | uint64_t type; 2506 | 2507 | printf("Elf imported functions:\n"); 2508 | 2509 | printf(" %s: %s\n", 2510 | "ID", "Name"); 2511 | 2512 | if (elf_dynsym) 2513 | { 2514 | for (i = 0; i < dynsym_num; i++) 2515 | { 2516 | if (is_32_bit_binary()) 2517 | type = ELF32_ST_TYPE(elf_dynsym[i].st_info); 2518 | else if (is_64_bit_binary()) 2519 | type = ELF64_ST_TYPE(elf_dynsym[i].st_info); 2520 | 2521 | if (type == STT_FUNC) 2522 | { 2523 | if (elf_dynsym[i].st_name != 0 && elf_dynsym[i].st_value == 0) 2524 | { 2525 | if (&DynSymbolStringTable[elf_dynsym[i].st_name]) 2526 | printf(" %4d: %s\n", j++, &DynSymbolStringTable[elf_dynsym[i].st_name]); 2527 | } 2528 | } 2529 | } 2530 | } 2531 | 2532 | if (elf_symtab) 2533 | { 2534 | for (i = 0; i < symtab_num; i++) 2535 | { 2536 | if (is_32_bit_binary()) 2537 | type = ELF32_ST_TYPE(elf_symtab[i].st_info); 2538 | else if (is_64_bit_binary()) 2539 | type = ELF64_ST_TYPE(elf_symtab[i].st_info); 2540 | 2541 | if (type == STT_FUNC && elf_symtab[i].st_value == 0) 2542 | { 2543 | if (elf_symtab[i].st_name != 0) 2544 | { 2545 | if (&SymbolStringTable[elf_symtab[i].st_name]) 2546 | printf(" %4d: %s\n", j++, &SymbolStringTable[elf_symtab[i].st_name]); 2547 | } 2548 | } 2549 | } 2550 | } 2551 | return; 2552 | } 2553 | 2554 | void 2555 | print_exported_libraries() 2556 | { 2557 | int i, j = 0; 2558 | 2559 | printf("Elf binary exported libraries:\n"); 2560 | 2561 | printf(" %s: %s\n", 2562 | "ID", "Name"); 2563 | 2564 | for (i = 0; i < dynamic_headers; i++) 2565 | { 2566 | if (elf_dyn[i].d_tag == DT_SONAME) 2567 | { 2568 | printf(" %4d: %s\n", j++, &DynSymbolStringTable[elf_dyn[i].d_un.d_val]); 2569 | } 2570 | } 2571 | } 2572 | 2573 | void 2574 | print_exported_functions() 2575 | { 2576 | int i, j = 0; 2577 | uint64_t type; 2578 | 2579 | printf("Elf exported functions:\n"); 2580 | 2581 | printf(" %s: %s\n", 2582 | "ID", "Name"); 2583 | 2584 | if (elf_dynsym) 2585 | { 2586 | for (i = 0; i < dynsym_num; i++) 2587 | { 2588 | if (is_32_bit_binary()) 2589 | type = ELF32_ST_TYPE(elf_dynsym[i].st_info); 2590 | else if (is_64_bit_binary()) 2591 | type = ELF64_ST_TYPE(elf_dynsym[i].st_info); 2592 | 2593 | if (type == STT_FUNC) 2594 | { 2595 | if (elf_dynsym[i].st_name != 0 && elf_dynsym[i].st_value != 0) 2596 | { 2597 | if (&DynSymbolStringTable[elf_dynsym[i].st_name]) 2598 | printf(" %4d: %s\n", j++, &DynSymbolStringTable[elf_dynsym[i].st_name]); 2599 | } 2600 | } 2601 | } 2602 | } 2603 | 2604 | if (elf_symtab) 2605 | { 2606 | for (i = 0; i < symtab_num; i++) 2607 | { 2608 | if (is_32_bit_binary()) 2609 | type = ELF32_ST_TYPE(elf_symtab[i].st_info); 2610 | else if (is_64_bit_binary()) 2611 | type = ELF64_ST_TYPE(elf_symtab[i].st_info); 2612 | 2613 | if (type == STT_FUNC && elf_symtab[i].st_value != 0) 2614 | { 2615 | if (elf_symtab[i].st_name != 0) 2616 | { 2617 | if (&SymbolStringTable[elf_symtab[i].st_name]) 2618 | printf(" %4d: %s\n", j++, &SymbolStringTable[elf_symtab[i].st_name]); 2619 | } 2620 | } 2621 | } 2622 | } 2623 | return; 2624 | } 2625 | 2626 | void close_everything() 2627 | { 2628 | size_t i; 2629 | 2630 | if (elf_ehdr && elf_ehdr != (Elf_Ehdr *)-1) 2631 | free_memory(elf_ehdr); 2632 | 2633 | if (elf_phdr && elf_phdr != (Elf_Phdr *)-1) 2634 | free_memory(elf_phdr); 2635 | 2636 | if (elf_shdr && elf_shdr != (Elf_Shdr *)-1) 2637 | free_memory(elf_shdr); 2638 | 2639 | if (elf_dynsym && elf_dynsym != (Elf_Sym *)-1) 2640 | free_memory(elf_dynsym); 2641 | 2642 | if (elf_symtab && elf_symtab != (Elf_Sym *)-1) 2643 | free_memory(elf_symtab); 2644 | 2645 | if (elf_rel && elf_rel != (Elf_Rel **)-1) 2646 | { 2647 | for (i = 0; i < rel_sections; i++) 2648 | { 2649 | free_memory(elf_rel[i]); 2650 | } 2651 | free_memory(elf_rel); 2652 | } 2653 | 2654 | if (elf_rela && elf_rela != (Elf_Rela **)-1) 2655 | { 2656 | for (i = 0; i < rela_sections; i++) 2657 | { 2658 | free_memory(elf_rela[i]); 2659 | } 2660 | free_memory(elf_rela); 2661 | } 2662 | 2663 | if (elf_dyn && elf_dyn != (Elf_Dyn *)-1) 2664 | { 2665 | free_memory(elf_dyn); 2666 | } 2667 | 2668 | if (buf_ptr && buf_ptr != (uint8_t *)-1) 2669 | munmap_memory(buf_ptr, buf_ptr_size); 2670 | } -------------------------------------------------------------------------------- /elfparser_e/src/file_management.c: -------------------------------------------------------------------------------- 1 | #include "file_management.h" 2 | #include 3 | 4 | 5 | int 6 | open_file(const char *pathname, int flags) 7 | { 8 | int fd; 9 | 10 | if (pathname == NULL) 11 | { 12 | fprintf(stderr, "open_file: error pathname cannot be NULL\n"); 13 | return (-1); 14 | } 15 | 16 | if ((fd = open(pathname, flags)) < 0) 17 | { 18 | perror("open_file"); 19 | return (-1); 20 | } 21 | 22 | return (fd); 23 | } 24 | 25 | int 26 | open_file_reading(const char *pathname) 27 | { 28 | int fd; 29 | 30 | if (pathname == NULL) 31 | { 32 | fprintf(stderr, "open_file_reading: error pathname cannot be NULL\n"); 33 | return (-1); 34 | } 35 | 36 | if ((fd = open(pathname, O_RDONLY)) < 0) 37 | { 38 | perror("open_file_reading"); 39 | return (-1); 40 | } 41 | 42 | return (fd); 43 | } 44 | 45 | 46 | int 47 | open_file_writing(const char *pathname) 48 | { 49 | int fd; 50 | 51 | if (pathname == NULL) 52 | { 53 | fprintf(stderr, "open_file_writing: error pathname cannot be NULL\n"); 54 | return (-1); 55 | } 56 | 57 | if ((fd = open(pathname, O_WRONLY)) < 0) 58 | { 59 | perror("open_file_writing"); 60 | return (-1); 61 | } 62 | 63 | return (fd); 64 | } 65 | 66 | int 67 | open_file_read_write(const char *pathname) 68 | { 69 | int fd; 70 | 71 | if (pathname == NULL) 72 | { 73 | fprintf(stderr, "open_file_read_Write: error pathname cannot be NULL\n"); 74 | return (-1); 75 | } 76 | 77 | if ((fd = open(pathname, O_RDWR)) < 0) 78 | { 79 | perror("open_file_read_write"); 80 | return (-1); 81 | } 82 | 83 | return (fd); 84 | } 85 | 86 | ssize_t 87 | get_file_size(int fd) 88 | { 89 | struct stat buf_stat; 90 | 91 | if (fd < 0) 92 | { 93 | fprintf(stderr, "close_file: file descriptor cannot be negative number\n"); 94 | return (INVALID_FILE_DESCRIPTOR); 95 | } 96 | 97 | if (fstat(fd, &buf_stat) < 0) 98 | { 99 | perror("get_file_size"); 100 | return (-1); 101 | } 102 | 103 | return (buf_stat.st_size); 104 | } 105 | 106 | int 107 | close_file(int fd) 108 | { 109 | if (fd < 0) 110 | { 111 | fprintf(stderr, "close_file: file descriptor cannot be negative number\n"); 112 | return (INVALID_FILE_DESCRIPTOR); 113 | } 114 | 115 | return close(fd); 116 | } -------------------------------------------------------------------------------- /elfparser_e/src/memory_management.c: -------------------------------------------------------------------------------- 1 | #include "memory_management.h" 2 | 3 | 4 | void* 5 | allocate_memory(size_t size) 6 | { 7 | void* ret_address; 8 | 9 | if (size == 0) 10 | { 11 | fprintf(stderr, "allocate_memory: size cannot be 0\n"); 12 | return ((void*)-1); 13 | } 14 | 15 | if ((ret_address = malloc(size)) == NULL) 16 | { 17 | fprintf(stderr, "allocate_memory: error memory allocation\n"); 18 | return ((void*)-1); 19 | } 20 | 21 | return (ret_address); 22 | } 23 | 24 | 25 | void* 26 | realloc_memory(void* ptr, size_t size) 27 | { 28 | void* ret_address; 29 | 30 | if (size == 0) 31 | { 32 | fprintf(stderr, "realloc_memory: size cannot be 0\n"); 33 | return ((void*)-1); 34 | } 35 | 36 | if (ptr == NULL) 37 | { 38 | fprintf(stderr, "realloc_memory: cannot realloc NULL pointer\n"); 39 | return ((void*)-1); 40 | } 41 | 42 | if ((ret_address = realloc(ptr, size)) == NULL) 43 | { 44 | fprintf(stderr, "realloc_memory: error memory allocation\n"); 45 | return ((void*)-1); 46 | } 47 | return (ret_address); 48 | } 49 | 50 | void* 51 | mmap_file_read(size_t length, int fd) 52 | { 53 | void* file_memory; 54 | 55 | if (length == 0) 56 | { 57 | fprintf(stderr, "mmap_file_read: length cannot be 0\n"); 58 | return ((void*)-1); 59 | } 60 | 61 | if (fd < 0) 62 | { 63 | fprintf(stderr, "mmap_file_read: file descriptor cannot be lower than zero\n"); 64 | return ((void*)-1); 65 | } 66 | 67 | if ((file_memory = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) 68 | { 69 | perror("mmap_file_read"); 70 | return ((void*)-1); 71 | } 72 | 73 | return (file_memory); 74 | } 75 | 76 | void* 77 | mmap_file_write(size_t length, int fd) 78 | { 79 | void* file_memory; 80 | 81 | if (length == 0) 82 | { 83 | fprintf(stderr, "mmap_file_write: length cannot be 0\n"); 84 | return ((void*)-1); 85 | } 86 | 87 | if (fd < 0) 88 | { 89 | fprintf(stderr, "mmap_file_write: file descriptor cannot be lower than zero\n"); 90 | return ((void*)-1); 91 | } 92 | 93 | if ((file_memory = mmap(NULL, length, PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED) 94 | { 95 | perror("mmap_file_write"); 96 | return ((void*)-1); 97 | } 98 | 99 | return (file_memory); 100 | } 101 | 102 | 103 | void* 104 | mmap_file_read_write(size_t length, int fd) 105 | { 106 | void* file_memory; 107 | 108 | if (length == 0) 109 | { 110 | fprintf(stderr, "mmap_file_read_write: length cannot be 0\n"); 111 | return ((void*)-1); 112 | } 113 | 114 | if (fd < 0) 115 | { 116 | fprintf(stderr, "mmap_file_read_write: file descriptor cannot be lower than zero\n"); 117 | return ((void*)-1); 118 | } 119 | 120 | if ((file_memory = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED) 121 | { 122 | perror("mmap_file_read_write"); 123 | return ((void*)-1); 124 | } 125 | 126 | return (file_memory); 127 | } 128 | 129 | int 130 | free_memory(void *ptr) 131 | { 132 | if (ptr == NULL) 133 | { 134 | fprintf(stderr, "free_memory: cannot free NULL pointer\n"); 135 | return (-1); 136 | } 137 | 138 | free(ptr); 139 | 140 | ptr = NULL; 141 | 142 | return (0); 143 | } 144 | 145 | int 146 | munmap_memory(void* ptr, size_t size) 147 | { 148 | if (size == 0) 149 | { 150 | fprintf(stderr, "munmap_memory: size cannot be 0\n"); 151 | return (-1); 152 | } 153 | 154 | if (ptr == NULL) 155 | { 156 | fprintf(stderr, "munmap_memory: cannot munmap NULL pointer\n"); 157 | return (-1); 158 | } 159 | 160 | if (munmap(ptr, size) < 0) 161 | { 162 | perror("munmap_memory"); 163 | return (-1); 164 | } 165 | 166 | return (0); 167 | } -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | #-*- coding: utf-8 -*- 3 | 4 | ###################################################### 5 | # Dextripador 6 | # File: utils.py 7 | # Version: 0.7 8 | ###################################################### 9 | 10 | VERSION = 0.7 11 | 12 | COMMAND_FLAG = False 13 | VERBOSE_1 = False 14 | VERBOSE_2 = False 15 | VERBOSE_3 = False 16 | 17 | credits = ''' 18 | 19 | ██████╗ ███████╗██╗ ██╗████████╗██████╗ ██╗██████╗ █████╗ ██████╗ ██████╗ ██████╗ 20 | ██╔══██╗██╔════╝╚██╗██╔╝╚══██╔══╝██╔══██╗██║██╔══██╗██╔══██╗██╔══██╗██╔═══██╗██╔══██╗ 21 | ██║ ██║█████╗ ╚███╔╝ ██║ ██████╔╝██║██████╔╝███████║██║ ██║██║ ██║██████╔╝ 22 | ██║ ██║██╔══╝ ██╔██╗ ██║ ██╔══██╗██║██╔═══╝ ██╔══██║██║ ██║██║ ██║██╔══██╗ 23 | ██████╔╝███████╗██╔╝ ██╗ ██║ ██║ ██║██║██║ ██║ ██║██████╔╝╚██████╔╝██║ ██║ 24 | ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝ 25 | Version %0.1f 26 | 27 | Dextripador is a tool aimed to provide parsing of odex files and internal dex files, 28 | with the possibility to extract these latter. 29 | 30 | This tool is part of a research made by UC3M COSEC Lab & IMDEA Networks. 31 | 32 | Programmers & Ideas: 33 | 34 | - Eduardo Blazquez 35 | - Julien Gamba 36 | 37 | https://androidobservatory.com 38 | ''' % (VERSION) 39 | 40 | def SET_COMMAND_FLAG(BOOLEAN): 41 | global COMMAND_FLAG 42 | COMMAND_FLAG = BOOLEAN 43 | 44 | def SET_VERBOSE1(BOOLEAN): 45 | global VERBOSE_1 46 | VERBOSE_1 = BOOLEAN 47 | 48 | def SET_VERBOSE2(BOOLEAN): 49 | global VERBOSE_2 50 | VERBOSE_2 = BOOLEAN 51 | 52 | def SET_VERBOSE3(BOOLEAN): 53 | global VERBOSE_3 54 | VERBOSE_3 = BOOLEAN 55 | 56 | class Printer(): 57 | 58 | def print(msg): 59 | global COMMAND_FLAG 60 | if COMMAND_FLAG: 61 | print(msg) 62 | 63 | def verbose1(msg): 64 | global COMMAND_FLAG 65 | global VERBOSE_1 66 | if COMMAND_FLAG and VERBOSE_1: 67 | print(msg) 68 | 69 | def verbose2(msg): 70 | global COMMAND_FLAG 71 | global VERBOSE_2 72 | if COMMAND_FLAG and VERBOSE_2: 73 | print(msg) 74 | 75 | def verbose3(msg): 76 | global COMMAND_FLAG 77 | global VERBOSE_3 78 | 79 | if COMMAND_FLAG and VERBOSE_3: 80 | print(msg) --------------------------------------------------------------------------------