The memory usage of my C# application increases - c#

I have a C# application which controls and monitors a PMAC controller. This application should be able to run for a few days at least, but I see that its memory usage would increase all the time. At first the memory usage is about 230M, and it will increase with 25M each hour.
I have found that memory does not increase unless I call the ReadDataFromDPRam() method.
I call this method 10msec intervals.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PmacServoRead
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)MotorNo.All)]
public float[] CurPosition; // M4000,
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)MotorNo.All)]
public float[] CurVelocity;
public int AmpEnable;
public int PosLimit;
public int NegLimit;
public int HomeComp;
public int DesiredVelocityZero;
...
}
[DllImport("Pcomm32.dll")]
public static extern IntPtr PmacDPRGetMem(UInt32 dwDevice, UInt32 offset, UInt32 count, IntPtr val);
public IntPtr GetDpramMemory(UInt32 devNo, UInt32 offset, UInt32 count, IntPtr val)
{
return PmacDPRGetMem(devNo, offset, count, val);
}
private PmacServoRead m_PmacServoRead = new PmacServoRead();
private PmacInput m_PmacInput = new PmacInput();
int m_ReadSize = Marshal.SizeOf(typeof(PmacServoRead));
int m_ReadSizeDi = Marshal.SizeOf(typeof(PmacInput));
private int ReadDataFromDPRam()
{
if (IsOpen == true)
{
IntPtr ptr1 = Marshal.AllocHGlobal(m_ReadSize);
GetDpramMemory(DeviceNo, CcpPmacComm.DpramReadOffset, (uint)m_ReadSize, ptr1);
m_PmacServoRead =(PmacServoRead)Marshal.PtrToStructure(ptr1, typeof(PmacServoRead));
Marshal.DestroyStructure(ptr1, typeof(PmacServoRead));
Marshal.FreeHGlobal(ptr1);
ptr1 = Marshal.AllocHGlobal(m_ReadSizeDi);
GetDpramMemory(DeviceNo, CcpPmacComm.DpramInputReadOffset, (uint)m_ReadSizeDi, ptr1);
m_PmacInput = (PmacInput)Marshal.PtrToStructure(ptr1, typeof(PmacInput));
Marshal.DestroyStructure(ptr1, typeof(PmacInput));
Marshal.FreeHGlobal(ptr1);
}
return -1;
}
Please help me.

Related

Trouble converting function from vmm.dll (C) to vmmsharp.dll (C#). (DMA) (PCILEECH) (C#)

I am attempting to bring over a function from vmmdll.h to vmmsharp.cs. In this case, I am trying to bring over Map_GetPool.
You can see here my implementation to C#:
//Please view the images:
Bringing function over
internal static uint VMMDLL_POOLMAP_FLAG_ALL = 0;
internal static uint VMMDLL_POOLMAP_FLAG_BIG = 1;
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal unsafe struct VMMDLL_MAP_POOLENTRYTAG
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] internal char[] szTag;
//szTag struct
/*internal uint dwTag;
internal uint _Filler;
internal uint cEntry;
internal uint iTag2Map;*/
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal unsafe struct VMMDLL_MAP_POOLENTRY
{
internal ulong va;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] internal char[] szTag;
//szTag struct
/*internal uint dwTag;
internal byte _ReservedZero;
internal byte fAlloc;
internal byte tpPool;
internal byte tpSS;*/
internal uint cb;
internal uint _Filler;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal unsafe struct VMMDLL_MAP_POOL
{
internal uint dwVersion;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] internal uint[] _Reserved1;
internal uint cbTotal;
internal uint* piTag2Map;
internal VMMDLL_MAP_POOLENTRYTAG* pTag;
internal uint cTag;
internal uint cMap;
internal VMMDLL_MAP_POOLENTRY[] pMap;
}
[DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetPoolEx")]
internal static extern unsafe bool VMMDLL_Map_GetPoolEx(
byte* pNetMap,
ref uint pcbNetMap);
Implementing it into c#
//My map pool
public unsafe struct MAP_POOL
{
public uint dwVersion;
public uint[] _Reserved1;
//public unsafe fixed uint _Reserved1[6];
public uint cbTotal;
public uint[] piTag2Map;
public MAP_POOLENTRYTAG* pTag;
public uint cTag;
public uint cMap;
public MAP_POOLENTRY[] pMap;
}
//szTag[5] -> POOLENTRY 4th tpPool MAP_POOL_TYPE 5th tpSS MAP_POOL_TYPE_SUBSEGMENT
public enum MAP_POOL_TYPE
{
MAP_POOL_TYPE_Unknown = 0,
MAP_POOL_TYPE_NonPagedPool = 1,
MAP_POOL_TYPE_NonPagedPoolNx = 2,
MAP_POOL_TYPE_PagedPool = 3
}
public enum MAP_POOL_TYPE_SUBSEGMENT
{
VMM_MAP_POOL_TYPE_SUBSEGMENT_UNKNOWN = 0,
VMM_MAP_POOL_TYPE_SUBSEGMENT_NA = 1,
VMM_MAP_POOL_TYPE_SUBSEGMENT_BIG = 2,
VMM_MAP_POOL_TYPE_SUBSEGMENT_LARGE = 3,
VMM_MAP_POOL_TYPE_SUBSEGMENT_VS = 4,
VMM_MAP_POOL_TYPE_SUBSEGMENT_LFH = 5
}
public unsafe struct MAP_POOLENTRYTAG
{
//union
public char[] szTag;
/*
* struct {
DWORD dwTag;
DWORD _Filler;
DWORD cEntry;
DWORD iTag2Map;
};
*/
}
public unsafe struct MAP_POOLENTRY
{
public ulong va;
public char[] szTag;
//public unsafe fixed char szTag[5];
public uint cb;
public uint _Filler;
}
Function
public static unsafe MAP_POOLENTRY[] Map_GetPoolEx()
{
bool result;
uint cb = 0;
int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_POOL));
int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_POOLENTRY));
result = vmmi.VMMDLL_Map_GetPoolEx(null, ref cb);
if (!result || (cb == 0)) { return new MAP_POOLENTRY[0]; }
fixed (byte* pb = new byte[cb])
{
result = vmmi.VMMDLL_Map_GetPoolEx(pb, ref cb);
if (!result) { return new MAP_POOLENTRY[0]; }
vmmi.VMMDLL_MAP_POOL pm = Marshal.PtrToStructure<vmmi.VMMDLL_MAP_POOL>((System.IntPtr)pb);
if (pm.dwVersion != vmmi.VMMDLL_MAP_PHYSMEM_VERSION) { return new MAP_POOLENTRY[0]; }
MAP_POOLENTRY[] m = new MAP_POOLENTRY[pm.cMap];
for (int i = 0; i < pm.cMap; i++)
{
vmmi.VMMDLL_MAP_POOLENTRY n = Marshal.PtrToStructure<vmmi.VMMDLL_MAP_POOLENTRY>((System.IntPtr)(pb + cbMAP + i * cbENTRY));
MAP_POOLENTRY e;
e.va = n.va;
e.cb = n.cb;
e.szTag = n.szTag;
//m[i] = e;
}
return m;
}
}
As you can see, the pointer PVMMDLL -> VMMDLL* throws an error stating it can't do that.
For the function, for some reason, e is undefined even though it is indeed defined. Also, is my overall setup correct?
Thanks, I appreciate any help.
Here are the links again to the implementations if needed (This doesn't have my implementation in it, but it has other implementations for similar functions):
vmmdll: https://github.com/ufrisk/MemProcFS/blob/master/vmm/vmmdll.h#L1506
vmmsharp: https://github.com/ufrisk/MemProcFS/blob/master/vmmsharp/vmmsharp.cs

Get Multiple Cell IDs for location using Cellular Towers C# Windows Mobile

Following Microsoft's documentation on RIL I've been able to implement a code that retrieves Cell ID, LAC, MCC, MNC and Signal Strength. Using these data and http://www.opencellid.org/ I'm able to retrieve latitude and longitude of that cell tower. The problem is that I need to implement some kind of triangulation algorithm to get a more accurate position. But before even thinking in triangulation, I'm going to need more than one tower ID to work with. How can I get them? I tried to create an array of towerIDs and populate it in a loop, while a tower id does not exist in the array then add it, but if it exists then ignore it and keep looking for another one. Obviously it did not work, once it gets one it keeps it and if I delete the object and create a new one it gets the same tower. How can I get a different one?
Thanks in advance.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace GPS_Test
{
public class CellTower
{
public int CellID { get; set; }
// LAC (Local Area Code)
public int LAC { get; set; }
// MCC (Mobile Country Code)
public int MCC { get; set; }
// MNC (Mobile Network Code)
public int MNC { get; set; }
// Received signal strength
public int signalStrength { get; set; }
// Base Station ID
//public int baseStationID { get; set; }
}
public class RIL
{
public delegate void RILRESULTCALLBACK(uint dwCode,
IntPtr hrCmdID, IntPtr lpData, uint cbData, uint dwParam);
public delegate void RILNOTIFYCALLBACK(uint dwCode,
IntPtr lpData, uint cbData, uint dwParam);
[DllImport("ril.dll")]
public static extern IntPtr RIL_Initialize(uint dwIndex,
RILRESULTCALLBACK pfnResult,
RILNOTIFYCALLBACK pfnNotify,
uint dwNotificationClasses,
uint dwParam,
out IntPtr lphRil);
[DllImport("ril.dll", EntryPoint = "RIL_GetCellTowerInfo")]
public static extern IntPtr RIL_GetCellTowerInfo(IntPtr hril);
[DllImport("ril.dll")]
public static extern IntPtr RIL_Deinitialize(IntPtr hril);
[DllImport("ril.dll", EntryPoint = "RIL_GetSignalQuality")]
public static extern IntPtr RIL_GetSignalQuality(IntPtr hRil);
[StructLayout(LayoutKind.Explicit)]
internal class RILCELLTOWERINFO
{
[FieldOffset(0)]
uint dwSize;
[FieldOffset(4)]
uint dwParams;
[FieldOffset(8)]
public uint dwMobileCountryCode;
[FieldOffset(12)]
public uint dwMobileNetworkCode;
[FieldOffset(16)]
public uint dwLocationAreaCode;
[FieldOffset(20)]
public uint dwCellID;
[FieldOffset(28)]
public uint dwBaseStationID;
[FieldOffset(36)]
public uint dwRxLevel;
}
[StructLayout(LayoutKind.Explicit)]
internal class RILSIGNALQUALITY
{
[FieldOffset(0)]
uint dwSize;
[FieldOffset(4)]
uint dwParams;
[FieldOffset(8)]
public int nSignalStrength;
[FieldOffset(12)]
public uint nMinSignalStrength;
[FieldOffset(16)]
public uint nMaxSignalStrength;
[FieldOffset(20)]
public uint dwBitErrorRate;
[FieldOffset(24)]
public uint nLowSignalStrength;
[FieldOffset(28)]
public uint nHighSignalStrength;
}
}
public class CellTowerInfo
{
private static AutoResetEvent dataReceived = new AutoResetEvent(false);
private static AutoResetEvent whSignalQuality = new AutoResetEvent(false);
private static RIL.RILCELLTOWERINFO towerInfo;
private static RIL.RILSIGNALQUALITY signalQuality;
public static CellTower GetCellTowerInfo()
{
IntPtr hRil = IntPtr.Zero;
IntPtr hResult = IntPtr.Zero;
hResult = RIL.RIL_Initialize(1,
new RIL.RILRESULTCALLBACK(CellTowerData),
null, 0, 0, out hRil);
if (hResult != IntPtr.Zero)
return null;
hResult = RIL.RIL_GetCellTowerInfo(hRil);
dataReceived.WaitOne();
RIL.RIL_Deinitialize(hRil);
CellTower ct = new CellTower();
ct.LAC = (int)towerInfo.dwLocationAreaCode;
ct.MCC = (int)towerInfo.dwMobileCountryCode;
ct.MNC = (int)towerInfo.dwMobileNetworkCode;
ct.CellID = (int)towerInfo.dwCellID;
ct.signalStrength = GetSignalQuality();
return ct;
}
public static int GetSignalQuality()
{
IntPtr hRes = IntPtr.Zero;
IntPtr hSignalQ = IntPtr.Zero;
hRes = RIL.RIL_Initialize(1, new RIL.RILRESULTCALLBACK(SignalQualityCallback),
null, 0, 0, out hSignalQ);
hRes = RIL.RIL_GetSignalQuality(hSignalQ);
whSignalQuality.WaitOne();
RIL.RIL_Deinitialize(hSignalQ);
return signalQuality.nSignalStrength;
}
private static void CellTowerData(uint dwCode, IntPtr hrCmdID,
IntPtr lpData, uint cbData, uint dwPara)
{
towerInfo = new RIL.RILCELLTOWERINFO();
Marshal.PtrToStructure(lpData, (object)towerInfo);
dataReceived.Set();
}
private static void SignalQualityCallback(uint dwCode, IntPtr hrCmdID,
IntPtr lpData, uint cbData, uint dwPara)
{
signalQuality = new RIL.RILSIGNALQUALITY();
Marshal.PtrToStructure(lpData, (object)signalQuality);
whSignalQuality.Set();
}
}
}
Try to save all the info regarding the current signal, after doing so restart the service looking to another signal but first check the one you had stored, if it's the same disregard and keep looking.
Good luck!

Why raw disk read in C# reads from slightly shifted offset?

I'm trying to read raw disk. I've successfully opened the drive and obtained valid handle (CreateFile), set offset for that handle to zero (SetFilePointerEx) and read the data to a buffer Byte[] (ReadFile). So far so good. But for some unknown reason, when I compare the buffer (took my a while to figure it out actually) to what 3rd party utilities (Disk Investigator) shows. It doesn't contain a boot information (jump instruction), but correct disk data, but starting at offset 85 = 0x55. So somewhere in the middle of volume boot information.
Why is that? Is there something, I'm missing (obviously I am)?
System: Windows 8 (in VmWare Workstation)
Code:
// moves the pointer to a given offset
Int64 offset = 0;
Int64 newOffset;
Int32 bufferSize = (Int32) clusterSizeInBytes;
SetFilePointerEx(driveHandle.Handle, offset, out newOffset, WinMoveMethod.Begin);
Int32 error = Marshal.GetLastWin32Error();
// reads the raw buffer
Int32 numberOfBytesRead;
rawData = new Byte[bufferSize];
Boolean result = ReadFile(driveHandle.Handle, rawData, bufferSize,
out numberOfBytesRead, IntPtr.Zero);
CreateFile (elsewhere)
driveHandle = CreateFile("\\.\PhysicalDrive1", WinFileAccessMode.GenericRead,
WinFileSharedAccess.All, IntPtr.Zero, WinFileMode.OpenExisting,
WinFileAttribute.None, IntPtr.Zero);
PInvoke methods:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern Boolean SetFilePointerEx(
[In] SafeFileHandle fileHandle,
[In] Int64 distanceToMove,
[Out] out Int64 newOffset,
[In] WinMoveMethod moveMethod);
[DllImport("kernel32", SetLastError = true)]
public extern static Boolean ReadFile(
[In] SafeFileHandle handle,
[Out] Byte[] buffer,
[In] Int32 numBytesToRead,
[Out] out Int32 numBytesRead,
[In] IntPtr overlapped);
Enumerations:
public enum WinMoveMethod : uint
{
Begin = 0,
Current = 1,
End = 2
}
Can't find anymore a library using a namespace "DiskLib". I can't test that or completely upload now, even I don't know anymore who wrote that piece of code, but the lines you may find interesting are
public class DiskStream : Stream
{
public const int DEFAULT_SECTOR_SIZE = 512;
private const int BUFFER_SIZE = 4096;
private string diskID;
private DiskInfo diskInfo;
private FileAccess desiredAccess;
private SafeFileHandle fileHandle;
public DiskInfo DiskInfo
{
get { return this.diskInfo; }
}
public uint SectorSize
{
get { return this.diskInfo.BytesPerSector; }
}
public DiskStream(string diskID, FileAccess desiredAccess)
{
this.diskID = diskID;
this.diskInfo = new DiskInfo(diskID);
this.desiredAccess = desiredAccess;
// if desiredAccess is Write or Read/Write
// find volumes on this disk
// lock the volumes using FSCTL_LOCK_VOLUME
// unlock the volumes on Close() or in destructor
this.fileHandle = this.openFile(diskID, desiredAccess);
}
private SafeFileHandle openFile(string id, FileAccess desiredAccess)
{
uint access;
switch (desiredAccess)
{
case FileAccess.Read:
access = DeviceIO.GENERIC_READ;
break;
case FileAccess.Write:
access = DeviceIO.GENERIC_WRITE;
break;
case FileAccess.ReadWrite:
access = DeviceIO.GENERIC_READ | DeviceIO.GENERIC_WRITE;
break;
default:
access = DeviceIO.GENERIC_READ;
break;
}
SafeFileHandle ptr = DeviceIO.CreateFile(
id,
access,
DeviceIO.FILE_SHARE_READ,
IntPtr.Zero,
DeviceIO.OPEN_EXISTING,
DeviceIO.FILE_FLAG_NO_BUFFERING | DeviceIO.FILE_FLAG_WRITE_THROUGH,
IntPtr.Zero);
if (ptr.IsInvalid)
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
return ptr;
}
public override bool CanRead
{
get
{
return (this.desiredAccess == FileAccess.Read || this.desiredAccess == FileAccess.ReadWrite) ? true : false;
}
}
public override bool CanWrite
{
get
{
return (this.desiredAccess == FileAccess.Write || this.desiredAccess == FileAccess.ReadWrite) ? true : false;
}
}
public override bool CanSeek
{
get
{
return true;
}
}
public override long Length {
get { return (long)this.Length; }
}
public ulong LengthU
{
get { return this.diskInfo.Size; }
}
public override long Position {
get {
return (long)PositionU;
}
set {
PositionU = (ulong)value;
}
}
public ulong PositionU
{
get
{
ulong n = 0;
if (!DeviceIO.SetFilePointerEx(this.fileHandle, 0, out n, (uint)SeekOrigin.Current))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
return n;
}
set
{
if (value > (this.LengthU - 1))
throw new EndOfStreamException("Cannot set position beyond the end of the disk.");
ulong n = 0;
if (!DeviceIO.SetFilePointerEx(this.fileHandle, value, out n, (uint)SeekOrigin.Begin))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
}
public override void Flush()
{
// not required, since FILE_FLAG_WRITE_THROUGH and FILE_FLAG_NO_BUFFERING are used
//if (!Unmanaged.FlushFileBuffers(this.fileHandle))
// Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
public override void Close()
{
if (this.fileHandle != null) {
DeviceIO.CloseHandle(this.fileHandle);
this.fileHandle.SetHandleAsInvalid();
this.fileHandle = null;
}
base.Close();
}
public override void SetLength(long value)
{
throw new NotSupportedException("Setting the length is not supported with DiskStream objects.");
}
public override int Read(byte[] buffer, int offset, int count) {
return (int)Read(buffer, (uint)offset, (uint)count);
}
public unsafe uint Read(byte[] buffer, uint offset, uint count)
{
uint n = 0;
fixed (byte* p = buffer)
{
if (!DeviceIO.ReadFile(this.fileHandle, p + offset, count, &n, IntPtr.Zero))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
return n;
}
public override void Write(byte[] buffer, int offset, int count) {
Write(buffer, (uint)offset, (uint)count);
}
public unsafe void Write(byte[] buffer, uint offset, uint count)
{
uint n = 0;
fixed (byte* p = buffer)
{
if (!DeviceIO.WriteFile(this.fileHandle, p + offset, count, &n, IntPtr.Zero))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
}
public override long Seek(long offset, SeekOrigin origin) {
return (long)SeekU((ulong)offset, origin);
}
public ulong SeekU(ulong offset, SeekOrigin origin)
{
ulong n = 0;
if (!DeviceIO.SetFilePointerEx(this.fileHandle, offset, out n, (uint)origin))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
return n;
}
public uint ReadSector(DiskSector sector)
{
return this.Read(sector.Data, 0, sector.SectorSize);
}
public void WriteSector(DiskSector sector)
{
this.Write(sector.Data, 0, sector.SectorSize);
}
public void SeekSector(DiskSector sector)
{
this.Seek(sector.Offset, SeekOrigin.Begin);
}
}
The DeviceIO class is a p/invoke boilerplate for Win32 API.
The DiskInfo class is a wrapper to WMI Win32_DiskDrive and Win32_DiskPartition classes.
I used that library once to clone a disk (on Win7). Hope that helps to find the solution.
For completeness and because of the details, the DeviceIO class is throughout using unsigned integers:
/// <summary>
/// P/Invoke wrappers around Win32 functions and constants.
/// </summary>
internal partial class DeviceIO
{
#region Constants used in unmanaged functions
public const uint FILE_SHARE_READ = 0x00000001;
public const uint FILE_SHARE_WRITE = 0x00000002;
public const uint FILE_SHARE_DELETE = 0x00000004;
public const uint OPEN_EXISTING = 3;
public const uint GENERIC_READ = (0x80000000);
public const uint GENERIC_WRITE = (0x40000000);
public const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
public const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;
public const uint FILE_READ_ATTRIBUTES = (0x0080);
public const uint FILE_WRITE_ATTRIBUTES = 0x0100;
public const uint ERROR_INSUFFICIENT_BUFFER = 122;
#endregion
#region Unamanged function declarations
[DllImport("kernel32.dll", SetLastError = true)]
public static unsafe extern SafeFileHandle CreateFile(
string FileName,
uint DesiredAccess,
uint ShareMode,
IntPtr SecurityAttributes,
uint CreationDisposition,
uint FlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(SafeFileHandle hHandle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool DeviceIoControl(
SafeFileHandle hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
[Out] IntPtr lpOutBuffer,
uint nOutBufferSize,
ref uint lpBytesReturned,
IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern unsafe bool WriteFile(
SafeFileHandle hFile,
byte* pBuffer,
uint NumberOfBytesToWrite,
uint* pNumberOfBytesWritten,
IntPtr Overlapped);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern unsafe bool ReadFile(
SafeFileHandle hFile,
byte* pBuffer,
uint NumberOfBytesToRead,
uint* pNumberOfBytesRead,
IntPtr Overlapped);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetFilePointerEx(
SafeFileHandle hFile,
ulong liDistanceToMove,
out ulong lpNewFilePointer,
uint dwMoveMethod);
[DllImport("kernel32.dll")]
public static extern bool FlushFileBuffers(
SafeFileHandle hFile);
#endregion
}

This memory scanner only work on strings. How can I find numbers?

I'm writing a memory scanner in C#. It's able to find strings, but not numerical values. How can I enhance it to find addresses with numbers in them?
Edit: I give my app a specific number or string to search for within the memory of a running process. I want to use this to change those values later, but for now I'm just trying to figure out there the values are stored.
Edit 2: Looks like it only works on strings that are in the loaded files/modules' binaries; not values that have changed in-proc. Grrr.
public class Search
{
public Search(int pid, string value) {
SearchValues = new List<string>();
PossibleAddresses = new List<IntPtr>();
PID = pid;
DoSearch(value); }
public int PID { get; set; }
public Process getProcess { get { return Process.GetProcessById(PID); } }
public List<string> SearchValues { get; private set; }
public List<IntPtr> PossibleAddresses { get; private set; }
public bool hasLockedOn { get; set; }
private IntPtr processPointer { get; set; }
public void DoSearch(string value)
{
SearchValues.Add(value);
IntPtr baseAddress, lastAddress;
Process process = getProcess;
baseAddress = process.MainModule.BaseAddress;
lastAddress = baseAddress + process.MainModule.ModuleMemorySize;
processPointer = OpenProcess((uint)(0x0010), 1, (uint)PID);
int iVal;
double dVal;
int.TryParse(value, out iVal);
double.TryParse(value, out dVal);
if (SearchValues.Count == 1) // new searches
for (int addr = (int)baseAddress; addr + value.Length < (int)lastAddress; addr++)
{
// Match numbers
if (dVal > 0 && MemoryContainsNumber((IntPtr)addr, dVal, ((IntPtr)addr)))
PossibleAddresses.Add((IntPtr)addr);
else if (iVal > 0 && MemoryContainsNumber((IntPtr)addr, iVal, ((IntPtr)addr)))
PossibleAddresses.Add((IntPtr)addr);
// Match strings
else if (ReadMemory((IntPtr)addr, (uint)value.Length, (IntPtr)addr).Trim().ToLower() == value.Trim().ToLower())
PossibleAddresses.Add((IntPtr)addr);
}
else { // TODO: Existing searches
}
hasLockedOn = PossibleAddresses.Count == 1;
CloseHandle(processPointer);
}
private string ReadMemory(IntPtr memAddress, uint size, IntPtr BaseAddress)
{
byte[] buffer = new byte[size];
IntPtr bytesRead;
unsafe
{
ReadProcessMemory(processPointer, BaseAddress, buffer, size, out bytesRead);
return Encoding.Default.GetString(buffer);
//string result = "";
//foreach (string c in BitConverter.ToString(buffer).Split('-'))
// result += char.ConvertFromUtf32(Int32.Parse(c, System.Globalization.NumberStyles.HexNumber));
//return result;
}
}
private bool MemoryContainsNumber(IntPtr memAddress, int number, IntPtr BaseAddress)
{
byte[] numberBytes = BitConverter.GetBytes(number);
byte[] buffer = new byte[numberBytes.Length];
IntPtr bytesRead;
unsafe { ReadProcessMemory(processPointer, BaseAddress, buffer, (uint)numberBytes.Length, out bytesRead); }
for (int i = 0; i < buffer.Length; i++)
if (buffer[i] != numberBytes[i])
return false;
return true;
}
private bool MemoryContainsNumber(IntPtr memAddress, double number, IntPtr BaseAddress)
{
byte[] numberBytes = BitConverter.GetBytes(number);
byte[] buffer = new byte[numberBytes.Length];
IntPtr bytesRead;
unsafe { ReadProcessMemory(processPointer, BaseAddress, buffer, (uint)numberBytes.Length, out bytesRead); }
for (int i = 0; i < buffer.Length; i++)
if (buffer[i] != numberBytes[i])
return false;
return true;
}
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId);
[DllImport("kernel32.dll")]
public static extern Int32 CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
public static extern Int32 WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesWritten);
}
Looks like it only works on strings that are in the loaded files/modules' binaries; not values that have changed in-proc. Grrr.
Therefore it's not a string vs numeric issue and this whole question is moot. Thanks for your help.
Next question in the series...

How to get Hard-Disk SerialNumber in C# (no WMI)?

I know there are two articles in CodeProject (one uses WMI and the other no WMI but in C++). I tried the WMI way, not only it's slow, but it is also unreliable. So, that's why I decided not to pursue that way. I want to do it in C# through pInvoke. I tried it but got stuck in DeviceIoControl API. Can anybody give me a hint? Here is my code:
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace Chemulator.Common
{
public class HDSerialNumber
{
[StructLayout(LayoutKind.Sequential)]
private struct IDEREGS
{
public byte bFeaturesReg;
public byte bSectorCountReg;
public byte bSectorNumberReg;
public byte bCylLowReg;
public byte bCylHighReg;
public byte bDriveHeadReg;
public byte bCommandReg;
public byte bReserved;
}
[StructLayout(LayoutKind.Sequential)]
private struct SENDCMDINPARAMS
{
public Int32 cBufferSize;
public IDEREGS irDriveRegs;
public byte bDriveNumber;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] bReserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public Int32[] dwReserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public byte[] bBuffer;
}
[StructLayout(LayoutKind.Sequential)]
private struct DRIVERSTATUS
{
public byte bDriverError;
public byte bIDEError;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] bReserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public Int32[] dwReserved;
}
[StructLayout(LayoutKind.Sequential)]
private struct SENDCMDOUTPARAMS
{
public Int32 cBufferSize;
public DRIVERSTATUS DriverStatus;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = IDENTIFY_BUFFER_SIZE)]
public byte[] bBuffer;
}
[StructLayout(LayoutKind.Sequential)]
private struct GETVERSIONOUTPARAMS
{
public byte bVersion;
public byte bRevision;
public byte bReserved;
public byte bIDEDeviceMap;
public Int32 fCapabilities;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public Int32 dwReserved;
}
[StructLayout(LayoutKind.Sequential)]
private struct STORAGE_PROPERTY_QUERY
{
public Int32 PropertyId;
public Int32 QueryType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public byte[] AdditionalParameters;
}
[StructLayout(LayoutKind.Sequential)]
private struct STORAGE_DEVICE_DESCRIPTOR
{
public Int32 Version;
public Int32 Size;
public byte DeviceType;
public byte DeviceTypeModifier;
public byte RemovableMedia;
public byte CommandQueueing;
public Int32 VendorIdOffset;
public Int32 ProductIdOffset;
public Int32 ProductRevisionOffset;
public Int32 SerialNumberOffset;
public byte BusType;
public Int32 RawPropertiesLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10240)]
public byte[] RawDeviceProperties;
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern SafeFileHandle CreateFile(string lpFileName, Int32 dwDesiredAccess, Int32 dwShareMode, IntPtr lpSecurityAttributes, Int32 dwCreationDisposition, Int32 dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32")]
private static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, ref uint lpBytesReturned, IntPtr lpOverlapped);
private const Int32 OPEN_EXISTING = 3;
private const Int32 GENERIC_READ = unchecked((int)0x80000000);
private const Int32 GENERIC_WRITE = 0x40000000;
private const Int32 FILE_SHARE_READ = 0x1;
private const Int32 FILE_SHARE_WRITE = 0x2;
private const Int32 FILE_SHARE_DELETE = 0x4;
private const Int32 SMART_GET_VERSION = 0x74080;
private const Int32 SMART_RCV_DRIVE_DATA = 0x7C088;
private const Int32 ID_CMD = 0xEC;
private const Int32 IDENTIFY_BUFFER_SIZE = 512;
private const Int32 CAP_SMART_CMD = 0x4;
private const Int32 IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400;
private const Int32 PropertyStandardQuery = 0;
private const Int32 StorageDeviceProperty = 0;
public static string GetSerialNumber(int diskNumber)
{
string str = GetSerialNumberUsingStorageQuery(diskNumber);
if (string.IsNullOrEmpty(str))
str = GetSerialNumberUsingSmart(diskNumber);
return str;
}
public static string GetSerialNumberUsingStorageQuery(int diskNumber)
{
using (SafeFileHandle hDisk = OpenDisk(diskNumber))
{
uint iBytesReturned = 0;
var spq = new STORAGE_PROPERTY_QUERY();
var sdd = new STORAGE_DEVICE_DESCRIPTOR();
spq.PropertyId = StorageDeviceProperty;
spq.QueryType = PropertyStandardQuery;
if (DeviceIoControl(hDisk, IOCTL_STORAGE_QUERY_PROPERTY, spq, (uint)Marshal.SizeOf(spq), sdd, (uint)Marshal.SizeOf(sdd), ref iBytesReturned, IntPtr.Zero))
throw CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(IOCTL_STORAGE_QUERY_PROPERTY)");
var result = new StringBuilder();
if (sdd.SerialNumberOffset > 0)
{
var rawDevicePropertiesOffset = Marshal.SizeOf(sdd) - sdd.RawDeviceProperties.Length;
int pos = sdd.SerialNumberOffset - rawDevicePropertiesOffset;
while (pos < iBytesReturned && sdd.RawDeviceProperties[pos] != 0)
{
result.Append(Encoding.ASCII.GetString(sdd.RawDeviceProperties, pos, 1));
pos += 1;
}
}
return result.ToString();
}
}
public static string GetSerialNumberUsingSmart(int diskNumber)
{
using (SafeFileHandle hDisk = OpenDisk(diskNumber))
{
if (IsSmartSupported(hDisk))
{
Int32 iBytesReturned = 0;
var sci = new SENDCMDINPARAMS();
var sco = new SENDCMDOUTPARAMS();
sci.irDriveRegs.bCommandReg = ID_CMD;
sci.bDriveNumber = (byte)diskNumber;
sci.cBufferSize = IDENTIFY_BUFFER_SIZE;
if (DeviceIoControl(hDisk, SMART_RCV_DRIVE_DATA, sci, (uint)Marshal.SizeOf(sci), sco, (uint)Marshal.SizeOf(sco), ref iBytesReturned, IntPtr.Zero))
throw CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(SMART_RCV_DRIVE_DATA)");
var result = new StringBuilder();
for (int index = 20; index < 39; index += 2)
{
result.Append(Encoding.ASCII.GetString(sco.bBuffer, index + 1, 1));
result.Append(Encoding.ASCII.GetString(sco.bBuffer, index, 1));
}
return result.ToString();
}
return string.Empty;
}
}
private static Win32Exception CreateWin32Exception(Int32 errorCode, string context)
{
var win32Exception = new Win32Exception(errorCode);
win32Exception.Data["Context"] = context;
return win32Exception;
}
private static SafeFileHandle OpenDisk(int diskNumber)
{
SafeFileHandle hDevice = CreateFile(string.Format(#"\\.\PhysicalDrive{0}", diskNumber), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (!hDevice.IsInvalid)
return hDevice;
else
throw CreateWin32Exception(Marshal.GetLastWin32Error(), "CreateFile");
}
private static bool IsSmartSupported(SafeFileHandle hDisk)
{
uint iBytesReturned = 0;
var gvo = new GETVERSIONOUTPARAMS();
IntPtr pGVO = Marshal.AllocHGlobal(512);
if (DeviceIoControl(hDisk, SMART_GET_VERSION, IntPtr.Zero, 0, pGVO, 512, ref iBytesReturned, IntPtr.Zero))
return false;
return (gvo.fCapabilities & CAP_SMART_CMD) > 0;
}
}
}
Check out the pinvoke.net tutorial about DeviceIOcontrol.
Scroll down the page where you can see VB .NET 3.0 Full Example (Thanks to "bogdandaniel") Edited by pPumkiN. It is a complete example of accessing diffferent IO devices. I beleieve there is DRIVE_INFO too.
Also i dont have any experience with this. Try it yourself

Categories