Cómo implementar el monitoreo de pantalla bajo los permisos del SISTEMA
1. Principios básicos del monitoreo de pantalla
El monitoreo de pantalla simplemente significa tomar una captura de pantalla del escritorio actual del proceso y guardarla como un mapa de bits, y luego transmitir los datos del mapa de bits al remoto.
La captura del escritorio debe completarse a través de una serie de API GDI de Windows.
Primero, asocie el contexto del dispositivo del controlador "DISPLAY" con el identificador del mapa de bits a través de API como CreateDC, CreateCompatibleDC, CreateCompatibleBitmap, SelectObject, etc.
La paleta luego se procesa a través de API como GetStockObject, GetDC, SelectPalette, etc.
Finalmente, todos los datos de píxeles de líneas horizontales se almacenan en el búfer a través de GetDIBits en un bucle.
Este búfer son los datos de mapa de bits que queremos, siempre que los datos estén organizados, se pueden mostrar como un mapa de bits. Al transmitir continuamente el mapa de bits, la pantalla remota se puede monitorear en tiempo real. Este proceso es relativamente sencillo, por lo que no se desperdician palabras.
2. Window Station y Escritorio
En primer lugar, debes comprender varios conceptos importantes:
Window Station (WindowsStation) y Desktop (Desktop) son Windows. sistemas operativos La capa inferior está expuesta al objeto ejecutor de la API de Windows (hay dos tipos de objetos dentro de Windows: objetos ejecutores y objetos del kernel. El objeto ejecutor se refiere al objeto de ejecución implementado por varios componentes del ejecutor, como el proceso administrador, administrador de memoria, etc. Los objetos del kernel son un conjunto más básico de objetos implementados por el kernel de Windows).
Entre ellos, el objeto de estación de ventana incluye un portapapeles, un conjunto de átomos globales y un conjunto de objetos de escritorio. Un objeto de escritorio es un objeto contenido dentro de una estación de ventana. El objeto de escritorio tiene una superficie de visualización lógica que contiene ventanas, menús y ganchos.
La estación de ventana número 0 (WinSta0) y el objeto de escritorio predeterminado (escritorio predeterminado) se crean mediante el proceso Winlogon. La estación de ventana es la estructura organizativa del siguiente nivel de la sesión. Una sesión puede tener varias estaciones de ventana, pero solo una estación de ventana puede interactuar con el usuario al mismo tiempo. Cada estación de ventana tiene su propio portapapeles y puede tener varios escritorios. El proceso Winlogon llama a la función NtUserCreateWindowsStation para crear una estación de ventana y luego llama a NtUserCreateDesktop para crear el escritorio. Primero creará un escritorio llamado Winlogon para su propio uso (la interfaz de inicio de sesión de Windows pertenece a este escritorio) y luego creará un escritorio llamado Predeterminado para que lo use la aplicación. Después de crear el escritorio, Winlogon llama a la función SetActiveDesktop para configurar el escritorio de Winlogon como el escritorio activo actual.
Después, Winlogon creará un administrador de servicios (Service.exe) y un subsistema de autenticación de seguridad local (LSASS.exe) para administrar los servicios del sistema. Después de verificar la información de inicio de sesión del usuario, Winlogon activará el escritorio de la aplicación, iniciará el programa UserInit, UserInit ejecutará el script de inicio de sesión definido en el registro y luego iniciará el shell del sistema operativo (Shell: el valor predeterminado es explorer.exe). Este es el comienzo de la separación del escritorio de visualización lógica de los procesos privilegiados del SISTEMA y los procesos de usuario ordinarios. En el proceso de creación de CreateProcess en el futuro, si no se especifica ningún escritorio, el proceso se asociará con el escritorio actual de la persona que llama.
En la prueba real, se encontró que los servicios y procesos svchost no parecían estar asociados con ningún escritorio (las capturas de pantalla estaban todas en negro). Los procesos ordinarios son el escritorio predeterminado y la interfaz de inicio de sesión es el escritorio Winlogon. Por lo tanto, cuando el dll se inserta en un proceso como service.exe, para tomar una captura de pantalla, el proceso debe estar asociado con el escritorio predeterminado. Cuando el usuario cierra sesión, sale o no inicia sesión, el proceso debe estar asociado. asociado con el escritorio de Winlogon.
Windows nos proporciona algunas API que nos permiten hacer estas cosas.
Primero, puede abrir un objeto de estación de ventana a través de OpenWindowStation, luego asociar el proceso con la estación de ventana a través de SetProcessWindowStation, abrir un objeto de escritorio a través de OpenDesktop y luego asociar el hilo con el escritorio a través de SetThreadDesktop. De esta forma, service.exe puede realizar capturas de pantalla. Pero ¿cómo podemos saber en qué escritorio se encuentra el usuario actual? Esto se puede lograr mediante las siguientes funciones:
OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, MAXIMUM_ALLOWED);//Abrir el escritorio de entrada
GetUserObjectInformation(hActiveDesktop, UOI_NAME, pvInfo, sizeof(pvInfo) , &dwLen); //Obtiene la información del objeto de escritorio especificado. Generalmente, el estado del protector de pantalla es el predeterminado y la interfaz de inicio de sesión es winlogon
El búfer pvInfo contiene el escritorio actual. De esta forma, podrás llamar a OpenDesktop para abrirlo con confianza.
El código completo es el siguiente:
BOOL OpenDesktop(LPCWSTR szName)
{
WCHAR pvInfo[128] = {0 };
WCHAR tmp[1024] = {0};
if(szName != NULL)
lstrcpy(pvInfo, szName);
else
{
HDESK hActiveDesktop;
DWORD dwLen;
hActiveDesktop = OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, MAXIMUM_ALLOWED) ; p>
if(!hActiveDesktop)//No se pudo abrir
{
return FALSE;
}
//Obtener Especifique la información del objeto del escritorio. La situación general y el estado del protector de pantalla son predeterminados y la interfaz de inicio de sesión es winlogon
GetUserObjectInformation(hActiveDesktop, UOI_NAME, pvInfo, sizeof(pvInfo), &dwLen). ;
if( dwLen==0)//No se pudo obtener
{
return FALSE;
}
CloseDesktop(hActiveDesktop);
//Abrir winsta0
m_hwinsta = OpenWindowStation(_T("winsta0"), FALSE,
WINSTA_ACCESSCLIPBOARD | p>
WINSTA_ACCESSGLOBALATOMS |
WINSTA_CREATEDESKTOP |
WINSTA_ENUMDESKTOPS |
WINSTA_ENUMERATE |
WINSTA_EXITWINDOWS |
WINSTA_READATTRIBUTES |
WINSTA_READSCREEN
WINSTA_WRITEATTRIBUTES)
;
if (m_hwinsta == NULL){
return FALSE;
}
if (!SetProcessWindowStation(m_hwinsta)){
return FALSE;
}
//Abrir escritorio
m_hdesk = OpenDesktop(pvInfo, 0, FALSE,
DESKTOP_CREATEMENU |
DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE |
DESKTOP_HOOKCONTROL |
DESKTOP_JOURNALRECORD |
DESKTOP_JOURNALRECORD |
DESKTOP_READOBJECTS |
DESKTOP_SWITCHDESKTOP |
DESKTOP_WRITEOBJECTS);
if (m_hdesk == NULL){
devuelve FALSO;
}
SetThreadDesktop(m_hdesk);
devuelve VERDADERO;
}
El código Es un poco Caos, ¡confórmate con ello!
3. Postscript
El código anterior es solo para procesos como service.exe. Si desea que sea universal, debe agregar algo de código.