Update WinApi

This commit is contained in:
Gregory Lirent 2025-07-02 18:13:00 +03:00
parent 49abc808a4
commit 09af9d5091
6 changed files with 260 additions and 49 deletions

View File

@ -22,7 +22,7 @@ namespace WebmrAPI.Models
} }
public string? BaseAddress public string? BaseAddress
{ {
get => (MemoryAddress > 0) ? $"0x{MemoryAddress:X12}" : null; get => (MemoryAddress > 0) ? $"0x{MemoryAddress:X16}" : null;
} }
} }
} }

View File

@ -1,24 +1,26 @@
// File: Models/MemoryRegionInfo.cs // File: Models/MemoryRegionInfo.cs
using WebmrAPI.Services;
namespace WebmrAPI.Models namespace WebmrAPI.Models
{ {
public class MemoryRegionInfo : MemoryRegion public class MemoryRegionInfo : MemoryRegion
{ {
private string _state = String.Empty; private WinApi.MemoryState _state = 0;
private string _protect = String.Empty; private WinApi.MemoryPageProtectionState _protect = 0;
private string _type = String.Empty; private WinApi.MemoryType _type = 0;
public string State public WinApi.MemoryState MemoryState
{ {
get => LockedGet(ref _state); get => LockedGet(ref _state);
set => LockedSet(ref _state, value); set => LockedSet(ref _state, value);
} }
public string Protect public WinApi.MemoryPageProtectionState MemoryPageProtection
{ {
get => LockedGet(ref _protect); get => LockedGet(ref _protect);
set => LockedSet(ref _protect, value); set => LockedSet(ref _protect, value);
} }
public string Type public WinApi.MemoryType MemoryType
{ {
get => LockedGet(ref _type); get => LockedGet(ref _type);
set => LockedSet(ref _type, value); set => LockedSet(ref _type, value);

View File

@ -34,7 +34,7 @@ namespace WebmrAPI.Models
[JsonIgnore] [JsonIgnore]
public double ProcessorTime public double ProcessorTime
{ {
get { lock (_lock) return (_lastPTime - _curPTime).TotalMilliseconds; } get { lock (_lock) return (_curPTime - _lastPTime).TotalMilliseconds; }
} }
public int PID public int PID
{ {

View File

@ -128,15 +128,15 @@ namespace WebmrAPI.Services
break; break;
} }
if (mbi.State == WinApi.MEM_COMMIT || mbi.State == WinApi.MEM_RESERVE) if (mbi.State == WinApi.MemoryState.Commit || mbi.State == WinApi.MemoryState.Reserve)
{ {
regions.Add(new MemoryRegionInfo regions.Add(new MemoryRegionInfo
{ {
MemoryAddress = mbi.BaseAddress.ToInt64(), MemoryAddress = mbi.BaseAddress.ToInt64(),
MemorySize = mbi.RegionSize.ToUInt64(), MemorySize = mbi.RegionSize.ToUInt64(),
State = WinApi.GetStateString(mbi.State), MemoryState = mbi.State,
Protect = WinApi.GetProtectString(mbi.Protect), MemoryPageProtection = mbi.PageProtection,
Type = WinApi.GetTypeString(mbi.Type) MemoryType = mbi.Type
}); });
} }
@ -153,7 +153,7 @@ namespace WebmrAPI.Services
private void PopulateBaseProcessInfo(ProcessInfo dst, System.Diagnostics.Process process, Dictionary<int, (string? Name, string? CommandLine, int ParentPID)> wmiData) private void PopulateBaseProcessInfo(ProcessInfo dst, System.Diagnostics.Process process, Dictionary<int, (string? Name, string? CommandLine, int ParentPID)> wmiData)
{ {
dst.PID = process.Id; dst.PID = process.Id;
dst.MemorySize = (ulong)process.VirtualMemorySize64; dst.MemorySize = (ulong)process.WorkingSet64;
dst.ThreadCount = process.Threads.Count; dst.ThreadCount = process.Threads.Count;
dst.TotalProcessorTime = process.TotalProcessorTime; dst.TotalProcessorTime = process.TotalProcessorTime;
dst.MemoryAddress = 0x000000000000; dst.MemoryAddress = 0x000000000000;

View File

@ -1,60 +1,58 @@
// File: Services/WinApi.cs // File: Services/WinApi.cs
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.Json.Serialization;
using WebmrAPI.Utils;
namespace WebmrAPI.Services namespace WebmrAPI.Services
{ {
[SupportedOSPlatform("windows")]
public static class WinApi public static class WinApi
{ {
public const uint PROCESS_QUERY_INFORMATION = 0x00000400; public const uint PROCESS_QUERY_INFORMATION = 0x00000400;
public const uint PROCESS_VM_READ = 0x00000010; public const uint PROCESS_VM_READ = 0x00000010;
public const uint PROCESS_VM_OPERATION = 0x00000008; public const uint PROCESS_VM_OPERATION = 0x00000008;
public const uint MEM_COMMIT = 0x00001000;
public const uint MEM_FREE = 0x00010000;
public const uint MEM_RESERVE = 0x00002000;
public const uint MEM_IMAGE = 0x01000000;
public const uint MEM_MAPPED = 0x00040000;
public const uint MEM_PRIVATE = 0x00020000;
public static int LastError { get => Marshal.GetLastWin32Error(); } public static int LastError { get => Marshal.GetLastWin32Error(); }
public static uint MBISize { get => (uint)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION)); } public static uint MBISize { get => (uint)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION)); }
private static string GetHexValue(uint data) [JsonConverter(typeof(JsonEnumConverter<MemoryState>))]
public enum MemoryState : uint
{ {
return $"0x{data:X8}"; Undefined = 0,
Commit = 0x00001000,
Reserve = 0x00002000,
Free = 0x00010000,
} }
public static string GetStateString(uint state) [JsonConverter(typeof(JsonEnumConverter<MemoryType>))]
public enum MemoryType : uint
{ {
switch (state) Undefined = 0,
{ Image = 0x01000000,
case MEM_COMMIT: return "MEM_COMMIT"; Mapped = 0x00040000,
case MEM_FREE: return "MEM_FREE"; Private = 0x00020000,
case MEM_RESERVE: return "MEM_RESERVE";
default: return GetHexValue(state);
}
} }
public static string GetProtectString(uint protect) [JsonConverter(typeof(JsonEnumConverter<MemoryPageProtectionState>))]
public enum MemoryPageProtectionState : uint
{ {
switch (protect) Undefined = 0,
{ NoAccess = 0x0001,
default: return GetHexValue(protect); ReadOnly = 0x0002,
} ReadWrite = 0x0004,
WriteCopy = 0x0008,
Execute = 0x0010,
ExecuteRead = 0x0020,
ExecuteReadWrite = 0x0040,
ExecuteWriteCopy = 0x0080,
Guard = 0x0100,
NoCache = 0x0200,
WriteCombine = 0x0400,
} }
public static string GetTypeString(uint type) // --- P/Invoke Declarations ---
{
switch (type)
{
case MEM_IMAGE: return "MEM_IMAGE";
case MEM_MAPPED: return "MEM_MAPPED";
case MEM_PRIVATE: return "MEM_PRIVATE";
default: return GetHexValue(type);
}
}
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information // https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
@ -65,9 +63,9 @@ namespace WebmrAPI.Services
public uint AllocationProtect; public uint AllocationProtect;
public ushort PartitionId; public ushort PartitionId;
public UIntPtr RegionSize; public UIntPtr RegionSize;
public uint State; public MemoryState State;
public uint Protect; public MemoryPageProtectionState PageProtection;
public uint Type; public MemoryType Type;
} }
@ -92,5 +90,162 @@ namespace WebmrAPI.Services
out MEMORY_BASIC_INFORMATION lpBuffer, out MEMORY_BASIC_INFORMATION lpBuffer,
uint dwLength uint dwLength
); );
// --- Module-related P/Invokes (from psapi.dll and kernel32.dll) ---
// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodulesex
[DllImport("psapi.dll", SetLastError = true)]
public static extern bool EnumProcessModulesEx(
IntPtr hProcess,
[Out] IntPtr[] lphModule, // Array to receive module handles
uint cb, // Size of the lphModule array, in bytes
out uint lpcbNeeded, // Number of bytes required to store all module handles
uint dwFilterFlag // Filter for modules (e.g., LIST_MODULES_ALL)
);
// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulefilenameexw
[DllImport("psapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint GetModuleFileNameEx(
IntPtr hProcess,
IntPtr hModule,
[Out] System.Text.StringBuilder lpFilename,
uint nSize
);
// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulebasenamew
[DllImport("psapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint GetModuleBaseName(
IntPtr hProcess,
IntPtr hModule,
[Out] System.Text.StringBuilder lpBaseName,
uint nSize
);
// https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-_moduleinfo
[StructLayout(LayoutKind.Sequential)]
public struct MODULEINFO
{
public IntPtr lpBaseOfDll;
public uint SizeOfImage;
public IntPtr EntryPoint;
}
// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmoduleinformation
[DllImport("psapi.dll", SetLastError = true)]
public static extern bool GetModuleInformation(
IntPtr hProcess,
IntPtr hModule,
out MODULEINFO lpmodinfo,
uint cb
);
// --- Thread-related P/Invokes (from kernel32.dll and ntdll.dll) ---
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthread
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenThread(
uint dwDesiredAccess,
[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
uint dwThreadId
);
// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationthread
[DllImport("ntdll.dll", SetLastError = true)]
public static extern int NtQueryInformationThread(
IntPtr ThreadHandle,
THREAD_INFO_CLASS ThreadInformationClass,
IntPtr ThreadInformation, // Pointer to buffer
uint ThreadInformationLength,
out uint ReturnLength
);
// Enum for ThreadInformationClass in NtQueryInformationThread
// https://ntdoc.m417z.com/threadinfoclass
public enum THREAD_INFO_CLASS : int
{
ThreadBasicInformation, // q: THREAD_BASIC_INFORMATION
ThreadTimes, // q: KERNEL_USER_TIMES
ThreadPriority, // s: KPRIORITY (requires SeIncreaseBasePriorityPrivilege)
ThreadBasePriority, // s: KPRIORITY
ThreadAffinityMask, // s: KAFFINITY
ThreadImpersonationToken, // s: HANDLE
ThreadDescriptorTableEntry, // q: DESCRIPTOR_TABLE_ENTRY (or WOW64_DESCRIPTOR_TABLE_ENTRY)
ThreadEnableAlignmentFaultFixup, // s: BOOLEAN
ThreadEventPair, // Obsolete
ThreadQuerySetWin32StartAddress, // qs: PVOID (requires THREAD_Set_LIMITED_INFORMATION)
ThreadZeroTlsCell, // s: ULONG // TlsIndex // 10
ThreadPerformanceCount, // q: LARGE_INTEGER
ThreadAmILastThread, // q: ULONG
ThreadIdealProcessor, // s: ULONG
ThreadPriorityBoost, // qs: ULONG
ThreadSetTlsArrayAddress, // s: ULONG_PTR
ThreadIsIoPending, // q: ULONG
ThreadHideFromDebugger, // q: BOOLEAN; s: void
ThreadBreakOnTermination, // qs: ULONG
ThreadSwitchLegacyState, // s: void // NtCurrentThread // NPX/FPU
ThreadIsTerminated, // q: ULONG // 20
ThreadLastSystemCall, // q: THREAD_LAST_SYSCALL_INFORMATION
ThreadIoPriority, // qs: IO_PRIORITY_HINT (requires SeIncreaseBasePriorityPrivilege)
ThreadCycleTime, // q: THREAD_CYCLE_TIME_INFORMATION (requires THREAD_QUERY_LIMITED_INFORMATION)
ThreadPagePriority, // qs: PAGE_PRIORITY_INFORMATION
ThreadActualBasePriority, // s: LONG (requires SeIncreaseBasePriorityPrivilege)
ThreadTebInformation, // q: THREAD_TEB_INFORMATION (requires THREAD_GET_CONTEXT + THREAD_SET_CONTEXT)
ThreadCSwitchMon, // Obsolete
ThreadCSwitchPmu, // Obsolete
ThreadWow64Context, // qs: WOW64_CONTEXT, ARM_NT_CONTEXT since 20H1
ThreadGroupInformation, // qs: GROUP_AFFINITY // 30
ThreadUmsInformation, // q: THREAD_UMS_INFORMATION // Obsolete
ThreadCounterProfiling, // q: BOOLEAN; s: THREAD_PROFILING_INFORMATION?
ThreadIdealProcessorEx, // qs: PROCESSOR_NUMBER; s: previous PROCESSOR_NUMBER on return
ThreadCpuAccountingInformation, // q: BOOLEAN; s: HANDLE (NtOpenSession) // NtCurrentThread // since WIN8
ThreadSuspendCount, // q: ULONG // since WINBLUE
ThreadHeterogeneousCpuPolicy, // q: KHETERO_CPU_POLICY // since THRESHOLD
ThreadContainerId, // q: GUID
ThreadNameInformation, // qs: THREAD_NAME_INFORMATION (requires THREAD_SET_LIMITED_INFORMATION)
ThreadSelectedCpuSets, // q: ULONG[]
ThreadSystemThreadInformation, // q: SYSTEM_THREAD_INFORMATION // 40
ThreadActualGroupAffinity, // q: GROUP_AFFINITY // since THRESHOLD2
ThreadDynamicCodePolicyInfo, // q: ULONG; s: ULONG (NtCurrentThread)
ThreadExplicitCaseSensitivity, // qs: ULONG; s: 0 disables, otherwise enables // (requires SeDebugPrivilege and PsProtectedSignerAntimalware)
ThreadWorkOnBehalfTicket, // ALPC_WORK_ON_BEHALF_TICKET // RTL_WORK_ON_BEHALF_TICKET_EX // NtCurrentThread
ThreadSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2
ThreadDbgkWerReportActive, // s: ULONG; s: 0 disables, otherwise enables
ThreadAttachContainer, // s: HANDLE (job object) // NtCurrentThread
ThreadManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3
ThreadPowerThrottlingState, // qs: POWER_THROTTLING_THREAD_STATE // since REDSTONE3 (set), WIN11 22H2 (query)
ThreadWorkloadClass, // THREAD_WORKLOAD_CLASS // since REDSTONE5 // 50
ThreadCreateStateChange, // since WIN11
ThreadApplyStateChange,
ThreadStrongerBadHandleChecks, // s: ULONG // NtCurrentThread // since 22H1
ThreadEffectiveIoPriority, // q: IO_PRIORITY_HINT
ThreadEffectivePagePriority, // q: ULONG
ThreadUpdateLockOwnership, // THREAD_LOCK_OWNERSHIP // since 24H2
ThreadSchedulerSharedDataSlot, // SCHEDULER_SHARED_DATA_SLOT_INFORMATION
ThreadTebInformationAtomic, // q: THREAD_TEB_INFORMATION (requires THREAD_GET_CONTEXT + THREAD_QUERY_INFORMATION)
ThreadIndexInformation, // THREAD_INDEX_INFORMATION
MaxThreadInfoClass
}
// Structure for ThreadBasicInformation (if needed, though ThreadQuerySetWin32StartAddress directly gives address)
// https://ntdoc.m417z.com/thread_basic_information
[StructLayout(LayoutKind.Sequential)]
public struct THREAD_BASIC_INFORMATION
{
public int ExitStatus;
public IntPtr TebBaseAddress;
public CLIENT_ID ClientId;
public IntPtr AffinityMask;
public int Priority;
public int BasePriority;
}
// https://ntdoc.m417z.com/client_id
[StructLayout(LayoutKind.Sequential)]
public struct CLIENT_ID
{
public IntPtr UniqueProcess;
public IntPtr UniqueThread;
}
} }
} }

View File

@ -0,0 +1,54 @@
// File: Utils/JsonEnumConverter.cs
using System.Text.Json;
using System.Text.Json.Serialization;
namespace WebmrAPI.Utils
{
public class JsonEnumConverter<T> : JsonConverter<T> where T : Enum
{
private T GetDefaultValue(Type type)
{
if (Enum.TryParse(type, "Undefined", true, out object? result) && result != null)
{
return (T)result;
}
return (T)Enum.ToObject(type, 0);
}
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
{
if (Enum.TryParse(typeToConvert, reader.GetString(), true, out object? result) && result != null)
{
return (T)result;
}
}
else if (reader.TokenType == JsonTokenType.Number)
{
if (reader.TryGetInt32(out int intValue))
{
T status = (T)Enum.ToObject(typeToConvert, intValue);
if (Enum.IsDefined(typeof(T), status))
{
return status;
}
}
}
return GetDefaultValue(typeToConvert);
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
if (Enum.IsDefined(typeof(T), value))
{
writer.WriteStringValue(value.ToString());
}
else
{
writer.WriteStringValue("Undefined");
}
}
}
}