Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 680b6ac

Browse files
Arnaud DiederenArnaud Diederen
authored andcommitted
Backported fixes
1 parent f7e52a0 commit 680b6ac

4 files changed

Lines changed: 157 additions & 18 deletions

File tree

examples/hexrays/vds17.py

Lines changed: 155 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,21 @@
1313

1414
import ida_idaapi
1515
import ida_hexrays
16+
import ida_lines
17+
import ida_typeinf
1618

1719
# --------------------------------------------------------------------------
1820
class func_stroff_ah_t(ida_kernwin.action_handler_t):
1921
def __init__(self):
2022
ida_kernwin.action_handler_t.__init__(self)
2123

2224
def activate(self, ctx):
23-
# get current item
25+
# get the current item
2426
vu = ida_hexrays.get_widget_vdui(ctx.widget)
25-
vu.get_current_item(idaapi.USE_KEYBOARD)
27+
vu.get_current_item(ida_hexrays.USE_KEYBOARD)
2628

27-
# check the current item is union field
29+
# REGION1, will be referenced latter
30+
# check that the current item is a union field
2831
if not vu.item.is_citem():
2932
return 0
3033
e = vu.item.e
@@ -41,8 +44,10 @@ def activate(self, ctx):
4144
break
4245
if not e.type.is_udt():
4346
return 0
47+
# END REGION1
4448

45-
# calculate member's offset
49+
# REGION2
50+
# calculate the member offset
4651
off = 0
4752
e = vu.item.e
4853
while True:
@@ -55,16 +60,18 @@ def activate(self, ctx):
5560
break
5661
if not e2.type.is_udt():
5762
break
63+
# END REGION2
5864

65+
# REGION3
5966
# go up and collect more member references (in order to calculate the final offset)
6067
p = vu.item.e
6168
while True:
6269
p2 = vu.cfunc.body.find_parent_of(p)
6370
if p2.op == ida_hexrays.cot_memptr:
6471
break
6572
if p2.op == ida_hexrays.cot_memref:
66-
e2 = p2
67-
tif = remove_pointer(e2.x.type)
73+
e2 = p2.cexpr
74+
tif = ida_typeinf.remove_pointer(e2.x.type)
6875
if not tif.is_union():
6976
off += e2.m
7077
p = p2
@@ -81,45 +88,59 @@ def activate(self, ctx):
8188
objsize = add.type.get_ptrarr_objsize()
8289
nbytes = delta * objsize
8390
off += nbytes
84-
# we can use the calling helpers like WORD/BYTE/...
85-
# to calculate the more precise offset
91+
# we could use helpers like WORD/BYTE/... to calculate a more precise offset
8692
# if ( p2->op == cot_call && (e2->exflags & EXFL_LVALUE) != 0 )
8793
break
94+
# END REGION3
8895

96+
# REGION4
8997
ea = vu.item.e.ea
9098
# the item itself may be unaddressable.
9199
# TODO: find its addressable parent
92-
if ea == idaapi.BADADDR:
100+
if ea == ida_idaapi.BADADDR:
93101
return 0
102+
# END REGION4
94103

104+
# REGION5
95105
# prepare the text representation for the item,
96106
# use the neighborhoods of cursor
97-
line = idaapi.tag_remove(ida_kernwin.get_custom_viewer_curline(vu.ct, False))
107+
line = ida_lines.tag_remove(ida_kernwin.get_custom_viewer_curline(vu.ct, False))
98108
line_len = len(line)
99109
x = max(0, vu.cpos.x - 10)
100110
l = min(10, line_len - vu.cpos.x) + 10
101111
line = line[x:x+l]
112+
# END REGION5
102113

114+
# REGION6
103115
ops = ida_hexrays.ui_stroff_ops_t()
104116
op = ops.push_back()
105117
op.offset = off
106118
op.text = line
119+
# END REGION6
107120

121+
# REGION7
108122
class set_union_sel_t(ida_hexrays.ui_stroff_applicator_t):
109-
def __init__(self, eas):
123+
def __init__(self, ea):
110124
ida_hexrays.ui_stroff_applicator_t.__init__(self)
111-
self.eas = eas
125+
self.ea = ea
112126

113-
def apply(self, opnum, path):
114-
vu.cfunc.set_user_union_selection(self.eas[opnum], path)
127+
def apply(self, opnum, path, top_tif, spath):
128+
typename = ida_typeinf.print_tinfo('', 0, 0, ida_typeinf.PRTYPE_1LINE, top_tif, '', '')
129+
idaapi.msg("User selected %s of type %s\n" % (spath, typename))
130+
if path.empty():
131+
return False
132+
vu.cfunc.set_user_union_selection(self.ea, path)
115133
vu.cfunc.save_user_unions()
116134
return True
135+
# END REGION7
117136

118-
su = set_union_sel_t([ea])
137+
# REGION8
138+
su = set_union_sel_t(ea)
119139
res = ida_hexrays.select_udt_by_offset(None, ops, su)
120140
if res != 0:
121141
# regenerate ctree
122142
vu.refresh_view(True)
143+
# END REGION8
123144

124145
return 1
125146

@@ -131,7 +152,7 @@ def update(self, ctx):
131152

132153
# --------------------------------------------------------------------------
133154
if ida_hexrays.init_hexrays_plugin():
134-
print("Hex-rays version %s has been detected, Structure offsets ready to use" % idaapi.get_hexrays_version())
155+
print("Hex-rays version %s has been detected, Structure offsets ready to use" % ida_hexrays.get_hexrays_version())
135156
ida_kernwin.register_action(
136157
ida_kernwin.action_desc_t(
137158
"vds17:strchoose",
@@ -140,3 +161,121 @@ def update(self, ctx):
140161
"Shift+T"))
141162
else:
142163
print('vds17: Hex-rays is not available.')
164+
165+
"""
166+
# A few notes about the VDS17 sample
167+
168+
You can find two VDS17 samples in the IDA Pro install directory:
169+
170+
python/examples/hexrays/vds17.py
171+
plugins/hexrays_sdk/plugins/vds17
172+
173+
The former is an IDAPython plugin and the latter is a C++ IDA Pro plugin.
174+
Actually they have the same functionality.
175+
Just to be more concrete the vds17.py plugin will be used below.
176+
177+
178+
## How the user interface works
179+
180+
Let us suppose that we have the following local types:
181+
182+
1 C struct {int c0;int c1;}
183+
2 U union {int u0;__int16 u1;}
184+
3 D struct {int d0;C d1;U d2;}
185+
4 E struct {int e0;D e1;}
186+
5 res_t struct {int r0;int r1;__int16 r2;}
187+
188+
and the decompiler generates the following pseudocode:
189+
190+
void __cdecl f(res_t *r)
191+
{
192+
r->r0 = e->e1.d1.c0;
193+
r->r1 = e->e1.d2.u0;
194+
r->r2 = e->e1.d2.u1;
195+
}
196+
197+
As we see, it looks good, the decompiler did a really good job.
198+
199+
But let us imagine that we need reference to the ```e1.d2.u0``` union member on the last line.
200+
201+
At first we need to load the VDS17 plugin. For that,
202+
place the cursor at the ```u1``` union member on the last line
203+
and use ```Shift-T```.
204+
205+
The "Structure offsets" dialog appears on the screen.
206+
The left pane of the dialog contains the available local types
207+
and the right pane has the following view:
208+
209+
[checked] e->e1.d2.u1; | 10h | |
210+
211+
Use the left pane to select ```E```, expand it, and select (Double-click) on the ```u0``` member.
212+
213+
The right pane will change to:
214+
215+
[checked] e->e1.d2.u1; | 10h | [checke] E.e1.d2.u0 |
216+
217+
Since this is what we want, press the ```OK``` button and the pseudocode gets changed:
218+
219+
void __cdecl f(res_t *r)
220+
{
221+
r->r0 = e->e1.d1.c0;
222+
r->r1 = e->e1.d2.u0;
223+
r->r2 = e->e1.d2.u0;
224+
}
225+
226+
227+
### What do we need this plugin for?
228+
229+
All union members have the same offset in the parent structure.
230+
The decompiler selects the first suitable union member.
231+
Sometimes we need to change this selection and use another union member.
232+
233+
234+
## API details
235+
236+
Let us look into ```python/examples/hexrays/vds17.py```.
237+
238+
* REGION1: check that the cursor points to the union member
239+
* REGION2: calculate the member offset
240+
* REGION3: sometimes there is a need to adjust the offset
241+
* REGION4: the pointed item must be addressable
242+
243+
Then the magic begins:
244+
245+
* REGION5: we need something to show in the ```Operand``` column of the right pane.
246+
The text around the cursor looks like a good compromise.
247+
* REGION6: we are ready to fill the right pane: we have calculated the offset and
248+
have prepared the descriptive text for the operand.
249+
* REGION7: it is a callback that informs us about the user selection (will be described later)
250+
* REGION8: activate the "Structure offsets" dialog, let the user select,
251+
the callback specified above will update the union member, refresh pseudocode
252+
253+
254+
### The devil is in the details
255+
256+
The main part of callback is the ```apply``` method (REGION7).
257+
It receives two arguments:
258+
259+
1. ```opnum``` is the number of the selected operand (line) in the right pane of the dialog.
260+
We need something to map the line number to our operand.
261+
In the case of VDS17 ```ea``` performs this role.
262+
2. ```path``` the path that describes the union selection.
263+
3. ```top_tif``` typeinfo of the top-level UDT which user selected
264+
4. ```spath``` the field names path to the selected member
265+
266+
The union selection path is denotes a concrete member inside a UDT.
267+
268+
For structure types there is no need in the union selection path because the member
269+
offset uniquely denotes the desired member.
270+
271+
For unions, on the other hand, the member offset is not enough because all union
272+
members start at the same offset zero. For them, we remember the ordinal number of the
273+
union member in the path. E.g., for the local types given above, the following holds:
274+
275+
* e1.d1.c0 is denoted by an empty path because it does not have any unions
276+
* e1.d2.u0 is denoted by path consisting of 0: we use the first member of U
277+
* e1.d2.u1 is denoted by path consisting of 1: we use the second member of U
278+
279+
You can retrieve the union selection path using API call ```get_user_union_selection```
280+
or apply it using ```set_user_union_selection```.
281+
"""
110 Bytes
Binary file not shown.

release_pydoc_injections2.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31124,7 +31124,7 @@ class ui_stroff_applicator_t(__builtin__.object)
3112431124
| __repr__ = _swig_repr(self)
3112531125
|
3112631126
| apply(self, *args)
31127-
| apply(self, opnum, path) -> bool
31127+
| apply(self, opnum, path, top_tif, spath) -> bool
3112831128
|
3112931129
| ----------------------------------------------------------------------
3113031130
| Data descriptors defined here:

release_pydoc_injections3.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31074,7 +31074,7 @@ class ui_stroff_applicator_t(builtins.object)
3107431074
| delete_ui_stroff_applicator_t(self)
3107531075
|
3107631076
| apply(self, *args) -> 'bool'
31077-
| apply(self, opnum, path) -> bool
31077+
| apply(self, opnum, path, top_tif, spath) -> bool
3107831078
|
3107931079
| ----------------------------------------------------------------------
3108031080
| Data descriptors defined here:

0 commit comments

Comments
 (0)