Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IDA 9 support #108

Merged
merged 11 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading