static PPH_STRING EspGetServiceSidString( _In_ PPH_STRINGREF ServiceName ) { PSID serviceSid = NULL; UNICODE_STRING serviceNameUs; ULONG serviceSidLength = 0; PPH_STRING sidString = NULL; if (!RtlCreateServiceSid_I) return NULL; PhStringRefToUnicodeString(ServiceName, &serviceNameUs); if (RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength) == STATUS_BUFFER_TOO_SMALL) { serviceSid = PhAllocate(serviceSidLength); if (NT_SUCCESS(RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength))) sidString = PhSidToStringSid(serviceSid); PhFree(serviceSid); } return sidString; }
static PPH_STRING NetworkAdapterQueryName( _Inout_ PPH_NETADAPTER_SYSINFO_CONTEXT Context ) { NDIS_OID opcode; IO_STATUS_BLOCK isb; WCHAR adapterNameBuffer[MAX_PATH] = L""; // https://msdn.microsoft.com/en-us/library/windows/hardware/ff569584.aspx opcode = OID_GEN_FRIENDLY_NAME; if (NT_SUCCESS(NtDeviceIoControlFile( Context->DeviceHandle, NULL, NULL, NULL, &isb, IOCTL_NDIS_QUERY_GLOBAL_STATS, &opcode, sizeof(NDIS_OID), adapterNameBuffer, sizeof(adapterNameBuffer) ))) { return PhCreateString(adapterNameBuffer); } // HACK: Query adapter description using undocumented function. if (Context->GetInterfaceDescriptionFromGuid_I) { GUID deviceGuid = GUID_NULL; UNICODE_STRING guidStringUs; PhStringRefToUnicodeString(&Context->AdapterEntry->InterfaceGuid->sr, &guidStringUs); if (NT_SUCCESS(RtlGUIDFromString(&guidStringUs, &deviceGuid))) { SIZE_T adapterDescriptionLength = 0; WCHAR adapterDescription[NDIS_IF_MAX_STRING_SIZE + 1] = L""; adapterDescriptionLength = sizeof(adapterDescription); // This is what the API expects apparently... if (SUCCEEDED(Context->GetInterfaceDescriptionFromGuid_I(&deviceGuid, adapterDescription, &adapterDescriptionLength, NULL, NULL))) { return PhCreateString(adapterDescription); } } } return PhCreateString(L"Unknown"); }
static VOID WINAPI RunAsServiceMain( _In_ DWORD dwArgc, _In_ LPTSTR *lpszArgv ) { PPH_STRING portName; UNICODE_STRING portNameUs; LARGE_INTEGER timeout; memset(&RunAsServiceStop, 0, sizeof(PHSVC_STOP)); RunAsServiceStatusHandle = RegisterServiceCtrlHandlerEx(RunAsServiceName->Buffer, RunAsServiceHandlerEx, NULL); SetRunAsServiceStatus(SERVICE_RUNNING); portName = PhConcatStrings2(L"\\BaseNamedObjects\\", RunAsServiceName->Buffer); PhStringRefToUnicodeString(&portName->sr, &portNameUs); // Use a shorter timeout value to reduce the time spent running as SYSTEM. timeout.QuadPart = -5 * PH_TIMEOUT_SEC; PhSvcMain(&portNameUs, &timeout, &RunAsServiceStop); SetRunAsServiceStatus(SERVICE_STOPPED); }
/** * Starts a program as another user. * * \param hWnd A handle to the parent window. * \param Program The command line of the program to start. * \param UserName The user to start the program as. The user * name should be specified as: domain\\name. This parameter * can be NULL if \a ProcessIdWithToken is specified. * \param Password The password for the specified user. If there * is no password, specify an empty string. This parameter * can be NULL if \a ProcessIdWithToken is specified. * \param LogonType The logon type for the specified user. This * parameter can be 0 if \a ProcessIdWithToken is specified. * \param ProcessIdWithToken The ID of a process from which * to duplicate the token. * \param SessionId The ID of the session to run the program * under. * \param DesktopName The window station and desktop to run the * program under. * \param UseLinkedToken Uses the linked token if possible. * * \retval STATUS_CANCELLED The user cancelled the operation. * * \remarks This function will cause another instance of * Process Hacker to be executed if the current security context * does not have sufficient system access. This is done * through a UAC elevation prompt. */ NTSTATUS PhExecuteRunAsCommand2( _In_ HWND hWnd, _In_ PWSTR Program, _In_opt_ PWSTR UserName, _In_opt_ PWSTR Password, _In_opt_ ULONG LogonType, _In_opt_ HANDLE ProcessIdWithToken, _In_ ULONG SessionId, _In_ PWSTR DesktopName, _In_ BOOLEAN UseLinkedToken ) { NTSTATUS status = STATUS_SUCCESS; PH_RUNAS_SERVICE_PARAMETERS parameters; WCHAR serviceName[32]; PPH_STRING portName; UNICODE_STRING portNameUs; memset(¶meters, 0, sizeof(PH_RUNAS_SERVICE_PARAMETERS)); parameters.ProcessId = HandleToUlong(ProcessIdWithToken); parameters.UserName = UserName; parameters.Password = Password; parameters.LogonType = LogonType; parameters.SessionId = SessionId; parameters.CommandLine = Program; parameters.DesktopName = DesktopName; parameters.UseLinkedToken = UseLinkedToken; // Try to use an existing instance of the service if possible. if (RunAsOldServiceName[0] != 0) { PhAcquireQueuedLockExclusive(&RunAsOldServiceLock); portName = PhConcatStrings2(L"\\BaseNamedObjects\\", RunAsOldServiceName); PhStringRefToUnicodeString(&portName->sr, &portNameUs); if (NT_SUCCESS(PhSvcConnectToServer(&portNameUs, 0))) { parameters.ServiceName = RunAsOldServiceName; status = PhSvcCallInvokeRunAsService(¶meters); PhSvcDisconnectFromServer(); PhDereferenceObject(portName); PhReleaseQueuedLockExclusive(&RunAsOldServiceLock); return status; } PhDereferenceObject(portName); PhReleaseQueuedLockExclusive(&RunAsOldServiceLock); } // An existing instance was not available. Proceed normally. memcpy(serviceName, L"ProcessHacker", 13 * sizeof(WCHAR)); PhGenerateRandomAlphaString(&serviceName[13], 16); PhAcquireQueuedLockExclusive(&RunAsOldServiceLock); memcpy(RunAsOldServiceName, serviceName, sizeof(serviceName)); PhReleaseQueuedLockExclusive(&RunAsOldServiceLock); parameters.ServiceName = serviceName; if (PhGetOwnTokenAttributes().Elevated) { status = PhExecuteRunAsCommand(¶meters); } else { if (PhUiConnectToPhSvc(hWnd, FALSE)) { status = PhSvcCallExecuteRunAsCommand(¶meters); PhUiDisconnectFromPhSvc(); } else { status = STATUS_CANCELLED; } } return status; }
/** * Executes the run-as service. * * \param Parameters The run-as parameters. * * \remarks This function requires administrator-level access. */ NTSTATUS PhExecuteRunAsCommand( _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters ) { NTSTATUS status; ULONG win32Result; PPH_STRING commandLine; SC_HANDLE scManagerHandle; SC_HANDLE serviceHandle; PPH_STRING portName; UNICODE_STRING portNameUs; ULONG attempts; LARGE_INTEGER interval; if (!(scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE))) return PhGetLastWin32ErrorAsNtStatus(); commandLine = PhFormatString(L"\"%s\" -ras \"%s\"", PhApplicationFileName->Buffer, Parameters->ServiceName); serviceHandle = CreateService( scManagerHandle, Parameters->ServiceName, Parameters->ServiceName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, commandLine->Buffer, NULL, NULL, NULL, L"LocalSystem", L"" ); win32Result = GetLastError(); PhDereferenceObject(commandLine); CloseServiceHandle(scManagerHandle); if (!serviceHandle) { return NTSTATUS_FROM_WIN32(win32Result); } PhSetDesktopWinStaAccess(); StartService(serviceHandle, 0, NULL); DeleteService(serviceHandle); portName = PhConcatStrings2(L"\\BaseNamedObjects\\", Parameters->ServiceName); PhStringRefToUnicodeString(&portName->sr, &portNameUs); attempts = 10; // Try to connect several times because the server may take // a while to initialize. do { status = PhSvcConnectToServer(&portNameUs, 0); if (NT_SUCCESS(status)) break; interval.QuadPart = -50 * PH_TIMEOUT_MS; NtDelayExecution(FALSE, &interval); } while (--attempts != 0); PhDereferenceObject(portName); if (NT_SUCCESS(status)) { status = PhSvcCallInvokeRunAsService(Parameters); PhSvcDisconnectFromServer(); } if (serviceHandle) CloseServiceHandle(serviceHandle); return status; }
static VOID RemoveAppCompatEntry( _In_ HANDLE ParentKey ) { static PH_STRINGREF keyName = PH_STRINGREF_INIT(L"ProcessHacker.exe"); ULONG bufferLength; KEY_FULL_INFORMATION fullInfo; memset(&fullInfo, 0, sizeof(KEY_FULL_INFORMATION)); if (!NT_SUCCESS(NtQueryKey( ParentKey, KeyFullInformation, &fullInfo, sizeof(KEY_FULL_INFORMATION), &bufferLength ))) { return; } for (ULONG i = 0; i < fullInfo.Values; i++) { PPH_STRING value; PKEY_VALUE_FULL_INFORMATION buffer; bufferLength = sizeof(KEY_VALUE_FULL_INFORMATION); buffer = PhAllocate(bufferLength); memset(buffer, 0, bufferLength); if (NT_SUCCESS(NtEnumerateValueKey( ParentKey, i, KeyValueFullInformation, buffer, bufferLength, &bufferLength ))) { PhFree(buffer); break; } //bufferLength = bufferLength; buffer = PhReAllocate(buffer, bufferLength); memset(buffer, 0, bufferLength); if (!NT_SUCCESS(NtEnumerateValueKey( ParentKey, i, KeyValueFullInformation, buffer, bufferLength, &bufferLength ))) { PhFree(buffer); break; } if (value = PhCreateStringEx(buffer->Name, buffer->NameLength)) { UNICODE_STRING us; PhStringRefToUnicodeString(&value->sr, &us); if (PhEndsWithStringRef(&value->sr, &keyName, TRUE)) { NtDeleteValueKey(ParentKey, &us); } PhDereferenceObject(value); } PhFree(buffer); } }
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 __cdecl main(int argc, char *argv[]) { static PH_COMMAND_LINE_OPTION options[] = { { FI_ARG_HELP, L"h", NoArgumentType }, { FI_ARG_ACTION, L"a", MandatoryArgumentType }, { FI_ARG_NATIVE, L"N", NoArgumentType }, { FI_ARG_PATTERN, L"p", MandatoryArgumentType }, { FI_ARG_CASESENSITIVE, L"C", NoArgumentType }, { FI_ARG_OUTPUT, L"o", MandatoryArgumentType }, { FI_ARG_FORCE, L"f", NoArgumentType }, { FI_ARG_LENGTH, L"L", MandatoryArgumentType } }; PH_STRINGREF commandLine; NTSTATUS status = STATUS_SUCCESS; if (!NT_SUCCESS(PhInitializePhLibEx(0, 0, 0))) return 1; PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine); if (!PhParseCommandLine( &commandLine, options, sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), PH_COMMAND_LINE_IGNORE_FIRST_PART, FiCommandLineCallback, NULL ) || FiArgHelp) { FiPrintHelp(); return 0; } if (!FiArgFileName && ( FiArgAction && PhEqualString2(FiArgAction, L"dir", TRUE) )) { FiArgFileName = PhCreateStringFromUnicodeString(&NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath); } if (!FiArgAction) { FiPrintHelp(); return 1; } else if (PhEqualString2(FiArgAction, L"map", TRUE)) { WCHAR deviceNameBuffer[7] = L"\\??\\ :"; ULONG i; WCHAR targetNameBuffer[0x100]; UNICODE_STRING targetName; targetName.Buffer = targetNameBuffer; targetName.MaximumLength = sizeof(targetNameBuffer); for (i = 0; i < 26; i++) { HANDLE linkHandle; OBJECT_ATTRIBUTES oa; UNICODE_STRING deviceName; deviceNameBuffer[4] = (WCHAR)('A' + i); deviceName.Buffer = deviceNameBuffer; deviceName.Length = 6 * sizeof(WCHAR); InitializeObjectAttributes( &oa, &deviceName, OBJ_CASE_INSENSITIVE, NULL, NULL ); if (NT_SUCCESS(NtOpenSymbolicLinkObject( &linkHandle, SYMBOLIC_LINK_QUERY, &oa ))) { if (NT_SUCCESS(NtQuerySymbolicLinkObject( linkHandle, &targetName, NULL ))) { wprintf(L"%c: %.*s\n", 'A' + i, targetName.Length / 2, targetName.Buffer); } NtClose(linkHandle); } } } else if (!FiArgFileName) { wprintf(L"Error: file name missing.\n"); FiPrintHelp(); return 1; } else if (PhEqualString2(FiArgAction, L"hash", TRUE)) { HANDLE fileHandle; LARGE_INTEGER fileSize; IO_STATUS_BLOCK isb; ULONG mode; if (!FiArgOutput) mode = HASH_MD5; else if (PhEqualString2(FiArgOutput, L"md5", TRUE)) mode = HASH_MD5; else if (PhEqualString2(FiArgOutput, L"sha1", TRUE)) mode = HASH_SHA1; else if (PhEqualString2(FiArgOutput, L"crc32", TRUE)) mode = HASH_CRC32; else { wprintf(L"Invalid hash algorithm. Possibilities: md5, sha1, crc32\n"); return 1; } if (FiCreateFile( &fileHandle, FILE_GENERIC_READ, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY )) { if (NT_SUCCESS(status = PhGetFileSize(fileHandle, &fileSize))) { MD5_CTX md5Context; A_SHA_CTX shaContext; ULONG crc; UCHAR buffer[PAGE_SIZE * 4]; ULONG64 bytesRemaining; bytesRemaining = fileSize.QuadPart; switch (mode) { case HASH_MD5: MD5Init(&md5Context); break; case HASH_SHA1: A_SHAInit(&shaContext); break; case HASH_CRC32: crc = 0; break; } while (bytesRemaining) { status = NtReadFile( fileHandle, NULL, NULL, NULL, &isb, buffer, sizeof(buffer), NULL, NULL ); if (!NT_SUCCESS(status)) break; switch (mode) { case HASH_MD5: MD5Update(&md5Context, buffer, (ULONG)isb.Information); break; case HASH_SHA1: A_SHAUpdate(&shaContext, buffer, (ULONG)isb.Information); break; case HASH_CRC32: crc = PhCrc32(crc, buffer, isb.Information); break; } bytesRemaining -= (ULONG)isb.Information; } if (status == STATUS_END_OF_FILE) status = STATUS_SUCCESS; switch (mode) { case HASH_MD5: { MD5Final(&md5Context); wprintf(L"%s", PhBufferToHexString(md5Context.digest, 16)->Buffer); } break; case HASH_SHA1: { UCHAR hash[20]; A_SHAFinal(&shaContext, hash); wprintf(L"%s", PhBufferToHexString(hash, 20)->Buffer); } break; case HASH_CRC32: { wprintf(L"%08x", crc); } break; } if (!NT_SUCCESS(status)) wprintf(L"Warning: I/O error encountered: %s\n", PhGetNtMessage(status)->Buffer); } NtClose(fileHandle); } if (!NT_SUCCESS(status)) { wprintf(L"Error: %s\n", PhGetNtMessage(status)->Buffer); return 1; } } else if (PhEqualString2(FiArgAction, L"execute", TRUE)) { if (FiArgNative) { if (!NT_SUCCESS(status = PhCreateProcess( FiFormatFileName(FiArgFileName)->Buffer, FiArgOutput ? &FiArgOutput->sr : NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL ))) { wprintf(L"Error: %s\n", PhGetNtMessage(status)->Buffer); return 1; } } else { if (!NT_SUCCESS(status = PhCreateProcessWin32( FiArgFileName->Buffer, PhGetString(FiArgOutput), NULL, NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath.Buffer, PH_CREATE_PROCESS_NEW_CONSOLE, NULL, NULL, NULL ))) { wprintf(L"Error: %s\n", PhGetNtMessage(status)->Buffer); return 1; } } } else if (PhEqualString2(FiArgAction, L"del", TRUE)) { HANDLE fileHandle; if (FiCreateFile( &fileHandle, DELETE | SYNCHRONIZE, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT )) { FILE_DISPOSITION_INFORMATION dispositionInfo; IO_STATUS_BLOCK isb; dispositionInfo.DeleteFile = TRUE; if (!NT_SUCCESS(status = NtSetInformationFile(fileHandle, &isb, &dispositionInfo, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation))) { wprintf(L"Error deleting file: %s\n", PhGetNtMessage(status)->Buffer); } NtClose(fileHandle); } } else if (PhEqualString2(FiArgAction, L"touch", TRUE)) { HANDLE fileHandle; if (FiCreateFile( &fileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT )) { NtClose(fileHandle); } } else if (PhEqualString2(FiArgAction, L"mkdir", TRUE)) { HANDLE fileHandle; if (FiCreateFile( &fileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, FiArgFileName, FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT )) { NtClose(fileHandle); } } else if (PhEqualString2(FiArgAction, L"rename", TRUE)) { HANDLE fileHandle; PPH_STRING newFileName; if (!FiArgOutput) { wprintf(L"Error: new file name missing.\n"); FiPrintHelp(); return 1; } newFileName = FiFormatFileName(FiArgOutput); if (FiCreateFile( &fileHandle, DELETE | SYNCHRONIZE, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT )) { PFILE_RENAME_INFORMATION renameInfo; ULONG renameInfoSize; IO_STATUS_BLOCK isb; renameInfoSize = FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) + (ULONG)newFileName->Length; renameInfo = PhAllocate(renameInfoSize); renameInfo->ReplaceIfExists = FiArgForce; renameInfo->RootDirectory = NULL; renameInfo->FileNameLength = (ULONG)newFileName->Length; memcpy(renameInfo->FileName, newFileName->Buffer, newFileName->Length); status = NtSetInformationFile(fileHandle, &isb, renameInfo, renameInfoSize, FileRenameInformation); PhFree(renameInfo); if (!NT_SUCCESS(status)) { wprintf(L"Error renaming file: %s\n", PhGetNtMessage(status)->Buffer); } NtClose(fileHandle); } } else if (PhEqualString2(FiArgAction, L"copy", TRUE)) { HANDLE fileHandle; HANDLE outFileHandle; LARGE_INTEGER fileSize; FILE_BASIC_INFORMATION basicInfo; if (!FiArgOutput) { wprintf(L"Error: output file name missing.\n"); FiPrintHelp(); return 1; } if (FiCreateFile( &fileHandle, FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT ) && FiCreateFile( &outFileHandle, FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | SYNCHRONIZE, FiArgOutput, 0, FILE_SHARE_READ | FILE_SHARE_DELETE, !FiArgForce ? FILE_CREATE : FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT )) { #define COPY_BUFFER_SIZE 0x10000 IO_STATUS_BLOCK isb; PVOID buffer; ULONG64 bytesToCopy = FiArgLength; if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize))) { PhSetFileSize(outFileHandle, &fileSize); } buffer = PhAllocatePage(COPY_BUFFER_SIZE, NULL); if (!buffer) { wprintf(L"Error allocating buffer.\n"); return 1; } while (bytesToCopy) { status = NtReadFile( fileHandle, NULL, NULL, NULL, &isb, buffer, bytesToCopy >= COPY_BUFFER_SIZE ? COPY_BUFFER_SIZE : (ULONG)bytesToCopy, NULL, NULL ); if (status == STATUS_END_OF_FILE) { break; } else if (!NT_SUCCESS(status)) { wprintf(L"Error reading from file: %s\n", PhGetNtMessage(status)->Buffer); break; } status = NtWriteFile( outFileHandle, NULL, NULL, NULL, &isb, buffer, (ULONG)isb.Information, // number of bytes read NULL, NULL ); if (!NT_SUCCESS(status)) { wprintf(L"Error writing to output file: %s\n", PhGetNtMessage(status)->Buffer); break; } bytesToCopy -= (ULONG)isb.Information; } PhFreePage(buffer); // Copy basic attributes over. if (NT_SUCCESS(NtQueryInformationFile( fileHandle, &isb, &basicInfo, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation ))) { NtSetInformationFile( outFileHandle, &isb, &basicInfo, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation ); } NtClose(fileHandle); NtClose(outFileHandle); } } else if (PhEqualString2(FiArgAction, L"dir", TRUE)) { HANDLE fileHandle; UNICODE_STRING pattern; PPH_STRING totalSize, totalAllocSize; if (FiCreateFile( &fileHandle, FILE_LIST_DIRECTORY | SYNCHRONIZE, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT )) { FipDirFileCount = 0; FipDirDirCount = 0; FipDirTotalSize = 0; FipDirTotalAllocSize = 0; if (FiArgPattern) PhStringRefToUnicodeString(&FiArgPattern->sr, &pattern); PhEnumDirectoryFile( fileHandle, FiArgPattern ? &pattern : NULL, FipEnumDirectoryFileForDir, NULL ); NtClose(fileHandle); totalSize = PhFormatUInt64(FipDirTotalSize, TRUE); totalAllocSize = PhFormatUInt64(FipDirTotalAllocSize, TRUE); wprintf( L"%12I64u file(s) %11s bytes\n" L"%12I64u dir(s) %11s bytes allocated\n", FipDirFileCount, totalSize->Buffer, FipDirDirCount, totalAllocSize->Buffer ); PhDereferenceObject(totalSize); PhDereferenceObject(totalAllocSize); } } else if (PhEqualString2(FiArgAction, L"streams", TRUE)) { HANDLE fileHandle; PVOID streams; PFILE_STREAM_INFORMATION stream; if (FiCreateFile( &fileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, FiArgFileName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT )) { if (NT_SUCCESS(PhEnumFileStreams(fileHandle, &streams))) { stream = PH_FIRST_STREAM(streams); while (stream) { PPH_STRING size, allocationSize; size = PhFormatUInt64(stream->StreamSize.QuadPart, TRUE); allocationSize = PhFormatUInt64(stream->StreamAllocationSize.QuadPart, TRUE); wprintf( L"%11s %11s %.*s\n", size->Buffer, allocationSize->Buffer, stream->StreamNameLength / 2, stream->StreamName ); PhDereferenceObject(size); PhDereferenceObject(allocationSize); stream = PH_NEXT_STREAM(stream); } } NtClose(fileHandle); } } else { wprintf(L"Error: invalid action \"%s\".\n", FiArgAction->Buffer); FiPrintHelp(); return 1; } }
BOOLEAN FiCreateFile( _Out_ PHANDLE FileHandle, _In_ ACCESS_MASK DesiredAccess, _In_ PPH_STRING FileName, _In_opt_ ULONG FileAttributes, _In_ ULONG ShareAccess, _In_ ULONG CreateDisposition, _In_opt_ ULONG Options ) { NTSTATUS status; HANDLE fileHandle; OBJECT_ATTRIBUTES oa; IO_STATUS_BLOCK isb; PPH_STRING fileName; UNICODE_STRING fileNameUs; if (!FileAttributes) FileAttributes = FILE_ATTRIBUTE_NORMAL; if (!Options) Options = FILE_SYNCHRONOUS_IO_NONALERT; // Not needed, because we handle Win32 paths anyway. //if (!(FiArgNative)) //{ // status = PhCreateFileWin32( // FileHandle, // FileName->Buffer, // DesiredAccess, // FileAttributes, // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // CreateDisposition, // Options // ); // if (!NT_SUCCESS(status)) // { // wprintf(L"Error creating/opening file: %s\n", PhGetNtMessage(status)->Buffer); // return FALSE; // } // return TRUE; //} fileName = FiFormatFileName(FileName); if (!PhStringRefToUnicodeString(&fileName->sr, &fileNameUs)) { PhDereferenceObject(fileName); return FALSE; } InitializeObjectAttributes( &oa, &fileNameUs, (!FiArgCaseSensitive ? OBJ_CASE_INSENSITIVE : 0), NULL, NULL ); status = NtCreateFile( &fileHandle, DesiredAccess, &oa, &isb, NULL, FileAttributes, ShareAccess, CreateDisposition, Options, NULL, 0 ); if (!NT_SUCCESS(status)) { wprintf(L"Error creating/opening file: %s\n", PhGetNtMessage(status)->Buffer); return FALSE; } *FileHandle = fileHandle; return TRUE; }
PPH_LIST QueryDotNetAppDomainsForPid_V4( _In_ BOOLEAN Wow64, _In_ HANDLE ProcessHandle, _In_ HANDLE ProcessId ) { HANDLE legacyPrivateBlockHandle = NULL; PVOID ipcControlBlockTable = NULL; LARGE_INTEGER sectionOffset = { 0 }; SIZE_T viewSize = 0; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING sectionNameUs; PPH_LIST appDomainsList = NULL; if (!PhStringRefToUnicodeString(&GeneratePrivateNameV4(ProcessId)->sr, §ionNameUs)) goto CleanupExit; InitializeObjectAttributes( &objectAttributes, §ionNameUs, OBJ_CASE_INSENSITIVE, NULL, NULL ); if (!NT_SUCCESS(NtOpenSection( &legacyPrivateBlockHandle, SECTION_MAP_READ, &objectAttributes ))) { goto CleanupExit; } if (!NT_SUCCESS(NtMapViewOfSection( legacyPrivateBlockHandle, NtCurrentProcess(), &ipcControlBlockTable, 0, viewSize, §ionOffset, &viewSize, ViewShare, 0, PAGE_READONLY ))) { goto CleanupExit; } if (Wow64) { LegacyPrivateIPCControlBlock_Wow64* legacyPrivateBlock; AppDomainEnumerationIPCBlock_Wow64* appDomainEnumBlock; legacyPrivateBlock = (LegacyPrivateIPCControlBlock_Wow64*)ipcControlBlockTable; appDomainEnumBlock = &legacyPrivateBlock->AppDomainBlock; // Check the IPCControlBlock is initialized. if ((legacyPrivateBlock->FullIPCHeader.Header.Flags & IPC_FLAG_INITIALIZED) != IPC_FLAG_INITIALIZED) { goto CleanupExit; } // Check the IPCControlBlock version is valid. if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK) { goto CleanupExit; } appDomainsList = EnumerateAppDomainIpcBlockWow64( ProcessHandle, appDomainEnumBlock ); } else { LegacyPrivateIPCControlBlock* legacyPrivateBlock; AppDomainEnumerationIPCBlock* appDomainEnumBlock; legacyPrivateBlock = (LegacyPrivateIPCControlBlock*)ipcControlBlockTable; appDomainEnumBlock = &legacyPrivateBlock->AppDomainBlock; // Check the IPCControlBlock is initialized. if ((legacyPrivateBlock->FullIPCHeader.Header.Flags & IPC_FLAG_INITIALIZED) != IPC_FLAG_INITIALIZED) { goto CleanupExit; } // Check the IPCControlBlock version is valid. if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK) { goto CleanupExit; } appDomainsList = EnumerateAppDomainIpcBlock( ProcessHandle, appDomainEnumBlock ); } CleanupExit: if (ipcControlBlockTable) { NtUnmapViewOfSection(NtCurrentProcess(), ipcControlBlockTable); } if (legacyPrivateBlockHandle) { NtClose(legacyPrivateBlockHandle); } return appDomainsList; }
BOOLEAN OpenDotNetPublicControlBlock_V4( _In_ BOOLEAN IsImmersive, _In_ HANDLE ProcessHandle, _In_ HANDLE ProcessId, _Out_ HANDLE* BlockTableHandle, _Out_ PVOID* BlockTableAddress ) { BOOLEAN result = FALSE; PVOID boundaryDescriptorHandle = NULL; HANDLE privateNamespaceHandle = NULL; HANDLE blockTableHandle = NULL; HANDLE tokenHandle = NULL; PSID everyoneSIDHandle = NULL; PVOID blockTableAddress = NULL; LARGE_INTEGER sectionOffset = { 0 }; SIZE_T viewSize = 0; UNICODE_STRING prefixNameUs; UNICODE_STRING sectionNameUs; UNICODE_STRING boundaryNameUs; OBJECT_ATTRIBUTES namespaceObjectAttributes; OBJECT_ATTRIBUTES sectionObjectAttributes; PTOKEN_APPCONTAINER_INFORMATION appContainerInfo = NULL; SID_IDENTIFIER_AUTHORITY SIDWorldAuth = SECURITY_WORLD_SID_AUTHORITY; if (!PhStringRefToUnicodeString(&GenerateBoundaryDescriptorName(ProcessId)->sr, &boundaryNameUs)) goto CleanupExit; if (!(boundaryDescriptorHandle = RtlCreateBoundaryDescriptor(&boundaryNameUs, 0))) goto CleanupExit; if (!NT_SUCCESS(RtlAllocateAndInitializeSid(&SIDWorldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyoneSIDHandle))) goto CleanupExit; if (!NT_SUCCESS(RtlAddSIDToBoundaryDescriptor(&boundaryDescriptorHandle, everyoneSIDHandle))) goto CleanupExit; if (WINDOWS_HAS_IMMERSIVE && IsImmersive) { if (NT_SUCCESS(NtOpenProcessToken(&tokenHandle, TOKEN_QUERY, ProcessHandle))) { ULONG returnLength = 0; if (NtQueryInformationToken( tokenHandle, TokenAppContainerSid, NULL, 0, &returnLength ) != STATUS_BUFFER_TOO_SMALL) { goto CleanupExit; } appContainerInfo = PhAllocate(returnLength); if (!NT_SUCCESS(NtQueryInformationToken( tokenHandle, TokenAppContainerSid, appContainerInfo, returnLength, &returnLength ))) { goto CleanupExit; } if (!NT_SUCCESS(RtlAddSIDToBoundaryDescriptor(&boundaryDescriptorHandle, appContainerInfo->TokenAppContainer))) goto CleanupExit; } } RtlInitUnicodeString(&prefixNameUs, CorSxSReaderPrivateNamespacePrefix); InitializeObjectAttributes( &namespaceObjectAttributes, &prefixNameUs, OBJ_CASE_INSENSITIVE, boundaryDescriptorHandle, NULL ); if (!NT_SUCCESS(NtOpenPrivateNamespace( &privateNamespaceHandle, MAXIMUM_ALLOWED, &namespaceObjectAttributes, boundaryDescriptorHandle ))) { goto CleanupExit; } RtlInitUnicodeString(§ionNameUs, CorSxSVistaPublicIPCBlock); InitializeObjectAttributes( §ionObjectAttributes, §ionNameUs, OBJ_CASE_INSENSITIVE, privateNamespaceHandle, NULL ); if (!NT_SUCCESS(NtOpenSection( &blockTableHandle, SECTION_MAP_READ, §ionObjectAttributes ))) { goto CleanupExit; } if (!NT_SUCCESS(NtMapViewOfSection( blockTableHandle, NtCurrentProcess(), &blockTableAddress, 0, viewSize, §ionOffset, &viewSize, ViewShare, 0, PAGE_READONLY ))) { goto CleanupExit; } *BlockTableHandle = blockTableHandle; *BlockTableAddress = blockTableAddress; result = TRUE; CleanupExit: if (!result) { if (blockTableHandle) { NtClose(blockTableHandle); } if (blockTableAddress) { NtUnmapViewOfSection(NtCurrentProcess(), blockTableAddress); } *BlockTableHandle = NULL; *BlockTableAddress = NULL; } if (tokenHandle) { NtClose(tokenHandle); } if (appContainerInfo) { PhFree(appContainerInfo); } if (privateNamespaceHandle) { NtClose(privateNamespaceHandle); } if (everyoneSIDHandle) { RtlFreeSid(everyoneSIDHandle); } if (boundaryDescriptorHandle) { RtlDeleteBoundaryDescriptor(boundaryDescriptorHandle); } return result; }
BOOLEAN OpenDotNetPublicControlBlock_V2( _In_ HANDLE ProcessId, _Out_ HANDLE* BlockTableHandle, _Out_ PVOID* BlockTableAddress ) { BOOLEAN result = FALSE; HANDLE blockTableHandle = NULL; PVOID blockTableAddress = NULL; UNICODE_STRING sectionNameUs; OBJECT_ATTRIBUTES objectAttributes; LARGE_INTEGER sectionOffset = { 0 }; SIZE_T viewSize = 0; if (!PhStringRefToUnicodeString(&GenerateLegacyPublicName(ProcessId)->sr, §ionNameUs)) return FALSE; InitializeObjectAttributes( &objectAttributes, §ionNameUs, OBJ_CASE_INSENSITIVE, NULL, NULL ); if (!NT_SUCCESS(NtOpenSection( &blockTableHandle, SECTION_MAP_READ, &objectAttributes ))) { return FALSE; } if (NT_SUCCESS(NtMapViewOfSection( blockTableHandle, NtCurrentProcess(), &blockTableAddress, 0, viewSize, §ionOffset, &viewSize, ViewShare, 0, PAGE_READONLY ))) { *BlockTableHandle = blockTableHandle; *BlockTableAddress = blockTableAddress; return TRUE; } if (blockTableHandle) NtClose(blockTableHandle); if (blockTableAddress) NtUnmapViewOfSection(NtCurrentProcess(), blockTableAddress); return FALSE; }
PPH_LIST QueryDotNetAppDomainsForPid_V2( _In_ BOOLEAN Wow64, _In_ HANDLE ProcessHandle, _In_ HANDLE ProcessId ) { LARGE_INTEGER sectionOffset = { 0 }; SIZE_T viewSize = 0; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING sectionNameUs; HANDLE legacyPrivateBlockHandle = NULL; PVOID ipcControlBlockTable = NULL; PPH_LIST appDomainsList = NULL; __try { if (!PhStringRefToUnicodeString(&GeneratePrivateName(ProcessId)->sr, §ionNameUs)) __leave; InitializeObjectAttributes( &objectAttributes, §ionNameUs, 0, NULL, NULL ); if (!NT_SUCCESS(NtOpenSection( &legacyPrivateBlockHandle, SECTION_MAP_READ, &objectAttributes ))) { __leave; } if (!NT_SUCCESS(NtMapViewOfSection( legacyPrivateBlockHandle, NtCurrentProcess(), &ipcControlBlockTable, 0, viewSize, §ionOffset, &viewSize, ViewShare, 0, PAGE_READONLY ))) { __leave; } if (Wow64) { LegacyPrivateIPCControlBlock_Wow64* legacyPrivateBlock; AppDomainEnumerationIPCBlock_Wow64* appDomainEnumBlock; legacyPrivateBlock = (LegacyPrivateIPCControlBlock_Wow64*)ipcControlBlockTable; // NOTE: .NET 2.0 processes do not have the IPC_FLAG_INITIALIZED flag. // Check the IPCControlBlock version is valid. if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK) { __leave; } appDomainEnumBlock = GetLegacyBlockTableEntry( Wow64, ipcControlBlockTable, eLegacyPrivateIPC_AppDomain ); appDomainsList = EnumerateAppDomainIpcBlockWow64( ProcessHandle, appDomainEnumBlock ); } else { LegacyPrivateIPCControlBlock* legacyPrivateBlock; AppDomainEnumerationIPCBlock* appDomainEnumBlock; legacyPrivateBlock = (LegacyPrivateIPCControlBlock*)ipcControlBlockTable; // NOTE: .NET 2.0 processes do not have the IPC_FLAG_INITIALIZED flag. // Check the IPCControlBlock version is valid. if (legacyPrivateBlock->FullIPCHeader.Header.Version > VER_LEGACYPRIVATE_IPC_BLOCK) { __leave; } appDomainEnumBlock = GetLegacyBlockTableEntry( Wow64, ipcControlBlockTable, eLegacyPrivateIPC_AppDomain ); appDomainsList = EnumerateAppDomainIpcBlock( ProcessHandle, appDomainEnumBlock ); } } __finally { if (ipcControlBlockTable) { NtUnmapViewOfSection(NtCurrentProcess(), ipcControlBlockTable); } if (legacyPrivateBlockHandle) { NtClose(legacyPrivateBlockHandle); } } return appDomainsList; }