Skip to content

Commit

Permalink
IDA 9 support (#108)
Browse files Browse the repository at this point in the history
* IDA 9 support

* Fix stack variables

* Fix an off-by-one

* Fix enum listing

* Fix enum hooks

* Fix struct setting (95%)

* Fix stack var setting

* Maintain minimal backwards compatability

* More fixes to structs

* Update the readme

* Major bump
  • Loading branch information
mahaloz authored Sep 29, 2024
1 parent 0647570 commit 7ca6534
Show file tree
Hide file tree
Showing 11 changed files with 640 additions and 293 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The minimum Python version is **3.10**. **If you plan on using libbs alone (with
you must do `libbs --install` after pip install**. This will copy the appropriate files to your decompiler.

## Supported Decompilers
- IDA Pro: **8.4 >= V >= 7.3**
- IDA Pro: **>= 8.4** (if you have an older version, use `v1.26.0`)
- Binary Ninja: **>= 2.4**
- angr-management: **>= 9.0**
- Ghidra: **>= 11.1**
Expand Down
7 changes: 5 additions & 2 deletions examples/change_watcher_plugin/bs_change_watcher/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

__version__ = "0.0.1"


def create_plugin(*args, **kwargs):
"""
This is the entry point that all decompilers will call in various ways. To remain agnostic,
Expand Down Expand Up @@ -33,11 +32,15 @@ def create_plugin(*args, **kwargs):
)
}

def _start_watchers(*x, **y):
deci.start_artifact_watchers()
deci.info("Artifact watchers started!")

# register a menu to open when you right click on the psuedocode view
deci.gui_register_ctx_menu(
"StartArtifactChangeWatcher",
"Start watching artifact changes",
lambda *x, **y: deci.start_artifact_watchers(),
_start_watchers,
category="ArtifactChangeWatcher"
)

Expand Down
2 changes: 1 addition & 1 deletion libbs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "1.26.0"
__version__ = "2.0.0"


import logging
Expand Down
9 changes: 5 additions & 4 deletions libbs/api/artifact_lifter.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
import typing

from libbs.artifacts import StackVariable, Artifact
from libbs.artifacts import StackVariable, Artifact, FunctionArgument, StructMember
from libbs.api.type_parser import CTypeParser

if typing.TYPE_CHECKING:
Expand Down Expand Up @@ -105,9 +105,10 @@ def _lift_or_lower_artifact(self, artifact, mode):
setattr(lifted_art, attr, self._lift_or_lower_artifact(attr_val, mode))
# nested args, stack_vars, or struct_members
elif isinstance(attr_val, dict):
nested_arts = {
k: self._lift_or_lower_artifact(v, mode) for k, v in attr_val.items()
}
nested_arts = {}
for k, v in attr_val.items():
nested_art = self._lift_or_lower_artifact(v, mode)
nested_arts[nested_art.offset if isinstance(nested_art, (StackVariable, FunctionArgument, StructMember)) else k] = nested_art
setattr(lifted_art, attr, nested_arts)

return lifted_art
2 changes: 1 addition & 1 deletion libbs/api/decompiler_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,7 @@ def get_identifiers(artifact: Artifact) -> Tuple:
elif isinstance(artifact, FunctionArgument):
# TODO: add addr to function arguments
return (artifact.offset,)
elif isinstance(artifact, (Struct, Enum)):
elif isinstance(artifact, (Struct, Enum, Typedef)):
return (artifact.name,)

def get_defined_type(self, type_str) -> Optional[Artifact]:
Expand Down
2 changes: 1 addition & 1 deletion libbs/artifacts/artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Artifact:
ATTR_ATTR_IGNORE_SET
)

def __init__(self, last_change: Optional[datetime.datetime] = None, **kwargs):
def __init__(self, last_change: Optional[datetime.datetime] = None):
self.last_change = last_change
self._attr_ignore_set = set()

Expand Down
18 changes: 18 additions & 0 deletions libbs/artifacts/typedef.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,21 @@ def __init__(

def __str__(self):
return f"<TypeDef: {self.name}={self.type}>"

def nonconflict_merge(self, typedef2: "Typedef", **kwargs):
typedef1: Typedef = self.copy()
if not typedef2 or typedef1 == typedef2:
return typedef1.copy()

master_state = kwargs.get("master_state", None)
local_names = {typedef1.name}
if master_state:
for _, typedef in master_state.get_typedefs().items():
local_names.add(typedef.name)
else:
local_names = {typedef1.name}

if typedef2.name not in local_names:
typedef1.name = typedef2.name
typedef1.type = typedef2.type
return typedef1
30 changes: 23 additions & 7 deletions libbs/decompilers/ida/artifact_lifter.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,45 @@

l = logging.getLogger(name=__name__)


class IDAArtifactLifter(ArtifactLifter):
lift_map = {
"__int64": "long long",
"__int32": "int",
"__int16": "short",
"__int8": "char",
"_BOOL": "bool",
"_BOOL1": "bool",
"_BOOL2": "short",
"_BOOL4": "int",
"_BOOL8": "long long",
"_BYTE": "char",
"_WORD": "unsigned short",
"_DWORD": "unsigned int",
"_QWORD": "unsigned long long",
}

def __init__(self, deci):
super(IDAArtifactLifter, self).__init__(deci)

def lift_type(self, type_str: str) -> str:
for ida_t, bs_t in self.lift_map.items():
type_str = type_str.replace(ida_t, bs_t)

return type_str
return self.lift_ida_type(type_str)

def lift_stack_offset(self, offset: int, func_addr: int) -> int:
return offset
from . import compat
return compat.ida_to_bs_stack_offset(func_addr, offset)

def lower_type(self, type_str: str) -> str:
# no need to lift type for IDA, since it parses normal C
# types by default
return type_str

def lower_stack_offset(self, offset: int, func_addr: int) -> int:
return abs(offset) #compat.ida_to_angr_stack_offset(func_addr, offset)
from . import compat
return compat.bs_to_ida_stack_offset(self.lower_addr(func_addr), offset)

@staticmethod
def lift_ida_type(type_str: str) -> str:
for ida_t, bs_t in IDAArtifactLifter.lift_map.items():
type_str = type_str.replace(ida_t, bs_t)

return type_str
Loading

0 comments on commit 7ca6534

Please sign in to comment.