|
41 | 41 | from . import binaryview |
42 | 42 | from . import variable |
43 | 43 | from . import basicblock |
| 44 | +from . import log |
44 | 45 |
|
45 | 46 | RegisterIndex = NewType('RegisterIndex', int) |
46 | 47 | RegisterStackIndex = NewType('RegisterStackIndex', int) |
@@ -412,6 +413,117 @@ def finalize(self) -> None: |
412 | 413 | core.BNAnalyzeBasicBlocksContextFinalize(self._handle) |
413 | 414 |
|
414 | 415 |
|
| 416 | +@dataclass |
| 417 | +class FunctionLifterContext: |
| 418 | + """Used by ``lift_function`` and contains contextual information for function-level lifting |
| 419 | +
|
| 420 | + .. note:: This class is meant to be used by Architecture plugins only |
| 421 | + """ |
| 422 | + |
| 423 | + _handle: core.BNFunctionLifterContext |
| 424 | + _function: "function.Function" |
| 425 | + _platform: "platform.Platform" |
| 426 | + _logger: "log.Logger" |
| 427 | + _blocks: List["basicblock.BasicBlock"] |
| 428 | + _contextual_returns: Dict["function.ArchAndAddr", bool] |
| 429 | + _inline_remapping: Dict["function.ArchAndAddr", "function.ArchAndAddr"] |
| 430 | + _user_indirect_branches: Dict["function.ArchAndAddr", Set["function.ArchAndAddr"]] |
| 431 | + _auto_indirect_branches: Dict["function.ArchAndAddr", Set["function.ArchAndAddr"]] |
| 432 | + _inlined_calls: Set[int] |
| 433 | + |
| 434 | + @staticmethod |
| 435 | + def from_core_struct(func: core.BNLowLevelILFunction, |
| 436 | + bn_fl_context: core.BNFunctionLifterContext) -> "FunctionLifterContext": |
| 437 | + """Create a FunctionLifterContext from a core.BNFunctionLifterContext structure.""" |
| 438 | + |
| 439 | + session_id = core.BNLoggerGetSessionId(bn_fl_context.logger) |
| 440 | + name = core.BNLoggerGetName(bn_fl_context.logger) |
| 441 | + logger = log.Logger(session_id, name, handle=core.BNNewLoggerReference(bn_fl_context.logger)) |
| 442 | + |
| 443 | + plat = platform.CorePlatform._from_cache(core.BNNewPlatformReference(bn_fl_context.platform)) |
| 444 | + blocks = [] |
| 445 | + for i in range(0, bn_fl_context.basicBlockCount): |
| 446 | + blocks.append( |
| 447 | + basicblock.BasicBlock( |
| 448 | + core.BNNewBasicBlockReference(bn_fl_context.basicBlocks[i]) |
| 449 | + ) |
| 450 | + ) |
| 451 | + |
| 452 | + contextual_returns = {} |
| 453 | + for i in range(0, bn_fl_context.contextualFunctionReturnCount): |
| 454 | + loc = function.ArchAndAddr( |
| 455 | + CoreArchitecture._from_cache(bn_fl_context.contextualFunctionReturnLocations[i].arch), |
| 456 | + bn_fl_context.contextualFunctionReturnLocations[i].address, |
| 457 | + ) |
| 458 | + |
| 459 | + contextual_returns[loc] = bn_fl_context._contextualFunctionReturnValues[i] |
| 460 | + |
| 461 | + inline_remapping = {} |
| 462 | + for i in range(0, bn_fl_context.inlinedRemappingEntryCount): |
| 463 | + key = function.ArchAndAddr( |
| 464 | + CoreArchitecture._from_cache(bn_fl_context.inlinedRemappingKeys[i].arch), |
| 465 | + bn_fl_context.inlinedRemappingKeys[i].address, |
| 466 | + ) |
| 467 | + dest = function.ArchAndAddr( |
| 468 | + CoreArchitecture._from_cache(bn_fl_context.inlinedRemappingEntries[i].destination.arch), |
| 469 | + bn_fl_context.inlinedRemappingEntries[i].destination.address, |
| 470 | + ) |
| 471 | + inline_remapping[src] = dest |
| 472 | + |
| 473 | + user_indirect_branches = {} |
| 474 | + auto_indirect_branches = {} |
| 475 | + for i in range(0, bn_fl_context.indirectBranchesCount): |
| 476 | + src = function.ArchAndAddr( |
| 477 | + CoreArchitecture._from_cache(bn_fl_context.indirectBranches[i].sourceArch), |
| 478 | + bn_fl_context.indirectBranches[i].sourceAddr, |
| 479 | + ) |
| 480 | + |
| 481 | + dest = function.ArchAndAddr( |
| 482 | + CoreArchitecture._from_cache(bn_fl_context.indirectBranches[i].destArch), |
| 483 | + bn_fl_context.indirectBranches[i].dests[j].destAddr, |
| 484 | + ) |
| 485 | + |
| 486 | + if bn_fl_context.indirectBranches[i].dests[j].isAutoDefined: |
| 487 | + if src not in auto_indirect_branches: |
| 488 | + auto_indirect_branches[src] = set() |
| 489 | + auto_indirect_branches[src].add(dest) |
| 490 | + else: |
| 491 | + if src not in user_indirect_branches: |
| 492 | + user_indirect_branches[src] = set() |
| 493 | + user_indirect_branches[src].add(dest) |
| 494 | + |
| 495 | + |
| 496 | + inlined_calls = set() |
| 497 | + for i in range(0, bn_fl_context.inlinedCallsCount): |
| 498 | + inlined_calls.add(bn_fl_context.inlinedCalls[i]) |
| 499 | + |
| 500 | + return FunctionLifterContext( |
| 501 | + _handle=bn_fl_context, |
| 502 | + _function=lowlevelil.LowLevelILFunction( |
| 503 | + plat.arch, core.BNNewLowLevelILFunctionReference(func) |
| 504 | + ), |
| 505 | + _platform=plat, |
| 506 | + _logger=logger, |
| 507 | + _blocks=blocks, |
| 508 | + _contextual_returns=contextual_returns, |
| 509 | + _inline_remapping=inline_remapping, |
| 510 | + _user_indirect_branches=user_indirect_branches, |
| 511 | + _auto_indirect_branches=auto_indirect_branches, |
| 512 | + _inlined_calls=inlined_calls, |
| 513 | + ) |
| 514 | + |
| 515 | + def prepare_block_translation(self, function, arch, address): |
| 516 | + """Prepare block for translation""" |
| 517 | + |
| 518 | + core.BNPrepareBlockTranslation(function.handle, arch.handle, address) |
| 519 | + |
| 520 | + @property |
| 521 | + def blocks(self) -> List["basicblock.BasicBlock"]: |
| 522 | + """Get the list of basic blocks in this context.""" |
| 523 | + |
| 524 | + return self._blocks |
| 525 | + |
| 526 | + |
415 | 527 | @dataclass(frozen=True) |
416 | 528 | class RegisterInfo: |
417 | 529 | full_width_reg: RegisterName |
@@ -611,6 +723,7 @@ def __init__(self): |
611 | 723 | self._get_instruction_low_level_il |
612 | 724 | ) |
613 | 725 | self._cb.analyzeBasicBlocks = self._cb.analyzeBasicBlocks.__class__(self._analyze_basic_blocks) |
| 726 | + self._cb.liftFunction = self._cb.liftFunction.__class__(self._lift_function) |
614 | 727 | self._cb.getRegisterName = self._cb.getRegisterName.__class__(self._get_register_name) |
615 | 728 | self._cb.getFlagName = self._cb.getFlagName.__class__(self._get_flag_name) |
616 | 729 | self._cb.getFlagWriteTypeName = self._cb.getFlagWriteTypeName.__class__(self._get_flag_write_type_name) |
@@ -1084,6 +1197,15 @@ def _analyze_basic_blocks(self, ctx, func, ptr_bn_bb_context): |
1084 | 1197 | except: |
1085 | 1198 | log_error_for_exception("Unhandled Python exception in Architecture._analyze_basic_blocks") |
1086 | 1199 |
|
| 1200 | + def _lift_function(self, ctx, func, ptr_bn_fl_context): |
| 1201 | + try: |
| 1202 | + bn_fl_context = ptr_bn_fl_context.contents |
| 1203 | + context = FunctionLifterContext.from_core_struct(func, bn_fl_context) |
| 1204 | + return self.lift_function(lowlevelil.LowLevelILFunction(arch=self, handle=core.BNNewLowLevelILFunctionReference(func)), context) |
| 1205 | + except: |
| 1206 | + log_error_for_exception("Unhandled Python exception in Architecture._lift_function") |
| 1207 | + return False |
| 1208 | + |
1087 | 1209 | def _get_register_name(self, ctxt, reg): |
1088 | 1210 | try: |
1089 | 1211 | if reg in self._regs_by_index: |
@@ -1814,6 +1936,23 @@ def analyze_basic_blocks(self, func: 'function.Function', context: BasicBlockAna |
1814 | 1936 | except: |
1815 | 1937 | log_error_for_exception("Unhandled Python exception in Architecture.analyze_basic_blocks") |
1816 | 1938 |
|
| 1939 | + def lift_function(self, func: "lowlevelil.LowLevelILFunction", context: FunctionLifterContext) -> bool: |
| 1940 | + """ |
| 1941 | + ``lift_function`` performs lifting of the function and commits the results to the function analysis |
| 1942 | +
|
| 1943 | + .. note:: Architecture subclasses should only implement this method if function-level analysis is required |
| 1944 | +
|
| 1945 | + :param LowLevelILFunction func: the function to analyze |
| 1946 | + :param FunctionLifterContext context: the lifting context |
| 1947 | + :return: True on success, False otherwise |
| 1948 | + """ |
| 1949 | + |
| 1950 | + try: |
| 1951 | + return core.BNArchitectureDefaultLiftFunction(func.handle, context._handle) |
| 1952 | + except: |
| 1953 | + log_error_for_exception("Unhandled Python exception in Architecture.lift_function") |
| 1954 | + return False |
| 1955 | + |
1817 | 1956 | def get_low_level_il_from_bytes(self, data: bytes, addr: int) -> 'lowlevelil.LowLevelILInstruction': |
1818 | 1957 | """ |
1819 | 1958 | ``get_low_level_il_from_bytes`` converts the instruction in bytes to ``il`` at the given virtual address |
|
0 commit comments