License Check fails on Citrix XenApp

imageA while ago I was asked to assist in getting an Excel Add-In to work on Citrix XenApp.

The application was packaged into a Thinapp by one of our package engineers.

However when testing the Add-In on Citrix XenApp the following message appeared:

image

Apparently this application does a license check that fails when run from another server (how bad).

Disclaimer
Before we go on: I would like to make clear that my goal is not to be able to use an application without license. I am just trying to make it work within the customer’s environment.

Analysis
The application consisted of an xla (Excel Add-In Sheet) and two Dll’s called analyse.dll and analyse12.dll.

It seemed logical to me that the license check was in the Dll’s and that there were two versions: one for Excel 2003 and one for Excel 2007 (version 12) and possibly 2010.

I loaded analyse.dll in Ida Pro so I could analyze it.

The exports Tab shows a few exports that are common to XLL Files:

SNAGHTML14624cb3

Inside the Dll there was a lot of trace/debug output, like this:

sub_9A6E9AD("restoring licence");
...
sub_9A6E9AD("checking network status");
...
sub_9A6E9AD("clock turned back");

So I looked into sub_9A6E9AD to see if we could output this trace info:

 

    result = sub_9ADA1F6((DWORD)ValueName, "DumpLog", 0);
    if ( result )
    {
      if ( hFile != (HANDLE)-1
        || ((GetTempPathA(0x400u, &FileName),
             strcat("FileName, "analyse-it.log"),
             hFile = CreateFileA(&FileName, 0xC0000000u, 3u, 0, 4u, 0, 0),

sub_9ADA1F6 is a function for registry access:

 

int __thiscall sub_9ADA1F6(void *this, DWORD lpSubKey, LPCSTR lpKeyName, int a3)
{
  int result; // eax@2
  BYTE Dst[4]; // [sp+4h] [bp-4h]@3

  if ( sub_9ADA46A(this, (LPCSTR)lpSubKey, lpKeyName, 4u, 0) )
  {
    sub_9ADA53F(lpSubKey, lpKeyName, 4, Dst, 4u);
    result = *(_DWORD *)Dst;
  }
  else
  {
    result = a3;
  }
  return result;
}

From this code I concluded that if a DWORD registry value Dumplog (Value 1) exists in the application’s registry key (HKLM\SOFTWARE\Analyse-it\Analyse-it for Excel\1.0) a logfile would be written to the Temp directory.

The logfile was helpful in determining what happended:

checking registry access

checking registry access
  computer ID=2801b214
comparing computer IDs 14065cba, 2801b214
  computer ID=2801b214
tampered

That confirmed the computer check, but where does it come from?

Again the debug output was helpful:

 sub_9A6E9AD("comparing computer IDs %x, %x", *((_DWORD *)v2 + 3), v6);
  if ( *((_DWORD *)v2 + 13) "" *((_DWORD *)v2 + 3) != sub_9A6AFDB(v2) )
  {
    sub_9A6E9AD("tampered");
    sub_9AE745C(40013, 0, v22);
  }

Let’s have a look inside the check, sub_9A6AFDB (only showing the relevant piece):

 

  v2 = *(_BYTE *)this == 0;
  VolumeSerialNumber = 0;
  if ( v2 )
  {
    GetWindowsDirectoryA(&RootPathName, 0x100u);
    strchr("RootPathName, 92)[1] = 0;
    GetVolumeInformationA(&RootPathName, 0, 0, &VolumeSerialNumber, 0, 0, 0, 0);
  }

The location of the Windows directory is retreived and then the volume serial number is requested for that volume.

The obtained serial number is compared to the serial that was saved during activation:

v6 = sub_10079FFE("v12, "Excel.App", -2147483648, 131103);
LOBYTE(v19) = 3;
sub_1007A128(v6, chText, "Flags32d", (const BYTE *)lpBuffer, *(int *)nNumberOfBytesToWrite, 1);
LOBYTE(v19) = 1;
v7 = sub_10077A81((unsigned int *)"v12);

If we analyze the code above we can determine that a registry key is accessed in the HKEY_CLASSES_ROOT hive (-2147483648 = 0x80000000 in HEX which is the constant for HKEY_CLASSES_ROOT)

The key is Excel.App and the value is Flags32d.

The value of this key on the machine that had been activated matched 14065cba and was also the machine’s volume serial.

So the solution was there: I placed the Flags32d value in the ThinApp and in the package.ini I added the following line:

VirtualDrives=Drive=c, Serial=14065cba, Type=FIXED

Now the application worked nicely on my testmachine (even though it has a different volume serial number):

image

On the production XenApp however the Thinapp failed!

It took me some time to realize why, rember this code?

  v2 = *(_BYTE *)this == 0;
  VolumeSerialNumber = 0;
  if ( v2 )
  {
    GetWindowsDirectoryA(&RootPathName, 0x100u);
    strchr("RootPathName, 92)[1] = 0;
    GetVolumeInformationA(&RootPathName, 0, 0, &VolumeSerialNumber, 0, 0, 0, 0);
  }

It retrieves the Windows directory and application that are not Terminal Server aware have the Windows directory redirected to their User Profile!

In this case the User Profile was on the H drive so I change the package.ini to:

VirtualDrives=Drive=h, Serial=14065cba, Type=FIXED

And not it worked nicely!

And a small PS to developers: First of all: License check’s don’t work at all, removing them is often very easy. Secondly license checks often do more harm than good. If a bug in the license check hurts a paying customer what have you accomplished? In this case there are at least two bugs (or bad design) in only a few lines of code!

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *