|
8 | 8 | import re |
9 | 9 | import libr |
10 | 10 | from dataclasses import dataclass, field, fields |
11 | | -from functools import cached_property, wraps |
| 11 | +from functools import cached_property |
12 | 12 | from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Pattern, Tuple, Union |
13 | 13 | from qiling.const import QL_ARCH |
14 | 14 | from qiling.extensions import trace |
15 | 15 | from unicorn import UC_PROT_NONE, UC_PROT_READ, UC_PROT_WRITE, UC_PROT_EXEC, UC_PROT_ALL |
16 | 16 | from .callstack import CallStack |
17 | 17 | from .deflat import R2Deflator |
| 18 | +from .utils import wrap_aaa, wrap_arg_addr |
18 | 19 |
|
19 | 20 | if TYPE_CHECKING: |
20 | 21 | from qiling.extensions.r2 import R2Qiling |
@@ -279,15 +280,6 @@ def _cmdj(self, cmd: str, r2c = None) -> Union[Dict, List[Dict]]: |
279 | 280 | def offset(self) -> int: |
280 | 281 | return self._r2c.contents.offset |
281 | 282 |
|
282 | | - def aaa(fun): |
283 | | - @wraps(fun) |
284 | | - def wrapper(self, *args, **kwargs): |
285 | | - if self.analyzed is False: |
286 | | - self._cmd("aaa") |
287 | | - self.analyzed = True |
288 | | - return fun(self, *args, **kwargs) |
289 | | - return wrapper |
290 | | - |
291 | 283 | @cached_property |
292 | 284 | def binfo(self) -> Dict[str, str]: |
293 | 285 | return self._cmdj("iIj") |
@@ -316,46 +308,50 @@ def symbols(self) -> Dict[str, Symbol]: |
316 | 308 | return {dic['name']: Symbol(**dic).vaddr for dic in sym_lst} |
317 | 309 |
|
318 | 310 | @cached_property |
319 | | - @aaa |
| 311 | + @wrap_aaa |
320 | 312 | def functions(self) -> Dict[str, Function]: |
321 | 313 | fcn_lst = self._cmdj("aflj") |
322 | 314 | return {dic['name']: Function(**dic) for dic in fcn_lst} |
323 | 315 |
|
324 | 316 | @cached_property |
325 | | - @aaa |
| 317 | + @wrap_aaa |
326 | 318 | def flags(self) -> List[Flag]: |
327 | 319 | return [Flag(**dic) for dic in self._cmdj("fj")] |
328 | 320 |
|
329 | 321 | @cached_property |
330 | | - @aaa |
| 322 | + @wrap_aaa |
331 | 323 | def xrefs(self) -> List[Xref]: |
332 | 324 | return [Xref(**dic) for dic in self._cmdj("axj")] |
333 | 325 |
|
334 | | - @aaa |
| 326 | + @wrap_aaa |
| 327 | + @wrap_arg_addr |
335 | 328 | def get_fcn_bbs(self, addr: int): |
336 | 329 | '''list basic blocks of function''' |
337 | 330 | return [BasicBlock(**dic) for dic in self._cmdj(f"afbj @ {addr}")] |
338 | 331 |
|
339 | | - @aaa |
340 | | - def get_bb_at(self, addr: int): |
| 332 | + @wrap_aaa |
| 333 | + @wrap_arg_addr |
| 334 | + def get_bb(self, addr: int): |
341 | 335 | '''get basic block at address''' |
342 | 336 | try: |
343 | 337 | dic = self._cmdj(f"afbj. {addr}")[0] |
344 | 338 | return BasicBlock(**dic) |
345 | 339 | except IndexError: |
346 | 340 | pass |
347 | 341 |
|
348 | | - @aaa |
349 | | - def get_fcn_at(self, addr: int): |
| 342 | + @wrap_aaa |
| 343 | + @wrap_arg_addr |
| 344 | + def get_fcn(self, addr: int): |
350 | 345 | try: |
351 | 346 | dic = self._cmdj(f"afij {addr}")[0] # afi show function information |
352 | 347 | return Function(**dic) |
353 | 348 | except IndexError: |
354 | 349 | pass |
355 | 350 |
|
356 | | - @aaa |
357 | | - def anal_op(self, target: Union[int, Instruction]): |
358 | | - addr = target.offset if isinstance(target, Instruction) else target |
| 351 | + @wrap_aaa |
| 352 | + @wrap_arg_addr |
| 353 | + def anal_op(self, addr: int): |
| 354 | + '''r2 opcode analysis (detail about an instruction) at address''' |
359 | 355 | dic = self._cmdj(f"aoj @ {addr}")[0] |
360 | 356 | return AnalOp(**dic) |
361 | 357 |
|
@@ -427,13 +423,12 @@ def _backtrace_fuzzy(self, at: int = None, depth: int = 128) -> Optional[CallSta |
427 | 423 | cursp += wordsize |
428 | 424 | return frame |
429 | 425 |
|
430 | | - def set_backtrace(self, target: Union[int, str]): |
| 426 | + @wrap_arg_addr |
| 427 | + def set_backtrace(self, addr: int): |
431 | 428 | '''Set backtrace at target address before executing''' |
432 | | - if isinstance(target, str): |
433 | | - target = self.where(target) |
434 | 429 | def bt_hook(__ql: 'R2Qiling', *args): |
435 | 430 | print(self._backtrace_fuzzy()) |
436 | | - self.ql.hook_address(bt_hook, target) |
| 431 | + self.ql.hook_address(bt_hook, addr) |
437 | 432 |
|
438 | 433 | def disassembler(self, ql: 'R2Qiling', addr: int, size: int, filt: Pattern[str]=None) -> int: |
439 | 434 | '''A human-friendly monkey patch of QlArchUtils.disassembler powered by r2, can be used for hook_code |
@@ -468,9 +463,9 @@ def enable_trace(self, mode='full'): |
468 | 463 | elif mode == 'history': |
469 | 464 | trace.enable_history_trace(self.ql) |
470 | 465 |
|
471 | | - def deflat(self, target: Union[int, R2Data]): |
472 | | - '''Create deflator with self r2 instance, will patch ql code''' |
473 | | - addr = target if isinstance(target, int) else target.start_ea |
| 466 | + @wrap_arg_addr |
| 467 | + def deflat(self, addr: int): |
| 468 | + '''Deflat function at given address, will patch ql code''' |
474 | 469 | deflator = R2Deflator(self) |
475 | 470 | deflator.parse_blocks_for_deobf(addr) |
476 | 471 | deflator._search_path() |
|
0 commit comments