├── .gitignore ├── README.md ├── abf ├── __init__.py ├── abstract.py ├── cpu.py ├── elf.py ├── elfFlags.py ├── exception.py ├── macho.py └── pe.py ├── binaries ├── MachO-OSX-x86-ls ├── elf-Linux-ARMv7-ls ├── elf-Linux-x86-bash └── pe-Windows-x86-cmd ├── helpers ├── abstract.py └── elf.py ├── setup.cfg └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | dist/* 2 | abf.egg-info/* 3 | build/* 4 | *.pyc 5 | *.swp 6 | clean.sh 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Abstract Binary Format 2 | ======================= 3 | 4 | Manage your **ELF**, **PE** or **Mach-O** format as an abstraction or more specifically. 5 | 6 | Install 7 | ------- 8 | 9 | $ sudo ./setup.py install 10 | 11 | Example 12 | ------- 13 | 14 | Via the abstraction : 15 | 16 | >>> from abf.abstract import * 17 | >>> binary = Abstract('/usr/bin/id') 18 | 19 | >>> binary.getFormat() 20 | 'ELF' 21 | >>> hex(binary.getEntryPoint()) 22 | '0x4022bcL' 23 | 24 | >>> binary = Abstract('./binaries/pe-Windows-x86-cmd') 25 | >>> binary.getFormat() 26 | 'PE' 27 | >>> hex(binary.getEntryPoint()) 28 | '0x4ad060dcL' 29 | 30 | >>> binary = Abstract('./binaries/MachO-OSX-x86-ls') 31 | >>> binary.getFormat() 32 | 'Mach-O' 33 | >>> hex(binary.getEntryPoint()) 34 | '0x1708L' 35 | 36 | >>> sectionsExec = binary.getExecSections() 37 | >>> len(sectionsExec) 38 | 3 39 | >>> for sect in sectionsExec: 40 | ... print hex(sect['vaddr']) 41 | ... 42 | 0x1708L 43 | 0x557cL 44 | 0x5750L 45 | 46 | Or more specifically : 47 | 48 | >>> binary = Abstract('/usr/bin/id') 49 | >>> elf = binary.getBinary() 50 | 51 | >>> elf 52 | 53 | 54 | >>> hex(elf.header.e_entry) 55 | '0x4022bcL' 56 | 57 | >>> shdrs = elf.shdrs 58 | >>> for shdr in shdrs: 59 | ... print hex(shdr.sh_addr) 60 | ... 61 | 0x0L 62 | 0x400270L 63 | 0x40028cL 64 | 0x4002b0L 65 | 0x400570L 66 | 0x4005d0L 67 | 0x400c18L 68 | 0x400ebeL 69 | 0x400f48L 70 | 0x400f98L 71 | 0x401028L 72 | 0x4015b0L 73 | 0x4015d0L 74 | 0x401990L 75 | 0x40536cL 76 | 0x405380L 77 | 0x40648cL 78 | 0x4066f8L 79 | 0x607df8L 80 | 0x607e00L 81 | 0x607e08L 82 | 0x607e10L 83 | 0x607ff0L 84 | 0x608000L 85 | 0x608200L 86 | 0x6082a0L 87 | 0x0L 88 | 89 | >>> binary = Abstract('./binaries/MachO-OSX-x86-ls') 90 | >>> macho = binary.getBinary() 91 | >>> macho 92 | 93 | >>> macho.header.cpusubtype 94 | 3L 95 | >>> hex(macho.header.flags) 96 | '0x1200085L' 97 | >>> 98 | 99 | Special thanks 100 | -------------- 101 | 102 | - Wannes Rombouts (wapiflapi) for python3 compatible. 103 | 104 | -------------------------------------------------------------------------------- /abf/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Jonathan Salwan - 2014-11-23 5 | ## 6 | ## http://shell-storm.org 7 | ## http://twitter.com/JonathanSalwan 8 | ## 9 | ## This program is free software: you can redistribute it and/or modify 10 | ## it under the terms of the GNU General Public License as published by 11 | ## the Free Software Foundation, either version 3 of the License, or 12 | ## (at your option) any later version. 13 | ## 14 | 15 | __MAJOR_VERSION__ = 0 16 | __MINOR_VERSION__ = 1 17 | 18 | __AUTHOR__ = 'Jonathan Salwan' 19 | __DESC__ = 'Abstract Binary Format manipulation : elf pe mach-o' 20 | __LICENSE__ = 'GPLv3' 21 | __MAIL__ = 'jonathan.salwan gmail com' 22 | __NAME__ = 'abf' 23 | __VERSION__ = '%d.%d' %(__MAJOR_VERSION__, __MINOR_VERSION__) 24 | 25 | 26 | -------------------------------------------------------------------------------- /abf/abstract.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Jonathan Salwan - 2014-11-23 5 | ## 6 | ## http://shell-storm.org 7 | ## http://twitter.com/JonathanSalwan 8 | ## 9 | ## This program is free software: you can redistribute it and/or modify 10 | ## it under the terms of the GNU General Public License as published by 11 | ## the Free Software Foundation, either version 3 of the License, or 12 | ## (at your option) any later version. 13 | ## 14 | 15 | 16 | from abf.elf import * 17 | from abf.exception import * 18 | from abf.macho import * 19 | from abf.pe import * 20 | 21 | 22 | 23 | class Abstract(object): 24 | 25 | def __init__(self, binary): 26 | self.__fileName = binary 27 | self.__rawBinary = None 28 | self.__binary = None 29 | 30 | try: 31 | fd = open(self.__fileName, 'rb') 32 | self.__rawBinary = fd.read() 33 | fd.close() 34 | except: 35 | raise AbfException('Can\'t open the binary or binary not found') 36 | 37 | if self.__rawBinary[:4] == b'\x7f\x45\x4c\x46': 38 | self.__binary = ELF(self.__rawBinary) 39 | 40 | elif self.__rawBinary[:2] == b'\x4d\x5a': 41 | self.__binary = PE(self.__rawBinary) 42 | 43 | #elif self.__rawBinary[:4] == b'\xca\xfe\xba\xbe': 44 | # self.__binary = UNIVERSAL(self.__rawBinary) 45 | 46 | elif self.__rawBinary[:4] == b'\xce\xfa\xed\xfe' or self.__rawBinary[:4] == b'\xcf\xfa\xed\xfe': 47 | self.__binary = MACHO(self.__rawBinary) 48 | 49 | else: 50 | raise AbfException('Binary format not supported') 51 | 52 | 53 | def getFileName(self): 54 | return self.__fileName 55 | 56 | 57 | def getRawBinary(self): 58 | return self.__rawBinary 59 | 60 | 61 | def getBinary(self): 62 | return self.__binary 63 | 64 | 65 | def getEntryPoint(self): 66 | return self.__binary.getEntryPoint() 67 | 68 | 69 | def getDataSections(self): 70 | return self.__binary.getDataSections() 71 | 72 | 73 | def getExecSections(self): 74 | return self.__binary.getExecSections() 75 | 76 | 77 | def getArch(self): 78 | return self.__binary.getArch() 79 | 80 | 81 | def getArchMode(self): 82 | return self.__binary.getArchMode() 83 | 84 | 85 | def getFormat(self): 86 | return self.__binary.getFormat() 87 | 88 | 89 | -------------------------------------------------------------------------------- /abf/cpu.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Jonathan Salwan - 2014-11-23 5 | ## 6 | ## http://shell-storm.org 7 | ## http://twitter.com/JonathanSalwan 8 | ## 9 | ## This program is free software: you can redistribute it and/or modify 10 | ## it under the terms of the GNU General Public License as published by 11 | ## the Free Software Foundation, either version 3 of the License, or 12 | ## (at your option) any later version. 13 | ## 14 | 15 | 16 | class CpuArch: 17 | CPU_UNKNOWN = -1 18 | CPU_ARM = 0 19 | CPU_ARM64 = 1 20 | CPU_MIPS = 2 21 | CPU_X86 = 3 22 | CPU_PPC = 4 23 | CPU_SPARC = 5 24 | 25 | 26 | 27 | 28 | class CpuMode: 29 | MODE_UNKNOWN = -1 30 | MODE_32 = 0 31 | MODE_64 = 1 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /abf/elf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Jonathan Salwan - 2014-11-23 5 | ## 6 | ## http://shell-storm.org 7 | ## http://twitter.com/JonathanSalwan 8 | ## 9 | ## This program is free software: you can redistribute it and/or modify 10 | ## it under the terms of the GNU General Public License as published by 11 | ## the Free Software Foundation, either version 3 of the License, or 12 | ## (at your option) any later version. 13 | ## 14 | 15 | from abf.cpu import * 16 | from abf.elfFlags import * 17 | from abf.exception import * 18 | from ctypes import * 19 | from struct import unpack_from 20 | 21 | 22 | 23 | class Elf32_Ehdr_LSB(LittleEndianStructure): 24 | _fields_ = [ 25 | ('e_ident', c_ubyte * 16), 26 | ('e_type', c_ushort), 27 | ('e_machine', c_ushort), 28 | ('e_version', c_uint), 29 | ('e_entry', c_uint), 30 | ('e_phoff', c_uint), 31 | ('e_shoff', c_uint), 32 | ('e_flags', c_uint), 33 | ('e_ehsize', c_ushort), 34 | ('e_phentsize', c_ushort), 35 | ('e_phnum', c_ushort), 36 | ('e_shentsize', c_ushort), 37 | ('e_shnum', c_ushort), 38 | ('e_shstrndx', c_ushort) 39 | ] 40 | 41 | 42 | 43 | 44 | class Elf64_Ehdr_LSB(LittleEndianStructure): 45 | _fields_ = [ 46 | ('e_ident', c_ubyte * 16), 47 | ('e_type', c_ushort), 48 | ('e_machine', c_ushort), 49 | ('e_version', c_uint), 50 | ('e_entry', c_ulonglong), 51 | ('e_phoff', c_ulonglong), 52 | ('e_shoff', c_ulonglong), 53 | ('e_flags', c_uint), 54 | ('e_ehsize', c_ushort), 55 | ('e_phentsize', c_ushort), 56 | ('e_phnum', c_ushort), 57 | ('e_shentsize', c_ushort), 58 | ('e_shnum', c_ushort), 59 | ('e_shstrndx', c_ushort) 60 | ] 61 | 62 | 63 | 64 | 65 | class Elf32_Phdr_LSB(LittleEndianStructure): 66 | _fields_ = [ 67 | ('p_type', c_uint), 68 | ('p_offset', c_uint), 69 | ('p_vaddr', c_uint), 70 | ('p_paddr', c_uint), 71 | ('p_filesz', c_uint), 72 | ('p_memsz', c_uint), 73 | ('p_flags', c_uint), 74 | ('p_align', c_uint) 75 | ] 76 | 77 | 78 | 79 | 80 | class Elf64_Phdr_LSB(LittleEndianStructure): 81 | _fields_ = [ 82 | ('p_type', c_uint), 83 | ('p_flags', c_uint), 84 | ('p_offset', c_ulonglong), 85 | ('p_vaddr', c_ulonglong), 86 | ('p_paddr', c_ulonglong), 87 | ('p_filesz', c_ulonglong), 88 | ('p_memsz', c_ulonglong), 89 | ('p_align', c_ulonglong) 90 | ] 91 | 92 | 93 | 94 | 95 | class Elf32_Shdr_LSB(LittleEndianStructure): 96 | _fields_ = [ 97 | ('sh_name', c_uint), 98 | ('sh_type', c_uint), 99 | ('sh_flags', c_uint), 100 | ('sh_addr', c_uint), 101 | ('sh_offset', c_uint), 102 | ('sh_size', c_uint), 103 | ('sh_link', c_uint), 104 | ('sh_info', c_uint), 105 | ('sh_addralign', c_uint), 106 | ('sh_entsize', c_uint) 107 | ] 108 | 109 | 110 | 111 | 112 | class Elf64_Shdr_LSB(LittleEndianStructure): 113 | _fields_ = [ 114 | ('sh_name', c_uint), 115 | ('sh_type', c_uint), 116 | ('sh_flags', c_ulonglong), 117 | ('sh_addr', c_ulonglong), 118 | ('sh_offset', c_ulonglong), 119 | ('sh_size', c_ulonglong), 120 | ('sh_link', c_uint), 121 | ('sh_info', c_uint), 122 | ('sh_addralign', c_ulonglong), 123 | ('sh_entsize', c_ulonglong) 124 | ] 125 | 126 | 127 | 128 | 129 | class Elf32_Ehdr_MSB(BigEndianStructure): 130 | _fields_ = [ 131 | ('e_ident', c_ubyte * 16), 132 | ('e_type', c_ushort), 133 | ('e_machine', c_ushort), 134 | ('e_version', c_uint), 135 | ('e_entry', c_uint), 136 | ('e_phoff', c_uint), 137 | ('e_shoff', c_uint), 138 | ('e_flags', c_uint), 139 | ('e_ehsize', c_ushort), 140 | ('e_phentsize', c_ushort), 141 | ('e_phnum', c_ushort), 142 | ('e_shentsize', c_ushort), 143 | ('e_shnum', c_ushort), 144 | ('e_shstrndx', c_ushort) 145 | ] 146 | 147 | 148 | 149 | 150 | class Elf64_Ehdr_MSB(BigEndianStructure): 151 | _fields_ = [ 152 | ('e_ident', c_ubyte * 16), 153 | ('e_type', c_ushort), 154 | ('e_machine', c_ushort), 155 | ('e_version', c_uint), 156 | ('e_entry', c_ulonglong), 157 | ('e_phoff', c_ulonglong), 158 | ('e_shoff', c_ulonglong), 159 | ('e_flags', c_uint), 160 | ('e_ehsize', c_ushort), 161 | ('e_phentsize', c_ushort), 162 | ('e_phnum', c_ushort), 163 | ('e_shentsize', c_ushort), 164 | ('e_shnum', c_ushort), 165 | ('e_shstrndx', c_ushort) 166 | ] 167 | 168 | 169 | 170 | 171 | class Elf32_Phdr_MSB(BigEndianStructure): 172 | _fields_ = [ 173 | ('p_type', c_uint), 174 | ('p_offset', c_uint), 175 | ('p_vaddr', c_uint), 176 | ('p_paddr', c_uint), 177 | ('p_filesz', c_uint), 178 | ('p_memsz', c_uint), 179 | ('p_flags', c_uint), 180 | ('p_align', c_uint) 181 | ] 182 | 183 | 184 | 185 | 186 | class Elf64_Phdr_MSB(BigEndianStructure): 187 | _fields_ = [ 188 | ('p_type', c_uint), 189 | ('p_flags', c_uint), 190 | ('p_offset', c_ulonglong), 191 | ('p_vaddr', c_ulonglong), 192 | ('p_paddr', c_ulonglong), 193 | ('p_filesz', c_ulonglong), 194 | ('p_memsz', c_ulonglong), 195 | ('p_align', c_ulonglong) 196 | ] 197 | 198 | 199 | 200 | 201 | class Elf32_Shdr_MSB(BigEndianStructure): 202 | _fields_ = [ 203 | ('sh_name', c_uint), 204 | ('sh_type', c_uint), 205 | ('sh_flags', c_uint), 206 | ('sh_addr', c_uint), 207 | ('sh_offset', c_uint), 208 | ('sh_size', c_uint), 209 | ('sh_link', c_uint), 210 | ('sh_info', c_uint), 211 | ('sh_addralign', c_uint), 212 | ('sh_entsize', c_uint) 213 | ] 214 | 215 | 216 | 217 | 218 | class Elf64_Shdr_MSB(BigEndianStructure): 219 | _fields_ = [ 220 | ('sh_name', c_uint), 221 | ('sh_type', c_uint), 222 | ('sh_flags', c_ulonglong), 223 | ('sh_addr', c_ulonglong), 224 | ('sh_offset', c_ulonglong), 225 | ('sh_size', c_ulonglong), 226 | ('sh_link', c_uint), 227 | ('sh_info', c_uint), 228 | ('sh_addralign', c_ulonglong), 229 | ('sh_entsize', c_ulonglong) 230 | ] 231 | 232 | 233 | 234 | 235 | ''' This class parses the ELF ''' 236 | class ELF: 237 | def __init__(self, binary): 238 | self.__binary = bytearray(binary) 239 | self.__ElfHeader = None 240 | self.__shdr_l = [] 241 | self.__phdr_l = [] 242 | 243 | self.__setHeaderElf() 244 | self.__setShdr() 245 | self.__setPhdr() 246 | 247 | 248 | ''' Parse ELF header ''' 249 | def __setHeaderElf(self): 250 | e_ident = self.__binary[:15] 251 | 252 | ei_class = unpack_from('' %(sys.argv[0]) 94 | sys.exit(-1) 95 | 96 | binary = Abstract(sys.argv[1]) 97 | 98 | print '== Format ==\n' 99 | 100 | print ' Format : %s' %(binary.getFormat()) 101 | print ' Arch : %s' %(binary.getArch()) 102 | print ' Mode : %s' %(binary.getArchMode()) 103 | 104 | print '\n== Header ==\n' 105 | 106 | print ' Entry point : %#x' %(binary.getEntryPoint()) 107 | 108 | print '\n== Exec sections ==\n' 109 | 110 | for sect in binary.getExecSections(): 111 | print ' vaddr : %#x' %(sect['vaddr']) 112 | print ' size : %#x' %(sect['size']) 113 | print ' offset : %#x' %(sect['offset']) 114 | print ' opcodes : %s ...' %(list(sect['opcodes'][0:6])) 115 | print 116 | 117 | print '\n== Data sections ==\n' 118 | 119 | for sect in binary.getDataSections(): 120 | print ' vaddr : %#x' %(sect['vaddr']) 121 | print ' size : %#x' %(sect['size']) 122 | print ' offset : %#x' %(sect['offset']) 123 | print ' data : %s ...' %(list(sect['data'][0:6])) 124 | print 125 | 126 | sys.exit(0) 127 | 128 | 129 | -------------------------------------------------------------------------------- /helpers/elf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Jonathan Salwan - 2014-11-23 5 | ## 6 | ## http://shell-storm.org 7 | ## http://twitter.com/JonathanSalwan 8 | ## 9 | ## This program is free software: you can redistribute it and/or modify 10 | ## it under the terms of the GNU General Public License as published by 11 | ## the Free Software Foundation, either version 3 of the License, or 12 | ## (at your option) any later version. 13 | ## 14 | ## 15 | ## $ ./helpers/elf.py ./binaries/elf-Linux-ARMv7-ls 16 | ## Entry: 0xc268 17 | ## 18 | ## sh_addr: 0x0 19 | ## sh_addr: 0x8134 20 | ## sh_addr: 0x8148 21 | ## sh_addr: 0x8168 22 | ## sh_addr: 0x818c 23 | ## sh_addr: 0x85a0 24 | ## sh_addr: 0x8e00 25 | ## sh_addr: 0x93e8 26 | ## sh_addr: 0x94f4 27 | ## sh_addr: 0x9584 28 | ## sh_addr: 0x95c4 29 | ## sh_addr: 0x993c 30 | ## sh_addr: 0x9948 31 | ## sh_addr: 0x9e90 32 | ## sh_addr: 0x1a4d0 33 | ## sh_addr: 0x1a4d8 34 | ## sh_addr: 0x1d8c0 35 | ## sh_addr: 0x1d8d8 36 | ## sh_addr: 0x258dc 37 | ## sh_addr: 0x258e0 38 | ## sh_addr: 0x258e4 39 | ## sh_addr: 0x258e8 40 | ## sh_addr: 0x259f0 41 | ## sh_addr: 0x25bc0 42 | ## sh_addr: 0x25cf8 43 | ## sh_addr: 0x0 44 | ## sh_addr: 0x0 45 | ## sh_addr: 0x0 46 | ## 47 | ## p_vaddr: 0x1d8c0 48 | ## p_vaddr: 0x8034 49 | ## p_vaddr: 0x8134 50 | ## p_vaddr: 0x8000 51 | ## p_vaddr: 0x258dc 52 | ## p_vaddr: 0x258e8 53 | ## p_vaddr: 0x8148 54 | ## p_vaddr: 0x0 55 | ## $ 56 | ## 57 | 58 | from abf.abstract import * 59 | import sys 60 | 61 | 62 | 63 | if __name__ == '__main__': 64 | 65 | if len(sys.argv) < 2: 66 | print 'Syntax: %s ' %(sys.argv[0]) 67 | sys.exit(-1) 68 | 69 | 70 | binary = Abstract(sys.argv[1]) 71 | elf = binary.getBinary() 72 | 73 | print 'Entry: %#x\n' %(elf.header.e_entry) 74 | 75 | for shdr in elf.shdrs: 76 | print 'sh_addr: %#x' %(shdr.sh_addr) 77 | 78 | print 79 | 80 | for phdr in elf.phdrs: 81 | print 'p_vaddr: %#x' %(phdr.p_vaddr) 82 | 83 | 84 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Jonathan Salwan - 2014-11-23 5 | ## 6 | ## http://shell-storm.org 7 | ## http://twitter.com/JonathanSalwan 8 | ## 9 | ## This program is free software: you can redistribute it and/or modify 10 | ## it under the terms of the GNU General Public License as published by 11 | ## the Free Software Foundation, either version 3 of the License, or 12 | ## (at your option) any later version. 13 | ## 14 | 15 | from abf import __NAME__, __VERSION__, __AUTHOR__, __MAIL__, __DESC__, __LICENSE__ 16 | from setuptools import setup 17 | 18 | setup( 19 | author = __AUTHOR__, 20 | author_email = __MAIL__, 21 | description = __DESC__, 22 | keywords = 'abstract binary format manipulation elf pe mach-o', 23 | license = __LICENSE__, 24 | name = __NAME__, 25 | packages = ['abf'], 26 | version = __VERSION__, 27 | 28 | classifiers = [ 29 | 'Operating System :: POSIX' 30 | ], 31 | ) 32 | 33 | --------------------------------------------------------------------------------