Hex-Rays v7.3 vs. v7.2 Decompiler Comparison Page

Below you will find side-by-side comparisons of v7.2 and v7.3 decompilations. Please maximize the window too see both columns simultaneously.

The following examples are displayed on this page:

NOTE: these are just some selected examples that can be illustrated as side-by-side differences. There are many other improvements and new features that are not mentioned on this page. We just got tired selecting them. Some of the improvements that did not do to this page:

  • objc-related improvements

  • value range analysis can eliminate more useless code

  • better resolving of got-relative memory references

  • too big shift amounts are converted to lower values (e.g. 33->1)

  • more for-loops

  • better handling of fragemented variables

  • many other things...


More hexadecimal numbers in the output

When a constant looks nicer as a hexadecimal number, we print it as a hexadecimal number by default. Naturally, beauty is in the eye of the beholder, but the new beahavior will produce more readable code, and less frequently you will fell compelled to change the number representation. By the way, this tiny change is just one of numerious improvements that we keep adding in each release. Most of them go literally unnoticed. It is just this time we decided to talk about them

bool __fastcall ge_100000001(__int64 a1)
{
  return a1 >= 0x100000001LL;
}

Support for variable size structures

EfiBootRecord points to a structure that has RecordExtents[0] as the last member. Such structures are considered as variable size structures in C/C++. Now we handle them nicely.

BlockNumber = EfiBootRecord->RecordExtents[ExtentIndex64].BlockNumber;
BlockCount = EfiBootRecord->RecordExtents[ExtentIndex64].BlockCount;

UTF-32 strings are printed inline

We were printing UTF-8 and other string types, UTF-32 was not supported yet. Now we print it with the 'U' prefix.

v3 = std::operator<<<std::char_traits<char>>(&std::cout, U"This is U\"Hello\"

Better argument detection for printf

The difference between these outputs is subtle but pleasant. The new version managed to determine the variable types based on the printf format string. While the old version ended up with int a2, int a3, the new version correctly determined them as one __int64 a2.

int __fastcall ididi(int a1, __int64 a2, int a3, __int64 a4, int a5)
{
  int varg_r0; // [sp+28h] [bp-10h]
  __int64 varg_r2; // [sp+30h] [bp-8h]

  varg_r0 = a1;
  varg_r2 = a2;
  my_print("d=%I64d\n", a2);
  my_print("d1=%I64d\n", a4);
  my_print("%d-%I64d-%d-%I64d-%d\n", varg_r0, varg_r2, a3, a4, a5);
  return 0;
}

Better argument detection for scanf

A similar logic works for scanf-like functions. Please note that the old version was misdetecting the number of arguments. It was possible to correct the misdetected arguments using the Numpad-Minus hotkey but it is always better when there is less routine work on your shoulders, right?

scanf("8: %d%i %x%o %s%s %C%c", &v12, &v7, &v3, &v4, &v2, &v9, &v8, &v13);
scanf("8:   %[ a-z]%c %2c%c %2c%2c %[ a-z]%c", &v12,