NTSTATUS PhGetServiceDllParameter( _In_ PPH_STRINGREF ServiceName, _Out_ PPH_STRING *ServiceDll ) { static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); static PH_STRINGREF parameters = PH_STRINGREF_INIT(L"\\Parameters"); NTSTATUS status; HANDLE keyHandle; PPH_STRING keyName; keyName = PhConcatStringRef3(&servicesKeyName, ServiceName, ¶meters); if (NT_SUCCESS(status = PhOpenKey( &keyHandle, KEY_READ, PH_KEY_LOCAL_MACHINE, &keyName->sr, 0 ))) { PPH_STRING serviceDllString; if (serviceDllString = PhQueryRegistryString(keyHandle, L"ServiceDll")) { PPH_STRING expandedString; if (expandedString = PhExpandEnvironmentStrings(&serviceDllString->sr)) { *ServiceDll = expandedString; PhDereferenceObject(serviceDllString); } else { *ServiceDll = serviceDllString; } } else { status = STATUS_NOT_FOUND; } NtClose(keyHandle); } PhDereferenceObject(keyName); return status; }
// NOTE: This function does not use the SCM due to major performance issues. // For now just query this information from the registry but it might be out-of-sync // with any recent services changes until the SCM flushes its cache. NTSTATUS QueryServiceFileName( _In_ PPH_STRINGREF ServiceName, _Out_ PPH_STRING *ServiceFileName, _Out_ PPH_STRING *ServiceBinaryPath ) { static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\"); static PH_STRINGREF typeKeyName = PH_STRINGREF_INIT(L"Type"); NTSTATUS status; HANDLE keyHandle; ULONG serviceType = 0; PPH_STRING keyName; PPH_STRING binaryPath; PPH_STRING fileName; keyName = PhConcatStringRef2(&servicesKeyName, ServiceName); binaryPath = NULL; fileName = NULL; if (NT_SUCCESS(status = PhOpenKey( &keyHandle, KEY_READ, PH_KEY_LOCAL_MACHINE, &keyName->sr, 0 ))) { PPH_STRING serviceImagePath; PKEY_VALUE_PARTIAL_INFORMATION buffer; if (NT_SUCCESS(status = PhQueryValueKey( keyHandle, &typeKeyName, KeyValuePartialInformation, &buffer ))) { if ( buffer->Type == REG_DWORD && buffer->DataLength == sizeof(ULONG) ) { serviceType = *(PULONG)buffer->Data; } PhFree(buffer); } if (serviceImagePath = PhQueryRegistryString(keyHandle, L"ImagePath")) { PPH_STRING expandedString; if (expandedString = PhExpandEnvironmentStrings(&serviceImagePath->sr)) { binaryPath = expandedString; PhDereferenceObject(serviceImagePath); } else { binaryPath = serviceImagePath; } } else { status = STATUS_NOT_FOUND; } NtClose(keyHandle); } if (NT_SUCCESS(status)) { PhGetServiceDllParameter(ServiceName, &fileName); if (!fileName) { if (serviceType & SERVICE_WIN32) { PH_STRINGREF dummyFileName; PH_STRINGREF dummyArguments; PhParseCommandLineFuzzy(&binaryPath->sr, &dummyFileName, &dummyArguments, &fileName); if (!fileName) PhSwapReference(&fileName, binaryPath); } else { fileName = PhGetFileName(binaryPath); } } *ServiceFileName = fileName; *ServiceBinaryPath = binaryPath; } else { if (binaryPath) PhDereferenceObject(binaryPath); } PhDereferenceObject(keyName); return status; }
BOOLEAN PhaGetProcessKnownCommandLine( __in PPH_STRING CommandLine, __in PH_KNOWN_PROCESS_TYPE KnownProcessType, __out PPH_KNOWN_PROCESS_COMMAND_LINE KnownCommandLine ) { switch (KnownProcessType & KnownProcessTypeMask) { case ServiceHostProcessType: { // svchost.exe -k <GroupName> static PH_COMMAND_LINE_OPTION options[] = { { 1, L"k", MandatoryArgumentType } }; KnownCommandLine->ServiceHost.GroupName = NULL; PhParseCommandLine( &CommandLine->sr, options, sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS, PhpSvchostCommandLineCallback, KnownCommandLine ); if (KnownCommandLine->ServiceHost.GroupName) { PhaDereferenceObject(KnownCommandLine->ServiceHost.GroupName); return TRUE; } else { return FALSE; } } break; case RunDllAsAppProcessType: { // rundll32.exe <DllName>,<ProcedureName> ... SIZE_T i; ULONG_PTR lastIndexOfComma; PPH_STRING dllName; PPH_STRING procedureName; i = 0; // Get the rundll32.exe part. dllName = PhParseCommandLinePart(&CommandLine->sr, &i); if (!dllName) return FALSE; PhDereferenceObject(dllName); // Get the DLL name part. while (i < CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ') i++; dllName = PhParseCommandLinePart(&CommandLine->sr, &i); if (!dllName) return FALSE; PhaDereferenceObject(dllName); // The procedure name begins after the last comma. lastIndexOfComma = PhFindLastCharInString(dllName, 0, ','); if (lastIndexOfComma == -1) return FALSE; procedureName = PhaSubstring( dllName, lastIndexOfComma + 1, dllName->Length / 2 - lastIndexOfComma - 1 ); dllName = PhaSubstring(dllName, 0, lastIndexOfComma); // If the DLL name isn't an absolute path, assume it's in system32. // TODO: Use a proper search function. if (RtlDetermineDosPathNameType_U(dllName->Buffer) == RtlPathTypeRelative) { dllName = PhaConcatStrings( 3, ((PPH_STRING)PHA_DEREFERENCE(PhGetSystemDirectory()))->Buffer, L"\\", dllName->Buffer ); } KnownCommandLine->RunDllAsApp.FileName = dllName; KnownCommandLine->RunDllAsApp.ProcedureName = procedureName; } break; case ComSurrogateProcessType: { // dllhost.exe /processid:<Guid> static PH_STRINGREF inprocServer32Name = PH_STRINGREF_INIT(L"InprocServer32"); SIZE_T i; ULONG_PTR indexOfProcessId; PPH_STRING argPart; PPH_STRING guidString; UNICODE_STRING guidStringUs; GUID guid; HANDLE clsidKeyHandle; HANDLE inprocServer32KeyHandle; PPH_STRING fileName; i = 0; // Get the dllhost.exe part. argPart = PhParseCommandLinePart(&CommandLine->sr, &i); if (!argPart) return FALSE; PhDereferenceObject(argPart); // Get the argument part. while (i < (ULONG)CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ') i++; argPart = PhParseCommandLinePart(&CommandLine->sr, &i); if (!argPart) return FALSE; PhaDereferenceObject(argPart); // Find "/processid:"; the GUID is just after that. PhUpperString(argPart); indexOfProcessId = PhFindStringInString(argPart, 0, L"/PROCESSID:"); if (indexOfProcessId == -1) return FALSE; guidString = PhaSubstring( argPart, indexOfProcessId + 11, (ULONG)argPart->Length / 2 - indexOfProcessId - 11 ); PhStringRefToUnicodeString(&guidString->sr, &guidStringUs); if (!NT_SUCCESS(RtlGUIDFromString( &guidStringUs, &guid ))) return FALSE; KnownCommandLine->ComSurrogate.Guid = guid; KnownCommandLine->ComSurrogate.Name = NULL; KnownCommandLine->ComSurrogate.FileName = NULL; // Lookup the GUID in the registry to determine the name and file name. if (NT_SUCCESS(PhOpenKey( &clsidKeyHandle, KEY_READ, PH_KEY_CLASSES_ROOT, &PhaConcatStrings2(L"CLSID\\", guidString->Buffer)->sr, 0 ))) { KnownCommandLine->ComSurrogate.Name = PHA_DEREFERENCE(PhQueryRegistryString(clsidKeyHandle, NULL)); if (NT_SUCCESS(PhOpenKey( &inprocServer32KeyHandle, KEY_READ, clsidKeyHandle, &inprocServer32Name, 0 ))) { KnownCommandLine->ComSurrogate.FileName = PHA_DEREFERENCE(PhQueryRegistryString(inprocServer32KeyHandle, NULL)); if (fileName = PHA_DEREFERENCE(PhExpandEnvironmentStrings( &KnownCommandLine->ComSurrogate.FileName->sr ))) { KnownCommandLine->ComSurrogate.FileName = fileName; } NtClose(inprocServer32KeyHandle); } NtClose(clsidKeyHandle); } } break; default: return FALSE; } return TRUE; }
INT_PTR CALLBACK PhpServiceGeneralDlgProc( _In_ HWND hwndDlg, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { switch (uMsg) { case WM_INITDIALOG: { LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam; PSERVICE_PROPERTIES_CONTEXT context = (PSERVICE_PROPERTIES_CONTEXT)propSheetPage->lParam; PPH_SERVICE_ITEM serviceItem = context->ServiceItem; SC_HANDLE serviceHandle; ULONG startType; ULONG errorControl; // HACK PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg))); SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context); PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_TYPE), PhServiceTypeStrings, sizeof(PhServiceTypeStrings) / sizeof(WCHAR *)); PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhServiceStartTypeStrings, sizeof(PhServiceStartTypeStrings) / sizeof(WCHAR *)); PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhServiceErrorControlStrings, sizeof(PhServiceErrorControlStrings) / sizeof(WCHAR *)); SetDlgItemText(hwndDlg, IDC_DESCRIPTION, serviceItem->DisplayName->Buffer); PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_TYPE), PhGetServiceTypeString(serviceItem->Type), FALSE); startType = serviceItem->StartType; errorControl = serviceItem->ErrorControl; serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG); if (serviceHandle) { LPQUERY_SERVICE_CONFIG config; PPH_STRING description; BOOLEAN delayedStart; if (config = PhGetServiceConfig(serviceHandle)) { SetDlgItemText(hwndDlg, IDC_GROUP, config->lpLoadOrderGroup); SetDlgItemText(hwndDlg, IDC_BINARYPATH, config->lpBinaryPathName); SetDlgItemText(hwndDlg, IDC_USERACCOUNT, config->lpServiceStartName); if (startType != config->dwStartType || errorControl != config->dwErrorControl) { startType = config->dwStartType; errorControl = config->dwErrorControl; PhMarkNeedsConfigUpdateServiceItem(serviceItem); } PhFree(config); } if (description = PhGetServiceDescription(serviceHandle)) { SetDlgItemText(hwndDlg, IDC_DESCRIPTION, description->Buffer); PhDereferenceObject(description); } if ( WindowsVersion >= WINDOWS_VISTA && PhGetServiceDelayedAutoStart(serviceHandle, &delayedStart) ) { context->OldDelayedStart = delayedStart; if (delayedStart) Button_SetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART), BST_CHECKED); } CloseServiceHandle(serviceHandle); } PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_STARTTYPE), PhGetServiceStartTypeString(startType), FALSE); PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_ERRORCONTROL), PhGetServiceErrorControlString(errorControl), FALSE); SetDlgItemText(hwndDlg, IDC_PASSWORD, L"password"); Button_SetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), BST_UNCHECKED); SetDlgItemText(hwndDlg, IDC_SERVICEDLL, L"N/A"); { HANDLE keyHandle; PPH_STRING keyName; keyName = PhConcatStrings( 3, L"System\\CurrentControlSet\\Services\\", serviceItem->Name->Buffer, L"\\Parameters" ); if (NT_SUCCESS(PhOpenKey( &keyHandle, KEY_READ, PH_KEY_LOCAL_MACHINE, &keyName->sr, 0 ))) { PPH_STRING serviceDllString; if (serviceDllString = PhQueryRegistryString(keyHandle, L"ServiceDll")) { PPH_STRING expandedString; if (expandedString = PhExpandEnvironmentStrings(&serviceDllString->sr)) { SetDlgItemText(hwndDlg, IDC_SERVICEDLL, expandedString->Buffer); PhDereferenceObject(expandedString); } PhDereferenceObject(serviceDllString); } NtClose(keyHandle); } PhDereferenceObject(keyName); } PhpRefreshControls(hwndDlg); context->Ready = TRUE; } break; case WM_DESTROY: { RemoveProp(hwndDlg, PhMakeContextAtom()); } break; case WM_COMMAND: { PSERVICE_PROPERTIES_CONTEXT context = (PSERVICE_PROPERTIES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); switch (LOWORD(wParam)) { case IDCANCEL: { // Workaround for property sheet + multiline edit: http://support.microsoft.com/kb/130765 SendMessage(GetParent(hwndDlg), uMsg, wParam, lParam); } break; case IDC_PASSWORD: { if (HIWORD(wParam) == EN_CHANGE) { Button_SetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK), BST_CHECKED); } } break; case IDC_DELAYEDSTART: { context->Dirty = TRUE; } break; case IDC_BROWSE: { static PH_FILETYPE_FILTER filters[] = { { L"Executable files (*.exe;*.sys)", L"*.exe;*.sys" }, { L"All files (*.*)", L"*.*" } }; PVOID fileDialog; PPH_STRING fileName; fileDialog = PhCreateOpenFileDialog(); PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER)); fileName = PhGetFileName(PHA_GET_DLGITEM_TEXT(hwndDlg, IDC_BINARYPATH)); PhSetFileDialogFileName(fileDialog, fileName->Buffer); PhDereferenceObject(fileName); if (PhShowFileDialog(hwndDlg, fileDialog)) { fileName = PhGetFileDialogFileName(fileDialog); SetDlgItemText(hwndDlg, IDC_BINARYPATH, fileName->Buffer); PhDereferenceObject(fileName); } PhFreeFileDialog(fileDialog); } break; } switch (HIWORD(wParam)) { case EN_CHANGE: case CBN_SELCHANGE: { PhpRefreshControls(hwndDlg); if (context->Ready) context->Dirty = TRUE; } break; } } break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; switch (header->code) { case PSN_QUERYINITIALFOCUS: { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)GetDlgItem(hwndDlg, IDC_STARTTYPE)); } return TRUE; case PSN_KILLACTIVE: { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE); } return TRUE; case PSN_APPLY: { NTSTATUS status; PSERVICE_PROPERTIES_CONTEXT context = (PSERVICE_PROPERTIES_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom()); PPH_SERVICE_ITEM serviceItem = context->ServiceItem; SC_HANDLE serviceHandle; PPH_STRING newServiceTypeString; PPH_STRING newServiceStartTypeString; PPH_STRING newServiceErrorControlString; ULONG newServiceType; ULONG newServiceStartType; ULONG newServiceErrorControl; PPH_STRING newServiceGroup; PPH_STRING newServiceBinaryPath; PPH_STRING newServiceUserAccount; PPH_STRING newServicePassword; SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); if (!context->Dirty) { return TRUE; } newServiceTypeString = PHA_DEREFERENCE(PhGetWindowText(GetDlgItem(hwndDlg, IDC_TYPE))); newServiceStartTypeString = PHA_DEREFERENCE(PhGetWindowText(GetDlgItem(hwndDlg, IDC_STARTTYPE))); newServiceErrorControlString = PHA_DEREFERENCE(PhGetWindowText(GetDlgItem(hwndDlg, IDC_ERRORCONTROL))); newServiceType = PhGetServiceTypeInteger(newServiceTypeString->Buffer); newServiceStartType = PhGetServiceStartTypeInteger(newServiceStartTypeString->Buffer); newServiceErrorControl = PhGetServiceErrorControlInteger(newServiceErrorControlString->Buffer); newServiceGroup = PHA_DEREFERENCE(PhGetWindowText(GetDlgItem(hwndDlg, IDC_GROUP))); newServiceBinaryPath = PHA_DEREFERENCE(PhGetWindowText(GetDlgItem(hwndDlg, IDC_BINARYPATH))); newServiceUserAccount = PHA_DEREFERENCE(PhGetWindowText(GetDlgItem(hwndDlg, IDC_USERACCOUNT))); if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_PASSWORDCHECK)) == BST_CHECKED) { newServicePassword = PhGetWindowText(GetDlgItem(hwndDlg, IDC_PASSWORD)); } else { newServicePassword = NULL; } if (newServiceType == SERVICE_KERNEL_DRIVER && newServiceUserAccount->Length == 0) { newServiceUserAccount = NULL; } serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_CHANGE_CONFIG); if (serviceHandle) { if (ChangeServiceConfig( serviceHandle, newServiceType, newServiceStartType, newServiceErrorControl, newServiceBinaryPath->Buffer, newServiceGroup->Buffer, NULL, NULL, PhGetString(newServiceUserAccount), PhGetString(newServicePassword), NULL )) { if (WindowsVersion >= WINDOWS_VISTA) { BOOLEAN newDelayedStart; newDelayedStart = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART)) == BST_CHECKED; if (newDelayedStart != context->OldDelayedStart) { PhSetServiceDelayedAutoStart(serviceHandle, newDelayedStart); } } PhMarkNeedsConfigUpdateServiceItem(serviceItem); CloseServiceHandle(serviceHandle); } else { CloseServiceHandle(serviceHandle); goto ErrorCase; } } else { if (GetLastError() == ERROR_ACCESS_DENIED && !PhElevated) { // Elevate using phsvc. if (PhUiConnectToPhSvc(hwndDlg, FALSE)) { if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig( serviceItem->Name->Buffer, newServiceType, newServiceStartType, newServiceErrorControl, newServiceBinaryPath->Buffer, newServiceGroup->Buffer, NULL, NULL, PhGetString(newServiceUserAccount), PhGetString(newServicePassword), NULL ))) { if (WindowsVersion >= WINDOWS_VISTA) { BOOLEAN newDelayedStart; newDelayedStart = Button_GetCheck(GetDlgItem(hwndDlg, IDC_DELAYEDSTART)) == BST_CHECKED; if (newDelayedStart != context->OldDelayedStart) { SERVICE_DELAYED_AUTO_START_INFO info; info.fDelayedAutostart = newDelayedStart; PhSvcCallChangeServiceConfig2( serviceItem->Name->Buffer, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &info ); } } PhMarkNeedsConfigUpdateServiceItem(serviceItem); } PhUiDisconnectFromPhSvc(); if (!NT_SUCCESS(status)) { SetLastError(PhNtStatusToDosError(status)); goto ErrorCase; } } else { // User cancelled elevation. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); } } else { goto ErrorCase; } } goto Cleanup; ErrorCase: if (PhShowMessage( hwndDlg, MB_ICONERROR | MB_RETRYCANCEL, L"Unable to change service configuration: %s", ((PPH_STRING)PHA_DEREFERENCE(PhGetWin32Message(GetLastError())))->Buffer ) == IDRETRY) { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID); } Cleanup: if (newServicePassword) { RtlSecureZeroMemory(newServicePassword->Buffer, newServicePassword->Length); PhDereferenceObject(newServicePassword); } } return TRUE; } } break; } return FALSE; }
VOID LoadNetworkAdapterImages( _In_ PDV_NETADAPTER_CONTEXT Context ) { HICON smallIcon; CONFIGRET result; ULONG deviceIconPathLength; DEVPROPTYPE deviceIconPathPropertyType; PPH_STRING deviceIconPath; deviceIconPathLength = 0x40; deviceIconPath = PhCreateStringEx(NULL, deviceIconPathLength); if ((result = CM_Get_Class_Property( &GUID_DEVCLASS_NET, &DEVPKEY_DeviceClass_IconPath, &deviceIconPathPropertyType, (PBYTE)deviceIconPath->Buffer, &deviceIconPathLength, 0 )) != CR_SUCCESS) { PhDereferenceObject(deviceIconPath); deviceIconPath = PhCreateStringEx(NULL, deviceIconPathLength); result = CM_Get_Class_Property( &GUID_DEVCLASS_NET, &DEVPKEY_DeviceClass_IconPath, &deviceIconPathPropertyType, (PBYTE)deviceIconPath->Buffer, &deviceIconPathLength, 0 ); } if (result != CR_SUCCESS) { PhDereferenceObject(deviceIconPath); return; } PhTrimToNullTerminatorString(deviceIconPath); { PPH_STRING dllIconPath; PH_STRINGREF dllPartSr; PH_STRINGREF indexPartSr; ULONG64 index = 0; if ( PhSplitStringRefAtChar(&deviceIconPath->sr, ',', &dllPartSr, &indexPartSr) && PhStringToInteger64(&indexPartSr, 10, &index) ) { if (dllIconPath = PhExpandEnvironmentStrings(&dllPartSr)) { if (PhExtractIconEx(dllIconPath->Buffer, (INT)index, &smallIcon, NULL)) { Context->ImageList = ImageList_Create( GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR32, 1, 1 ); ImageList_AddIcon(Context->ImageList, smallIcon); ListView_SetImageList(Context->ListViewHandle, Context->ImageList, LVSIL_SMALL); DestroyIcon(smallIcon); } PhDereferenceObject(dllIconPath); } } } PhDereferenceObject(deviceIconPath); }