Skip to content

Instantly share code, notes, and snippets.

@warabanshi
Last active December 14, 2015 01:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save warabanshi/5005372 to your computer and use it in GitHub Desktop.
Save warabanshi/5005372 to your computer and use it in GitHub Desktop.
make ELF part4
pType = {
'NULL' : 0,
'LOAD' : 1,
'DYNAMIC' : 2,
'INTERP' : 3,
'NOTE' : 4,
'SHLIB' : 5,
'PHDR' : 6,
'TLS' : 7,
'NUM' : 8,
'LOOS' : 0x60000000,
'GNU_EH_FRAME' : 0x6474e550,
'GNU_STACK' : 0x6474e551,
'GNU_RELRO' : 0x6474e552,
'LOSUNW' : 0x6ffffffa,
'SUNWBSS' : 0x6ffffffa,
'SUNWSTACK' : 0x6ffffffb,
'HISUNW' : 0x6fffffff,
'HIOS' : 0x6fffffff,
'LOPROC' : 0x70000000,
'HIPROC' : 0x7fffffff,
}
pFlag = {
'X' : (1 << 0),
'W' : (1 << 1),
'R' : (1 << 2),
'MASKOS' : 0x0ff00000,
'MASKPROC' : 0xf0000000,
}
pFlags = {
'X' : pFlag['X'],
'W' : pFlag['W'],
'R' : pFlag['R'],
'RW' : pFlag['R'] | pFlag['W'],
'RX' : pFlag['R'] | pFlag['X'],
'RWX' : pFlag['R'] | pFlag['W'] | pFlag['X'],
}
shType = {
'NULL' : 0,
'PROGBITS' : 1,
'SYMTAB' : 2,
'STRTAB' : 3,
'RELA' : 4,
'HASH' : 5,
'DYNAMIC' : 6,
'NOTE' : 7,
'NOBITS' : 8,
'REL' : 9,
'SHLIB' : 10,
'DYNSYM' : 11,
'INIT_ARRAY' : 14,
'FINI_ARRAY' : 15,
'PREINIT_ARRAY' : 16,
'GROUP' : 17,
'SYMTAB_SHNDX' : 18,
'NUM' : 19,
'LOOS' : 0x60000000,
'GNU_ATTRIBUTES': 0x6ffffff5,
'GNU_HASH' : 0x6ffffff6,
'GNU_LIBLIST' : 0x6ffffff7,
'CHECKSUM' : 0x6ffffff8,
'LOSUNW' : 0x6ffffffa,
'SUNW_move' : 0x6ffffffa,
'SUNW_COMDAT' : 0x6ffffffb,
'SUNW_syminfo' : 0x6ffffffc,
'GNU_verdef' : 0x6ffffffd,
'GNU_verneed' : 0x6ffffffe,
'GNU_versym' : 0x6fffffff,
'HISUNW' : 0x6fffffff,
'HIOS' : 0x6fffffff,
'LOPROC' : 0x70000000,
'HIPROC' : 0x7fffffff,
'LOUSER' : 0x80000000,
'HIUSER' : 0x8fffffff,
}
shFlag = {
'WRITE' : (1 << 0),
'ALLOC' : (1 << 1),
'EXECINSTR' : (1 << 2),
'MERGE' : (1 << 4),
'STRINGS' : (1 << 5),
'INFO_LINK' : (1 << 6),
'LINK_ORDER': (1 << 7),
'OS_NONCONFORMING' : (1 << 8),
'GROUP' : (1 << 9),
'TLS' : (1 << 10),
'MASKOS' : 0x0ff00000,
'MASKPROC' : 0xf0000000,
'ORDERED' : (1 << 30),
'EXCLUDE' : (1 << 31),
}
shFlags = {
'A' : shFlag['ALLOC'],
'W' : shFlag['WRITE'],
'X' : shFlag['EXECINSTR'],
'AW' : shFlag['ALLOC'] | shFlag['WRITE'],
'AX' : shFlag['ALLOC'] | shFlag['EXECINSTR'],
'AWX' : shFlag['ALLOC'] | shFlag['WRITE'] | shFlag['EXECINSTR'],
}
correspondence = {
shFlags['A'] : pFlags['R'],
shFlags['W'] : pFlags['W'],
shFlags['X'] : pFlags['X'],
shFlags['AW'] : pFlags['RW'],
shFlags['AX'] : pFlags['RX'],
shFlags['AWX'] : pFlags['RWX'],
}
def getPhFlag(flag):
try:
return correspondence[flag]
except:
return None
def getPtype(name):
try:
return pType[name]
except:
return None
from elf.Utils import *
class Header(object):
def __init__(self):
self.contents = {}
self.pos = 0
def set(self, key, val):
self.contents[key] = val
def get(self, key):
return self.contents[key]
def resetPos(self, pos):
self.pos = pos
# bs: bytesize
def fetch(self, bs, byteList):
r = convBin(byteList[self.pos:self.pos+bs])
self.pos += bs
return r
def getByte(self, byteList):
return self.fetch(1, byteList)
def getWord(self, byteList):
return self.fetch(2, byteList)
def getDw(self, byteList):
return self.fetch(4, byteList)
def getQw(self, byteList):
return self.fetch(8, byteList)
def retrieve(self):
raise('method retrieve() has to implement individualy')
from Header import Header
from elf.Utils import *
class Ph(Header):
def retrieve(self, binList, offset = 0):
self.resetPos(offset)
self.setBinList(binList)
self.set('segment_type', self.getDw())
self.set('permission_flag', self.getDw())
self.set('offset', self.getQw())
self.set('virtual_addr', self.getQw())
self.set('physical_addr', self.getQw())
self.set('filesize', self.getQw())
self.set('memory_size', self.getQw())
self.set('align', self.getQw())
self.clearBinList()
return self
def output(self):
r = []
r += convLE(self.get('segment_type'), 4)
r += convLE(self.get('permission_flag'), 4)
r += convLE(self.get('offset'), 8)
r += convLE(self.get('virtual_addr'), 8)
r += convLE(self.get('physical_addr'), 8)
r += convLE(self.get('filesize'), 8)
r += convLE(self.get('memory_size'), 8)
r += convLE(self.get('align'), 8)
return r
class Section(object):
def __init__(self, byteList, name, sh):
self.byteList = byteList
self.name = name
self.sh = sh
def getBodyList(self):
return self.byteList
def getName(self):
return self.name
def getSh(self):
return self.sh
def setBodyList(self, byteList):
self.byteList = byteList
def setName(self, name):
self.name = name
def setSh(self, sh):
self.sh = sh
def setAddr(self, addr):
None # implement later
# method for debug
def echo(self):
lm = lambda n: (n, hex(n))
try:
print('====== Section Header(%s) ======' % self.name)
except AttributeError:
print('====== Section Header(no name setting) ====')
print('name_index: %s' % self.sh.get('name_index'))
print('type: %s' % self.sh.get('type'))
print('flag: %s' % self.sh.get('flag'))
print('address: %s(%s)' % lm(self.sh.get('address')))
print('offset: %s(%s)' % lm(self.sh.get('offset')))
print('size: %s(%s)' % lm(self.sh.get('size')))
print('link: %s' % self.sh.get('link'))
print('info: %s' % self.sh.get('info'))
print('address_align: %s' % self.sh.get('address_align'))
print('entry_table_size:%s' % self.sh.get('entry_table_size'))
from elf.Utils import *
from elf.components.headers.Sh import Sh
from elf.components.Section import Section
class SectionController(object):
def __init__(self):
self.sectionList = []
def append(self, section):
self.sectionList.append(section)
def getSectionList(self):
nullSh = Sh()
nullSh.retrieve([0x00 for i in range(56)])
nullSection = Section([], '', nullSh)
strSection = self.makeShStrSection()
return (nullSection, self.sectionList, strSection)
def makeShStrSection(self):
shStr = "\0"
for s in self.sectionList:
sh = s.getSh()
sh.set('name_index', len(shStr))
shStr += s.getName() + "\0"
shStrIdx = len(shStr)
shStr += ".shstrtab\0"
shStrTab = map(ord, shStr)
shList = []
shList += convLE(shStrIdx, 4) # name_index
shList += convLE(3, 4) # type
shList += [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # flag
shList += [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # address
shList += [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # offset
shList += convLE(len(shStr), 8) # size
shList += [0x00, 0x00, 0x00, 0x00] # link
shList += [0x00, 0x00, 0x00, 0x00] # info
shList += convLE(1, 0) # address_align
shList += [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # entry_table_size
sh = Sh().retrieve(shList)
return Section(shStrTab, '.shstrtab', sh)
class Segment(object):
def __init__(self, ph, bodyList):
self.ph = ph
self.bodyList = bodyList
def getPh(self):
return self.ph
def getBodyList(self):
return self.bodyList
from elf.Attributes import *
from elf.SectionOrder import *
from elf.components.headers.Ph import Ph
from elf.components.Segment import Segment
class SegmentController(object):
loadAlign = 0x200000
orgAddr = 0x400000
def __init__(self):
self.segmentList = []
self.phSegment = None
self.startAddr = 0
def makeSegment(self, sctList):
# separate sections by flag value and sort section order
segBaseTbl = {}
for sct in sctList:
name = sct.getName()
try:
segBaseTbl[sct.getSh().get('flag')].append((getOrder(name), sct))
except:
segBaseTbl[sct.getSh().get('flag')] = []
segBaseTbl[sct.getSh().get('flag')].append((getOrder(name), sct))
segTbl = {}
for (flag, segList) in segBaseTbl.items():
segTbl[flag] = sorted(segList, key=lambda x: x[0])
# set base position
offset = 64 + 56 + 56 * len(segTbl) # EH + PHDR + PHs offset
addr = self.orgAddr + offset
phList = []
for (flag, contentList) in segTbl.items():
bodyList = []
sctOff = offset
sctAddr = addr
for (order, sct) in contentList:
sct.getSh().set('address', sctAddr)
sct.getSh().set('offset', sctOff)
bodyList += sct.getBodyList()
align = sct.getSh().get('address_align')
if sct.getName() == '.text':
self.startAddr = addr
# padding 0x00
if len(sct.getBodyList()) % align > 0:
bodyList += [0x0 for x in range(align - len(sct.getBodyList()) % align)]
sctOff = offset + len(bodyList)
sctAddr = addr + len(bodyList)
ph = Ph()
#ph.set('segment_type', getPhFlag(flag))
ph.set('segment_type', 1)
ph.set('permission_flag', flag)
ph.set('offset', offset)
ph.set('virtual_addr', addr)
ph.set('physical_addr', addr)
ph.set('filesize', len(bodyList))
ph.set('memory_size', len(bodyList))
ph.set('align', self.loadAlign)
self.segmentList.append(Segment(ph, bodyList))
phList.append(ph)
offset += len(bodyList)
addr += offset
# make PHDR
self.phSegment = self.setPhSegment([s.getPh() for s in self.segmentList], len(phList))
return sctList
def getSegments(self):
return self.phSegment, self.segmentList
def getStartAddr(self):
return self.startAddr
def setPhSegment(self, phList, phNum):
ph = Ph()
ph.set('segment_type', pType['PHDR'])
ph.set('permission_flag', 6)
ph.set('offset', 0x40)
ph.set('virtual_addr', self.orgAddr + 0x40)
ph.set('physical_addr', self.orgAddr + 0x40)
ph.set('filesize', 56*phNum)
ph.set('memory_size', 56*phNum)
ph.set('align', 8)
bodyList = []
for p in phList:
bodyList += p.output()
bodyList += ph.output()
return Segment(ph, bodyList)
from Header import Header
from elf.Utils import *
class Sh(Header):
def __init__(self):
Header.__init__(self)
self.contents = {
'name_index' : 0,
'type' : 0,
'flag' : 0,
'address' : 0,
'offset' : 0,
'size' : 0,
'link' : 0,
'info' : 0,
'address_align' : 0,
'entry_table_size': 0,
}
def retrieve(self, byteList, offset = 0):
self.resetPos(offset)
self.set('name_index', self.getDw(byteList))
self.set('type', self.getDw(byteList))
self.set('flag', self.getQw(byteList))
self.set('address', self.getQw(byteList))
self.set('offset', self.getQw(byteList))
self.set('size', self.getQw(byteList))
self.set('link', self.getDw(byteList))
self.set('info', self.getDw(byteList))
self.set('address_align', self.getQw(byteList))
self.set('entry_table_size', self.getQw(byteList))
return self
def output(self):
r = []
r += convLE(self.get('name_index'), 4)
r += convLE(self.get('type'), 4)
r += convLE(self.get('flag'), 8)
r += convLE(self.get('address'), 8)
r += convLE(self.get('offset'), 8)
r += convLE(self.get('size'), 8)
r += convLE(self.get('link'), 4)
r += convLE(self.get('info'), 4)
r += convLE(self.get('address_align'), 8)
r += convLE(self.get('entry_table_size'), 8)
return r
# convert val of specified number of byte to
# little endian list inlucdes each byte
def convLE(val, byteNum):
le = []
for i in range(byteNum):
le.append((val >> i*8) & 0xff)
return le
# convert from list to little endian binary value
# regards list elements are single byte respectively
def convBin(li):
b = 0
for byte in reversed(li):
b = (b << 8) | byte
return b
import sys, struct
from elf.Utils import *
from elf.components.headers.ElfHeader import ElfHeader
from ctypes import *
class WriteElf:
def __init__(self):
self.sectionList = {}
self.segmentList = {}
self.startAddr = 0
def setSection(self, sctNull, sctList, sctStr):
self.sectionList['null'] = sctNull
self.sectionList['list'] = sctList
self.sectionList['str'] = sctStr
def setSegment(self, segPhdr, segList):
self.segmentList['phdr'] = segPhdr
self.segmentList['list'] = segList
def setStartAddr(self, startAddr):
self.startAddr = startAddr
def make(self):
bodyLen = sum([len(s.bodyList) for s in self.segmentList['list']])
shStrLen = len(self.sectionList['str'].getBodyList())
shStrOff = 64 + 56 + 56 * len(self.segmentList['list']) + bodyLen
shOff = shStrOff + shStrLen
eh = self.makeEhBase()
eh.set('entry_addr', self.startAddr)
eh.set('ph_offset', 64)
eh.set('sh_offset', shOff)
eh.set('ph_num', len(self.segmentList['list'])+1)
eh.set('sh_num', len(self.sectionList['list'])+2)
eh.set('shstrndx', len(self.sectionList['list'])+1)
ph = self.segmentList['phdr'].getPh().output()
body = []
for seg in self.segmentList['list']:
ph += seg.getPh().output()
body += seg.getBodyList()
sh = self.sectionList['null'].getSh().output()
for sec in self.sectionList['list']:
sh += sec.getSh().output()
body += self.sectionList['str'].getBodyList()
strSh = self.sectionList['str'].getSh()
strSh.set('offset', shStrOff)
sh += strSh.output()
result = eh.output() + ph + body + sh
p = (c_ubyte * len(result))()
p[:] = result
with open('write.out', 'wb') as fp:
fp.write(p)
# eh expects ElfHeader object
def makeEhBase(self):
eh = []
eh += [0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01] # magic
eh += [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
eh += convLE(2, 2) # e_type (EXEC)
eh += convLE(0x3e, 2) # e_machine (amd64)
eh += convLE(1, 4) # e_version (1)
eh += convLE(0, 8) # e_entry (set later)
eh += convLE(0, 8) # e_phoff (set later)
eh += convLE(0, 8) # e_shoff (set later)
eh += convLE(0, 4) # e_flags
eh += convLE(64, 2) # e_ehsize (64)
eh += convLE(56, 2) # e_phentsize (56)
eh += convLE(0, 2) # e_phnum (set later)
eh += convLE(64, 2) # e_shentsize (64)
eh += convLE(0, 2) # e_shnum (set later)
eh += convLE(0, 2) # e_shstrndx (set later)
e = ElfHeader()
e.retrieve(eh)
return e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment