Application Compatibility Fixing to the Extreme?

Today’s blog is about an application that was migrated to Citrix XenApp. During testing the users reported that several application menu’s were missing.

An example is the settings menu where the System tab is missing:

Fat Client: XenApp:
clip_image002[5] clip_image002

I suspected a permissions issue so I added the account to the Local Administrator group to verify that. And indeed the System tab was visible.

Process Monitor
I removed the account from the Administrators group and fired up Process Monitor. I set a filter on the process name (ra60.exe) and on Result (ACCESS DENIED):


The Process Monitor trace shows that the application tries to register an ActiveX component at launch:


I don’t know why so many developers seem to think that’s a good idea, components should be registered at install time and only at install time!

Even though the failure to register the component is not blocking, it’s a good idea to fix this issue by either changing this registry keys permissions or by adding this key to HKCU\Software\Classes (HKCR is a merged view on HKLM and HKCU Classes key).

Applications tend to check permissions in two ways:

  1. Try to write in the filesystem (eg Program Files) or registry (eg HKLM) to see if that succeeds.
  2. Do a hardcoded "IsAdministrator" check

The Process Monitor trace does not show any trace of writing to Program Files or HKLM (other than the ActiveX component) so a hardcoded check is most likely the case here.

Ida Pro
A hardcoded check usually works by calling the GetTokenInformation API to inspect the current process token.

I loaded ra60.exe in Ida Pro and waited for the autoanalysis to finish. Then I went to the Imports tab and searched for the GetTokenInformation API then pressed Ctrl-X so search for code that calls into this API:


The first occurrence is a direct hit, let’s have a look at the pseudo code:

if ( AllocateAndInitializeSid(&pIdentifierAuthority, 2u, 0x20u, a1, 0, 0, 0, 0, 0, 0, &pSid) )
  v13 = &v21;
  v12 = (unsigned int)&loc_954D88;
  v11 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v11);
  v1 = 0;
  if ( (unsigned __int8)GetVersion_0() >= 5u )
    v2 = GetModuleHandleA_1("advapi32.dll");
    v1 = GetProcAddress_0(v2, "CheckTokenMembership");
  if ( v1 )
    if ( ((int (__stdcall *)(_DWORD, PSID, unsigned int *, unsigned __int32))v1)(0, pSid, &v18, v11) )
      v20 = v18 >= 1;

Let’s work on that code to make a little better readable:

bResult = 0;                                // FALSE
if ( AllocateAndInitializeSid(
       &pSid) )
  CheckTokenMembership = 0;
  if ( GetVersion() >= 5u )// Windows Version >= 2000 (win 5) ?
    hModule = GetModuleHandleA("advapi32.dll");
    CheckTokenMembership = GetProcAddress(hModule, "CheckTokenMembership");
  if ( CheckTokenMembership )
    if ( CheckTokenMembership(
           0,                               // If TokenHandle is NULL, CheckTokenMembership uses the impersonation token of the calling thread
           &bIsMember                      // TRUE if the SID is present
           ) )
      bResult = bIsMember >= 1;

The call to AllocateAndInitializeSid constructs the SID of the Administrators group. Then the CheckTokenMembership API is called to check if the current thread’s token contains the Administrators group SID. If it does the function returns 1 (TRUE), if not it returns 0 (FALSE).

Bug bug bug

Besides the fact that the developer who thought it was a good idea to include an admin check should be shot, this code is broken! On Vista and higher versions of Windows because the Admin token is filtered out by User Account Control (unless we are elevated).


I decided to patch this function and make it always return TRUE (1), this is actually quite easy.

Go to the Disassembly view (IDA View-A) and position the cursor on the first line of code in the function:


Go to the Edit Menu and choose the Assemble option from the Patch Program menu and enter the following code:

xor eax ,eax
inc eax

The first line xor’s eax with itself, the result is that the eax register contains the value 0.

The second line, inc eax, increments the eax register value by one. This makes eax contain the value 1 (TRUE).

The last line, ret, returns from the function.

This is the end result:


Finally use the Apply patches to input file option from the Edit | Patch Program menu to save our changes back to disk (don’t forget to select the Create backup option:


I started the patched executable and guess what? The missing menu is back!