-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpatchdyn.py
227 lines (204 loc) · 9 KB
/
patchdyn.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
import argparse
import sys
import lief.ELF as ELF
class PatchDynException(Exception):
pass
def retrieve_interpreter(binary: ELF.Binary):
if binary.has_interpreter:
print(binary.interpreter)
def update_interpreter(binary: ELF.Binary, interpreter: str):
binary.interpreter = interpreter
def retrieve_needed(binary: ELF.Binary):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicEntryLibrary):
print(dyn.name)
def update_needed(binary: ELF.Binary, old_needed: str, new_needed: str):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicEntryLibrary):
if dyn.name == old_needed:
dyn.name = new_needed
return
raise PatchDynException('No such needed')
def create_needed(binary: ELF.Binary, needed: str):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicEntryLibrary):
if dyn.name == needed:
raise PatchDynException('Needed already exists')
needed_entry = ELF.DynamicEntryLibrary(needed)
binary.add(needed_entry)
def delete_needed(binary: ELF.Binary, needed: str):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicEntryLibrary):
if dyn.name == needed:
binary.remove(dyn)
return
raise PatchDynException('No such needed')
def retrieve_soname(binary: ELF.Binary):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicSharedObject):
print(dyn.name)
return
def update_soname(binary: ELF.Binary, soname: str):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicSharedObject):
if soname == '': # delete soname
binary.remove(dyn)
else: # update soname
dyn.name = soname
return
if soname != '': # create soname
soname_entry = ELF.DynamicSharedObject(soname)
binary.add(soname_entry)
return
raise PatchDynException('Tried to delete non-existent soname')
def retrieve_rpath(binary: ELF.Binary):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicEntryRpath):
print(dyn.name)
return
def update_rpath(binary: ELF.Binary, rpath: str):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicEntryRpath):
if rpath == '': # delete rpath
binary.remove(dyn)
else: # update rpath
dyn.name = rpath
return
if rpath != '': # create rpath
rpath_entry = ELF.DynamicEntryRpath(rpath)
binary.add(rpath_entry)
return
raise PatchDynException('Tried to delete non-existent rpath')
def retrieve_runpath(binary: ELF.Binary):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicEntryRunPath):
print(dyn.name)
return
def update_runpath(binary: ELF.Binary, runpath: str):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicEntryRunPath):
if runpath == '': # delete runpath
binary.remove(dyn)
else: # update runpath
dyn.name = runpath
return
if runpath != '': # create runpath
runpath_entry = ELF.DynamicEntryRunPath(runpath)
binary.add(runpath_entry)
return
raise PatchDynException('Tried to delete non-existent runpath')
def retrieve_no_default_lib(binary: ELF.Binary):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicEntryFlags) \
and ELF.DYNAMIC_FLAGS_1.NODEFLIB in dyn:
print('Found')
return
print('Not found')
def set_no_default_lib(binary: ELF.Binary):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicEntryFlags):
dyn.add(ELF.DYNAMIC_FLAGS_1.NODEFLIB)
return
def unset_no_default_lib(binary: ELF.Binary):
dyns_iter = binary.dynamic_entries
for dyn in dyns_iter:
if isinstance(dyn, ELF.DynamicEntryFlags):
dyn.remove(ELF.DYNAMIC_FLAGS_1.NODEFLIB)
return
if __name__ == '__main__':
parser = argparse.ArgumentParser()
action = parser.add_mutually_exclusive_group(required=True)
action.add_argument('--retrieve-interpreter', '--ri', action='store_true', dest='retrieve_interpreter')
action.add_argument('--update-interpreter', '--ui', metavar='INTERPRETER', type=str, nargs=1,
dest='update_interpreter',
help='update dynamic linker/loader (in .interp section)')
action.add_argument('--retrieve-needed', '--rn', action='store_true', dest='retrieve_needed')
action.add_argument('--update-needed', '--un', metavar=('OLD_NEEDED', 'NEW_NEEDED'), type=str, nargs=2,
dest='update_needed',
help='update shared object/library dependency (DT_NEEDED entry in .dynamic section)')
action.add_argument('--create-needed', '--cn', metavar='NEEDED', type=str, nargs=1, dest='create_needed')
action.add_argument('--delete-needed', '--dn', metavar='NEEDED', type=str, nargs=1, dest='delete_needed')
action.add_argument('--retrieve-soname', '--rs', action='store_true', dest='retrieve_soname')
action.add_argument('--update-soname', '--us', metavar='SONAME', type=str, nargs=1, dest='update_soname',
help='update shared object/library name (DT_SONAME entry in .dynamic section)')
action.add_argument('--retrieve-rpath', '--rrpath', action='store_true', dest='retrieve_rpath')
action.add_argument('--update-rpath', '--urpath', metavar='RPATH', type=str, nargs=1, dest='update_rpath',
help='update rpath (DT_RPATH entry in .dynamic section)')
action.add_argument('--retrieve-runpath', '--rr', action='store_true', dest='retrieve_runpath',)
action.add_argument('--update-runpath', '--ur', metavar='RUNPATH', type=str, nargs=1, dest='update_runpath',
help='update runpath (DT_RUNPATH entry in .dynamic section)')
action.add_argument('--retrieve-no-default-lib', '--rndl', action='store_true', dest='retrieve_no_default_lib')
action.add_argument('--set-no-default-lib', '--sndl', action='store_true', dest='set_no_default_lib',
help='set DT_FLAGS_1 (DF_1_NODEFLIB) in .dynamic section')
action.add_argument('--unset-no-default-lib', '--usndl', action='store_true', dest='unset_no_default_lib')
parser.add_argument('input', metavar='FILENAME', type=str,
help='filename of the ELF file to be patched')
parser.add_argument('-o', '--output', metavar='OUTPUT_FILENAME', type=str, dest='output',
help='filename of the patched ELF file, <input filename>.patched by default')
args = parser.parse_args()
binary: ELF.Binary = ELF.parse(args.input)
updated = False
try:
if args.retrieve_interpreter:
retrieve_interpreter(binary)
elif args.update_interpreter:
update_interpreter(binary, args.update_interpreter[0])
updated = True
elif args.retrieve_needed:
retrieve_needed(binary)
elif args.update_needed:
update_needed(binary, args.update_needed[0], args.update_needed[1])
updated = True
elif args.create_needed:
create_needed(binary, args.create_needed[0])
updated = True
elif args.delete_needed:
delete_needed(binary, args.delete_needed[0])
updated = True
elif args.retrieve_soname:
retrieve_soname(binary)
elif args.update_soname:
update_soname(binary, args.update_soname[0])
updated = True
elif args.retrieve_rpath:
retrieve_rpath(binary)
elif args.update_rpath:
update_rpath(binary, args.update_rpath[0])
updated = True
elif args.retrieve_runpath:
retrieve_runpath(binary)
elif args.update_runpath:
update_runpath(binary, args.update_runpath[0])
updated = True
elif args.retrieve_no_default_lib:
retrieve_no_default_lib(binary)
elif args.set_no_default_lib:
set_no_default_lib(binary)
updated = True
elif args.unset_no_default_lib:
unset_no_default_lib(binary)
updated = True
except PatchDynException as e:
print(e)
sys.exit(1)
if updated:
if args.output is None:
output_filename = f'{args.input}.patched'
else:
output_filename = args.output
builder = ELF.Builder(binary)
builder.build()
builder.write(output_filename)
# binary.write(output_filename)