Run a Process when Citrix Receiver Exits
A while ago I was doing some research for Magic Filter when I stumbled upon something interesting within Receiver.
Inside wfica32.exe is a function called _Eng_RunExecutableOnExit. That name caught my interest, I’ve made it a little more readable with Ida Pro:
LSTATUS __cdecl _Eng_RunExecutableOnExit()
{
LSTATUS result; // eax@1
size_t v1; // eax@8
bool v2; // zf@10
char *v3; // eax@10
const CHAR *v4; // edi@11
size_t v5; // eax@13
HKEY hKey; // [sp+4h] [bp-38Ch]@1
DWORD cbData; // [sp+8h] [bp-388h]@2
DWORD Type; // [sp+Ch] [bp-384h]@2
BOOL bRunOnExit; // [sp+10h] [bp-380h]@2
struct _PROCESS_INFORMATION ProcessInformation; // [sp+14h] [bp-37Ch]@15
struct _STARTUPINFOA StartupInfo; // [sp+24h] [bp-36Ch]@15
char Src[4]; // [sp+68h] [bp-328h]@8
char v13; // [sp+6Fh] [bp-321h]@10
char Str; // [sp+70h] [bp-320h]@5
const CHAR ApplicationName; // [sp+71h] [bp-31Fh]@5
CHAR CommandLine; // [sp+178h] [bp-218h]@8
char v17; // [sp+179h] [bp-217h]@8
char lpApplicationName; // [sp+284h] [bp-10Ch]@5
hKey = 0;
result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Citrix\\XenDesktop", 0, KEY_READ, &hKey);
if ( !result )
{
bRunOnExit = 0;
cbData = REG_DWORD;
if ( !RegQueryValueExA(hKey, "XDControlRunOnExit", 0, &Type, (LPBYTE)&bRunOnExit, &cbData) && Type == REG_DWORD )
{
if ( bRunOnExit )
{
lpApplicationName = 0;
memset(&lpApplicationName + 1, 0, 260u);
Str = 0;
memset((void *)&ApplicationName, 0, 260u);
cbData = 260;
if ( !RegQueryValueExA(hKey, "XDControlExe", 0, &Type, (LPBYTE)&lpApplicationName, &cbData)
&& (Type == REG_SZ || Type == REG_EXPAND_SZ) )
{
strcpy(Src, "ctx ");
CommandLine = 0;
memset(&v17, 0, 265u);
_strcpy_s(&CommandLine, 266u, Src);
ExpandEnvironmentStringsA(&lpApplicationName, &Str, 0x105u);
v1 = _strnlen(&Str, 0x7FFFFFFFu);
if ( v1 > 0 && Str == 34 && (v2 = *(&v13 + v1) == 34, v3 = &v13 + v1, v2) )
{
*v3 = 0;
v4 = &ApplicationName;
}
else
{
v4 = &Str;
}
cbData = 260;
v5 = _strnlen(Src, 0x7FFFFFFFu);
if ( !RegQueryValueExA(hKey, "XDControlArgs", 0, &Type, (LPBYTE)&CommandLine + v5, &cbData) && Type == REG_SZ )
{
memset(&StartupInfo.lpReserved, 0, 0x40u);
ProcessInformation.hThread = 0;
ProcessInformation.dwProcessId = 0;
ProcessInformation.dwThreadId = 0;
ProcessInformation.hProcess = 0;
StartupInfo.cb = 68;
if ( CreateProcessA(v4, &CommandLine, 0, 0, 0, 0, 0, 0, &StartupInfo, &ProcessInformation) )
{
CloseHandle(ProcessInformation.hProcess);
CloseHandle(ProcessInformation.hThread);
}
}
}
}
}
result = RegCloseKey(hKey);
}
return result;
}
So what’s the conclusion?
We can create the following registry values in HKLM\SOFTWARE\Wow6432Node\Citrix\ICA Client\Engine\Lockdown Profiles\All Regions\Lockdown\XenDesktop:
| XDControlRunOnExit | DWORD: 0 for off 1 for on |
| XDControlExe | String or Expandable String: Executable including path to run, maximum length 260 characters. Environment variables can be used |
| XDControlArgs | String: Commandline arguments, maximum length 260 characters |
How is that useful?
An example is automatically locking the workstation when the Citrix session ends. Use the following settings:
| XDControlRunOnExit | 1 |
| XDControlExe | rundll32.exe |
| XDControlArgs | user32.dll,LockWorkStation |
Was once an enthusiastic PepperByte employee but is now working elsewhere. His blogs are still valuable to us and we hope to you too.