Latest available version: IDA and decompilers v8.4.240527sp2 see all releases
Hex-Rays logo State-of-the-art binary code analysis tools
email icon

We’ve covered the usage of symbolic constants (enums) in the disassembly. but they are also useful in the pseudocode view.

Reusing constants from disassembly

If a number has been converted to a symbolic constant in the disassembly and it is present in unchanged form in pseudocode, the decompiler will use it in the output. For example, consider this call:

.text:00405D72   push    1               ; nShowCmd
.text:00405D74   cmovnb  eax, [esp+114h+lpParameters]
.text:00405D79   push    0               ; lpDirectory
.text:00405D7B   push    eax             ; lpParameters
.text:00405D7C   push    offset File     ; "explorer.exe"
.text:00405D81   push    0               ; lpOperation
.text:00405D83   push    0               ; hwnd
.text:00405D85   call    ShellExecuteW

Initially, it is  decompiled like this:

ShellExecuteW(0, 0, L"explorer.exe", v136, 0, 1);

However, we can look up that nShowCmd’s value 1 corresponds to the constant SW_NORMAL, and apply it to the disassembly:

push    SW_NORMAL       ; nShowCmd         
cmovnb  eax, [esp+114h+lpParameters]       
push    0               ; lpDirectory      
push    eax             ; lpParameters     
push    offset File     ; "explorer.exe"   
push    0               ; lpOperation      
push    0               ; hwnd             
call    ShellExecuteW

After refreshing the pseudocode, the constant appears there as well:

ShellExecuteW(0, 0, L"explorer.exe", v136, 0, SW_NORMAL);

Applying constants in pseudocode

In fact, you can do the same directly in the pseudocode, using the context menu or the same shortcut (M):

Note that there is no automatic propagation of the constants applied in pseudocode to disassembly. In fact, sometines it’s not possible to map a number you see in the pseudocode to the same number in the disassembly.

Consider this example from a Windows driver’s initialization routine (DriverEntry):

      DriverObject->DriverStartIo = (PDRIVER_STARTIO)sub_1C0001840;
      DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_1C0001910;
      DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)&sub_1C0001510;
      DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)&sub_1C00011B0;
      DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)&sub_1C0001290;
      DriverObject->MajorFunction[18] = (PDRIVER_DISPATCH)&sub_1C0001070;

We know that indexes into the MajorFunction array correspond to the major IRP codes (IRP_MJ_xxx), so we can convert numerical indexes to the corresponding constants:

and the pseudocode becomes:

DriverObject->DriverStartIo = (PDRIVER_STARTIO)sub_1C0001840;
DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_1C0001910;
DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)&sub_1C0001510;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)&sub_1C00011B0;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)&sub_1C0001290;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)&sub_1C0001070;

However, if we check the corresponding disassembly (e.g by using Tab or synchronizing pseudocode and IDA View), we can see that the array indexes are not present as such in the instruction operands:

Another common situation where you can use symbolic constants in pseudocode but not disassembly is swich cases.

See also:

Igor’s tip of the week #99: Enums

Decompiler Manual: Hex-Rays interactive operation: Set Number Representation