Well, first off, this is the first post using the new blogging solution! Let's hope it works!
I'm presenting here a low level memory management class I wrote for C# that allows you to pass an IntPtr and then manipulate the bytes inside as indexers of an array (of the MemoryManager object).
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace Switch
{
public class MemoryManager
{
public IntPtr mmPtr = IntPtr.Zero;
public byte this[int index]
{
get
{
return Marshal.ReadByte(mmPtr, index);
}
set
{
Marshal.WriteByte(mmPtr, index, value);
}
}
public byte[] this[int startindex, int endindex]
{
get
{
byte[] ret = new byte[endindex - startindex];
for (int y = startindex; y < endindex; y++)
{
ret[y - startindex] = Marshal.ReadByte(mmPtr, y);
}
return ret;
}
set
{
for (int y = startindex; y < endindex; y++)
{
Marshal.WriteByte(mmPtr, y, value[y - startindex]);
}
}
}
public void SubtractInt(int index, uint value)
{
Byte[] bytes = BitConverter.GetBytes(((uint)(Marshal.ReadInt32(mmPtr, index))) - value);
Marshal.WriteByte(mmPtr, index, bytes[0]);
Marshal.WriteByte(mmPtr, index + 1, bytes[1]);
Marshal.WriteByte(mmPtr, index + 2, bytes[2]);
Marshal.WriteByte(mmPtr, index + 3, bytes[3]);
}
public int WriteStringToMemory(string s, int offset)
{
int writtenCount = 0;
for (int charByteCount = 0; charByteCount < s.Length; charByteCount++)
{
Byte[] charConverted = BitConverter.GetBytes(s[charByteCount]);
Marshal.WriteByte(mmPtr, charByteCount + offset, charConverted[0]);
writtenCount++;
}
return writtenCount;
}
public MemoryManager(IntPtr start)
{
mmPtr = start;
}
public static string plainText(IntPtr buffer, bool changePlain)
{
string ret = string.Empty;
for (int y = 0; y < 64; y++)
{
Byte b = Marshal.ReadByte(buffer, (y == 0 && changePlain ? 60 : y));
if (b == 0x80) return ret;
ret += (char)b;
}
return ret;
}
public void WriteUintToMemory(int offset, uint data)
{
writeOrd32Chunk(offset, BitConverter.GetBytes(data));
}
public void WriteByteToMemory(int offset, byte data)
{
Marshal.WriteByte(mmPtr, offset, data);
}
}
}
As an example of how to use this class (although perhaps not why you might want to!), consider the following:
//Setup buffer
bufferPtr = Marshal.AllocHGlobal(64);
MemoryManager mmBuffer = new MemoryManager(bufferPtr);
Console.WriteLine("bufferPtr begins at {0} and occupies {1} bytes.", bufferPtr.ToString(), 64);
//Write zeroes from 0->56 (14*4)
mmBuffer.WriteZeros(0, 14);
Console.WriteLine("buffer[0->56] written with zeroes.");
//Write the start value
mmBuffer.WriteStringToMemory("astring", 0);
Console.WriteLine("String written to buffer[0].");
//Write the padding marker
mmBuffer[searchLen] = 0x80;
Console.WriteLine("Padding marker (0x80) written to buffer[" + searchLen.ToString() + "].");
//Write the tail at position 56
mmBuffer.WriteUintToMemory(56, (uint)tailStringPtr);
Console.WriteLine("tailStringPtr written to buffer[56].");
//Write the working area to position 60->63
mmBuffer[60, 63] = mmBuffer[0, 3];
This class is primarily useful when you need to pass a memory structure via a pInvoke and want to easily manipulate the data.