mirror of https://github.com/mono/CppSharp.git
Browse Source
This is done by obtaining the value of UCRTVersion by means of executing the vcvarsqueryregistry.bat from the standard VS 2015 set-up. Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>pull/1134/head
2 changed files with 754 additions and 11 deletions
@ -0,0 +1,697 @@
@@ -0,0 +1,697 @@
|
||||
/* *************************************************************************** |
||||
|
||||
The component allows to read the environment variables of another process |
||||
running in a Windows system. |
||||
|
||||
History: |
||||
- v1.2: Added support for inspection of 64 bit processes from 32 bit host |
||||
- v1.1: Fixed issue with environment block size detection |
||||
- v1.0: Initial |
||||
|
||||
|
||||
****************************************************************************** |
||||
|
||||
The MIT License (MIT) |
||||
|
||||
Copyright (c) 2011-2014 Oleksiy Gapotchenko |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in |
||||
all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
THE SOFTWARE. |
||||
|
||||
*************************************************************************** */ |
||||
|
||||
using System; |
||||
using System.Collections.Specialized; |
||||
using System.Diagnostics; |
||||
using System.Runtime.CompilerServices; |
||||
using System.Runtime.InteropServices; |
||||
using System.Text; |
||||
|
||||
namespace ReadEnvSample |
||||
{ |
||||
static class ProcessEnvironment |
||||
{ |
||||
public static StringDictionary ReadEnvironmentVariables(this Process process) |
||||
{ |
||||
return _GetEnvironmentVariablesCore(process.Handle); |
||||
} |
||||
|
||||
public static StringDictionary TryReadEnvironmentVariables(this Process process) |
||||
{ |
||||
try |
||||
{ |
||||
return ReadEnvironmentVariables(process); |
||||
} |
||||
catch |
||||
{ |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Universal pointer.
|
||||
/// </summary>
|
||||
struct UniPtr |
||||
{ |
||||
public UniPtr(IntPtr p) |
||||
{ |
||||
Value = p.ToInt64(); |
||||
Size = IntPtr.Size; |
||||
} |
||||
|
||||
public UniPtr(long p) |
||||
{ |
||||
Value = p; |
||||
Size = sizeof(long); |
||||
} |
||||
|
||||
public long Value; |
||||
public int Size; |
||||
|
||||
public static implicit operator IntPtr(UniPtr p) |
||||
{ |
||||
return new IntPtr(p.Value); |
||||
} |
||||
|
||||
public static implicit operator UniPtr(IntPtr p) |
||||
{ |
||||
return new UniPtr(p); |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return Value.ToString(); |
||||
} |
||||
|
||||
public bool FitsInNativePointer |
||||
{ |
||||
get |
||||
{ |
||||
return Size <= IntPtr.Size; |
||||
} |
||||
} |
||||
|
||||
public bool CanBeRepresentedByNativePointer |
||||
{ |
||||
get |
||||
{ |
||||
int actualSize = Size; |
||||
|
||||
if (actualSize == 8) |
||||
{ |
||||
if (Value >> 32 == 0) |
||||
actualSize = 4; |
||||
} |
||||
|
||||
return actualSize <= IntPtr.Size; |
||||
} |
||||
} |
||||
|
||||
public long ToInt64() |
||||
{ |
||||
return Value; |
||||
} |
||||
} |
||||
|
||||
static StringDictionary _GetEnvironmentVariablesCore(IntPtr hProcess) |
||||
{ |
||||
var penv = _GetPenv(hProcess); |
||||
|
||||
const int maxEnvSize = 32767; |
||||
byte[] envData; |
||||
|
||||
if (penv.CanBeRepresentedByNativePointer) |
||||
{ |
||||
int dataSize; |
||||
if (!_HasReadAccess(hProcess, penv, out dataSize)) |
||||
throw new Exception("Unable to read environment block."); |
||||
|
||||
if (dataSize > maxEnvSize) |
||||
dataSize = maxEnvSize; |
||||
|
||||
envData = new byte[dataSize]; |
||||
var res_len = IntPtr.Zero; |
||||
bool b = WindowsApi.ReadProcessMemory( |
||||
hProcess, |
||||
penv, |
||||
envData, |
||||
new IntPtr(dataSize), |
||||
ref res_len); |
||||
|
||||
if (!b || (int)res_len != dataSize) |
||||
throw new Exception("Unable to read environment block data."); |
||||
} |
||||
else if (penv.Size == 8 && IntPtr.Size == 4) |
||||
{ |
||||
// Accessing 64 bit process under 32 bit host.
|
||||
|
||||
int dataSize; |
||||
if (!_HasReadAccessWow64(hProcess, penv.ToInt64(), out dataSize)) |
||||
throw new Exception("Unable to read environment block with WOW64 API."); |
||||
|
||||
if (dataSize > maxEnvSize) |
||||
dataSize = maxEnvSize; |
||||
|
||||
envData = new byte[dataSize]; |
||||
long res_len = 0; |
||||
int result = WindowsApi.NtWow64ReadVirtualMemory64( |
||||
hProcess, |
||||
penv.ToInt64(), |
||||
envData, |
||||
dataSize, |
||||
ref res_len); |
||||
|
||||
if (result != WindowsApi.STATUS_SUCCESS || res_len != dataSize) |
||||
throw new Exception("Unable to read environment block data with WOW64 API."); |
||||
} |
||||
else |
||||
{ |
||||
throw new Exception("Unable to access process memory due to unsupported bitness cardinality."); |
||||
} |
||||
|
||||
return _EnvToDictionary(envData); |
||||
} |
||||
|
||||
static StringDictionary _EnvToDictionary(byte[] env) |
||||
{ |
||||
var result = new StringDictionary(); |
||||
|
||||
int len = env.Length; |
||||
if (len < 4) |
||||
return result; |
||||
|
||||
int n = len - 3; |
||||
for (int i = 0; i < n; ++i) |
||||
{ |
||||
byte c1 = env[i]; |
||||
byte c2 = env[i + 1]; |
||||
byte c3 = env[i + 2]; |
||||
byte c4 = env[i + 3]; |
||||
|
||||
if (c1 == 0 && c2 == 0 && c3 == 0 && c4 == 0) |
||||
{ |
||||
len = i + 3; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
char[] environmentCharArray = Encoding.Unicode.GetChars(env, 0, len); |
||||
|
||||
for (int i = 0; i < environmentCharArray.Length; i++) |
||||
{ |
||||
int startIndex = i; |
||||
while ((environmentCharArray[i] != '=') && (environmentCharArray[i] != '\0')) |
||||
{ |
||||
i++; |
||||
} |
||||
if (environmentCharArray[i] != '\0') |
||||
{ |
||||
if ((i - startIndex) == 0) |
||||
{ |
||||
while (environmentCharArray[i] != '\0') |
||||
{ |
||||
i++; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
string str = new string(environmentCharArray, startIndex, i - startIndex); |
||||
i++; |
||||
int num3 = i; |
||||
while (environmentCharArray[i] != '\0') |
||||
{ |
||||
i++; |
||||
} |
||||
string str2 = new string(environmentCharArray, num3, i - num3); |
||||
result[str] = str2; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
static bool _TryReadIntPtr32(IntPtr hProcess, IntPtr ptr, out IntPtr readPtr) |
||||
{ |
||||
bool result; |
||||
RuntimeHelpers.PrepareConstrainedRegions(); |
||||
try |
||||
{ |
||||
} |
||||
finally |
||||
{ |
||||
int dataSize = sizeof(Int32); |
||||
var data = Marshal.AllocHGlobal(dataSize); |
||||
IntPtr res_len = IntPtr.Zero; |
||||
bool b = WindowsApi.ReadProcessMemory( |
||||
hProcess, |
||||
ptr, |
||||
data, |
||||
new IntPtr(dataSize), |
||||
ref res_len); |
||||
readPtr = new IntPtr(Marshal.ReadInt32(data)); |
||||
Marshal.FreeHGlobal(data); |
||||
if (!b || (int)res_len != dataSize) |
||||
result = false; |
||||
else |
||||
result = true; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static bool _TryReadIntPtr(IntPtr hProcess, IntPtr ptr, out IntPtr readPtr) |
||||
{ |
||||
bool result; |
||||
RuntimeHelpers.PrepareConstrainedRegions(); |
||||
try |
||||
{ |
||||
} |
||||
finally |
||||
{ |
||||
int dataSize = IntPtr.Size; |
||||
var data = Marshal.AllocHGlobal(dataSize); |
||||
IntPtr res_len = IntPtr.Zero; |
||||
bool b = WindowsApi.ReadProcessMemory( |
||||
hProcess, |
||||
ptr, |
||||
data, |
||||
new IntPtr(dataSize), |
||||
ref res_len); |
||||
readPtr = Marshal.ReadIntPtr(data); |
||||
Marshal.FreeHGlobal(data); |
||||
if (!b || (int)res_len != dataSize) |
||||
result = false; |
||||
else |
||||
result = true; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static bool _TryReadIntPtrWow64(IntPtr hProcess, long ptr, out long readPtr) |
||||
{ |
||||
bool result; |
||||
RuntimeHelpers.PrepareConstrainedRegions(); |
||||
try |
||||
{ |
||||
} |
||||
finally |
||||
{ |
||||
int dataSize = sizeof(long); |
||||
var data = Marshal.AllocHGlobal(dataSize); |
||||
long res_len = 0; |
||||
int status = WindowsApi.NtWow64ReadVirtualMemory64( |
||||
hProcess, |
||||
ptr, |
||||
data, |
||||
dataSize, |
||||
ref res_len); |
||||
readPtr = Marshal.ReadInt64(data); |
||||
Marshal.FreeHGlobal(data); |
||||
if (status != WindowsApi.STATUS_SUCCESS || res_len != dataSize) |
||||
result = false; |
||||
else |
||||
result = true; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static UniPtr _GetPenv(IntPtr hProcess) |
||||
{ |
||||
int processBitness = _GetProcessBitness(hProcess); |
||||
|
||||
if (processBitness == 64) |
||||
{ |
||||
if (Environment.Is64BitProcess) |
||||
{ |
||||
// Accessing 64 bit process under 64 bit host.
|
||||
|
||||
IntPtr pPeb = _GetPeb64(hProcess); |
||||
|
||||
IntPtr ptr; |
||||
if (!_TryReadIntPtr(hProcess, pPeb + 0x20, out ptr)) |
||||
throw new Exception("Unable to read PEB."); |
||||
|
||||
IntPtr penv; |
||||
if (!_TryReadIntPtr(hProcess, ptr + 0x80, out penv)) |
||||
throw new Exception("Unable to read RTL_USER_PROCESS_PARAMETERS."); |
||||
|
||||
return penv; |
||||
} |
||||
else |
||||
{ |
||||
// Accessing 64 bit process under 32 bit host.
|
||||
|
||||
var pPeb = _GetPeb64(hProcess); |
||||
|
||||
long ptr; |
||||
if (!_TryReadIntPtrWow64(hProcess, pPeb.ToInt64() + 0x20, out ptr)) |
||||
throw new Exception("Unable to read PEB."); |
||||
|
||||
long penv; |
||||
if (!_TryReadIntPtrWow64(hProcess, ptr + 0x80, out penv)) |
||||
throw new Exception("Unable to read RTL_USER_PROCESS_PARAMETERS."); |
||||
|
||||
return new UniPtr(penv); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
// Accessing 32 bit process under 32 bit host.
|
||||
|
||||
IntPtr pPeb = _GetPeb32(hProcess); |
||||
|
||||
IntPtr ptr; |
||||
if (!_TryReadIntPtr32(hProcess, pPeb + 0x10, out ptr)) |
||||
throw new Exception("Unable to read PEB."); |
||||
|
||||
IntPtr penv; |
||||
if (!_TryReadIntPtr32(hProcess, ptr + 0x48, out penv)) |
||||
throw new Exception("Unable to read RTL_USER_PROCESS_PARAMETERS."); |
||||
|
||||
return penv; |
||||
} |
||||
} |
||||
|
||||
static int _GetProcessBitness(IntPtr hProcess) |
||||
{ |
||||
if (Environment.Is64BitOperatingSystem) |
||||
{ |
||||
bool wow64; |
||||
if (!WindowsApi.IsWow64Process(hProcess, out wow64)) |
||||
return 32; |
||||
if (wow64) |
||||
return 32; |
||||
return 64; |
||||
} |
||||
else |
||||
{ |
||||
return 32; |
||||
} |
||||
} |
||||
|
||||
static IntPtr _GetPeb32(IntPtr hProcess) |
||||
{ |
||||
if (Environment.Is64BitProcess) |
||||
{ |
||||
var ptr = IntPtr.Zero; |
||||
int res_len = 0; |
||||
int pbiSize = IntPtr.Size; |
||||
int status = WindowsApi.NtQueryInformationProcess( |
||||
hProcess, |
||||
WindowsApi.ProcessWow64Information, |
||||
ref ptr, |
||||
pbiSize, |
||||
ref res_len); |
||||
if (res_len != pbiSize) |
||||
throw new Exception("Unable to query process information."); |
||||
return ptr; |
||||
} |
||||
else |
||||
{ |
||||
return _GetPebNative(hProcess); |
||||
} |
||||
} |
||||
|
||||
static IntPtr _GetPebNative(IntPtr hProcess) |
||||
{ |
||||
var pbi = new WindowsApi.PROCESS_BASIC_INFORMATION(); |
||||
int res_len = 0; |
||||
int pbiSize = Marshal.SizeOf(pbi); |
||||
int status = WindowsApi.NtQueryInformationProcess( |
||||
hProcess, |
||||
WindowsApi.ProcessBasicInformation, |
||||
ref pbi, |
||||
pbiSize, |
||||
ref res_len); |
||||
if (res_len != pbiSize) |
||||
throw new Exception("Unable to query process information."); |
||||
return pbi.PebBaseAddress; |
||||
} |
||||
|
||||
static UniPtr _GetPeb64(IntPtr hProcess) |
||||
{ |
||||
if (Environment.Is64BitProcess) |
||||
{ |
||||
return _GetPebNative(hProcess); |
||||
} |
||||
else |
||||
{ |
||||
// Get PEB via WOW64 API.
|
||||
var pbi = new WindowsApi.PROCESS_BASIC_INFORMATION_WOW64(); |
||||
int res_len = 0; |
||||
int pbiSize = Marshal.SizeOf(pbi); |
||||
int status = WindowsApi.NtWow64QueryInformationProcess64( |
||||
hProcess, |
||||
WindowsApi.ProcessBasicInformation, |
||||
ref pbi, |
||||
pbiSize, |
||||
ref res_len); |
||||
if (res_len != pbiSize) |
||||
throw new Exception("Unable to query process information."); |
||||
return new UniPtr(pbi.PebBaseAddress); |
||||
} |
||||
} |
||||
|
||||
static bool _HasReadAccess(IntPtr hProcess, IntPtr address, out int size) |
||||
{ |
||||
size = 0; |
||||
|
||||
var memInfo = new WindowsApi.MEMORY_BASIC_INFORMATION(); |
||||
int result = WindowsApi.VirtualQueryEx( |
||||
hProcess, |
||||
address, |
||||
ref memInfo, |
||||
Marshal.SizeOf(memInfo)); |
||||
|
||||
if (result == 0) |
||||
return false; |
||||
|
||||
if (memInfo.Protect == WindowsApi.PAGE_NOACCESS || memInfo.Protect == WindowsApi.PAGE_EXECUTE) |
||||
return false; |
||||
|
||||
try |
||||
{ |
||||
size = Convert.ToInt32(memInfo.RegionSize.ToInt64() - (address.ToInt64() - memInfo.BaseAddress.ToInt64())); |
||||
} |
||||
catch (OverflowException) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
if (size <= 0) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
static bool _HasReadAccessWow64(IntPtr hProcess, long address, out int size) |
||||
{ |
||||
size = 0; |
||||
|
||||
WindowsApi.MEMORY_BASIC_INFORMATION_WOW64 memInfo; |
||||
var memInfoType = typeof(WindowsApi.MEMORY_BASIC_INFORMATION_WOW64); |
||||
int memInfoLength = Marshal.SizeOf(memInfoType); |
||||
const int memInfoAlign = 8; |
||||
|
||||
long resultLength = 0; |
||||
int result; |
||||
|
||||
IntPtr hMemInfo = Marshal.AllocHGlobal(memInfoLength + memInfoAlign * 2); |
||||
try |
||||
{ |
||||
// Align to 64 bits.
|
||||
IntPtr hMemInfoAligned = new IntPtr(hMemInfo.ToInt64() & ~(memInfoAlign - 1L)); |
||||
|
||||
result = WindowsApi.NtWow64QueryVirtualMemory64( |
||||
hProcess, |
||||
address, |
||||
WindowsApi.MEMORY_INFORMATION_CLASS.MemoryBasicInformation, |
||||
hMemInfoAligned, |
||||
memInfoLength, |
||||
ref resultLength); |
||||
|
||||
memInfo = (WindowsApi.MEMORY_BASIC_INFORMATION_WOW64)Marshal.PtrToStructure(hMemInfoAligned, memInfoType); |
||||
} |
||||
finally |
||||
{ |
||||
Marshal.FreeHGlobal(hMemInfo); |
||||
} |
||||
|
||||
if (result != WindowsApi.STATUS_SUCCESS) |
||||
return false; |
||||
|
||||
if (memInfo.Protect == WindowsApi.PAGE_NOACCESS || memInfo.Protect == WindowsApi.PAGE_EXECUTE) |
||||
return false; |
||||
|
||||
try |
||||
{ |
||||
size = Convert.ToInt32(memInfo.RegionSize - (address - memInfo.BaseAddress)); |
||||
} |
||||
catch (OverflowException) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
if (size <= 0) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
static class WindowsApi |
||||
{ |
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)] |
||||
public struct PROCESS_BASIC_INFORMATION |
||||
{ |
||||
public IntPtr Reserved1; |
||||
public IntPtr PebBaseAddress; |
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] |
||||
public IntPtr[] Reserved2; |
||||
public IntPtr UniqueProcessId; |
||||
public IntPtr Reserved3; |
||||
} |
||||
|
||||
public const int ProcessBasicInformation = 0; |
||||
public const int ProcessWow64Information = 26; |
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)] |
||||
public static extern int NtQueryInformationProcess( |
||||
IntPtr hProcess, |
||||
int pic, |
||||
ref PROCESS_BASIC_INFORMATION pbi, |
||||
int cb, |
||||
ref int pSize); |
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)] |
||||
public static extern int NtQueryInformationProcess( |
||||
IntPtr hProcess, |
||||
int pic, |
||||
ref IntPtr pi, |
||||
int cb, |
||||
ref int pSize); |
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)] |
||||
public static extern int NtQueryInformationProcess( |
||||
IntPtr hProcess, |
||||
int pic, |
||||
ref long pi, |
||||
int cb, |
||||
ref int pSize); |
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)] |
||||
public struct PROCESS_BASIC_INFORMATION_WOW64 |
||||
{ |
||||
public long Reserved1; |
||||
public long PebBaseAddress; |
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] |
||||
public long[] Reserved2; |
||||
public long UniqueProcessId; |
||||
public long Reserved3; |
||||
} |
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)] |
||||
public static extern int NtWow64QueryInformationProcess64( |
||||
IntPtr hProcess, |
||||
int pic, |
||||
ref PROCESS_BASIC_INFORMATION_WOW64 pbi, |
||||
int cb, |
||||
ref int pSize); |
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)] |
||||
public static extern bool ReadProcessMemory( |
||||
IntPtr hProcess, |
||||
IntPtr lpBaseAddress, |
||||
[Out] byte[] lpBuffer, |
||||
IntPtr dwSize, |
||||
ref IntPtr lpNumberOfBytesRead); |
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)] |
||||
public static extern bool ReadProcessMemory( |
||||
IntPtr hProcess, |
||||
IntPtr lpBaseAddress, |
||||
IntPtr lpBuffer, |
||||
IntPtr dwSize, |
||||
ref IntPtr lpNumberOfBytesRead); |
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)] |
||||
public static extern int NtWow64ReadVirtualMemory64( |
||||
IntPtr hProcess, |
||||
long lpBaseAddress, |
||||
IntPtr lpBuffer, |
||||
long dwSize, |
||||
ref long lpNumberOfBytesRead); |
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)] |
||||
public static extern int NtWow64ReadVirtualMemory64( |
||||
IntPtr hProcess, |
||||
long lpBaseAddress, |
||||
[Out] byte[] lpBuffer, |
||||
long dwSize, |
||||
ref long lpNumberOfBytesRead); |
||||
|
||||
public const int STATUS_SUCCESS = 0; |
||||
|
||||
public const int PAGE_NOACCESS = 0x01; |
||||
public const int PAGE_EXECUTE = 0x10; |
||||
|
||||
[StructLayout(LayoutKind.Sequential)] |
||||
public struct MEMORY_BASIC_INFORMATION |
||||
{ |
||||
public IntPtr BaseAddress; |
||||
public IntPtr AllocationBase; |
||||
public int AllocationProtect; |
||||
public IntPtr RegionSize; |
||||
public int State; |
||||
public int Protect; |
||||
public int Type; |
||||
} |
||||
|
||||
[DllImport("kernel32.dll")] |
||||
public static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, int dwLength); |
||||
|
||||
[StructLayout(LayoutKind.Sequential)] |
||||
public struct MEMORY_BASIC_INFORMATION_WOW64 |
||||
{ |
||||
public long BaseAddress; |
||||
public long AllocationBase; |
||||
public int AllocationProtect; |
||||
public long RegionSize; |
||||
public int State; |
||||
public int Protect; |
||||
public int Type; |
||||
} |
||||
|
||||
public enum MEMORY_INFORMATION_CLASS |
||||
{ |
||||
MemoryBasicInformation |
||||
} |
||||
|
||||
[DllImport("ntdll.dll")] |
||||
public static extern int NtWow64QueryVirtualMemory64( |
||||
IntPtr hProcess, |
||||
long lpAddress, |
||||
MEMORY_INFORMATION_CLASS memoryInformationClass, |
||||
IntPtr lpBuffer, // MEMORY_BASIC_INFORMATION_WOW64, pointer must be 64-bit aligned
|
||||
long memoryInformationLength, |
||||
ref long returnLength); |
||||
|
||||
[DllImport("kernel32.dll")] |
||||
public static extern bool IsWow64Process(IntPtr hProcess, out bool wow64Process); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue