public static void Free(byte *p) { var remaining = (int)((long)p % 4096); var firstWritablePage = p - remaining; for (int i = 0; i < remaining; i++) { if (firstWritablePage[i] != 0xED) { throw new InvalidOperationException("Invalid memory usage, you killed Ed!"); } } Win32MemoryProtectMethods.MemoryProtection protect; var address = firstWritablePage - 4096; // this will access the memory, which will error if this was already freed if (Win32MemoryProtectMethods.VirtualProtect(address, (UIntPtr)4096, Win32MemoryProtectMethods.MemoryProtection.READWRITE, out protect) == false) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to VirtualProtect (ElectricFence) at address=" + new IntPtr(address)); } var dwSize = *(int *)address; // decommit, not release, they are not available for reuse again, any // future access will throw if (Win32MemoryProtectMethods.VirtualFree(address, (UIntPtr)dwSize, Win32MemoryProtectMethods.FreeType.MEM_DECOMMIT) == false) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to VirtualFree (ElectricFence) at address=" + new IntPtr(address)); } }
private static string GetEncodedFilename(IntPtr processHandle, ref Win32MemoryProtectMethods.MEMORY_BASIC_INFORMATION memoryBasicInformation) { var memData = BuffersPool.Allocate(2048); var pFilename = memData.Address; try { int stringLength; stringLength = Win32MemoryProtectMethods.GetMappedFileName(processHandle, memoryBasicInformation.BaseAddress.ToPointer(), pFilename, 2048); if (stringLength == 0) { return(null); } var foundRelevantFilename = false; foreach (var item in RelevantFilesPostFixes) { fixed(byte *pItem = item) { if (stringLength < item.Length || Memory.Compare(pItem, pFilename + stringLength - item.Length, item.Length) != 0) { continue; } foundRelevantFilename = true; break; } } if (foundRelevantFilename == false) { return(null); } return(Encodings.Utf8.GetString(pFilename, stringLength)); } finally { BuffersPool.Return(memData); } }
public static byte *Allocate(int size) { var remaining = size % 4096; var sizeInPages = (size / 4096) + (remaining == 0 ? 0 : 1); var allocatedSize = ((sizeInPages + 2) * 4096); var virtualAlloc = Win32MemoryProtectMethods.VirtualAlloc(null, (UIntPtr)allocatedSize, Win32MemoryProtectMethods.AllocationType.COMMIT, Win32MemoryProtectMethods.MemoryProtection.READWRITE); if (virtualAlloc == null) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to VirtualAlloc (ElectricFence) size=" + size); } *(int *)virtualAlloc = allocatedSize; Win32MemoryProtectMethods.MemoryProtection protect; if (Win32MemoryProtectMethods.VirtualProtect(virtualAlloc, (UIntPtr)(4096), Win32MemoryProtectMethods.MemoryProtection.NOACCESS, out protect) == false) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to VirtualProtect (ElectricFence) at address=" + new IntPtr(virtualAlloc)); } if (Win32MemoryProtectMethods.VirtualProtect(virtualAlloc + (sizeInPages + 1) * 4096, (UIntPtr)(4096), Win32MemoryProtectMethods.MemoryProtection.NOACCESS, out protect) == false) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to VirtualProtect (ElectricFence) at address=" + new IntPtr(virtualAlloc + (sizeInPages + 1) * 4096)); } var firstWritablePage = virtualAlloc + 4096; Memory.Set(firstWritablePage, 0xED, 4096 * sizeInPages); // don't assume zero'ed mem if (remaining == 0) { return(firstWritablePage); } // give the memory out so its end would be at the 2nd guard page return(firstWritablePage + (4096 - remaining)); }
public static (long ProcessClean, DynamicJsonArray Json) GetMaps() { long processClean = 0; const uint uintMaxVal = uint.MaxValue; var dja = new DynamicJsonArray(); GetSystemInfo(out var systemInfo); var procMinAddress = systemInfo.minimumApplicationAddress; var procMaxAddress = systemInfo.maximumApplicationAddress; var processHandle = GetCurrentProcess(); var results = new Dictionary <string, (long Size, long Clean, long Dirty)>(); while (procMinAddress.ToInt64() < procMaxAddress.ToInt64()) { Win32MemoryProtectMethods.MEMORY_BASIC_INFORMATION memoryBasicInformation; Win32MemoryProtectMethods.VirtualQueryEx(processHandle, (byte *)procMinAddress.ToPointer(), &memoryBasicInformation, new UIntPtr((uint)sizeof(Win32MemoryProtectMethods.MEMORY_BASIC_INFORMATION))); // if this memory chunk is accessible if (memoryBasicInformation.Protect == (uint)MemoryProtectionConstants.PAGE_READWRITE && memoryBasicInformation.State == (uint)MemoryStateConstants.MEM_COMMIT && memoryBasicInformation.Type == (uint)MemoryTypeConstants.MEM_MAPPED) { var encodedString = GetEncodedFilename(processHandle, ref memoryBasicInformation); if (encodedString != null) { var regionSize = memoryBasicInformation.RegionSize.ToInt64(); for (long size = uintMaxVal; size < regionSize + uintMaxVal; size += uintMaxVal) { var partLength = size > regionSize ? regionSize % uintMaxVal : uintMaxVal; var totalDirty = AddressWillCauseHardPageFault((byte *)memoryBasicInformation.BaseAddress.ToPointer(), (uint)partLength, performCount: true); var totalClean = partLength - totalDirty; if (results.TryGetValue(encodedString, out var values)) { var prevValClean = values.Item1 + totalClean; var prevValDirty = values.Item2 + totalDirty; var prevValSize = values.Item3 + partLength; results[encodedString] = (prevValSize, prevValClean, prevValDirty); } else { results[encodedString] = (partLength, totalClean, totalDirty); } processClean += totalClean; } } } // move to the next memory chunk procMinAddress = new IntPtr(procMinAddress.ToInt64() + memoryBasicInformation.RegionSize.ToInt64()); } foreach (var result in results) { var djv = new DynamicJsonValue { ["File"] = result.Key, ["Size"] = result.Value.Size, ["SizeHumanly"] = Sizes.Humane(result.Value.Size), ["Rss"] = "N/A", ["SharedClean"] = "N/A", ["SharedDirty"] = "N/A", ["PrivateClean"] = "N/A", ["PrivateDirty"] = "N/A", ["TotalClean"] = result.Value.Clean, ["TotalCleanHumanly"] = Sizes.Humane(result.Value.Clean), ["TotalDirty"] = result.Value.Dirty, ["TotalDirtyHumanly"] = Sizes.Humane(result.Value.Dirty) }; dja.Add(djv); } return(processClean, dja); }