SAPGUI Multi Logon – Override the multiple logon restriction

A long time ago, when we still used SAPGUI 6xx, there was a little bug special feature that allowed us to log into an SAP system even though someone else was already logged in with the same user ID. It was the Ctrl+click.

If you are not familiar with that bug special feature, this is what I’m talking about:

Since the advent of SAPGUI 720, this is no longer possible. If you’re not using my sapgui-multilogon tool, of course.

This little tool brings back the feature we consultants often need. You can now stop using SAPGUI 710 and update already.

You can download the ready-to-use (Windows only, sorry) binaries in the Releases section.
(And yes, it’s open source!)

How does it work?

The app is composed of two files: an executable program and a DLL.
The important part goes like this:

1) The .exe program finds (or starts) the SAPGUI process:

// Check if SAP Logon is already running
int iPID = GetPID("saplogon.exe");
if (! iPID)
  iPID = GetPID("saplgpad.exe");
if (iPID) {
  // Process found, open it to inject the library
  hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, iPID);
  if (! hProcess) {
    ShowLastErrorMessage();
    return -1;
  }
}
else {
  // Create the SAP Logon process //
  STARTUPINFO stStartupInfo = { sizeof(STARTUPINFO) };
  PROCESS_INFORMATION stProcInfo;
  if(! CreateProcess(szExePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, szDirPath, &stStartupInfo, &stProcInfo)) {
    ShowLastErrorMessage();
    return -1;
  }
  hProcess = stProcInfo.hProcess;
  hMainThread = stProcInfo.hThread;
}

2) The .exe then injects the DLL into the SAPGUI process:

// Copy the DLL path to the remote process //
int iSize = strlen (szDllPath) + 1;
void * pRemoteLibraryPath = VirtualAllocEx (hProcess, NULL, iSize, MEM_COMMIT, PAGE_READWRITE);
if (! WriteProcessMemory (hProcess, pRemoteLibraryPath, szDllPath, iSize, NULL)) {
  ShowLastErrorMessage();
  return -1;
}

// Create a remote LoadLibraryA suspended thread //
HANDLE hInjThread = CreateRemoteThread (hProcess, NULL, 0,
  (LPTHREAD_START_ROUTINE) GetProcAddress (GetModuleHandle ("kernel32"),
  "LoadLibraryA"), pRemoteLibraryPath, 0, NULL);
if (! hInjThread) return FALSE;

ResumeThread(hInjThread);
ResumeThread(hMainThread);

3) The DLL installs hooks to alter the working of some SAPGUI internal methods (this is done using my Hook library:

// SAPfewui.dll (User Interface Manager) hooks
ASSERT_HOOK_INSTALL(CUiObject_IsChecked, "SAPfewui.dll", "?IsChecked@CUiObject@@QBEHXZ");
ASSERT_HOOK_INSTALL(CUiObject_SetChecked, "SAPfewui.dll", "?SetChecked@CUiObject@@UAEXH@Z");

4) When you click on a radiobutton, these methods are called, then our hook stub takes care of the magic:

/**
 * UI objects (screen controls) IsCheck method
 * Called to determine if a screen control is checked (eg checkboxes)
 * Here, if Ctrl key is pressed, we invert the checked state of the UIObject.
 * This makes any radiobutton act as a checkbox when clicked (with Ctrl pressed ofc).
 */
HOOK_STUB_FUNCTION(CUiObject_IsChecked, int, __thiscall, (void)) {
  void * pThis;
  int iChecked;

  GET_THIS(pThis);
  iChecked = HOOK_HOP(CUiObject_IsChecked)();

  // If Ctrl is pressed, invert the checked state
  //  (check if not checked and vice versa)
  if (IS_KEY_PRESSED(VK_CONTROL)) {
    SET_THIS(pThis);
    HOOK_HOP(CUiObject_SetChecked)(!iChecked);
    return FALSE;
  }
  else
    return iChecked;
}

/**
 * UI objects (screen controls) SetChecked method
 * Called to change the checked state of a screen control (eg checkboxes)
 * Here, if Ctrl key is pressed, we just ignore the calls.
 * This makes the radiobuttons act as checkboxes, because no radiobuttons are de-checked
 *  when another radiobutton in the same group is checked.
 */
HOOK_STUB_FUNCTION(CUiObject_SetChecked, void, __thiscall, (int iChecked)) {
  void * pThis;

  GET_THIS(pThis);

  // If Ctrl is pressed, ignore this call
  if (IS_KEY_PRESSED(VK_CONTROL))
    return;

  SET_THIS(pThis);
  HOOK_HOP(CUiObject_SetChecked)(iChecked);
}
 

abapninja

A coder/dancer/actor/singer, usually in that order. Works as an SAP consultant/developer, and loves to tinker with software.