This repository has been archived by the owner on Feb 11, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
loader.py
141 lines (116 loc) · 5.14 KB
/
loader.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
import traceback
import sys
import lief
from binaryninja.enums import SegmentFlag, SymbolType
from binaryninja.platform import Platform
from binaryninja.binaryview import BinaryView
from binaryninja.types import Symbol
from binaryninja.log import log_error, log_info
from binaryninja.interaction import get_choice_input
from functools import wraps
class exceptions_handler(object):
def __init__(self, exceptions):
self.exceptions = exceptions
self.func = None
def __call__(self, func):
self.func = func
@wraps(func)
def wrapped_func(*args, **kwargs):
try:
return self.func(*args, **kwargs)
except self.exceptions as e:
log_error("-" * 60)
log_error("Exception in {}: {}".format(self.func.__name__, e))
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_tb(exc_traceback)
log_error("-" * 60)
return False
return wrapped_func
class LiefElfView(BinaryView):
name = "LIEF"
long_name = "LIEF ELF loader"
LIEF2BN = {
lief.ELF.ARCH.AARCH64: "aarch64",
lief.ELF.ARCH.ARM: "armv7",
lief.ELF.ARCH.x86_64: "x86_64",
lief.ELF.ARCH.i386: "x86",
}
def __init__(self, data):
BinaryView.__init__(self, parent_view=data, file_metadata=data.file)
self._lief_handler: lief.ELF.Binary = lief.parse(data.file.filename)
@classmethod
def is_valid_for_data(self, data):
hdr = data.read(0, 16)
if len(hdr) < 16:
return False
if hdr[0:4] != b"\x7fELF":
return False
choice: int = get_choice_input("Do you want to load the binary with LIEF?", "choices", ["Yes", "No"])
return choice == 0
@exceptions_handler(Exception)
def init(self):
if self._lief_handler is None:
log_error("Can't load the binary with LIEF")
return False
# TODO(romain): Handle other platforms supported by Binary Ninja (e.g. freebsd)
arch = self.LIEF2BN.get(self._lief_handler.header.machine_type, None)
if arch is None:
log_error("Unsupported architecture: {}".format(str(self._lief_handler.header.machine_type)))
self.platform = Platform[f"linux-{arch}"]
# Add segments
for segment in self._lief_handler.segments:
if segment.type == lief.ELF.SEGMENT_TYPES.LOAD:
bn_flags = 0
if segment.has(lief.ELF.SEGMENT_FLAGS.R):
bn_flags |= SegmentFlag.SegmentReadable
if segment.has(lief.ELF.SEGMENT_FLAGS.W):
bn_flags |= SegmentFlag.SegmentWritable
if segment.has(lief.ELF.SEGMENT_FLAGS.X):
bn_flags |= SegmentFlag.SegmentExecutable
if segment.file_offset > 0:
self.add_auto_segment(segment.virtual_address, segment.virtual_address,
segment.file_offset, segment.physical_size, bn_flags)
else:
# Workaround: BN does not enable to add segment which starts at 0 (while is it
# valid with the ASLR)
OFF = 1
self.add_auto_segment(OFF, segment.virtual_size,
OFF, segment.physical_size, bn_flags)
# TODO(romain): Handle sections: add_auto_section
# Add functions
for func in self._lief_handler.functions:
log_info(f"Adding function {func!s}")
self.add_function(func.address)
if func.name:
self.define_auto_symbol(Symbol(SymbolType.FunctionSymbol, func.address, func.name))
# Init entrypoint
if lief.ELF.DYNAMIC_TAGS.INIT_ARRAY in self._lief_handler:
for func in self._lief_handler[lief.ELF.DYNAMIC_TAGS.INIT_ARRAY].array:
if func > 0 and self.entry_point == 0:
log_info(f"Adding constructor function 0x{func:x}")
self.add_entry_point(func)
# TODO: Hand DT_INIT / DT_PREINIT_ARRAY / header.entrypoint / _start / JNI_OnLoad / ...
# Add imports: TODO
# for symbol in self._lief_handler.imported_functions:
# sym = Symbol(SymbolType.ImportedFunctionSymbol, 0, symbol.name)
# # TODO: How to instanciate a function.Function object ?
# # self.define_imported_function(sym, func)
return True
def perform_is_valid_offset(self, addr):
try:
res = self._lief_handler.virtual_address_to_offset(addr)
self._lief_handler.get_content_from_virtual_address(addr, 1)
return res > 0
except Exception:
return False
def perform_read(self, addr, length):
try:
return bytes(self._lief_handler.get_content_from_virtual_address(addr, length))
except Exception:
return None
def relocation_ranges_at(addr):
raise NotImplementedError("Relocation is not supported yet")
def perform_is_executable(self):
return True
def perform_is_relocatable(self):
return self._lief_handler.is_pie