Link to home
Start Free TrialLog in
Avatar of cc16
cc16

asked on

Hooking the Logon Desktop (Windows C++)

Hello

Is it possible to install a hook in the windows login desktop?

So far, I have built a windows service which means the program can remain running after the user has logged off. However i do not know how to hook the login desktop.

Note, this research is strictly only for educational/experimental purposes.

Any help would be much appreciated,
Southern Curriez
ASKER CERTIFIED SOLUTION
Avatar of cookre
cookre
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of cc16
cc16

ASKER

regarding finding which window to hook...

take EnumWindowStatiosn() for example
it will return the names of every WindowStation to the callback function - how will i know which is the correct one?


i will need some exceptions like

IF(STATION_NAME == MAGIC_VALUE_1) //go ahead and call EnumDesktops
IF(DESKTOP_NAME == MAGIC_VALUE_2) //go ahead and call EnumDesktopWindows
IF(DESKTOP_WINDOW_NAME == MAGIC_VALUE_3) //go ahead and hook

but what can i use for these magic values?
That's why you first just log them all - so you can see what the machine looks like before logon and after logon.  It's also a good exercize just to have coded a full enumeration.

Under XP after logon, you may find a desktop called "Winlogon".  Within that desktop, you'll find one of the windows:

* "Windows Security" - what you see when you CTRL/ALT/DEL
* "Computer Locked" - what you see when you lock the workstation
* "Unlock Computer" - the window to enter a password to unlock the workstation

Alas, I don't recall the XP logon window name, but you should see it in your enumeration log.


In your service, do a full enumeration, say, every 30 seconds, making sure you include a time stamp with each full enumeration. Then boot and wait one minute after the logon screen comes up before entering you info, and wait another minute after the box settles down before stopping the service and examining the enumeration log.  It will be fairly easy to identify therein the name of the logon station, desktop, and window.
Avatar of cc16

ASKER

for some annoying reason GetWindowText dosnt seem to work when called from this service...

should i just use the only window in Winlogon, or would a global hook work (a global hook would be easier)

here is what it looks like before i log in:




NEW WINDOW STATION: WinSta0
            New Desktop: Default
                        New Desktop Window: 0x000B0050
            New Desktop: Disconnect
            New Desktop: Winlogon
                        New Desktop Window: 0x000C0052


NEW WINDOW STATION: Service-0x0-3e7$
            New Desktop: WinSta0
                        New Desktop Window: 0x000B0050
            New Desktop: Service-0x0-3e7$
                        New Desktop Window: 0x000B0050
            New Desktop: Service-0x0-3e4$
                        New Desktop Window: 0x000B0050
            New Desktop: Service-0x0-3e5$
                        New Desktop Window: 0x000B0050
            New Desktop: SAWinSta
                        New Desktop Window: 0x000B0050


NEW WINDOW STATION: Service-0x0-3e4$
            New Desktop: WinSta0
                        New Desktop Window: 0x000B0050
            New Desktop: Service-0x0-3e7$
                        New Desktop Window: 0x000B0050
            New Desktop: Service-0x0-3e4$
                        New Desktop Window: 0x000B0050
            New Desktop: Service-0x0-3e5$
                        New Desktop Window: 0x000B0050
            New Desktop: SAWinSta
                        New Desktop Window: 0x000B0050


NEW WINDOW STATION: Service-0x0-3e5$
            New Desktop: WinSta0
                        New Desktop Window: 0x000B0050
            New Desktop: Service-0x0-3e7$
                        New Desktop Window: 0x000B0050
            New Desktop: Service-0x0-3e4$
                        New Desktop Window: 0x000B0050
            New Desktop: Service-0x0-3e5$
                        New Desktop Window: 0x000B0050
            New Desktop: SAWinSta
                        New Desktop Window: 0x000B0050


NEW WINDOW STATION: SAWinSta
            New Desktop: SADesktop
                        New Desktop Window: 0x000B0050
Do you create the service with:
CreateService(...
                    ,...
                    ,..
                    ,SERVICE_ALL_ACCESS
                    ,SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS      
                    ,SERVICE_AUTO_START
                    ,SERVICE_ERROR_NORMAL
                    ,...
                    ,null
                    ,0
                    ,null
                    ,null
                    ,null);




,SERVICE_ALL_ACCESS
                      ,SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS
                      ,SERVICE_AUTO_START
                      ,SERVICE_ERROR_NORMAL
Avatar of cc16

ASKER

i wasnt using CreateService...

is

ServiceStatus.dwServiceType = SERVICE_ALL_ACCESS | SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS | SERVICE_AUTO_START | SERVICE_ERROR_NORMAL;

ok?
Avatar of cc16

ASKER

Oh i get it... CreateService is to put the service into the database...
Avatar of cc16

ASKER

Ok I added it to the DB using CreateService.

Now GetWindowText returns ÝÝÝÝÝ each time (the length of the Ý string varies). I also couldnt help noticing that Ý is 11111111 in binary.

Anyways i dont think GetWindowText is so important.

The important thing is do I hook the only window in Winlogon, or should i use a global hook, or what?
I'll post some code later this weekend.

As far as the eventual hook is concerned, I believe it would have to be global.  A hook is either for a single thread or for all threads, and I believe GINA may very well have several threads to worry about.  With the global hook, you're not realy concerned with any specific thread, rather you'll want to see the messages associated with the specific window.
Slight delay - I lost a drive.
Should have everything rebuilt by tomorrow.
Here's some straight C code you can use to enumerate stations, desktops, and windows.

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <winbase.h>
#include <winsvc.h>
#include <process.h>
#include <shellapi.h>
#include <time.h>
#include <sys/types.h>
#include <sys/timeb.h>


BOOL CALLBACK EnumWindowStaCallback(LPTSTR,LPARAM);
BOOL CALLBACK EnumDesktopCallback(LPTSTR,LPARAM);
BOOL CALLBACK EnumWindowsCallback(HWND,LPARAM);
void          PutMSG(char*);

char MyFullName[512];
char LOGFile[512];
char EXEFile[512];


////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////// main
/////////////////////////////////////////////////////////////////////////////////
void main(int argc ,char * argv[])
{
int   RC;
char  ts[512];

// Get our full name
GetModuleFileName(NULL,MyFullName,511);
sprintf(EXEFile,"%s",MyFullName);

// Put the log file in the same directory
MyFullName[strlen(MyFullName)-4]='\0';
sprintf(LOGFile,"%s.log",MyFullName);

RC=EnumWindowStations(EnumWindowStaCallback,0);
return;
}

/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// EnumWindowStaCallback
///////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumWindowStaCallback(char* StationName,LPARAM lParam)
{
char ts[512];
HWINSTA hstation;
BOOL RC;

// Say who we found
PutMSG(" ");
sprintf(ts,"Station: <%s>",StationName);
PutMSG(ts);

// Enumerate this station's desktops
hstation=OpenWindowStation(StationName,true,STANDARD_RIGHTS_REQUIRED
                                           |WINSTA_ACCESSGLOBALATOMS
                                           |WINSTA_ENUMDESKTOPS
                                           |WINSTA_ENUMERATE
                                           |WINSTA_READATTRIBUTES
                                           |WINSTA_READSCREEN);
if (hstation==NULL)
   {
   sprintf(ts,"OpenWindowStation failure(%d)",GetLastError());
   PutMSG(ts);
   return true;
   }

RC=EnumDesktops(hstation,EnumDesktopCallback,lParam);
if (!RC)
   {
   sprintf(ts,"EnumDesktops failure(%d)",GetLastError());
   PutMSG(ts);
   }

CloseWindowStation(hstation);

return true;
}

///////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////// EnumDesktopCallback
///////////////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumDesktopCallback(LPTSTR DesktopName,LPARAM lParam)
{
char ts[512];
HDESK hdesktop;
BOOL RC;

// Say who we found
sprintf(ts,"         Desktop: <%s>",DesktopName);
PutMSG(ts);

// Enumerate this desktop's windows
hdesktop=OpenDesktop(DesktopName,0,true,DESKTOP_ENUMERATE|DESKTOP_READOBJECTS);
if (hdesktop==NULL)
   {
   sprintf(ts,"         OpenDesktop failure(%d)",GetLastError());
   PutMSG(ts);
   return true;
   }
RC=EnumDesktopWindows(hdesktop,EnumWindowsCallback,lParam);
if (!RC)
   {
   sprintf(ts,"         EnumWindows failure(%d)",GetLastError());
   PutMSG(ts);
   }

CloseDesktop(hdesktop);
return true;
}

///////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////// EnumWindowsCallback
///////////////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumWindowsCallback(HWND hwnd,LPARAM lParam)
{
int  TitleLen;
char Title[512];
char ts[512];

// Say who we found
Title[0]='\0';
TitleLen=GetWindowText(hwnd,Title,511);
Title[511]='\0';
sprintf(ts,"                  Window: <%s>",Title);
PutMSG(ts);

return true;
}

/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// PutMSG
////////////////////////////////////////////////////////////////////////////////////
void PutMSG(char * msg)
{
FILE   * fh;
char   tmpbuf[128];
struct _timeb tstruct;

_strtime(tmpbuf);
_ftime( &tstruct );

fh=fopen(LOGFile,"a");
fprintf(fh,"%s.%u - %s\n",tmpbuf,tstruct.millitm,msg);
fclose(fh);
}




Avatar of cc16

ASKER

Wow that is a fast recovery time for a lost drive :O

the code is cool... it works n everything, but im getting

11:23:18.539 -          Desktop: <Winlogon>
11:23:18.539 -          OpenDesktop failure(5)

for the winlogon desktop. maybe it is because i was already logged on or something.

im *really* getting held up with excess assignments here, so i dont think i will be able to spend any time on this until the weekend.

when i do eventually get around to it, ill put your code into a service and see what's going on...

cheers,
southern curriez
>>Wow that is a fast recovery time for a lost drive :O
Actually, the drive crashed on Saturday and the restore and various installs today went faster than expected.
(sure am glad I daily incrementals)

Anyway, if the error 5 is accurate, that means it's a rights problem.  

I just ran it and got a similar result.

I posted the code from an old archive of working code from a little over a year ago - when it worked.  I haven't moved to XP SP2 yet, so I can only assume one of the many intermediate fixes, uh, 'fixed' something.

I'll look into it.
I put in in a LocalSystem service, and it was happy with WinLogon:

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <winbase.h>
#include <winsvc.h>
#include <process.h>
#include <shellapi.h>
#include <time.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <winreg.h>


VOID WINAPI   SvcMain(DWORD,LPTSTR*);
VOID WINAPI   SvcHandler(DWORD);
VOID          Install(char*,char*);
BOOL CALLBACK EnumWindowStaCallback(LPTSTR,LPARAM);
BOOL CALLBACK EnumDesktopCallback(LPTSTR,LPARAM);
BOOL CALLBACK EnumWindowsCallback(HWND,LPARAM);

void          PutMSG(char*);

char MyFullName[512];
char LOGFile[512];
char EXEFile[512];
char SvcName[512];


// Service management
SERVICE_STATUS         SvcStatusInfo;
SERVICE_STATUS_HANDLE  SvcStatusHandle;
SERVICE_TABLE_ENTRY    DispatchTable[]={{"EnumSvc",SvcMain},{NULL, NULL}};



////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////// main
/////////////////////////////////////////////////////////////////////////////////
void main(int argc ,char * argv[])
{
strcpy(SvcName,"EnumSvc");

// Get our full name
GetModuleFileName(NULL,MyFullName,511);
sprintf(EXEFile,"%s",MyFullName);

// Put the log file in the same directory
MyFullName[strlen(MyFullName)-4]='\0';
sprintf(LOGFile,"%s.log",MyFullName);

// -i parm says to install and start the service
if (argc>1)
   {
   if (0==stricmp(argv[1],"-i"))
      {
      Install(EXEFile,SvcName);
      return;
      }
   }

// We're not installing - this is the real thing
if (!StartServiceCtrlDispatcher(DispatchTable))
   {
   char ts[512];
   sprintf(ts,"StartServiceCtrlDispatcher failure (%d)",GetLastError());
   PutMSG(ts);
   }
return;
}

////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////// Install
////////////////////////////////////////////////////////////////////////////////////
VOID Install(char* ExePath, char* SvcName)
{
SC_HANDLE SCM,svc;
char      ts[256];

PutMSG("Installing");

SCM=OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE);
if (SCM==0)
   {
   sprintf(ts,"OpenSCManager failure (%d)",GetLastError());
   PutMSG(ts);
   }
else
   {
   svc=CreateService(SCM
                    ,SvcName
                    ,SvcName
                    ,SERVICE_ALL_ACCESS
                    ,SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS
                    ,SERVICE_AUTO_START
                    ,SERVICE_ERROR_NORMAL
                    ,ExePath
                    ,NULL
                    ,NULL
                    ,NULL
                    ,".\\LocalSystem"
                    ,"");
   if (svc==0)
      {
      sprintf(ts,"CreateService failure (%d)",GetLastError());
      PutMSG(ts);
      }
   else
      {
      PutMSG("Install successful");
      if (!StartService(svc,0,NULL))
         {
         sprintf(ts,"StartService failure (%d)",GetLastError());
         PutMSG(ts);
         }
      CloseServiceHandle(svc);
      }
   CloseServiceHandle(SCM);
   }
}

//////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////// SvcMain
//////////////////////////////////////////////////////////////////////////////
VOID WINAPI SvcMain(DWORD SvcArgc,LPTSTR *SvcArgv )
{
int   RC;
DWORD status=0;
char  ts[512];

SvcStatusInfo.dwServiceType             =SERVICE_WIN32;
SvcStatusInfo.dwCurrentState            =SERVICE_START_PENDING;
SvcStatusInfo.dwControlsAccepted        =SERVICE_ACCEPT_STOP
                                        |SERVICE_ACCEPT_SHUTDOWN
                                        |SERVICE_ACCEPT_PAUSE_CONTINUE;
SvcStatusInfo.dwWin32ExitCode           =0;
SvcStatusInfo.dwServiceSpecificExitCode =0;
SvcStatusInfo.dwCheckPoint              =0;
SvcStatusInfo.dwWaitHint                =0;

SvcStatusHandle=RegisterServiceCtrlHandler(SvcName,SvcHandler);
if (SvcStatusHandle==0)
   {
   sprintf(ts,"RegisterServiceCtrlHandler failure (%d)",GetLastError());
   PutMSG(ts);
   //@@@@@ shut down
   return;
   }

// oopsie?
status=GetLastError();
if (status!=NO_ERROR)
   {
   SvcStatusInfo.dwCurrentState            =SERVICE_STOPPED;
   SvcStatusInfo.dwCheckPoint              =0;
   SvcStatusInfo.dwWaitHint                =0;
   SvcStatusInfo.dwWin32ExitCode           =status;
   SvcStatusInfo.dwServiceSpecificExitCode =0;

   SetServiceStatus(SvcStatusHandle,&SvcStatusInfo);
   return;
   }

// Initialization complete - report running status
SvcStatusInfo.dwCurrentState =SERVICE_RUNNING;
SvcStatusInfo.dwCheckPoint   =0;
SvcStatusInfo.dwWaitHint     =0;

if (!SetServiceStatus(SvcStatusHandle,&SvcStatusInfo))
   {
   sprintf(ts,"SetServiceStatus failure(%d)",GetLastError());
   PutMSG(ts);
   //@@@@@ shut down
   }

PutMSG("SvcMain Initialized");
while (true)
      {
      RC=EnumWindowStations(EnumWindowStaCallback,0);
      sprintf(ts,"RC=%d LE=%d",RC,GetLastError());
      Sleep(10000);
      }
}

/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// EnumWindowStaCallback
///////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumWindowStaCallback(char* StationName,LPARAM lParam)
{
char ts[512];
HWINSTA hstation;
BOOL RC;

// Say who we found
PutMSG(" ");
sprintf(ts,"Station: %s",StationName);
PutMSG(ts);

// Enumerate this station's desktops
hstation=OpenWindowStation(StationName,true,STANDARD_RIGHTS_REQUIRED
                                           |WINSTA_ACCESSGLOBALATOMS
                                           |WINSTA_ENUMDESKTOPS
                                           |WINSTA_ENUMERATE
                                           |WINSTA_READATTRIBUTES
                                           |WINSTA_READSCREEN);
if (hstation==NULL)
   {
   sprintf(ts,"OpenWindowStation failure(%d)",GetLastError());
   PutMSG(ts);
   return true;
   }

RC=EnumDesktops(hstation,EnumDesktopCallback,lParam);
if (!RC)
   {
   sprintf(ts,"EnumDesktops failure(%d)",GetLastError());
   PutMSG(ts);
   }

CloseWindowStation(hstation);

return true;
}

///////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////// EnumDesktopCallback
///////////////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumDesktopCallback(LPTSTR DesktopName,LPARAM lParam)
{
char ts[512];
HDESK hdesktop;
BOOL RC;

// Say who we found
sprintf(ts,"         Desktop: %s",DesktopName);
PutMSG(ts);

// Enumerate this desktop's windows
hdesktop=OpenDesktop(DesktopName,0,true,DESKTOP_ENUMERATE|DESKTOP_READOBJECTS|MAXIMUM_ALLOWED);
if (hdesktop==NULL)
   {
   sprintf(ts,"         OpenDesktop failure(%d)",GetLastError());
   PutMSG(ts);
   return true;
   }
RC=EnumDesktopWindows(hdesktop,EnumWindowsCallback,lParam);
if (!RC)
   {
   sprintf(ts,"         EnumWindows failure(%d)",GetLastError());
   PutMSG(ts);
   }

CloseDesktop(hdesktop);
return true;
}

///////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////// EnumWindowsCallback
///////////////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumWindowsCallback(HWND hwnd,LPARAM lParam)
{
int  TitleLen;
char Title[512];
char ts[512];

// Say who we found
Title[0]='\0';
TitleLen=GetWindowText(hwnd,Title,511);
Title[511]='\0';
sprintf(ts,"                  Window: %s",Title);
PutMSG(ts);

return true;
}

///////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////// SvcHandler
//////////////////////////////////////////////////////////////////////////////
VOID WINAPI SvcHandler(DWORD fdwControl)
{
char ts[256];

switch (fdwControl)
       {
       case SERVICE_CONTROL_STOP:

       case SERVICE_CONTROL_SHUTDOWN:

            SvcStatusInfo.dwWin32ExitCode = 0;
            SvcStatusInfo.dwCurrentState  = SERVICE_STOPPED;
            SvcStatusInfo.dwCheckPoint    = 0;
            SvcStatusInfo.dwWaitHint      = 0;
            SetServiceStatus(SvcStatusHandle,&SvcStatusInfo);

            PutMSG("Stopped");
            return;

       case SERVICE_CONTROL_INTERROGATE:
            break;

       default:
               sprintf(ts,"Unhandled message (%d)",fdwControl);
               PutMSG(ts);
               break;
       };
if (!SetServiceStatus(SvcStatusHandle,  &SvcStatusInfo))
   {
   sprintf(ts,"SetServiceStatus failure (%d)",GetLastError());
   PutMSG(ts);
   }
}

/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// PutMSG
////////////////////////////////////////////////////////////////////////////////////
void PutMSG(char * msg)
{
FILE   * fh;
char   tmpbuf[128];
struct _timeb tstruct;

_strtime(tmpbuf);
_ftime( &tstruct );

fh=fopen(LOGFile,"a");
fprintf(fh,"%s.%u - %s\n",tmpbuf,tstruct.millitm,msg);
fclose(fh);
}


Avatar of cc16

ASKER

i finally managed to get on top of my workload, so my spare time is gradually increasing...

i tested out (my modified c++ code) in a service and everything (including GetWindowText) worked fine...

i wrote a new code which was basically

if(WINDOW_STATION == "WinSta0")
{
        if(DESKTOP == "Winlogon")
        {
                launch_cmd();
        }
}

void launch_cmd()
{
     STARTUPINFO si ;
     PROCESS_INFORMATION pi ;
     
     ZeroMemory(&si, sizeof(si));
     si.cb = sizeof (STARTUPINFO);
     si.wShowWindow = SW_SHOW;
     si.lpDesktop = THE_HDESK_OF_WINLOGON;
     CreateProcess (NULL, "cmd.exe"  , NULL , NULL , FALSE , 0 , NULL , NULL, &si, &pi);
}

however it didnt work...

any ideaz why?
Avatar of cc16

ASKER

* replace THE_HDESK_OF_WINLOGON with THE_STRING_NAME_OF_WINLOGON
Avatar of cc16

ASKER

i got it to work

thanks for the help :)
Well, with all that spare time they can dump more work on you...
Help, I am using that code example above in a windows service in Vista and i am not seeing my windows. here is the output i get:

17:13:24.988 -  
17:13:24.989 - Station: <WinSta0>
17:13:24.989 -          Desktop: <Default>
17:13:24.989 -                   Window: <Wrapper Controlled JVM Console ID 114132523 (Do not close)>
17:13:24.990 -                   Window: <>
17:13:24.990 -                   Window: <>
17:13:24.990 -                   Window: <Default IME>
17:13:24.991 -                   Window: <Default IME>
17:13:24.991 -          Desktop: <Disconnect>
17:13:24.991 -          EnumWindows failure(183)
17:13:24.991 -          Desktop: <Winlogon>
17:13:24.992 -          EnumWindows failure(183)
17:13:24.992 -  
17:13:24.992 - Station: <Service-0x0-3e7$>
17:13:24.993 - OpenWindowStation failure(5)
17:13:24.993 -  
17:13:24.993 - Station: <Service-0x0-3e4$>
17:13:24.994 - OpenWindowStation failure(5)
17:13:24.994 -  
17:13:24.994 - Station: <Service-0x0-3e5$>
17:13:24.995 - OpenWindowStation failure(5)
17:13:24.995 -  
17:13:24.996 - Station: <msswindowstation>
17:13:24.996 - OpenWindowStation failure(5)