1

How can I tell IDA what the indexes of an array in a struct are? I think I need to tell it to use an enum, but I'm not sure how. I'm working on Practical Reverse Engineering and following the x86 Rootkit walkthrough in Chapter 3.

It walks through reversing the setup of the DriverObject function pointers here:

01: .text:00010643   mov     ecx, [ebp+DriverObject]
02: .text:00010646   mov     dword ptr [ecx+38h], offset sub_10300
03: .text:0001064D   mov     edx, [ebp+DriverObject]
04: .text:00010650   mov     dword ptr [edx+40h], offset sub_10300
05: .text:00010657   mov     eax, [ebp+DriverObject]
06: .text:0001065A   mov     dword ptr [eax+70h], offset sub_10300
07: .text:00010661   mov     ecx, [ebp+DriverObject]
08: .text:00010664   mov     dword ptr [ecx+34h], offset sub_10580

Following along, I have a Driver_Object struct defined, and IDA picks up the MajorFunction offset

.text:00010643 mov     ecx, [ebp+DriverObject]
.text:00010646 mov     [ecx+_DRIVER_OBJECT.MajorFunction], offset sub_10300
.text:0001064D mov     edx, [ebp+DriverObject]
.text:00010650 mov     [edx+(_DRIVER_OBJECT.MajorFunction+8)], offset sub_10300
.text:00010657 mov     eax, [ebp+DriverObject]
.text:0001065A mov     [eax+(_DRIVER_OBJECT.MajorFunction+38h)], offset sub_10300
.text:00010661 mov     ecx, [ebp+DriverObject]
.text:00010664 mov     [ecx+_DRIVER_OBJECT.DriverUnload], offset driverUnload

MajorFunction is defined as an array, but I'd like to get IDA to display what those offsets represent. wdm.h defines the offsets as follows:

#define IRP_MJ_CREATE                   0x00
#define IRP_MJ_CREATE_NAMED_PIPE        0x01
#define IRP_MJ_CLOSE                    0x02
...

Basically, I'd like to see something like the following in the disassembly:

.text:0001064D mov     edx, [ebp+DriverObject]
.text:00010650 mov     [edx+(_DRIVER_OBJECT.MajorFunction+IRP_MJ_CLOSE)], offset sub_10300
.text:00010657 mov     eax, [ebp+DriverObject]
.text:0001065A mov     [eax+(_DRIVER_OBJECT.MajorFunction+IRP_MJ_DEVICE_CONTROL)], offset sub_10300

IDA has the Driver Object defined as follows:

struct __declspec(align(4)) _DRIVER_OBJECT
{
  ...
  void (__stdcall *DriverUnload)(_DRIVER_OBJECT *);
  int (__stdcall *MajorFunction[28])(_DEVICE_OBJECT *, _IRP *);
};
3

I don't think you can do that directly in IDA, although Hex-Rays does it. For example, in the PE header IMAGE_DATA_DIRECTORY DataDirectory[16] array, the names of the individual elements are specified by #define constants such as IMAGE_DIRECTORY_ENTRY_EXPORT. Here we see an access to the element at index 0:

Access to pe->DataDirectory 0

It would be nice to see the symbolic name for the enumeration element 0. We can simply place our cursor on the 0, press m, and change the constant into an enumeration element the same way we would do in the disassembly listing:

Changing the index to an enumeration element

There is a workaround for your particular example in the disassembly listing. You can declare a new structure type -- say, DRIVER_CALLBACK_FUNCTIONS, like so:

struct DRIVER_CALLBACK_FUNCTIONS {
  int (__stdcall *IRP_MJ_CREATE)(_DEVICE_OBJECT *, _IRP *);
  int (__stdcall *IRP_MJ_CREATE_NAMED_PIPE)(_DEVICE_OBJECT *, _IRP *);
  int (__stdcall *IRP_MJ_CLOSE)(_DEVICE_OBJECT *, _IRP *);
  // ... all 28 functions ...
};

And then modify the definition of _DRIVER_OBJECT: change the definition of the MajorFunction[28] array to DRIVER_CALLBACK_FUNCTIONS instead.

  • ahh! that worked like a charm! for us peons without hex-rays, is ghidra capable of doing the same, setting the symbolic constant? – gr0k Nov 17 '20 at 21:24
  • I don't know; hopefully somebody more informed about Ghidra can chime in here. I would guess not, but again, I'm ignorant on the subject. – Rolf Rolles Nov 17 '20 at 22:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.