Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add elf64 support #1

Merged
merged 2 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [2.7, 3.5, 3.6, 3.7, 3.8]
python-version: [3.8, 3.9, "3.10", 3.11]

steps:
- uses: actions/checkout@v2
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ Try it out:
from simpleelf.elf_builder import ElfBuilder
from simpleelf import elf_consts

e = ElfBuilder()
# can also be used with ELFCLASS32 to create 64bit layouts
e = ElfBuilder(elf_consts.ELFCLASS32)
e.set_endianity('<')
e.set_machine(elf_consts.EM_ARM)

Expand Down
22 changes: 15 additions & 7 deletions simpleelf/elf_builder.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from collections import namedtuple

from construct import Padding
from simpleelf.elf_consts import ELFCLASS32

from simpleelf.elf_structs import ElfStructs
from simpleelf import elf_consts
Expand All @@ -11,17 +12,24 @@ class ElfBuilder:
Section = namedtuple('Section',
['type', 'name', 'address', 'flags', 'size'])

def __init__(self):
def __init__(self, elf_class=ELFCLASS32):
self._class = elf_class
self._segments = []
self._sections = []
self._machine = 0
self._entry = 0
self._endianity = '<'
self._structs = ElfStructs(self._endianity)
self._e_ehsize = self._structs.Elf32_Ehdr.sizeof()
self._e_phoff = self._e_ehsize
self._e_phentsize = 0x20 # TODO: calculate according to the struct
self._e_shentsize = 0x28 # TODO: calculate according to the struct
if elf_class == ELFCLASS32:
self._e_ehsize = self._structs.Elf32_Ehdr.sizeof()
self._e_phoff = self._e_ehsize
self._e_phentsize = 0x20 # TODO: calculate according to the struct
self._e_shentsize = 0x28 # TODO: calculate according to the struct
else:
self._e_ehsize = self._structs.Elf64_Ehdr.sizeof()
self._e_phoff = self._e_ehsize
self._e_phentsize = 0x38 # TODO: calculate according to the struct
self._e_shentsize = 0x40 # TODO: calculate according to the struct
self._e_phnum = 0
self._e_shnum = 0
self._e_shoff = self._e_phoff + self._e_phentsize * self._e_phnum
Expand Down Expand Up @@ -125,7 +133,7 @@ def build(self):
'header': {
'e_ident': {
'magic': elf_consts.ELFMAG,
'class': elf_consts.ELFCLASS32,
'class': self._class,
'data': e_ident_data,
'osabi': elf_consts.ELFOSABI_NONE,
'pad': Padding(8),
Expand Down Expand Up @@ -214,4 +222,4 @@ def build(self):
'data': contents
})

return structs.Elf32.build(elf)
return structs.Elf32.build(elf) if self._class == ELFCLASS32 else structs.Elf64.build(elf)
100 changes: 92 additions & 8 deletions simpleelf/elf_structs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from construct import (Int8ub, Int8ul, Int16ul, Int32ul, Int16ub, Int32ub,
Enum, Hex, If, Struct, this, Pointer, Bytes,
Const, Default, Padding, Array)
Const, Default, Padding, Array, Int64ul, Int64ub)

from simpleelf import elf_consts


Expand All @@ -9,11 +10,32 @@ def __init__(self, endianity='<'):
if endianity == '<':
Int8u = Int8ul
Int16u = Int16ul
# Int32s = Int32sl
Int32u = Int32ul
# Int64s = Int64sl
Int64u = Int64ul
else:
Int8u = Int8ub
Int16u = Int16ub
# Int32s = Int32sb
Int32u = Int32ub
# Int64s = Int64sb
Int64u = Int64ub

Elf32_Addr = Int32u
# Elf32_Half = Int16u
Elf32_Off = Int32u
# Elf32_Sword = Int32s
Elf32_Word = Int32u

Elf64_Addr = Int64u
# Elf64_Half = Int16u
# Elf64_SHalf = Int16u
Elf64_Off = Int64u
# Elf64_Sword = Int32s
Elf64_Word = Int32u
Elf64_Xword = Int64u
# Elf64_Sxword = Int64s

self.Elf_Class = Enum(Hex(Int8u),
ELFCLASSNONE=elf_consts.ELFCLASSNONE,
Expand Down Expand Up @@ -290,13 +312,26 @@ def __init__(self, endianity='<'):

self.Elf32_Phdr = Struct(
'p_type' / self.Elf_SegmentType,
'p_offset' / Hex(Int32u),
'p_vaddr' / Hex(Int32u),
'p_paddr' / Hex(Int32u),
'p_filesz' / Hex(Int32u),
'p_memsz' / Hex(Int32u),
'p_flags' / Hex(Int32u),
'p_align' / Hex(Int32u),
'p_offset' / Hex(Elf32_Off),
'p_vaddr' / Hex(Elf32_Addr),
'p_paddr' / Hex(Elf32_Addr),
'p_filesz' / Hex(Elf32_Word),
'p_memsz' / Hex(Elf32_Word),
'p_flags' / Hex(Elf32_Word),
'p_align' / Hex(Elf32_Word),
'data' / If(this.p_type == self.Elf_SegmentType.PT_LOAD,
Pointer(this.p_offset, Bytes(this.p_filesz)))
)

self.Elf64_Phdr = Struct(
'p_type' / self.Elf_SegmentType,
'p_flags' / Hex(Elf64_Word),
'p_offset' / Hex(Elf64_Off),
'p_vaddr' / Hex(Elf64_Addr),
'p_paddr' / Hex(Elf64_Addr),
'p_filesz' / Hex(Elf64_Xword),
'p_memsz' / Hex(Elf64_Xword),
'p_align' / Hex(Elf64_Xword),
'data' / If(this.p_type == self.Elf_SegmentType.PT_LOAD,
Pointer(this.p_offset, Bytes(this.p_filesz)))
)
Expand Down Expand Up @@ -327,6 +362,32 @@ def __init__(self, endianity='<'):
'e_shstrndx' / Hex(Int16u),
)

self.Elf64_Ehdr = Struct(
'e_ident' / Struct(
'magic' / Const(elf_consts.ELFMAG),
'class' / self.Elf_Class,
'data' / self.Elf_Data,
'version' / Default(self.Elf_Version,
self.Elf_Version.EV_CURRENT),
'osabi' / self.Elf_OsAbi,
'pad' / Padding(8),
),
'e_type' / Default(self.Elf_Type, self.Elf_Type.ET_EXEC),
'e_machine' / Hex(self.Elf_Machine),
'e_version' / Default(self.Elf_Version2,
self.Elf_Version2.EV_CURRENT),
'e_entry' / Hex(Elf64_Addr),
'e_phoff' / Hex(Elf64_Off),
'e_shoff' / Hex(Elf64_Off),
'e_flags' / Default(Hex(Int32u), 0),
'e_ehsize' / Hex(Int16u),
'e_phentsize' / Hex(Int16u),
'e_phnum' / Hex(Int16u),
'e_shentsize' / Hex(Int16u),
'e_shnum' / Hex(Int16u),
'e_shstrndx' / Hex(Int16u),
)

self.Elf32_Shdr = Struct(
'sh_name' / self.Elf_SectionIndex,
'sh_type' / self.Elf_SectionType,
Expand All @@ -342,10 +403,33 @@ def __init__(self, endianity='<'):
Pointer(this.sh_offset, Bytes(this.sh_size)))
)

self.Elf64_Shdr = Struct(
'sh_name' / self.Elf_SectionIndex,
'sh_type' / self.Elf_SectionType,
'sh_flags' / Hex(Elf64_Xword),
'sh_addr' / Hex(Elf64_Addr),
'sh_offset' / Hex(Elf64_Off),
'sh_size' / Hex(Elf64_Xword),
'sh_link' / Hex(Elf64_Word),
'sh_info' / Hex(Elf64_Word),
'sh_addralign' / Hex(Elf64_Xword),
'sh_entsize' / Hex(Elf64_Xword),
'data' / If(this.sh_type != self.Elf_SectionType.SHT_NOBITS,
Pointer(this.sh_offset, Bytes(this.sh_size)))
)

self.Elf32 = Struct(
'header' / self.Elf32_Ehdr,
'segments' / Pointer(this.header.e_phoff,
Array(this.header.e_phnum, self.Elf32_Phdr)),
'sections' / Pointer(this.header.e_shoff,
Array(this.header.e_shnum, self.Elf32_Shdr)),
)

self.Elf64 = Struct(
'header' / self.Elf64_Ehdr,
'segments' / Pointer(this.header.e_phoff,
Array(this.header.e_phnum, self.Elf64_Phdr)),
'sections' / Pointer(this.header.e_shoff,
Array(this.header.e_shnum, self.Elf64_Shdr)),
)
42 changes: 41 additions & 1 deletion tests/test_build_elf.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from simpleelf.elf_consts import ELFCLASS64

from simpleelf.elf_builder import ElfBuilder, ElfStructs
from simpleelf import elf_consts

structs = ElfStructs('<')


def test_build_elf():
def test_build_elf32():
e = ElfBuilder()
e.set_endianity('<')
e.set_machine(elf_consts.EM_ARM)
Expand Down Expand Up @@ -40,3 +42,41 @@ def test_build_elf():

assert structs.Elf32.build(
parsed_raw_elf) == elf_raw, "rebuilt elf is not the same"


def test_build_elf64():
e = ElfBuilder(ELFCLASS64)
e.set_endianity('<')
e.set_machine(elf_consts.EM_ARM)

code = b'CODECODE'

# add a segment
text_address = 0x1234
text_buffer = b'cybercyberbitimbitim' + code
e.add_segment(text_address, text_buffer,
elf_consts.PF_R | elf_consts.PF_W | elf_consts.PF_X)

# add a second segment
e.add_segment(0x88771122, b'data in 0x88771122',
elf_consts.PF_R | elf_consts.PF_W | elf_consts.PF_X)

# add a code section inside the first segment
code_address = text_address + text_buffer.find(code) # point at CODECODE
code_size = len(code)
e.add_code_section('.text', code_address, code_size)

# set entry point
e.set_entry(code_address)

# add .bss section. not requiring a loaded segment from
# file
bss_address = 0x5678
bss_size = 0x200
e.add_empty_data_section('.bss', bss_address, bss_size)

elf_raw = e.build()
open('/tmp/foo', 'wb').write(elf_raw)
parsed_raw_elf = structs.Elf64.parse(elf_raw)

assert structs.Elf64.build(parsed_raw_elf) == elf_raw, "rebuilt elf is not the same"