$theTitle=wp_title(" - ", false); if($theTitle != "") { ?>
About Virtualization, VDI, SBC, Application Compatibility and anything else I feel like
23 May // php the_time('Y') ?>
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: |
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:
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | bResult = 0; // FALSE if ( AllocateAndInitializeSid( &pIdentifierAuthority, 2u, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMIN, 0, 0, 0, 0, 0, 0, &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 pSid, &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).
Patch
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:
1 2 3 | xor eax ,eax inc eax ret |
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!
Discussion
Question is though, should we go this far to get an application to run? Obviously it would be better if the vendor would fix this issue and in all honesty I didn’t ask…
It’s also possible that my customer is using an older version of the application (for whatever reason).
So let’s hear it, I am very much interested in your opinion! Is this solution acceptable for you? Or would you rather make those users Administrator?
5 Responses for "Application Compatibility Fixing to the Extreme?"
Not telling the vendor is stupid, then they are never going to change their stupid code…
I would not rather make the users Administrator.
Whether I would go to those length to fix the app? It depends on the app in question.
My view is that, as the IT Department, we are here to help the lines of business better server our retail customers. If an app honestly helps them do that- It doesn’t matter if it’s 15 years old. It doesn’t matter if the company is out of business, or whatever other scenario led to the source code not being updated. Software is not milk- It doesn’t become bad simply from being old.
Now, if software is old and the company is out of business- That’s a pretty good indication that the software they wrote doesn’t do a really good job of meeting a business need, and we’d be better off going to a different product that is being updated.
The approach I take is try and get something that is supported and fully function to meet the same business need- But on a rare exception basis, I’ll consider doing something like this.
I’m doing something similar for a product released by a big TLA Computer company whom I won’t name, but I’ve been told nobody ever got fired from being from.
Nice work! But I would have just used a shim to do the same thing! 😉
It looks like the software is still being supported and patches are available.
In this case I would try to get one of the developers to fix the problem as they probably had a reason to include the admin check(and there are probably more problems on the horizon if they didn’t test for TS/Citrix)
Most company’s jump at the help they can get if they hear that their software isn’t usable by larger company’s and they are missing opportunities.
(don’t talk about disassemblers and think about potential licensing/support problems!)
I’ve had a lot of luck with the above and I even had large (local) websites change their code to solve problems.
(Twitter/Facebook blocked by our proxy and their websites not loading)
If the software is abandoned and a replacement isn’t an option I would use a shim and otherwise a self made patch like the above.
It all depends on the many variables involved….
[…] Application Compatibility Fixing to the Extreme? […]
Leave a reply