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
{
get => (MemoryAddress > 0) ? $"0x{MemoryAddress:X12}" : null;
get => (MemoryAddress > 0) ? $"0x{MemoryAddress:X16}" : null;
}
}
}

View File

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

View File

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

View File

@ -128,15 +128,15 @@ namespace WebmrAPI.Services
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
{
MemoryAddress = mbi.BaseAddress.ToInt64(),
MemorySize = mbi.RegionSize.ToUInt64(),
State = WinApi.GetStateString(mbi.State),
Protect = WinApi.GetProtectString(mbi.Protect),
Type = WinApi.GetTypeString(mbi.Type)
MemoryState = mbi.State,
MemoryPageProtection = mbi.PageProtection,
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)
{
dst.PID = process.Id;
dst.MemorySize = (ulong)process.VirtualMemorySize64;
dst.MemorySize = (ulong)process.WorkingSet64;
dst.ThreadCount = process.Threads.Count;
dst.TotalProcessorTime = process.TotalProcessorTime;
dst.MemoryAddress = 0x000000000000;

View File

@ -1,60 +1,58 @@
// File: Services/WinApi.cs
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.Json.Serialization;
using WebmrAPI.Utils;
namespace WebmrAPI.Services
{
[SupportedOSPlatform("windows")]
public static class WinApi
{
public const uint PROCESS_QUERY_INFORMATION = 0x00000400;
public const uint PROCESS_VM_READ = 0x00000010;
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 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)
{
case MEM_COMMIT: return "MEM_COMMIT";
case MEM_FREE: return "MEM_FREE";
case MEM_RESERVE: return "MEM_RESERVE";
default: return GetHexValue(state);
}
Undefined = 0,
Image = 0x01000000,
Mapped = 0x00040000,
Private = 0x00020000,
}
public static string GetProtectString(uint protect)
[JsonConverter(typeof(JsonEnumConverter<MemoryPageProtectionState>))]
public enum MemoryPageProtectionState : uint
{
switch (protect)
{
default: return GetHexValue(protect);
}
Undefined = 0,
NoAccess = 0x0001,
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)
{
switch (type)
{
case MEM_IMAGE: return "MEM_IMAGE";
case MEM_MAPPED: return "MEM_MAPPED";
case MEM_PRIVATE: return "MEM_PRIVATE";
default: return GetHexValue(type);
}
}
// --- P/Invoke Declarations ---
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information
[StructLayout(LayoutKind.Sequential)]
@ -65,9 +63,9 @@ namespace WebmrAPI.Services
public uint AllocationProtect;
public ushort PartitionId;
public UIntPtr RegionSize;
public uint State;
public uint Protect;
public uint Type;
public MemoryState State;
public MemoryPageProtectionState PageProtection;
public MemoryType Type;
}
@ -92,5 +90,162 @@ namespace WebmrAPI.Services
out MEMORY_BASIC_INFORMATION lpBuffer,
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");
}
}
}
}