9
9
from util .elffile import EM
10
10
from util .patch .dis import irdis
11
11
12
+ def pfcol (s ):
13
+ return '[\033 [1m\033 [32m%s\033 [0m] ' % s
14
+
12
15
class Context (object ):
13
16
def __init__ (self , binary , verbose = False ):
14
17
self .binary = binary
@@ -40,7 +43,7 @@ def entry(self):
40
43
41
44
@entry .setter
42
45
def entry (self , val ):
43
- self .info ('[ MOVE ENTRY POINT] -> 0x%x' % val )
46
+ self .info (pfcol ( ' MOVE ENTRY POINT' ) + ' -> 0x%x' % val )
44
47
self .elf .entry = val
45
48
46
49
def funcs (self , marked = False ):
@@ -86,11 +89,11 @@ def info(self, *args, **kwargs):
86
89
87
90
# TODO: show warn/error at the end, and colorize
88
91
def warn (self , * args , ** kwargs ):
89
- kwargs ['prefix' ] = '\033 [33m[WARN]\033 [39m '
92
+ kwargs ['prefix' ] = '\033 [1m \033 [ 33m[WARN]\033 [0m '
90
93
self .info (* args , ** kwargs )
91
94
92
95
def error (self , * args , ** kwargs ):
93
- kwargs ['prefix' ] = '\033 [31m[ERR]\033 [39m '
96
+ kwargs ['prefix' ] = '\033 [1m \033 [ 31m[ERR]\033 [0m '
94
97
self .info (* args , ** kwargs )
95
98
96
99
def debug (self , * args , ** kwargs ):
@@ -155,22 +158,22 @@ def search(self, data):
155
158
idx = segment .data .index (data )
156
159
if idx >= 0 :
157
160
addr = segment .addr + idx
158
- self .debug ('[ SEARCH] "%s" found at 0x%x' % (tmp , addr ))
161
+ self .debug (pfcol ( ' SEARCH' ) + ' "%s" found at 0x%x' % (tmp , addr ))
159
162
return addr
160
163
except ValueError :
161
164
pass
162
- self .error ('[ SEARCH] "%s" not found.' % tmp )
165
+ self .error (pfcol ( ' SEARCH' ) + ' "%s" not found.' % tmp )
163
166
164
- def hook (self , src , dst , first = False ):
167
+ def hook (self , src , dst , first = False , noentry = False ):
165
168
# hooking the entry point is a special, more efficient case
166
- if src == self .entry :
169
+ if src == self .entry and not noentry :
167
170
if first :
168
171
self .binary .entry_hooks .insert (0 , dst )
169
172
else :
170
173
self .binary .entry_hooks .append (dst )
171
- self .debug ('[ HOOK] ENTRY -> 0x%x' % dst )
174
+ self .debug (pfcol ( ' HOOK' ) + ' ENTRY -> 0x%x' % dst )
172
175
return
173
- self .debug ('[ HOOK] @0x%x -> 0x%x' % (src , dst ))
176
+ self .debug (pfcol ( ' HOOK' ) + ' @0x%x -> 0x%x' % (src , dst ))
174
177
self .make_writable (src )
175
178
176
179
alloc = self .binary .next_alloc ()
@@ -207,37 +210,34 @@ def hook(self, src, dst, first=False):
207
210
jmpevict = str (self .elf .read (jmpoff , len (emptyjmp )))
208
211
209
212
stage0 = evicted + jmpevict
210
- stage1_addr = self .inject (raw = stage0 , internal = True )
211
- stage2_addr = self .inject (raw = stage0 , internal = True )
213
+ # TODO: self.alloc()?
214
+ stage1_addr = self .binary .alloc (len (stage0 ), target = 'patch' )
215
+ stage2_addr = self .binary .alloc (len (stage0 ), target = 'patch' )
212
216
217
+ # memcpy needs to be pc-relative
218
+ base = self .binary .next_alloc ()
213
219
hook1 = self .inject (asm = ';' .join ((
214
220
self .arch .call (dst ),
215
- self .arch .memcpy (src , stage2_addr , len (stage0 )),
221
+ self .arch .memcpy (src - base , stage2_addr - base , len (stage0 )),
216
222
self .arch .jmp (src ),
217
223
)), internal = True )
224
+ base = self .binary .next_alloc ()
218
225
hook2 = self .inject (asm = ';' .join ((
219
- self .arch .memcpy (src , stage1_addr , len (stage0 )),
226
+ self .arch .memcpy (src - base , stage1_addr - base , len (stage0 )),
220
227
self .arch .jmp (jmpoff ),
221
228
)), internal = True )
222
229
223
230
# we need to overwrite both stages because we didn't know the hook addrs at the time
224
231
stage1 = self .asm (';' .join (
225
232
(self .arch .jmp (hook1 ),) + (self .arch .nop (),) * (len (evicted ) - len (emptyjmp )),
226
233
), addr = src ) + jmpevict
227
- self .elf . write (stage1_addr , stage1 )
234
+ self .patch (stage1_addr , raw = stage1 , is_asm = True , internal = True , desc = 'hook stage 1' )
228
235
stage2 = evicted + self .asm (self .arch .jmp (hook2 ), addr = jmpoff )
229
- self .elf .write (stage2_addr , stage2 )
230
-
231
- '''
232
- print 'stage 1', binascii.hexlify(stage1)
233
- print self.pdis(self.arch.dis(stage1, src))
234
- print 'stage 2', binascii.hexlify(stage2)
235
- print self.pdis(self.arch.dis(stage2, src))
236
- '''
236
+ self .patch (stage2_addr , raw = stage2 , is_asm = True , internal = True , desc = 'hook stage 2' )
237
237
238
238
# TODO: act more like mobile substrate wrt orig calling?
239
239
# that is, make calling orig optional
240
- self .patch (src , raw = stage1 )
240
+ self .patch (src , raw = stage1 , is_asm = True , internal = True , desc = 'hook entry point' )
241
241
242
242
def _lint (self , addr , raw , typ , is_asm = False ):
243
243
if typ == 'asm' or is_asm :
@@ -273,6 +273,10 @@ def inject(self, **kwargs):
273
273
mark_func = kwargs .get ('mark_func' , False )
274
274
return_size = kwargs .get ('size' , False )
275
275
target = kwargs .get ('target' , 'patch' )
276
+ desc = kwargs .get ('desc' , '' )
277
+ if desc :
278
+ desc = ' | "%s"' % desc
279
+
276
280
addr = self .binary .next_alloc (target )
277
281
c = kwargs .get ('c' )
278
282
if c :
@@ -289,7 +293,7 @@ def inject(self, **kwargs):
289
293
if raw [- len (ret ):] != ret and not internal :
290
294
self .warn ('Injected asm does not return!' )
291
295
292
- self .info ('[ INJECT] @0x%x-0x%x' % (addr , addr + len (raw )))
296
+ self .info (pfcol ( ' INJECT' ) + ' @0x%x-0x%x%s ' % (addr , addr + len (raw ), desc ))
293
297
if not kwargs .get ('silent' ):
294
298
if typ == 'asm' or is_asm :
295
299
self .debug (dis = self .arch .dis (raw , addr = addr ))
@@ -307,22 +311,30 @@ def inject(self, **kwargs):
307
311
308
312
def patch (self , addr , ** kwargs ):
309
313
raw , typ = self ._compile (addr , ** kwargs )
314
+ desc = kwargs .get ('desc' , '' )
315
+ if desc :
316
+ desc = ' | "%s"' % desc
310
317
311
- self .info ('[ PATCH] @0x%x-0x%x' % (addr , addr + len (raw )))
318
+ self .info (pfcol ( ' PATCH' ) + ' @0x%x-0x%x%s ' % (addr , addr + len (raw ), desc ))
312
319
if len (raw ) == 0 :
313
320
self .warn ('Empty patch.' )
314
321
return
315
322
316
323
if typ == 'asm' or kwargs .get ('is_asm' ):
317
324
size = len ('' .join ([str (i .bytes ) for i in self .dis (addr , len (raw ))]))
318
- if size != len (raw ):
325
+ if size != len (raw ) and not kwargs . get ( 'internal' ) :
319
326
self .warn ('Assembly patch is not aligned with underlying instructions.' )
320
327
321
328
self ._lint (addr , raw , typ , is_asm = kwargs .get ('is_asm' ))
322
329
if not kwargs .get ('silent' ):
323
330
if typ == 'asm' or kwargs .get ('is_asm' ):
324
- for line in self .pdis (self .dis (addr , len (raw ))).split ('\n ' ):
325
- self .debug ('- %s' % line )
331
+ # collapse nulls
332
+ old = self .elf .read (addr , len (raw ))
333
+ if old == '\0 ' * len (raw ):
334
+ self .debug ('- %s' % ('00' * len (raw )))
335
+ else :
336
+ for line in self .pdis (self .dis (addr , len (raw ))).split ('\n ' ):
337
+ self .debug ('- %s' % line )
326
338
for line in self .pdis (self .arch .dis (raw , addr = addr )).split ('\n ' ):
327
339
self .debug ('+ %s' % line )
328
340
else :
0 commit comments