-
Notifications
You must be signed in to change notification settings - Fork 2
/
symbol.py
1388 lines (1135 loc) · 43.2 KB
/
symbol.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""
Copyright notice
================
Copyright (C) 2010
Lorenzo Martignoni <[email protected]>
Roberto Paleari <[email protected]>
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
ProcessTap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
"""
import platform
import os
import struct
import traceback
import warnings
import bisect
warnings.filterwarnings('ignore', category=FutureWarning)
import processtap
import glob
import re
__syscall2num = {}
__num2syscall = {}
__addr2sym = {}
__sym2addr = {}
__addr2module = []
__module2addr = {}
__objs = set()
def load_syscalls_linux():
global __syscall2num, __num2syscall
filename = "/usr/include/asm/unistd_%d.h"
mac = platform.machine()
if mac == 'i686':
filename = filename % 32
elif mac == 'x86_64':
filename = filename % 64
else:
assert False
if not os.path.isfile(filename):
print "[W] File '%s' is not available: no syscall names" % filename
return
f = open(filename, 'r')
data = {}
for l in f.readlines():
l = l.strip()
if not l.startswith("#define __NR_"):
continue
l = l.replace("#define __NR_", "")
tmp = l.split()
data[tmp[0]] = tmp[1]
f.close()
changed = True
while changed:
changed = False
for k in data:
v = data[k]
if isinstance(v, int):
continue
if v.isdigit():
data[k] = int(v)
else:
for m in re.finditer(r'__NR_([a-zA-Z_]+)\b', v):
x = v.replace("__NR_%s" % m.group(1), str(data[m.group(1)]))
data[k] = x
changed = True
break
for k in data:
v = data[k]
if isinstance(v, str):
data[k] = int(eval(v))
for k,v in data.iteritems():
__syscall2num[k] = v
__num2syscall[v] = k
class UnknownSymbol(Exception):
def __init__(self, s):
Exception.__init__(self, s)
class UnknownModule(Exception):
def __init__(self, s):
Exception.__init__(self, s)
def get_module(a):
if isinstance(a, (int, long)):
m = [b for n, b, s, obj in __addr2module]
i = bisect.bisect_right(m, a)
if i > 0 and i <= len(m) + 1:
n, b, s, obj = __addr2module[i-1]
if a >= b and a < b+s:
return obj
else:
return "unknown"
else:
if a in __module2addr:
return __module2addr[a]
else:
raise UnknownModule(a)
def set_symbol(s, v, l = 4):
assert isinstance(s, str) and isinstance(v, (int, long))
if s not in __sym2addr:
__sym2addr[s] = ([], [])
__sym2addr[s][0].append(v)
__sym2addr[s][1].append(l)
if v not in __addr2sym:
__addr2sym[v] = ([], [])
__addr2sym[v][0].append(s)
__addr2sym[v][1].append(l)
def __try_resolve_plt(mod):
obj = __module2addr[mod][2]
sec = obj.getSection(".plt")
if sec is not None:
if obj.getType()[1] == "DYN":
lo = obj.getImageBase() + sec.getOffset()
hi = lo + sec.getSize() - 1
else:
lo = sec.getLowAddr()
hi = sec.getHighAddr()
f = open('/proc/self/mem', 'rb')
for i in range(lo+16, hi, 16):
f.seek(i)
d = f.read(6)
assert d[0] == "\xff" and d[1] in ["\x25", "\xa3"]
if d[1] == '\x25':
# jmp *0xcafebabe
addr = struct.unpack("I", d[2:])[0]
else:
# jmp 0x8(%ebx) (only for PIC shared libraries)
assert obj.getType()[1] == "DYN"
addr = struct.unpack("I", d[2:])[0] + obj.getImageBase()
for x in get_symbol(addr):
set_symbol(x, i)
f.close()
def get_syscall(s):
global __syscall2num, __num2syscall
if isinstance(s, str):
m = __syscall2num
elif isinstance(s, (int, long)):
m = __num2syscall
else:
assert False
return m.get(s)
def get_symbol(s):
global __sym2addr, __addr2sym
if isinstance(s, str):
_map = __sym2addr
elif isinstance(s, (int, long)):
_map = __addr2sym
else:
assert False
if s in _map:
return _map[s][0]
else:
return []
def get_symbol_strict(s):
r = get_symbol(s)
if r is None:
raise UnknownSymbol(s)
return r
def set_get_symbol(s, v = None, l = 4):
if v:
set_symbol(s, v, l)
else:
return get_symbol(s)
def add_object(obj, libs, pid = None, recurse = False):
global __addr2sym, __syms2addr, __module2addr, __addr2module
obj = os.path.realpath(os.path.abspath(obj))
if obj in __module2addr:
# TODO: delete module
__module2addr[obj] = {}
if platform.architecture()[1] in ["ELF"]:
f = Elf(obj)
else:
raise processtap.UnsupportedPlatform(platform.platform())
if pid is not None and "EXEC" not in f.getType():
if platform.system() == "Linux":
# guess base address of object
for r in open("/proc/%d/maps" % pid).readlines():
r = r.strip().split()
if len(r) != 6:
continue
addrs, perms, offset, dev, inode, lib = r
if lib == obj:
addrs = addrs.split("-")
f.setImageBase(int(addrs[0], 16))
break
else:
raise processtap.UnsupportedPlatform(platform.platform())
if "EXEC" in f.getType() or ("DYN" in f.getType() and f.getImageBase()):
print "[*] Parsing '%s' [%.16x-%.16x]" % (obj, f.getLowAddr() + f.getImageBase(), f.getHighAddr() + f.getImageBase())
set_module(obj, f.getLowAddr() + f.getImageBase(), f.getHighAddr() - f.getLowAddr(), f)
for s in f.getSymbol():
set_symbol(s.getName(), s.getAddress() + f.getImageBase(), s.getSize())
# parse libs
if recurse:
for l in f.findLibrary():
for p in libs:
if os.path.isfile(os.path.join(p, l.getName())):
add_object(os.path.join(p, l.getName()), libs, pid)
def add_module(pid, mod, base, size, lib):
if mod in __module2addr or not os.path.isfile(mod):
# already present or missing image
return
add_object(mod, [], pid = pid, recurse = True)
if mod in __module2addr and platform.system() == "Linux":
__try_resolve_plt(mod)
def set_module(n, b, s, obj):
global __addr2module, __module2addr, __objs
if n not in __module2addr:
__addr2module += [(n, b, s, obj)]
__module2addr[n] = (b, s, obj)
__objs.add(obj)
def init(exe, libs_path = "/"):
global __libs_path, __syscall2num
__libs_path = libs_path
# Load system calls names
if platform.system() == "Linux":
load_syscalls_linux()
elif platform.system() == "Windows":
load_syscalls_windows()
else:
assert False
print "[*] Loaded %s system calls" % len(__syscall2num)
if __name__ == "__main__":
from symbol import Elf
import sys
print Elf(sys.argv[1])
###############################################################################
# Executable file abstraction
###############################################################################
class File(object):
def __init__(self, name = None, buf = None):
self.__name = name
if self.__name is not None:
self.__size = os.path.getsize(name)
self.__fileobject = open(name, "rb")
# self.__buf = mmap.mmap(self.__fileobject.fileno(), self.__size, mmap.MAP_SHARED, mmap.ACCESS_READ)
self.__buf = self.__fileobject.read()
self.__fileobject = None
else:
assert buf is not None
self.__buf = buf
self.__size = len(self.__buf)
self.__fileobject = None
self.__sections = []
self.__symbols = {}
self.__symbols_names = {}
self.__libraries = {}
self.__entrypoint = 0x0
self.__imagebase = 0x0
self.__type = "raw"
self.__machine = None
# def __del__(self):
# if self.__name is not None:
# self.__buf.close()
# self.__fileobject.close()
def __str__(self):
r = "File (%s): %s (%d bytes)\n" % (self.__type, self.__name, self.__size)
r+= "Imagebase: %.8x\n" % (self.__imagebase)
r += "\nSections:\n"
for s in self.__sections:
r += " * " + str(s) + "\n"
r += "\nSymbols:\n"
tmp = []
for ss in self.__symbols.itervalues():
tmp.extend(ss)
tmp.sort(cmp=lambda a,b: cmp(a.getName(), b.getName()))
for s in tmp:
r += " * " + str(s) + "\n"
r += "\nLibraries:\n"
for s in self.__libraries.itervalues():
r += " * " + str(s) + "\n"
return r
def get(self, address, size):
abstract()
def getQWord(self, address):
qword = self.get(address, 8)
return struct.unpack("Q", qword)[0]
def getDWord(self, address):
dword = self.get(address, 4)
return struct.unpack("L", dword)[0]
def getWord(self, address):
dword = self.get(address, 2)
return struct.unpack("H", dword)[0]
def getByte(self, address):
dword = self.get(address, 1)
return struct.unpack("B", dword)[0]
def getName(self):
return self.__name
def setType(self, t):
self.__type = t
def getType(self):
return self.__type
def getMachine(self):
return self.__machine
def setMachine(self, m):
self.__machine = m
def getCode(self, start = None, stop = None):
if start is not None:
if stop is not None:
return self.__buf[start:stop]
else:
return self.__buf[start:]
else:
return self.__buf
def getOffset(self, addr):
sec = self.findSection(addr)
return sec.getOffset() + (addr - sec.getLowAddr())
def addSection(self, sec):
self.__sections.append(sec)
# sort sections by address to speedup search
self.__sections.sort(lambda x,y: int(x.getLowAddr() - y.getLowAddr()))
def delSection(self, sec):
j = 0
for i in self.__sections:
if i == sec or i.getName() == sec.name or i.getLowAddr() == sec.getLowAddr():
self.__sections.remove(j)
j += 1
def findSection(self, address = None):
"""
Return the section holding the address, if any or the section with the
corresponding name
"""
if address is not None:
# search a section by address (binary search)
if isinstance(address, int) or isinstance(address, long):
i = 0
j = len(self.__sections)
# binary search
while j - i > 0:
k = (j - i) / 2 + i
# exact match
if address >= self.__sections[k].getLowAddr() and address <= self.__sections[k].getHighAddr():
return self.__sections[k]
# process the 1st half
elif address < self.__sections[k].getLowAddr():
j = k
# process the 2nd half
else:
i = k + 1
# assert None, "Address %.8x does not seem to belong to any section" % address
return None
# search a section by name (linear search)
elif isinstance(address, str):
for s in self.__sections:
if s.getName() == address:
return s
# assert None, "Section %s not found" % address
return None
return self.__sections
def getLowAddr(self):
lowaddr = 0xFFFFFFFF
for s in self.getSection():
if s.getLowAddr() < lowaddr:
lowaddr = s.getLowAddr()
return lowaddr
def getHighAddr(self):
highaddr = 0
for s in self.getSection():
if s.getHighAddr() > highaddr:
highaddr = s.getHighAddr()
return highaddr
def getSection(self, s = None):
return self.findSection(s)
def resolv(self, address):
abstract()
def addLibrary(self, lib):
self.__libraries[lib.getName()] = lib
def findLibrary(self, name = None):
if name is None: return self.__libraries.values();
if name in self.__libraries:
return self.__libraries[name]
for l in self.__libraries.itervalues():
r = l.findLibrary(name)
if r:
return r
return None
def addSymbol(self, s):
if s.getName() is None:
# Nothing to do
return
if s.getAddress() not in self.__symbols:
self.__symbols[s.getAddress()] = []
if s.getName() not in self.__symbols_names:
self.__symbols_names[s.getName()] = []
self.__symbols[s.getAddress()].append(s)
self.__symbols_names[s.getName()].append(s)
def getSymbol(self, s = None):
if s is None:
ll = []
for l in self.__symbols.values():
ll.extend(l)
return ll
elif s in self.__symbols:
return self.__symbols[s]
elif s in self.__symbols_names:
return self.__symbols_names[s]
else:
return None
def setEntryPoint(self, x):
self.__entrypoint = x
def getEntryPoint(self):
return self.__entrypoint
def getImageBase(self):
return self.__imagebase
def setImageBase(self, ib):
self.__imagebase = ib
SECTION_EXECUTABLE = 0x1
SECTION_WRITABLE = 0x2
SECTION_DYNAMIC = 0x4
SECTION_INITIALIZED = 0x8
SECTION_USERCODE = 0x10
class Section(object):
def __init__(self, name = None, lowaddr = None, highaddr = None, content = None, attribute = None, offset = None):
self.__name = name
self.__lowaddr = lowaddr
self.__highaddr = highaddr
self.__content = content
self.__attribute = attribute
self.__offset = offset
def getLowAddr(self):
return self.__lowaddr
def getHighAddr(self):
return self.__highaddr
def getSize(self):
return self.__highaddr - self.__lowaddr
def getOffset(self):
return self.__offset
def setOffset(self, offset):
self.__offset = offset
def getName(self):
return self.__name
def isCode(self):
return self.__attribute & SECTION_EXECUTABLE
def isData(self):
return not self.__attribute & SECTION_EXECUTABLE
def isReadWrite(self):
return self.__attribute & SECTION_WRITABLE
def isUserCode(self):
return self.__attribute & SECTION_EXECUTABLE and self.__attribute & SECTION_USERCODE
def isInitialized(self):
return self.__attribute & SECTION_INITIALIZED
def __str__(self):
f = ""
if self.isInitialized():
f += "I"
if self.isData():
f += "D"
if self.isCode():
f += "X"
if self.isReadWrite():
f += "W"
if self.isUserCode():
f += "U"
return "%-30s %0.8x-%0.8x %.8x %0.6d [%s]" % (self.__name, self.__lowaddr, self.__highaddr, self.__offset, self.__highaddr - self.__lowaddr, f)
SYMBOL_DATA = 0x1
SYMBOL_FUNCTION = 0x2
SYMBOL_NOTYPE = 0x3
class Symbol:
def __init__(self, name = None, address = None, symtype = None, size = None, module = None):
self.__size = size
self.__name = name
self.__address = address
self.__type = symtype
self.__module = module
def __str__(self):
if self.__type == SYMBOL_FUNCTION:
t = "F"
elif self.__type == SYMBOL_DATA:
t = "D"
elif self.__type == SYMBOL_NOTYPE:
t = "-"
else:
t = "?"
return "%-30s %0.8x (%0.6d) [%s]" % (self.__name, self.__address, self.__size, t)
def isFunction(self):
return self.__type == SYMBOL_FUNCTION
def isData(self):
return self.__type == SYMBOL_DATA
def getName(self):
return self.__name
def getModule(self):
return self.__module
def getAddress(self):
return self.__address
def setAddress(self, addr):
self.__address = addr
def getSize(self):
return self.__size
class Library:
def __init__(self, name = None):
self.__name = name
def __str__(self):
return "%s" % self.__name
def getName(self):
return self.__name
###############################################################################
# Elf file abstraction
###############################################################################
MACHINE_I386 = 0
MACHINE_X86_64 = 1
EI_MAG0 = 0
EI_MAG1 = 1
EI_MAG2 = 2
EI_MAG3 = 3
EI_CLASS = 4
EI_DATA = 5
EI_VERSION = 6
EI_OSABI = 7
EI_ABIVERSION = 8
EI_PAD = 9
EI_NIDENT = 16
ELFCLASS32 = 1 # Elf32
ELFCLASS64 = 2 # Elf64
ET_NONE = 0 # No file type
ET_REL = 1 # Relocatable file
ET_EXEC = 2 # Executable file
ET_DYN = 3 # Shared object file
ET_CORE = 4 # Core file
ET_NUM = 5 # Number of defined types
ET_LOOS = 0xfe00 # OS-specific range start
ET_HIOS = 0xfeff # OS-specific range end
ET_LOPROC = 0xff00 # Processor-specific range start
ET_HIPROC = 0xffff # Processor-specific range end
SHT_NULL = 0 # Section header table entry unused
SHT_PROGBITS = 1 # Program data
SHT_SYMTAB = 2 # Symbol table
SHT_STRTAB = 3 # String table
SHT_RELA = 4 # Relocation entries with addends
SHT_HASH = 5 # Symbol hash table
SHT_DYNAMIC = 6 # Dynamic linking information
SHT_NOTE = 7 # Notes
SHT_NOBITS = 8 # Program space with no data (bss)
SHT_REL = 9 # Relocation entries, no addends
SHT_SHLIB = 10 # Reserved
SHT_DYNSYM = 11 # Dynamic linker symbol table
SHT_INIT_ARRAY = 14 # Array of constructors
SHT_FINI_ARRAY = 15 # Array of destructors
SHT_PREINIT_ARRAY = 16 # Array of pre-constructors
SHT_GROUP = 17 # Section group
SHT_SYMTAB_SHNDX = 18 # Extended section indeces
SHT_NUM = 19 # Number of defined types
SHT_LOOS = 0x60000000L # Start OS-specific
SHT_GNU_LIBLIST = 0x6ffffff7L # Prelink library list
SHT_CHECKSUM = 0x6ffffff8L # Checksum for DSO content
SHT_LOSUNW = 0x6ffffffaL # Sun-specific low bound
SHT_SUNW_move = 0x6ffffffaL
SHT_SUNW_COMDAT = 0x6ffffffbL
SHT_SUNW_syminfo = 0x6ffffffcL
SHT_GNU_verdef = 0x6ffffffdL # Version definition section
SHT_GNU_verneed = 0x6ffffffeL # Version needs section
SHT_GNU_versym = 0x6fffffffL # Version symbol table
SHT_HISUNW = 0x6fffffffL # Sun-specific high bound
SHT_HIOS = 0x6fffffffL # End OS-specific type
SHT_LOPROC = 0x70000000L # Start of processor-specific
SHT_HIPROC = 0x7fffffffL # End of processor-specific
SHT_LOUSER = 0x80000000L # Start of application-specific
SHF_WRITE = (1 << 0) # Writable
SHF_ALLOC = (1 << 1) # Occupies memory during execution
SHF_EXECINSTR = (1 << 2) # Executable
SHF_MERGE = (1 << 4) # Might be merged
SHF_STRINGS = (1 << 5) # Contains nul-terminated strings
SHF_INFO_LINK = (1 << 6) # `sh_info' contains SHT index
SHF_LINK_ORDER = (1 << 7) # Preserve order after combining
SHF_OS_NONCONFORMING = (1 << 8) # Non-standard OS specific handling
SHF_GROUP = (1 << 9) # Section is member of a group
SHF_TLS = (1 << 10) # Section hold thread-local data
SHF_MASKOS = 0x0ff00000L # OS-specific.
SHF_MASKPROC = 0xf0000000L # Processor-specific
SHF_ORDERED = (1 << 30) # Special ordering requirement
SHF_EXCLUDE = (1 << 31) # Section is excluded unless
PT_NULL = 0 # Program header table entry unused
PT_LOAD = 1 # Loadable program segment
PT_DYNAMIC = 2 # Dynamic linking information
PT_INTERP = 3 # Program interpreter
PT_NOTE = 4 # Auxiliary information
PT_SHLIB = 5 # Reserved
PT_PHDR = 6 # Entry for header table itself
PT_TLS = 7 # Thread-local storage segment
PT_NUM = 8 # Number of defined types
PT_LOOS = 0x60000000L # Start of OS-specific
PT_GNU_EH_FRAME = 0x6474e550L # GCC .eh_frame_hdr segment
PT_GNU_STACK = 0x6474e551L # Indicates stack executability
PT_GNU_RELRO = 0x6474e552L # Read-only after relocation
PT_LOSUNW = 0x6ffffffaL
PT_SUNWBSS = 0x6ffffffaL # Sun Specific segment
PT_SUNWSTACK = 0x6ffffffbL # Stack segment
PT_HISUNW = 0x6fffffffL
PT_HIOS = 0x6fffffffL # End of OS-specific
PT_LOPROC = 0x70000000L # Start of processor-specific
PT_HIPROC = 0x7fffffffL # End of processor-specific
PF_X = (1 << 0) # Segment is executable
PF_W = (1 << 1) # Segment is writable
PF_R = (1 << 2) # Segment is readable
PF_MASKOS = 0x0ff00000L # OS-specific
PF_MASKPROC = 0xf0000000L # Processor-specific
STT_NOTYPE = 0 # Symbol type is unspecified
STT_OBJECT = 1 # Symbol is a data object
STT_FUNC = 2 # Symbol is a code object
STT_SECTION = 3 # Symbol associated with a section
STT_FILE = 4 # Symbol's name is file name
STT_COMMON = 5 # Symbol is a common data object
STT_TLS = 6 # Symbol is thread-local data object
STT_NUM = 7 # Number of defined types.
STT_LOOS = 10 # Start of OS-specific
STT_HIOS = 12 # End of OS-specific
STT_LOPROC = 13 # Start of processor-specific
STT_HIPROC = 15 # End of processor-specific
STB_LOCAL = 0 # Local symbol
STB_GLOBAL = 1 # Global symbol
STB_WEAK = 2 # Weak symbol
DT_NULL = 0 # Marks end of dynamic section
DT_NEEDED = 1 # Name of needed library
DT_PLTRELSZ = 2 # Size in bytes of PLT relocs
DT_PLTGOT = 3 # Processor defined value
DT_HASH = 4 # Address of symbol hash table
DT_STRTAB = 5 # Address of string table
DT_SYMTAB = 6 # Address of symbol table
DT_RELA = 7 # Address of Rela relocs
DT_RELASZ = 8 # Total size of Rela relocs
DT_RELAENT = 9 # Size of one Rela reloc
DT_STRSZ = 10 # Size of string table
DT_SYMENT = 11 # Size of one symbol table entry
DT_INIT = 12 # Address of init function
DT_FINI = 13 # Address of termination function
DT_SONAME = 14 # Name of shared object
DT_RPATH = 15 # Library search path (deprecated)
DT_SYMBOLIC = 16 # Start symbol search here
DT_REL = 17 # Address of Rel relocs
DT_RELSZ = 18 # Total size of Rel relocs
DT_RELENT = 19 # Size of one Rel reloc
DT_PLTREL = 20 # Type of reloc in PLT
DT_DEBUG = 21 # For debugging; unspecified
DT_TEXTREL = 22 # Reloc might modify .text
DT_JMPREL = 23 # Address of PLT relocs
DT_BIND_NOW = 24 # Process relocations of object
DT_INIT_ARRAY = 25 # Array with addresses of init fct
DT_FINI_ARRAY = 26 # Array with addresses of fini fct
DT_INIT_ARRAYSZ = 27 # Size in bytes of DT_INIT_ARRAY
DT_FINI_ARRAYSZ = 28 # Size in bytes of DT_FINI_ARRAY
DT_RUNPATH = 29 # Library search path
DT_FLAGS = 30 # Flags for the object being loaded
DT_ENCODING = 32 # Start of encoded range
DT_PREINIT_ARRAY = 32 # Array with addresses of preinit fct
DT_PREINIT_ARRAYSZ = 33 # size in bytes of DT_PREINIT_ARRAY
DT_NUM = 34 # Number used
DT_LOOS = 0x6000000dL # Start of OS-specific
DT_HIOS = 0x6ffff000L # End of OS-specific
DT_LOPROC = 0x70000000L # Start of processor-specific
DT_HIPROC = 0x7fffffffL # End of processor-specific
def qword(buf):
return struct.unpack("Q", buf[0:8])[0]
def dword(buf):
return struct.unpack("I", buf[0:4])[0]
def word(buf):
return struct.unpack("H", buf[0:2])[0]
def byte(buf):
return struct.unpack("B", buf[0])[0]
class ElfEhdr:
def __init__(self, buf):
abstract()
class ElfShdr:
def __init__(self, buf):
abstract()
class ElfPhdr:
def __init__(self, buf):
abstract()
class ElfRel:
def __init__(self):
abstract()
def size(self):
abstract()
class ElfSym:
def __init__(self):
abstract()
def size(self):
abstract()
class ElfDyn:
def __init__(self):
abstract()
def size(self):
abstract()
################################################################################
# ELF32
################################################################################
class Elf32Ehdr(ElfEhdr):
def __init__(self, buf):
self.e_ident = buf[0:16]
self.e_type = struct.unpack("H", buf[16:18])[0]
self.e_machine = struct.unpack("H", buf[18:20])[0]
self.e_version = struct.unpack("I", buf[20:24])[0]
self.e_entry = struct.unpack("I", buf[24:28])[0]
self.e_phoff = struct.unpack("I", buf[28:32])[0]
self.e_shoff = struct.unpack("I", buf[32:36])[0]
self.e_flags = struct.unpack("I", buf[36:40])[0]
self.e_ehsize = struct.unpack("H", buf[40:42])[0]
self.e_phentsize = struct.unpack("H", buf[42:44])[0]
self.e_phnum = struct.unpack("H", buf[44:46])[0]
self.e_shentsize = struct.unpack("H", buf[46:48])[0]
self.e_shnum = struct.unpack("H", buf[48:50])[0]
self.e_shstrndx = struct.unpack("H", buf[50:52])[0]
class Elf32Shdr(ElfShdr):
def __init__(self, buf):
self.sh_name = struct.unpack("I", buf[0:4])[0]
self.sh_type = struct.unpack("I", buf[4:8])[0]
self.sh_flags = struct.unpack("I", buf[8:12])[0]
self.sh_addr = struct.unpack("I", buf[12:16])[0]
self.sh_offset = struct.unpack("I", buf[16:20])[0]
self.sh_size = struct.unpack("I", buf[20:24])[0]
self.sh_link = struct.unpack("I", buf[24:28])[0]
self.sh_info = struct.unpack("I", buf[28:32])[0]
self.sh_addraling = struct.unpack("I", buf[32:36])[0]
self.sh_entsize = struct.unpack("I", buf[36:40])[0]
class Elf32Phdr(ElfPhdr):
def __init__(self, buf):
self.p_type = struct.unpack("I", buf[0:4])[0]
self.p_offset = struct.unpack("I", buf[4:8])[0]
self.p_vaddr = struct.unpack("I", buf[8:12])[0]
self.p_paddr = struct.unpack("I", buf[12:16])[0]
self.p_filesiz = struct.unpack("I", buf[16:20])[0]
self.p_memsz = struct.unpack("I", buf[20:24])[0]
self.p_flags = struct.unpack("I", buf[24:28])[0]
self.p_align = struct.unpack("I", buf[28:32])[0]
class Elf32Rel(ElfRel):
def __init__(self, buf):
self.r_offset = struct.unpack("I", buf[0:4])[0] # Address
self.r_info = struct.unpack("I", buf[4:8])[0] # Relocation type and symbol
# index
class Elf32Sym(ElfSym):
def __init__(self, buf):
self.st_name = struct.unpack("I", buf[0:4])[0] # Symbol name (string tbl
# index)
self.st_value = struct.unpack("I", buf[4:8])[0] # symbol value
self.st_size = struct.unpack("I", buf[8:12])[0] # symbol size
self.st_info = byte(buf[12:13]) # symbol type and binding
self.st_other = byte(buf[13:14]) # symbol visibility
self.st_shndx = struct.unpack("H", buf[14:16])[0] # section index
class Elf32Dyn(ElfDyn):
def __init__(self, buf):
self.d_tag = struct.unpack("i", buf[0:4])[0] # dynamic entry type
self.d_val = struct.unpack("I", buf[4:8])[0] # Integer value
self.d_ptr = self.d_val
def ELF32_ST_BIND(val):
return ((val) >> 4)
def ELF32_ST_TYPE(val):
return ((val) & 0xf)
def ELF32_ST_INFO(sym, type):
return (((sym) << 4) + ((type) & 0xf))
def ELF32_R_SYM(val):
return ((val) >> 8)
def ELF32_R_TYPE(val):
return ((val) & 0xff)
def ELF32_R_INFO(sym, type):
return (((sym) << 8) + ((type) & 0xff))
################################################################################
# ELF64
################################################################################
class Elf64Ehdr(ElfEhdr):
def __init__(self, buf):
self.e_ident = buf[0:16]
self.e_type = word(buf[16:18])
self.e_machine = word(buf[18:20])
self.e_version = dword(buf[20:24])
self.e_entry = qword(buf[24:32])
self.e_phoff = qword(buf[32:40])
self.e_shoff = qword(buf[40:48])
self.e_flags = dword(buf[48:52])
self.e_ehsize = word(buf[52:54])
self.e_phentsize = word(buf[54:56])
self.e_phnum = word(buf[56:58])
self.e_shentsize = word(buf[58:60])
self.e_shnum = word(buf[60:62])
self.e_shstrndx = word(buf[62:64])
class Elf64Shdr(ElfShdr):
def __init__(self, buf):
self.sh_name = dword(buf[0:4])
self.sh_type = dword(buf[4:8])
self.sh_flags = qword(buf[8:16])
self.sh_addr = qword(buf[16:24])
self.sh_offset = qword(buf[24:32])
self.sh_size = qword(buf[32:40])
self.sh_link = dword(buf[40:44])
self.sh_info = dword(buf[44:48])
self.sh_addraling = qword(buf[48:56])
self.sh_entsize = qword(buf[56:64])
class Elf64Phdr(ElfPhdr):
def __init__(self, buf):
self.p_type = dword(buf[0:4])
self.p_flags = dword(buf[4:8])
self.p_offset = qword(buf[8:16])
self.p_vaddr = qword(buf[16:24])
self.p_paddr = qword(buf[24:32])
self.p_filesiz = qword(buf[32:40])
self.p_memsz = qword(buf[40:48])
self.p_align = qword(buf[48:56])
class Elf64Rel(ElfRel):
def __init__(self, buf):
self.r_offset = qword(buf[0:8]) # Address
self.r_info = qword(buf[8:16]) # Relocation type and symbol
# index
class Elf64Sym(ElfSym):
def __init__(self, buf):
self.st_name = dword(buf[0:4]) # Symbol name (string tbl
# index)
self.st_info = byte(buf[4:5]) # symbol type and binding
self.st_other = byte(buf[5:6]) # symbol visibility
self.st_shndx = word(buf[6:8]) # section index
self.st_value = qword(buf[8:16]) # symbol value
self.st_size = qword(buf[16:24]) # symbol size
class Elf64Dyn(ElfDyn):
def __init__(self, buf):
self.d_tag = struct.unpack("q", buf[0:8])[0] # dynamic entry type
self.d_val = qword(buf[8:16]) # Integer value
self.d_ptr = self.d_val
def ELF64_ST_BIND(val):
return ((val) >> 4)