Hex-Rays' blog

Igor’s Tip of the Week #149: Using symbolic constants in the decompiler – Hex Rays

Written by Igor Skochinsky | Jul 20, 2023

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:

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):

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