1d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// found in the LICENSE file. 4d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 5d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using Microsoft.Win32.SafeHandles; 6d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System; 7d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Collections.Generic; 8d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.ComponentModel; 9d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.IO; 10d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Linq; 11d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Text; 12d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using System.Threading.Tasks; 13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using ChromeDebug.LowLevel; 158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)using System.Runtime.InteropServices; 168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)using System.Drawing; 17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace ChromeDebug { 19d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) internal class ProcessDetail : IDisposable { 20d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public ProcessDetail(int pid) { 21d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Initialize everything to null in case something fails. 22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) this.processId = pid; 23d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) this.processHandleFlags = LowLevelTypes.ProcessAccessFlags.NONE; 24d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) this.cachedProcessBasicInfo = null; 25d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) this.machineTypeIsLoaded = false; 26d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) this.machineType = LowLevelTypes.MachineType.UNKNOWN; 27d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) this.cachedPeb = null; 28d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) this.cachedProcessParams = null; 29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) this.cachedCommandLine = null; 30d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) this.processHandle = IntPtr.Zero; 31d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 32d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) OpenAndCacheProcessHandle(); 33d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 34d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 35d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Returns the machine type (x86, x64, etc) of this process. Uses lazy evaluation and caches 36d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // the result. 37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public LowLevelTypes.MachineType MachineType { 38d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) get { 39d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (machineTypeIsLoaded) 40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return machineType; 41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (!CanQueryProcessInformation) 42d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return LowLevelTypes.MachineType.UNKNOWN; 43d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 44d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) CacheMachineType(); 45d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return machineType; 46d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 47d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 48d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) public string NativeProcessImagePath { 508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) get { 518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (nativeProcessImagePath == null) { 528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) nativeProcessImagePath = QueryProcessImageName( 538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LowLevelTypes.ProcessQueryImageNameMode.NATIVE_SYSTEM_FORMAT); 548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return nativeProcessImagePath; 568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) public string Win32ProcessImagePath { 608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) get { 618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (win32ProcessImagePath == null) { 628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) win32ProcessImagePath = QueryProcessImageName( 638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LowLevelTypes.ProcessQueryImageNameMode.WIN32_FORMAT); 648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return win32ProcessImagePath; 668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) public Icon SmallIcon { 708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) get { 718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LowLevel.LowLevelTypes.SHFILEINFO info = new LowLevelTypes.SHFILEINFO(true); 728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LowLevel.LowLevelTypes.SHGFI flags = LowLevel.LowLevelTypes.SHGFI.Icon 738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) | LowLevelTypes.SHGFI.SmallIcon 748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) | LowLevelTypes.SHGFI.OpenIcon 758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) | LowLevelTypes.SHGFI.UseFileAttributes; 768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int cbFileInfo = Marshal.SizeOf(info); 778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LowLevel.NativeMethods.SHGetFileInfo(Win32ProcessImagePath, 788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 256, 798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ref info, 808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) (uint)cbFileInfo, 818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) (uint)flags); 828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return Icon.FromHandle(info.hIcon); 838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 86d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Returns the command line that this process was launched with. Uses lazy evaluation and 87d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // caches the result. Reads the command line from the PEB of the running process. 88d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public string CommandLine { 89d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) get { 90d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (!CanReadPeb) 91d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) throw new InvalidOperationException(); 92d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) CacheProcessInformation(); 93d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) CachePeb(); 94d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) CacheProcessParams(); 95d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) CacheCommandLine(); 96d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return cachedCommandLine; 97d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 98d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 99d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 100d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Determines if we have permission to read the process's PEB. 101d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public bool CanReadPeb { 102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) get { 103d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) LowLevelTypes.ProcessAccessFlags required_flags = 104d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) LowLevelTypes.ProcessAccessFlags.VM_READ 105d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) | LowLevelTypes.ProcessAccessFlags.QUERY_INFORMATION; 106d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // In order to read the PEB, we must have *both* of these flags. 108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if ((processHandleFlags & required_flags) != required_flags) 109d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return false; 110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 111d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // If we're on a 64-bit OS, in a 32-bit process, and the target process is not 32-bit, 112d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // we can't read its PEB. 113d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess 114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) && (MachineType != LowLevelTypes.MachineType.X86)) 115d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return false; 116d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 117d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return true; 118d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 119d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 120d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 121d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // If we can't read the process's PEB, we may still be able to get other kinds of information 122d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // from the process. This flag determines if we can get lesser information. 123d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private bool CanQueryProcessInformation { 124d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) get { 125d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) LowLevelTypes.ProcessAccessFlags required_flags = 126d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) LowLevelTypes.ProcessAccessFlags.QUERY_LIMITED_INFORMATION 127d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) | LowLevelTypes.ProcessAccessFlags.QUERY_INFORMATION; 128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 129d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // In order to query the process, we need *either* of these flags. 130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return (processHandleFlags & required_flags) != LowLevelTypes.ProcessAccessFlags.NONE; 131d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 132d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 133d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 1348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) private string QueryProcessImageName(LowLevelTypes.ProcessQueryImageNameMode mode) { 1358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) StringBuilder moduleBuffer = new StringBuilder(1024); 1368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int size = moduleBuffer.Capacity; 1378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) NativeMethods.QueryFullProcessImageName( 1388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) processHandle, 1398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) mode, 1408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) moduleBuffer, 1418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ref size); 1428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (mode == LowLevelTypes.ProcessQueryImageNameMode.NATIVE_SYSTEM_FORMAT) 1438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) moduleBuffer.Insert(0, "\\\\?\\GLOBALROOT"); 1448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return moduleBuffer.ToString(); 1458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 1468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 147d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Loads the top-level structure of the process's information block and caches it. 148d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private void CacheProcessInformation() { 149d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) System.Diagnostics.Debug.Assert(CanReadPeb); 150d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 151d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Fetch the process info and set the fields. 152d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) LowLevelTypes.PROCESS_BASIC_INFORMATION temp = new LowLevelTypes.PROCESS_BASIC_INFORMATION(); 153d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) int size; 154d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) LowLevelTypes.NTSTATUS status = NativeMethods.NtQueryInformationProcess( 155d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) processHandle, 156d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) LowLevelTypes.PROCESSINFOCLASS.PROCESS_BASIC_INFORMATION, 157d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ref temp, 158d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) Utility.UnmanagedStructSize<LowLevelTypes.PROCESS_BASIC_INFORMATION>(), 159d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) out size); 160d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 161d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (status != LowLevelTypes.NTSTATUS.SUCCESS) { 162d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) throw new Win32Exception(); 163d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 164d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 165d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) cachedProcessBasicInfo = temp; 166d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 167d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 168d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Follows a pointer from the PROCESS_BASIC_INFORMATION structure in the target process's 169d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // address space to read the PEB. 170d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private void CachePeb() { 171d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) System.Diagnostics.Debug.Assert(CanReadPeb); 172d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 173d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (cachedPeb == null) { 174d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) cachedPeb = Utility.ReadUnmanagedStructFromProcess<LowLevelTypes.PEB>( 175d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) processHandle, 176d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) cachedProcessBasicInfo.Value.PebBaseAddress); 177d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 178d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 179d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 180d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Follows a pointer from the PEB structure in the target process's address space to read the 181d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // RTL_USER_PROCESS_PARAMETERS structure. 182d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private void CacheProcessParams() { 183d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) System.Diagnostics.Debug.Assert(CanReadPeb); 184d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 185d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (cachedProcessParams == null) { 186d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) cachedProcessParams = 187d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) Utility.ReadUnmanagedStructFromProcess<LowLevelTypes.RTL_USER_PROCESS_PARAMETERS>( 188d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) processHandle, cachedPeb.Value.ProcessParameters); 189d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 190d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 191d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 192d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private void CacheCommandLine() { 193d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) System.Diagnostics.Debug.Assert(CanReadPeb); 194d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 195d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (cachedCommandLine == null) { 196d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) cachedCommandLine = Utility.ReadStringUniFromProcess( 197d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) processHandle, 198d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) cachedProcessParams.Value.CommandLine.Buffer, 199d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) cachedProcessParams.Value.CommandLine.Length / 2); 200d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 201d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 202d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 203d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private void CacheMachineType() { 204d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) System.Diagnostics.Debug.Assert(CanQueryProcessInformation); 205d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 206d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // If our extension is running in a 32-bit process (which it is), then attempts to access 207d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // files in C:\windows\system (and a few other files) will redirect to C:\Windows\SysWOW64 208d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // and we will mistakenly think that the image file is a 32-bit image. The way around this 209d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // is to use a native system format path, of the form: 210d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // \\?\GLOBALROOT\Device\HarddiskVolume0\Windows\System\foo.dat 2118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // NativeProcessImagePath gives us the full process image path in the desired format. 2128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) string path = NativeProcessImagePath; 213d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 214d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Open the PE File as a binary file, and parse just enough information to determine the 215d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // machine type. 216d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) //http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx 217d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) using (SafeFileHandle safeHandle = NativeMethods.CreateFile( 2188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) path, 219d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) LowLevelTypes.FileAccessFlags.GENERIC_READ, 220d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) LowLevelTypes.FileShareFlags.SHARE_READ, 221d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) IntPtr.Zero, 222d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) LowLevelTypes.FileCreationDisposition.OPEN_EXISTING, 223d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) LowLevelTypes.FileFlagsAndAttributes.NORMAL, 224d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) IntPtr.Zero)) { 225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) FileStream fs = new FileStream(safeHandle, FileAccess.Read); 226d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) using (BinaryReader br = new BinaryReader(fs)) { 227d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) fs.Seek(0x3c, SeekOrigin.Begin); 228d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) Int32 peOffset = br.ReadInt32(); 229d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) fs.Seek(peOffset, SeekOrigin.Begin); 230d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) UInt32 peHead = br.ReadUInt32(); 231d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (peHead != 0x00004550) // "PE\0\0", little-endian 232d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) throw new Exception("Can't find PE header"); 233d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) machineType = (LowLevelTypes.MachineType)br.ReadUInt16(); 234d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) machineTypeIsLoaded = true; 235d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 236d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 237d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 238d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 239d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private void OpenAndCacheProcessHandle() { 240d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Try to open a handle to the process with the highest level of privilege, but if we can't 241d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // do that then fallback to requesting access with a lower privilege level. 242d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) processHandleFlags = LowLevelTypes.ProcessAccessFlags.QUERY_INFORMATION 243d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) | LowLevelTypes.ProcessAccessFlags.VM_READ; 244d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) processHandle = NativeMethods.OpenProcess(processHandleFlags, false, processId); 245d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (processHandle == IntPtr.Zero) { 246d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) processHandleFlags = LowLevelTypes.ProcessAccessFlags.QUERY_LIMITED_INFORMATION; 247d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) processHandle = NativeMethods.OpenProcess(processHandleFlags, false, processId); 248d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (processHandle == IntPtr.Zero) { 249d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) processHandleFlags = LowLevelTypes.ProcessAccessFlags.NONE; 250d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) throw new Win32Exception(); 251d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 252d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 253d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 254d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 255d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // An open handle to the process, along with the set of access flags that the handle was 256d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // open with. 257d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private int processId; 258d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private IntPtr processHandle; 2598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) private LowLevelTypes.ProcessAccessFlags processHandleFlags; 2608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) private string nativeProcessImagePath; 2618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) private string win32ProcessImagePath; 262d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 263d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // The machine type is read by parsing the PE image file of the running process, so we cache 264d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // its value since the operation expensive. 265d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private bool machineTypeIsLoaded; 266d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private LowLevelTypes.MachineType machineType; 267d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 268d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // The following fields exist ultimately so that we can access the command line. However, 269d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // each field must be read separately through a pointer into another process's address 270d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // space so the access is expensive, hence we cache the values. 271d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private Nullable<LowLevelTypes.PROCESS_BASIC_INFORMATION> cachedProcessBasicInfo; 272d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private Nullable<LowLevelTypes.PEB> cachedPeb; 273d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private Nullable<LowLevelTypes.RTL_USER_PROCESS_PARAMETERS> cachedProcessParams; 274d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private string cachedCommandLine; 275d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 2768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ~ProcessDetail() { 2778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) Dispose(); 2788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 2798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 280d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public void Dispose() { 281d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (processHandle != IntPtr.Zero) 282d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) NativeMethods.CloseHandle(processHandle); 283d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) processHandle = IntPtr.Zero; 284d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 285d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 286d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 287