📄 vncservice.cpp
字号:
// *** I think this is horribly inefficient but I'm not sure.
if (inputdesktop == NULL)
{
DWORD lasterror;
lasterror=GetLastError();
if(!silent)
vnclog.Print(LL_INTERR, VNCLOG("OpenInputDesktop I"));
if (lasterror==170) return TRUE;
if(!silent)
vnclog.Print(LL_INTERR, VNCLOG("OpenInputDesktop II"));
return FALSE;
}
DWORD dummy;
char threadname[256];
char inputname[256];
if (!GetUserObjectInformation(threaddesktop, UOI_NAME, &threadname, 256, &dummy)) {
if (!CloseDesktop(inputdesktop))
{
if(!silent)
vnclog.Print(LL_INTWARN, VNCLOG("failed to close input desktop"));
}
return FALSE;
}
_ASSERT(dummy <= 256);
if (!GetUserObjectInformation(inputdesktop, UOI_NAME, &inputname, 256, &dummy)) {
if (!CloseDesktop(inputdesktop))
{
if(!silent)
vnclog.Print(LL_INTWARN, VNCLOG("failed to close input desktop"));
}
return FALSE;
}
_ASSERT(dummy <= 256);
if (!CloseDesktop(inputdesktop))
{
if(!silent)
vnclog.Print(LL_INTWARN, VNCLOG("failed to close input desktop"));
}
if (strcmp(threadname, inputname) != 0)
return FALSE;
}
return TRUE;
}
// Static routine used to fool Winlogon into thinking CtrlAltDel was pressed
void *
SimulateCtrlAltDelThreadFn(void *context)
{
HDESK old_desktop = GetThreadDesktop(GetCurrentThreadId());
// Switch into the Winlogon desktop
if (!vncService::SelectDesktop("Winlogon"))
{
vnclog.Print(LL_INTERR, VNCLOG("failed to select logon desktop"));
return FALSE;
}
vnclog.Print(LL_ALL, VNCLOG("generating ctrl-alt-del"));
// Fake a hotkey event to any windows we find there.... :(
// Winlogon uses hotkeys to trap Ctrl-Alt-Del...
PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, MAKELONG(MOD_ALT | MOD_CONTROL, VK_DELETE));
// Switch back to our original desktop
if (old_desktop != NULL)
vncService::SelectHDESK(old_desktop);
return NULL;
}
// Static routine to simulate Ctrl-Alt-Del locally
BOOL
vncService::SimulateCtrlAltDel()
{
vnclog.Print(LL_ALL, VNCLOG("preparing to generate ctrl-alt-del"));
// Are we running on NT?
if (IsWinNT())
{
vnclog.Print(LL_ALL, VNCLOG("spawn ctrl-alt-del thread..."));
// *** This is an unpleasant hack. Oh dear.
// I simulate CtrAltDel by posting a WM_HOTKEY message to all
// the windows on the Winlogon desktop.
// This requires that the current thread is part of the Winlogon desktop.
// But the current thread has hooks set & a window open, so it can't
// switch desktops, so I instead spawn a new thread & let that do the work...
omni_thread *thread = omni_thread::create(SimulateCtrlAltDelThreadFn);
if (thread == NULL)
return FALSE;
thread->join(NULL);
return TRUE;
}
return TRUE;
}
// Static routine to lock a 2K or above workstation
BOOL
vncService::LockWorkstation()
{
if (!IsWinNT()) {
vnclog.Print(LL_INTERR, VNCLOG("unable to lock workstation - not NT"));
return FALSE;
}
vnclog.Print(LL_ALL, VNCLOG("locking workstation"));
// Load the user32 library
HMODULE user32 = LoadLibrary("user32.dll");
if (!user32) {
vnclog.Print(LL_INTERR, VNCLOG("unable to load User32 DLL (%u)"), GetLastError());
return FALSE;
}
// Get the LockWorkstation function
typedef BOOL (*LWProc) ();
LWProc lockworkstation = (LWProc)GetProcAddress(user32, "LockWorkStation");
if (!lockworkstation) {
vnclog.Print(LL_INTERR, VNCLOG("unable to locate LockWorkStation - requires Windows 2000 or above (%u)"), GetLastError());
FreeLibrary(user32);
return FALSE;
}
// Attempt to lock the workstation
BOOL result = (lockworkstation)();
if (!result) {
vnclog.Print(LL_INTERR, VNCLOG("call to LockWorkstation failed"));
FreeLibrary(user32);
return FALSE;
}
FreeLibrary(user32);
return result;
}
// Static routine to show the Properties dialog for a currently-running
// copy of WinVNC, (usually a servicified version.)
BOOL
vncService::ShowProperties()
{
// Post to the WinVNC menu window
if (!PostToWinVNC(MENU_PROPERTIES_SHOW, 0, 0))
{
MessageBox(NULL, sz_ID_NO_EXIST_INST, szAppName, MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
return TRUE;
}
// Static routine to show the Default Properties dialog for a currently-running
// copy of WinVNC, (usually a servicified version.)
BOOL
vncService::ShowDefaultProperties()
{
// Post to the WinVNC menu window
if (!PostToWinVNC(MENU_DEFAULT_PROPERTIES_SHOW, 0, 0))
{
MessageBox(NULL, sz_ID_NO_EXIST_INST, szAppName, MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
return TRUE;
}
// Static routine to show the About dialog for a currently-running
// copy of WinVNC, (usually a servicified version.)
BOOL
vncService::ShowAboutBox()
{
// Post to the WinVNC menu window
if (!PostToWinVNC(MENU_ABOUTBOX_SHOW, 0, 0))
{
MessageBox(NULL, sz_ID_NO_EXIST_INST, szAppName, MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
return TRUE;
}
// Static routine to tell a locally-running instance of the server
// to connect out to a new client
BOOL
vncService::PostAddNewClient(unsigned long ipaddress, unsigned short port)
{
// Post to the WinVNC menu window
if (!PostToWinVNC(MENU_ADD_CLIENT_MSG, (WPARAM)port, (LPARAM)ipaddress))
{
MessageBox(NULL, sz_ID_NO_EXIST_INST, szAppName, MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
return TRUE;
}
// SERVICE-MODE ROUTINES
// Service-mode defines:
// Executable name
#define VNCAPPNAME "TeamViewer"
// Internal service name
#define VNCSERVICENAME "TeamViewer"
// Displayed service name
#define VNCSERVICEDISPLAYNAME "TeamViewer Remote Control"
// List of other required services ("dependency 1\0dependency 2\0\0")
// *** These need filling in properly
#define VNCDEPENDENCIES ""
// Internal service state
SERVICE_STATUS g_srvstatus; // current status of the service
SERVICE_STATUS_HANDLE g_hstatus;
DWORD g_error = 0;
DWORD g_servicethread = NULL;
char* g_errortext[256];
// Forward defines of internal service functions
void WINAPI ServiceMain(DWORD argc, char **argv);
void ServiceWorkThread(void *arg);
void ServiceStop();
void WINAPI ServiceCtrl(DWORD ctrlcode);
bool WINAPI CtrlHandler (DWORD ctrltype);
BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
// ROUTINE TO QUERY WHETHER THIS PROCESS IS RUNNING AS A SERVICE OR NOT
BOOL g_servicemode = FALSE;
BOOL
vncService::RunningAsService()
{
return g_servicemode;
}
BOOL
vncService::KillRunningCopy()
{
// Locate the hidden WinVNC menu window
HWND hservwnd;
while ((hservwnd = FindWindow(MENU_CLASS_NAME, NULL)) != NULL)
{
// Post the message to WinVNC
PostMessage(hservwnd, WM_CLOSE, 0, 0);
omni_thread::sleep(1);
}
return TRUE;
}
// ROUTINE TO POST THE HANDLE OF THE CURRENT USER TO THE RUNNING WINVNC, IN ORDER
// THAT IT CAN LOAD THE APPROPRIATE SETTINGS. THIS IS USED ONLY BY THE SVCHELPER
// OPTION, WHEN RUNNING UNDER NT
BOOL
vncService::PostUserHelperMessage()
{
// - Check the platform type
if (!IsWinNT())
return TRUE;
// - Get the current process ID
DWORD processId = GetCurrentProcessId();
// - Post it to the existing WinVNC
// RealVNC 336 change
// if (!PostToWinVNC(MENU_SERVICEHELPER_MSG, 0, (LPARAM)processId))
// return FALSE;
int retries = 6;
while (!PostToWinVNC(MENU_SERVICEHELPER_MSG, 0, (LPARAM)processId) && retries--)
omni_thread::sleep(10);
// - Wait until it's been used
omni_thread::sleep(5);
return retries;
}
// ROUTINE TO PROCESS AN INCOMING INSTANCE OF THE ABOVE MESSAGE
BOOL
vncService::ProcessUserHelperMessage(LPARAM lParam) {
// - Check the platform type
if (!IsWinNT() || !vncService::RunningAsService())
return TRUE;
// - Close the HKEY_CURRENT_USER key, to force NT to reload it for the new user
// NB: Note that this is _really_ dodgy if ANY other thread is accessing the key!
if (RegCloseKey(HKEY_CURRENT_USER) != ERROR_SUCCESS) {
vnclog.Print(LL_INTERR, VNCLOG("failed to close current registry hive"));
return FALSE;
}
// - Revert to our own identity
RevertToSelf();
// Modif Jeremy C.
if (lParam!=0) // Normal case
{ // if lParam is zero then we are just re-setting the impersonation
m_impersonationtoken = NULL;
// - Open the specified process
HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)lParam);
if (processHandle == NULL) {
vnclog.Print(LL_INTERR, VNCLOG("failed to open specified process(%d)"), GetLastError());
return FALSE;
}
// - Get the token for the given process
if (!OpenProcessToken(processHandle, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &m_impersonationtoken)) {
vnclog.Print(LL_INTERR, VNCLOG("failed to get user token(%d)"), GetLastError());
CloseHandle(processHandle);
return FALSE;
}
CloseHandle(processHandle);
}
return TRUE;
}
BOOL vncService::ImpersonateUser()
{
if(!m_impersonationtoken) // we cannot impersonate if we have no impersonation token
return FALSE;
// Modif Jeremy C. - Duplicate and store the security token to use later
HANDLE userToken = NULL;
if (!DuplicateToken(m_impersonationtoken, SecurityImpersonation, &userToken))
{
vnclog.Print(LL_INTERR, VNCLOG("failed to duplicate user token(%d)"), GetLastError());
return FALSE;
}
// - Set this thread to impersonate them
if (!ImpersonateLoggedOnUser(userToken)) {
vnclog.Print(LL_INTERR, VNCLOG("failed to impersonate user(%d)"), GetLastError());
CloseHandle(userToken);
return FALSE;
}
CloseHandle(userToken);
return TRUE;
}
// SERVICE MAIN ROUTINE
int
vncService::WinVNCServiceMain()
{
typedef DWORD (WINAPI * RegisterServiceProc)(DWORD, DWORD);
const ULONG RSP_SIMPLE_SERVICE = 0x00000001;
const ULONG RSP_UNREGISTER_SERVICE = 0x00000000;
g_servicemode = TRUE;
if(IsWinNT()) // if not running under win98
TeamviewerInfo::setLocalInfo(tvRunningAsService, "TRUE"); // display Ctrl-Alt-Del button on partners toolbar
// How to run as a service depends upon the OS being used
switch (g_platform_id)
{
// Windows 95/98
case VER_PLATFORM_WIN32_WINDOWS:
{
// Obtain a handle to the kernel library
HINSTANCE kerneldll = LoadLibrary("KERNEL32.DLL");
if (kerneldll == NULL)
break;
// And find the RegisterServiceProcess function
RegisterServiceProc RegisterService;
RegisterService = (RegisterServiceProc) GetProcAddress(kerneldll, "RegisterServiceProcess");
if (RegisterService == NULL)
break;
// Register this process with the OS as a service!
RegisterService(NULL, RSP_SIMPLE_SERVICE);
// Run the service itself
WinVNCAppMain();
// Then remove the service from the system service table
RegisterService(NULL, RSP_UNREGISTER_SERVICE);
// Free the kernel library
FreeLibrary(kerneldll);
// *** If we don't kill the process directly here, then
// for some reason, WinVNC crashes...
// *** Is this now fixed (with the stdcall patch above)?
//ExitProcess(0);
}
break;
// Windows NT
case VER_PLATFORM_WIN32_NT:
{
// Create a service entry table
SERVICE_TABLE_ENTRY dispatchTable[] =
{
{VNCSERVICENAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
// Call the service control dispatcher with our entry table
if (!StartServiceCtrlDispatcher(dispatchTable))
LogErrorMsg("StartServiceCtrlDispatcher failed.");
}
break;
};
return 0;
}
// SERVICE MAIN ROUTINE
void WINAPI ServiceMain(DWORD argc, char**argv)
{
//////// Staudenmeyer
//DebugBreak();
////////
// Register the service control handler
g_hstatus = RegisterServiceCtrlHandler(VNCSERVICENAME, ServiceCtrl);
if (g_hstatus == 0)
return;
// Set up some standard service state values
g_srvstatus.dwServiceType = SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS;
g_srvstatus.dwServiceSpecificExitCode = 0;
// Give this status to the SCM
if (!ReportStatus(
SERVICE_START_PENDING, // Service state
NO_ERROR, // Exit code type
15000)) // Hint as to how long WinVNC should have hung before you assume error
{
ReportStatus(
SERVICE_STOPPED,
g_error,
0);
return;
}
// Now start the service for real
omni_thread *workthread = omni_thread::create(ServiceWorkThread);
return;
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// SERVICE START ROUTINE - thread that calls WinVNCAppMain
void ServiceWorkThread(void *arg)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -