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

Absorb changes #13

Open
wants to merge 50 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
6cc56b6
Filter vtable & typeinfo
HexRabbit Aug 13, 2020
a3da024
Helper.py: Fix error when get_array_element returns int.
CycleOfTheAbsurd Aug 18, 2020
9b5ad90
improved score-table
sfinktah Jan 14, 2021
6bcfab3
add field Ctrl+X on struct window
Nrtyck Feb 25, 2021
9f8dae8
now you can load structures and adjust them
sfinktah Mar 20, 2021
c95c02d
Fix double click jump not tracking history correctly on 7.6
willxinc May 12, 2021
c695392
fixed sized based struct member naming
sfinktah May 20, 2021
7ea24d9
Merge remote-tracking branch 'sfinktah/sfink-load-struct'
BlueAmulet Jun 22, 2021
d82ad0f
Merge remote-tracking branch 'willxinc/master'
BlueAmulet Jun 22, 2021
d33f859
Merge remote-tracking branch 'Nrtyck/master'
BlueAmulet Jun 22, 2021
1bd6cb5
Merge remote-tracking branch 'CycleOfTheAbsurd/master'
BlueAmulet Jun 22, 2021
e9c1ab6
Merge remote-tracking branch 'HexRabbit/filter-vtable'
BlueAmulet Jun 22, 2021
1695881
Various improvements
BlueAmulet Jun 22, 2021
c4b73a6
Escape single colon in names
giladreti Jan 25, 2022
6fa36e5
Add RenameMemberFromFunctionName action.
haltarkon Jun 18, 2022
a9960cb
Merge pull request #1 from haltarkon/master
oopsmishap Sep 18, 2022
5ca4faf
Merge pull request #2 from giladreti/bugfix/escape-single-colon-in-names
oopsmishap Sep 18, 2022
0ba08f7
Merge pull request #3 from willxinc/master
oopsmishap Sep 18, 2022
b89281b
Merge pull request #4 from sfinktah/sfinktah-better-score-table
oopsmishap Sep 18, 2022
a289f98
Merge branch 'sfink-load-struct' of https://github.com/sfinktah/HexRa…
Sep 18, 2022
342bf87
Merge pull request #6 from oopsmishap/sfinktah-sfink-load-struct
oopsmishap Sep 18, 2022
783410f
Merge pull request #7 from BlueAmulet/master
oopsmishap Sep 18, 2022
8a27e45
Update readme.md
oopsmishap Sep 18, 2022
b12eb7f
Merge pull request #8 from oopsmishap/patch-1
oopsmishap Sep 18, 2022
abff3d7
Added Templated Types View to Structure Builder
Oct 30, 2022
1652066
Merge pull request #9 from oopsmishap/templated-types
oopsmishap Oct 30, 2022
5199c8e
Added type preview to template view
Oct 31, 2022
fd45c56
Templated types preview
oopsmishap Oct 31, 2022
05cb723
Updated Readme, Added Open TOML
Nov 1, 2022
d149e1d
Readme formatting
Nov 1, 2022
2438b82
Readme refactor
Nov 1, 2022
5f27eaf
updated readme and added requirements and config
herrcore Nov 5, 2022
784f8a7
Merge pull request #11 from herrcore/master
oopsmishap Nov 5, 2022
3751290
Old python syntax in negative_offsets.py causing `ContainingRecord` f…
Jan 20, 2023
14d63ad
Changed Structure View color scheme
oopsmishap Feb 4, 2023
e92fdcf
Refactored settings to point to $IDAUSR
oopsmishap Feb 7, 2023
414db17
renames default vtable functions based on vtable name
oopsmishap Feb 7, 2023
2965510
edited readme for reflected changes in e92fdcf
oopsmishap Feb 7, 2023
7235e02
Allow `:` in type name
oopsmishap Mar 9, 2023
3c3e918
updated type regex, added warning popup for invalid type
oopsmishap Mar 9, 2023
d3a40bf
Added rust templated types
oopsmishap Aug 18, 2023
3b925d7
Merge pull request #14 from oopsmishap/13-add-more-types
oopsmishap Aug 18, 2023
5c5496b
Fixed form_type warning
OrbitOn-line Sep 6, 2023
73ac0cc
Improved and refactored MemberDoubleClick
OrbitOn-line Sep 6, 2023
a847c9b
Fixed overlapping hotkeys
Mar 26, 2024
f9122f4
Use structure selection dialog to load the structure into StructureBu…
Mar 26, 2024
0e5a3dd
Support IDA 9.0
NyaMisty Aug 16, 2024
605a75f
Fix IDA 9.0 procName shim support
NyaMisty Dec 24, 2024
16124f0
More fixes for IDA 9.0 & Various minor fix
NyaMisty Dec 24, 2024
cd3e429
Copy all tinfo_t object when passing out to avoid IDA interr 918
NyaMisty Dec 27, 2024
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

# Apple crap
.DS_Store
.AppleDouble
.LSOverride

# User-specific files
*.suo
*.user
Expand Down
25 changes: 25 additions & 0 deletions HexRaysPyTools/callbacks/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,31 @@ def update(self, ctx):
return idaapi.AST_ENABLE_FOR_WIDGET
return idaapi.AST_DISABLE_FOR_WIDGET

class HexRaysXrefAction(Action):
"""
Wrapper around Action. Represents Action which can be added to menu after right-clicking in Decompile window.
Has `check` method that should tell whether Action should be added to popup menu when different items
are right-clicked.
Children of this class can also be fired by hot-key without right-clicking if one provided in `hotkey`
static member.
"""

def __init__(self):
super(HexRaysXrefAction, self).__init__()

def activate(self, ctx):
# type: (idaapi.action_activation_ctx_t) -> None
raise NotImplementedError

def check(self, hx_view):
# type: (idaapi.vdui_t) -> bool
raise NotImplementedError

def update(self, ctx):
if ctx.widget_type == idaapi.BWN_PSEUDOCODE or ctx.widget_type == (getattr(idaapi, 'BWN_STRUCTS', None) or getattr(idaapi, 'BWN_LOCTYPS')) :
return idaapi.AST_ENABLE_FOR_WIDGET
return idaapi.AST_DISABLE_FOR_WIDGET


class HexRaysPopupRequestHandler(HexRaysEventHandler):
"""
Expand Down
93 changes: 77 additions & 16 deletions HexRaysPyTools/callbacks/member_double_click.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,104 @@
import idaapi

import idc
import ida_hexrays
from . import callbacks
import HexRaysPyTools.core.helper as helper

CALLED_FROM_COMMENT = "CALLED_FROM =>"

class MemberDoubleClick(callbacks.HexRaysEventHandler):
def __init__(self):
super(MemberDoubleClick, self).__init__()

def _get_target_func_comment(self, func_ea, item):
target_func = idaapi.decompile(func_ea)
tl = ida_hexrays.treeloc_t()
tl.ea = target_func.body.ea
tl.itp = ida_hexrays.ITP_SEMI
old_comment = target_func.get_user_cmt(tl, 0)
jmp_src = item.e.ea
src_as_string = "0x{:x}".format(jmp_src)
if old_comment is None:
old_comment = CALLED_FROM_COMMENT
if src_as_string not in old_comment:
return "{} | {}".format(old_comment, src_as_string)
return old_comment

def _update_func_comment_and_jump(self, func_ea, new_comment):
target_func = idaapi.decompile(func_ea)
tl = ida_hexrays.treeloc_t()
tl.ea = target_func.body.ea
tl.itp = ida_hexrays.ITP_SEMI
target_func.set_user_cmt(tl, new_comment)
target_func.save_user_cmts()
idaapi.jumpto(func_ea)

def _handle_member_pointer(self, item):
if item.e.x.op == idaapi.cot_memref and item.e.x.x.op == idaapi.cot_memptr:
return item.e.x.type.get_pointed_object(), item.e.m, item.e.x.x.x.type.get_pointed_object(), item.e.x.x.m
elif item.e.x.op == idaapi.cot_memptr:
vtable_tinfo = item.e.x.type
if vtable_tinfo.is_ptr():
vtable_tinfo = vtable_tinfo.get_pointed_object()
return vtable_tinfo, item.e.m, item.e.x.x.type.get_pointed_object(), item.e.x.m

def handle(self, event, *args):
hx_view = args[0]
item = hx_view.item

if item.citype == idaapi.VDI_EXPR and item.e.op in (idaapi.cot_memptr, idaapi.cot_memref):
# Look if we double clicked on expression that is member pointer. Then get tinfo_t of the structure.
# After that remove pointer and get member name with the same offset
if item.e.x.op == idaapi.cot_memref and item.e.x.x.op == idaapi.cot_memptr:
vtable_tinfo = item.e.x.type.get_pointed_object()
method_offset = item.e.m
class_tinfo = item.e.x.x.x.type.get_pointed_object()
vtable_offset = item.e.x.x.m
elif item.e.x.op == idaapi.cot_memptr:
vtable_tinfo = item.e.x.type
if vtable_tinfo.is_ptr():
vtable_tinfo = vtable_tinfo.get_pointed_object()
method_offset = item.e.m
class_tinfo = item.e.x.x.type.get_pointed_object()
vtable_offset = item.e.x.m
if item.e.x.op in (idaapi.cot_memref, idaapi.cot_memptr):
vtable_tinfo, method_offset, class_tinfo, vtable_offset = self._handle_member_pointer(item)
else:
func_offset = item.e.m
struct_tinfo = item.e.x.type.get_pointed_object()
item_ea = item.e.ea if item.e.ea != idaapi.BADADDR else idc.here()

func_ea = helper.choose_virtual_func_address(helper.get_member_name(struct_tinfo, func_offset))
if func_ea:
idaapi.jumpto(func_ea)
else:
self._process_commented_address(struct_tinfo, func_offset, item)
return 0

func_name = helper.get_member_name(vtable_tinfo, method_offset)
func_ea = helper.choose_virtual_func_address(func_name, class_tinfo, vtable_offset)

if not func_ea:
func_ea = self._get_commented_address_from_vtable(vtable_tinfo, method_offset)

if func_ea:
idaapi.open_pseudocode(func_ea, 0)
new_comment = self._get_target_func_comment(func_ea, item)
self._update_func_comment_and_jump(func_ea, new_comment)
return 1

def _process_commented_address(self, struct_tinfo, func_offset, item):
sid = idc.get_struc_id(struct_tinfo.dstr())
if sid != idaapi.BADADDR:
comment = helper._get_member_cmt(struct_tinfo, func_offset)
# sptr = idaapi.get_struc(sid)
# mid = idaapi.get_member_id(sptr, func_offset)
# comment = idaapi.get_member_cmt(mid, False)
if comment:
try:
commented_address = int(comment, 16)
new_comment = self._get_target_func_comment(commented_address, item)
self._update_func_comment_and_jump(commented_address, new_comment)
except:
pass

def _get_commented_address_from_vtable(self, vtable_tinfo, method_offset):
sid = idc.get_struc_id(vtable_tinfo.get_type_name())
if sid != idaapi.BADADDR:
# sptr = idaapi.get_struc(sid)
# mid = idaapi.get_member_id(sptr, method_offset)
# comment = idaapi.get_member_cmt(mid, False)
comment = helper._get_member_cmt(vtable_tinfo, method_offset)
if comment:
try:
return int(comment, 16)
except:
return None
return None

callbacks.hx_callback_manager.register(idaapi.hxe_double_click, MemberDoubleClick())
6 changes: 3 additions & 3 deletions HexRaysPyTools/callbacks/negative_offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def find_containing_structures(self, type_library):
if not target_tinfo.get_named_type(type_library, self.tinfo.dstr()):
print("[Warning] Such type doesn't exist in '{0}' library".format(type_library.name))
return result
for ordinal in range(1, idaapi.get_ordinal_qty(type_library)):
for ordinal in range(1, helper.get_ordinal_limit(type_library)):
parent_tinfo.create_typedef(type_library, ordinal)
if parent_tinfo.get_size() >= min_struct_size:
for offset, name in find_deep_members(parent_tinfo, target_tinfo):
Expand Down Expand Up @@ -175,7 +175,7 @@ def create_containing_record(self, expression, index, offset):
new_cexpr_call.a.push_back(arg_field)
new_cexpr_call.thisown = False

parent = reversed(self.parents).next().cexpr
parent = next(reversed(self.parents)).cexpr

diff = negative_lvar.offset + offset
if diff:
Expand Down Expand Up @@ -226,7 +226,7 @@ def visit_expr(self, expression):
parent_tinfo.get_udt_details(udt_data)
udt_member = [x for x in udt_data if x.name == member_name]
if udt_member:
tinfo = udt_member[0].type
tinfo = udt_member[0].type.copy()
self.result[idx] = NegativeLocalInfo(
tinfo,
parent_tinfo,
Expand Down
2 changes: 1 addition & 1 deletion HexRaysPyTools/callbacks/new_field_creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def activate(self, ctx):

result = self.parse_declaration(declaration)
if result is None:
logger.warn("Bad member declaration")
logger.warning("Bad member declaration")
return

field_tinfo, field_name = result
Expand Down
62 changes: 60 additions & 2 deletions HexRaysPyTools/callbacks/renames.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def __extract_rename_info(cfunc, ctree_item):

class RenameInside(actions.HexRaysPopupAction):
description = "Rename inside argument"
hotkey = "Shift+N"
hotkey = "Shift+Alt+N"

def __init__(self):
super(RenameInside, self).__init__()
Expand Down Expand Up @@ -159,6 +159,63 @@ def __extract_rename_info(cfunc, ctree_item):
if arg_name and _should_be_renamed(lvar.name, arg_name):
return lvar, arg_name.lstrip("_")

class RenameMemberFromFunctionName(actions.HexRaysPopupAction):
description = "Take name from function"
hotkey = "Ctrl+Alt+N"

def __init__(self):
super(RenameMemberFromFunctionName, self).__init__()

def check(self, hx_view):
return self.__extract_rename_info(hx_view.cfunc, hx_view.item) is not None

def activate(self, ctx):
hx_view = idaapi.get_widget_vdui(ctx.widget)
info = self.__extract_rename_info(hx_view.cfunc, hx_view.item)

if info:
mname = info.name;
sname = re.sub('struct ', '', info.struct_name);

if not re.search("_vtbl$", sname):
mname = re.sub('^(get|set)*', 'm', mname, flags=re.IGNORECASE)

if not helper.change_member_name(sname, info.offset, mname):
mname = mname + '_' + hex(info.offset)[2:]
helper.change_member_name(sname, info.offset, mname)

hx_view.refresh_view(True)

@staticmethod
def __extract_rename_info(cfunc, ctree_item):
# type: (idaapi.cfunc_t, idaapi.ctree_item_t) -> api.StructRefObject

if ctree_item.citype != idaapi.VDI_EXPR:
return

expr = ctree_item.it.to_specific_type
if expr.op == idaapi.cot_memptr:
t = expr.x.type.get_pointed_object()
elif expr.op == idaapi.cot_memref:
t = expr.x.type
else:
return

# Get name string
result = api.StructRefObject(t.dstr(), expr.m)
result.name = idaapi.get_name(cfunc.entry_ea)
if idaapi.is_valid_typename(result.name):
return result

result.name = idc.demangle_name(result.name, idc.get_inf_attr(3)) # Get only main name
if result.name is None:
return

result.name = re.sub('^.*:', '', result.name)
if result.name is None:
return

return result

class _RenameUsingAssertVisitor(idaapi.ctree_parentee_t):

Expand Down Expand Up @@ -196,7 +253,7 @@ def __add_func_name(self, arg_expr):
# convert bytes to str (python 3)
new_name = new_name.decode('ascii')
if not idaapi.is_valid_typename(new_name):
logger.warn("Argument has a weird name `{}` at {}".format(
logger.warning("Argument has a weird name `{}` at {}".format(
new_name, helper.to_hex(helper.find_asm_address(arg_expr, self.parents))))
return

Expand Down Expand Up @@ -345,5 +402,6 @@ def activate(self, ctx):
actions.action_manager.register(RenameOther())
actions.action_manager.register(RenameInside())
actions.action_manager.register(RenameOutside())
actions.action_manager.register(RenameMemberFromFunctionName())
actions.action_manager.register(RenameUsingAssert())
actions.action_manager.register(PropagateName())
4 changes: 2 additions & 2 deletions HexRaysPyTools/callbacks/scanners.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def activate(self, ctx):

class DeepScanVariable(Scanner):
description = "Deep Scan Variable"
hotkey = "shift+F"
hotkey = "Shift+Alt+F"

def __init__(self):
super(DeepScanVariable, self).__init__()
Expand Down Expand Up @@ -127,7 +127,7 @@ def activate(self, ctx):
NewDeepSearchVisitor(cfunc, 0, obj, cache.temporary_structure).process()

def update(self, ctx):
if ctx.form_type == idaapi.BWN_FUNCS:
if ctx.widget_type == idaapi.BWN_FUNCS:
idaapi.attach_action_to_popup(ctx.widget, None, self.name)
return idaapi.AST_ENABLE_FOR_WIDGET
return idaapi.AST_DISABLE_FOR_WIDGET
Expand Down
Loading