mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-01-14 17:37:27 +01:00
Add service_query to ext_server_extapi
Once the user has queried the list of services they can now use the `service_query` function to get more detail about a specific service.
This commit is contained in:
parent
f720ca7bdb
commit
984880d8b2
@ -28,6 +28,10 @@ Command customCommands[] =
|
||||
{ request_service_enum, { 0 }, 0 },
|
||||
{ EMPTY_DISPATCH_HANDLER }
|
||||
},
|
||||
{ "extapi_service_query",
|
||||
{ request_service_query, { 0 }, 0 },
|
||||
{ EMPTY_DISPATCH_HANDLER }
|
||||
},
|
||||
// Terminator
|
||||
{ NULL,
|
||||
{ EMPTY_DISPATCH_HANDLER },
|
||||
|
@ -9,16 +9,24 @@
|
||||
|
||||
#define TLV_TYPE_EXTENSION_EXTAPI 0
|
||||
|
||||
#define TLV_TYPE_EXT_WINDOW_ENUM_GROUP MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 1)
|
||||
#define TLV_TYPE_EXT_WINDOW_ENUM_PID MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 2)
|
||||
#define TLV_TYPE_EXT_WINDOW_ENUM_HANDLE MAKE_CUSTOM_TLV(TLV_META_TYPE_QWORD, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 3)
|
||||
#define TLV_TYPE_EXT_WINDOW_ENUM_TITLE MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 4)
|
||||
#define TLV_TYPE_EXT_WINDOW_ENUM_GROUP MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 1)
|
||||
#define TLV_TYPE_EXT_WINDOW_ENUM_PID MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 2)
|
||||
#define TLV_TYPE_EXT_WINDOW_ENUM_HANDLE MAKE_CUSTOM_TLV(TLV_META_TYPE_QWORD, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 3)
|
||||
#define TLV_TYPE_EXT_WINDOW_ENUM_TITLE MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 4)
|
||||
|
||||
#define TLV_TYPE_EXT_SERVICE_ENUM_GROUP MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 10)
|
||||
#define TLV_TYPE_EXT_SERVICE_ENUM_NAME MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 11)
|
||||
#define TLV_TYPE_EXT_SERVICE_ENUM_DISPLAYNAME MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 12)
|
||||
#define TLV_TYPE_EXT_SERVICE_ENUM_PID MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 13)
|
||||
#define TLV_TYPE_EXT_SERVICE_ENUM_STATUS MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 14)
|
||||
#define TLV_TYPE_EXT_SERVICE_ENUM_INTERACTIVE MAKE_CUSTOM_TLV(TLV_META_TYPE_BOOL, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 15)
|
||||
#define TLV_TYPE_EXT_SERVICE_ENUM_GROUP MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 10)
|
||||
#define TLV_TYPE_EXT_SERVICE_ENUM_NAME MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 11)
|
||||
#define TLV_TYPE_EXT_SERVICE_ENUM_DISPLAYNAME MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 12)
|
||||
#define TLV_TYPE_EXT_SERVICE_ENUM_PID MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 13)
|
||||
#define TLV_TYPE_EXT_SERVICE_ENUM_STATUS MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 14)
|
||||
#define TLV_TYPE_EXT_SERVICE_ENUM_INTERACTIVE MAKE_CUSTOM_TLV(TLV_META_TYPE_BOOL, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 15)
|
||||
|
||||
#define TLV_TYPE_EXT_SERVICE_QUERY_STARTTYPE MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 20)
|
||||
#define TLV_TYPE_EXT_SERVICE_QUERY_DISPLAYNAME MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 21)
|
||||
#define TLV_TYPE_EXT_SERVICE_QUERY_STARTNAME MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 22)
|
||||
#define TLV_TYPE_EXT_SERVICE_QUERY_PATH MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 23)
|
||||
#define TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 24)
|
||||
#define TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE MAKE_CUSTOM_TLV(TLV_META_TYPE_BOOL, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 25)
|
||||
#define TLV_TYPE_EXT_SERVICE_QUERY_DACL MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 26)
|
||||
|
||||
#endif
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "service.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Sddl.h>
|
||||
|
||||
typedef SC_HANDLE (WINAPI * POPENSCMANAGERA)( LPCSTR lpMachineName, LPCSTR lpDatabaseName, DWORD dwDesiredAccess );
|
||||
typedef BOOL (WINAPI * PCLOSESERVICEHANDLE)( SC_HANDLE hSCObject );
|
||||
@ -21,39 +22,147 @@ typedef BOOL (WINAPI * PENUMSERVICESSTATUSEXA)(
|
||||
LPDWORD lpResumeHandle,
|
||||
LPCSTR pszGroupName
|
||||
);
|
||||
|
||||
typedef struct _EnumServicesState
|
||||
{
|
||||
Packet* pResponse;
|
||||
} EnumServicesState;
|
||||
typedef SC_HANDLE (WINAPI * POPENSERVICEA)( SC_HANDLE hSCManager, LPCSTR lpServiceName, DWORD dwDesiredAcces );
|
||||
typedef BOOL (WINAPI * PQUERYSERVICEOBJECTSECURITY)(
|
||||
SC_HANDLE hService,
|
||||
SECURITY_INFORMATION dwSecurityInformation,
|
||||
PSECURITY_DESCRIPTOR lpSecurityDescriptor,
|
||||
DWORD cbBufSize,
|
||||
LPDWORD pcbBytesNeeded
|
||||
);
|
||||
typedef BOOL (WINAPI * PQUERYSERVICECONFIGA)(
|
||||
SC_HANDLE hService,
|
||||
LPQUERY_SERVICE_CONFIGA lpServiceConfig,
|
||||
DWORD dbBufSize,
|
||||
LPDWORD pcbBytesNeeded
|
||||
);
|
||||
typedef BOOL (WINAPI * PCSDTSSDA)(
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||
DWORD RequestedStringSDRevision,
|
||||
SECURITY_INFORMATION SecurityInformation,
|
||||
LPCSTR *StringSecurityDescriptor,
|
||||
PULONG StringSecurityDescriptorLen
|
||||
);
|
||||
|
||||
VOID add_enumerated_service( Packet *pResponse, LPCSTR cpName, LPCSTR cpDisplayName, DWORD dwProcessId, DWORD dwStatus, BOOL bInteractive );
|
||||
DWORD get_service_config( HMODULE hAdvapi32, SC_HANDLE scService, Packet *pResponse );
|
||||
DWORD get_service_dacl( HMODULE hAdvapi32, SC_HANDLE scService, Packet *pResponse );
|
||||
#endif
|
||||
|
||||
DWORD enumerate_services( Packet *response );
|
||||
|
||||
DWORD request_service_enum(Remote *remote, Packet *packet)
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
Packet * response = packet_create_response( packet );
|
||||
|
||||
do
|
||||
{
|
||||
if( !response ) {
|
||||
dprintf( "Unable to create response packet" );
|
||||
result = ERROR_OUTOFMEMORY;
|
||||
dwResult = ERROR_OUTOFMEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
dprintf( "Beginning service enumeration" );
|
||||
result = enumerate_services( response );
|
||||
dwResult = enumerate_services( response );
|
||||
|
||||
} while(0);
|
||||
|
||||
dprintf( "Transmitting response back to caller." );
|
||||
packet_transmit_response( result, remote, response );
|
||||
if( response )
|
||||
packet_transmit_response( dwResult, remote, response );
|
||||
|
||||
return result;
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
DWORD request_service_query(Remote *remote, Packet *packet)
|
||||
{
|
||||
LPSTR lpServiceName = NULL;
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
Packet * response = packet_create_response( packet );
|
||||
|
||||
do
|
||||
{
|
||||
if( !response ) {
|
||||
dprintf( "Unable to create response packet" );
|
||||
dwResult = ERROR_OUTOFMEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
lpServiceName = packet_get_tlv_value_string( packet, TLV_TYPE_EXT_SERVICE_ENUM_NAME );
|
||||
if( !lpServiceName )
|
||||
BREAK_WITH_ERROR( "Missing service name parameter", ERROR_BAD_ARGUMENTS );
|
||||
|
||||
dprintf( "Beginning service enumeration" );
|
||||
dwResult = query_service( lpServiceName, response );
|
||||
|
||||
} while(0);
|
||||
|
||||
dprintf( "Transmitting response back to caller." );
|
||||
if( response )
|
||||
packet_transmit_response( dwResult, remote, response );
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
DWORD query_service( LPCSTR cpServiceName, Packet *pResponse )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// currently we only support Windoze
|
||||
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
HMODULE hAdvapi32 = NULL;
|
||||
POPENSCMANAGERA pOpenSCManagerA = NULL;
|
||||
PCLOSESERVICEHANDLE pCloseServiceHandle = NULL;
|
||||
POPENSERVICEA pOpenServiceA = NULL;
|
||||
SC_HANDLE scManager = NULL;
|
||||
SC_HANDLE scService = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
dprintf( "Loading advapi32.dll" );
|
||||
if( (hAdvapi32 = LoadLibraryA( "advapi32.dll" )) == NULL)
|
||||
BREAK_ON_ERROR( "Unable to load advapi32.dll" );
|
||||
|
||||
dprintf( "Searching for OpenSCManagerA" );
|
||||
if( (pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress( hAdvapi32, "OpenSCManagerA" )) == NULL )
|
||||
BREAK_ON_ERROR( "Unable to locate OpenSCManagerA in advapi32.dll" );
|
||||
|
||||
dprintf( "Searching for CloseServiceHandle" );
|
||||
if( (pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress( hAdvapi32, "CloseServiceHandle" )) == NULL )
|
||||
dprintf( "Unable to locate CloseServiceHandle in advapi32.dll. Continuing anyway." );
|
||||
|
||||
dprintf( "Searching for OpenServiceA" );
|
||||
if( (pOpenServiceA = (POPENSERVICEA)GetProcAddress( hAdvapi32, "OpenServiceA" )) == NULL )
|
||||
BREAK_ON_ERROR( "Unable to locate OpenServiceA in advapi32.dll." );
|
||||
|
||||
dprintf( "Opening the Service Control manager" );
|
||||
if( (scManager = pOpenSCManagerA( NULL, SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT|GENERIC_READ )) == NULL )
|
||||
BREAK_ON_ERROR( "Unable to open the service control manager" );
|
||||
|
||||
dprintf( "Opening the Service: %s", cpServiceName );
|
||||
if( (scService = pOpenServiceA( scManager, cpServiceName, SC_MANAGER_CONNECT|GENERIC_READ )) == NULL )
|
||||
BREAK_ON_ERROR( "Unable to open the service: %s", cpServiceName );
|
||||
|
||||
get_service_config( hAdvapi32, scService, pResponse );
|
||||
get_service_dacl( hAdvapi32, scService, pResponse );
|
||||
|
||||
} while(0);
|
||||
|
||||
if( scService && pCloseServiceHandle )
|
||||
pCloseServiceHandle( scService );
|
||||
|
||||
if( scManager && pCloseServiceHandle )
|
||||
pCloseServiceHandle( scManager );
|
||||
|
||||
if( hAdvapi32 )
|
||||
FreeLibrary( hAdvapi32 );
|
||||
|
||||
return dwResult;
|
||||
#else
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
DWORD enumerate_services( Packet *pResponse )
|
||||
@ -174,4 +283,92 @@ VOID add_enumerated_service( Packet *pResponse, LPCSTR cpName, LPCSTR cpDisplayN
|
||||
dprintf( "Adding group to response" );
|
||||
packet_add_tlv_group( pResponse, TLV_TYPE_EXT_SERVICE_ENUM_GROUP, entries, 5 );
|
||||
}
|
||||
|
||||
DWORD get_service_config( HMODULE hAdvapi32, SC_HANDLE scService, Packet *pResponse )
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
PQUERYSERVICECONFIGA pQueryServiceConfigA = NULL;
|
||||
LPQUERY_SERVICE_CONFIGA lpServiceConfig = NULL;
|
||||
DWORD cbBytesNeeded = 0;
|
||||
|
||||
do
|
||||
{
|
||||
dprintf( "Searching for QueryServiceConfigA" );
|
||||
if( (pQueryServiceConfigA = (PQUERYSERVICECONFIGA)GetProcAddress( hAdvapi32, "QueryServiceConfigA" )) == NULL )
|
||||
BREAK_ON_ERROR( "Unable to locate QueryServiceConfigA in advapi32.dll." );
|
||||
|
||||
if( pQueryServiceConfigA( scService, NULL, 0, &cbBytesNeeded ) )
|
||||
BREAK_ON_ERROR( "This query should have failed" );
|
||||
|
||||
if( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
|
||||
BREAK_ON_ERROR( "Unexpected error from QueryServiceConfigA" );
|
||||
|
||||
if( (lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)malloc( cbBytesNeeded )) == NULL )
|
||||
BREAK_ON_ERROR( "Out of memory" );
|
||||
|
||||
if( !pQueryServiceConfigA( scService, lpServiceConfig, cbBytesNeeded, &cbBytesNeeded ) )
|
||||
BREAK_ON_ERROR( "QueryServiceConfigA failed" );
|
||||
|
||||
dprintf( "Start type: %u", lpServiceConfig->dwStartType );
|
||||
packet_add_tlv_uint( pResponse, TLV_TYPE_EXT_SERVICE_QUERY_STARTTYPE, lpServiceConfig->dwStartType );
|
||||
packet_add_tlv_string( pResponse, TLV_TYPE_EXT_SERVICE_QUERY_DISPLAYNAME, lpServiceConfig->lpDisplayName );
|
||||
packet_add_tlv_string( pResponse, TLV_TYPE_EXT_SERVICE_QUERY_STARTNAME, lpServiceConfig->lpServiceStartName );
|
||||
packet_add_tlv_string( pResponse, TLV_TYPE_EXT_SERVICE_QUERY_PATH, lpServiceConfig->lpBinaryPathName );
|
||||
packet_add_tlv_string( pResponse, TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP, lpServiceConfig->lpLoadOrderGroup ? lpServiceConfig->lpLoadOrderGroup : "" );
|
||||
packet_add_tlv_bool( pResponse, TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE, lpServiceConfig->dwServiceType & SERVICE_INTERACTIVE_PROCESS);
|
||||
|
||||
} while(0);
|
||||
|
||||
if( lpServiceConfig )
|
||||
free( lpServiceConfig );
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
DWORD get_service_dacl( HMODULE hAdvapi32, SC_HANDLE scService, Packet *pResponse )
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
DWORD dwBytesNeeded = 0;
|
||||
PQUERYSERVICEOBJECTSECURITY pQueryServiceObjectSecurity = NULL;
|
||||
PCSDTSSDA pCSDTSSDA = NULL;
|
||||
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
|
||||
LPSTR lpDaclString;
|
||||
|
||||
do
|
||||
{
|
||||
dprintf( "Searching for QueryServiceObjectSecurity" );
|
||||
if( (pQueryServiceObjectSecurity = (PQUERYSERVICEOBJECTSECURITY)GetProcAddress( hAdvapi32, "QueryServiceObjectSecurity" )) == NULL )
|
||||
BREAK_ON_ERROR( "Unable to locate QueryServiceObjectSecurity in advapi32.dll." );
|
||||
|
||||
dprintf( "Searching for ConvertSecurityDescriptorToStringSecurityDescriptorA" );
|
||||
if( (pCSDTSSDA = (PCSDTSSDA)GetProcAddress( hAdvapi32, "ConvertSecurityDescriptorToStringSecurityDescriptorA" )) == NULL )
|
||||
BREAK_ON_ERROR( "Unable to locate ConvertSecurityDescriptorToStringSecurityDescriptorA in advapi32.dll." );
|
||||
|
||||
if( pQueryServiceObjectSecurity( scService, DACL_SECURITY_INFORMATION, (PSECURITY_DESCRIPTOR)&pSecurityDescriptor, 0, &dwBytesNeeded ) )
|
||||
BREAK_ON_ERROR( "Call should have failed" );
|
||||
|
||||
if( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
|
||||
BREAK_ON_ERROR( "Unexpected error getting security" );
|
||||
|
||||
if( (pSecurityDescriptor = (PSECURITY_DESCRIPTOR)malloc( dwBytesNeeded )) == NULL )
|
||||
BREAK_WITH_ERROR( "Out of memory", ERROR_OUTOFMEMORY );
|
||||
|
||||
if( !pQueryServiceObjectSecurity( scService, DACL_SECURITY_INFORMATION, pSecurityDescriptor, dwBytesNeeded, &dwBytesNeeded ) )
|
||||
BREAK_ON_ERROR( "Unable to query security information for DACL_SECURITY_INFORMATION" );
|
||||
|
||||
if( !pCSDTSSDA( pSecurityDescriptor, SDDL_REVISION_1, DACL_SECURITY_INFORMATION, &lpDaclString, NULL ) )
|
||||
BREAK_ON_ERROR( "Unable to get DACL string" );
|
||||
|
||||
packet_add_tlv_string( pResponse, TLV_TYPE_EXT_SERVICE_QUERY_DACL, lpDaclString );
|
||||
|
||||
} while(0);
|
||||
|
||||
if( lpDaclString )
|
||||
LocalFree( lpDaclString );
|
||||
|
||||
if( pSecurityDescriptor )
|
||||
free( pSecurityDescriptor );
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
#endif
|
@ -6,5 +6,6 @@
|
||||
#define _METERPRETER_SOURCE_EXTENSION_EXTAPI_SERVICE_H
|
||||
|
||||
DWORD request_service_enum(Remote *remote, Packet *packet);
|
||||
DWORD request_service_query(Remote *remote, Packet *packet);
|
||||
|
||||
#endif
|
||||
|
@ -101,26 +101,27 @@ DWORD enumerate_windows( Packet *response )
|
||||
|
||||
DWORD request_window_enum( Remote *remote, Packet *packet )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
Packet * response = packet_create_response( packet );
|
||||
|
||||
do
|
||||
{
|
||||
if( !response ) {
|
||||
dprintf( "Unable to create response packet" );
|
||||
result = ERROR_OUTOFMEMORY;
|
||||
dwResult = ERROR_OUTOFMEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
dprintf( "Beginning window enumeration" );
|
||||
result = enumerate_windows( response );
|
||||
dwResult = enumerate_windows( response );
|
||||
|
||||
} while(0);
|
||||
|
||||
dprintf( "Transmitting response back to caller." );
|
||||
packet_transmit_response( result, remote, response );
|
||||
if( response )
|
||||
packet_transmit_response( dwResult, remote, response );
|
||||
|
||||
return result;
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
VOID add_enumerated_window( Packet *pResponse, QWORD qwHandle, const char* cpWindowTitle, DWORD dwProcessId, BOOL bVisible )
|
||||
|
Loading…
Reference in New Issue
Block a user