Was going through my project folders for VS 2k8, and I found an old memory lib. (Similar to BlackMagic, but aimed more-so at .NET developers who want the Win32 API abstracted away as far as possible.)
Anyhow, here's a few snippets of code. Obviously, you'll need to tweak it to fit your needs, but it all works (on my side at least) without bugs.
Generic Read/Write Methods & CreateCodeCaves
The generic read/write can be used as follows:
Normal read procedure: [[[0x005]+0x002]+0x004]
uint myAddress = memoryManager.Read<uint>(0x005, 0x002, 0x004);
It will perform the incremental reads for you.
For instance, imagine the above read was for the playerbase, and another read at pbase + 0x0F54 was the local X address.
float localX = memoryManager.Read<float>(0x005, 0x002, 0x004, 0x0F54);
That would produce exactly what you are looking for.
Note: If you pass anything other than a ValueType (int, uint, long, byte, etc) it defaults to ReadObject, which may not be what you intend!
Code:
#region Read
/// <summary>
/// Reads the specified offsets. TODO: Add proper comments...
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="offsets">The offsets.</param>
/// <returns></returns>
/// 12/22/2008 6:41 PM
public T Read<T>(params uint[] offsets)
{
if (offsets.Length == 0)
{
throw new Exception("Invalid number of offsets passed! Must be > 0");
}
// Store the type so we don't need to make a bunch of
// typeof calls if there's a long list of offsets
Type t = typeof (T);
// If we only have 1 offset, there's no point in going
// through the for loop and doing more work than needed.
if (offsets.Length == 1)
{
return (T) _Read(offsets[0], t);
}
// This holds the last offset read.
// Once we reach offsets.Length -1, we'll return the
// proper T type needed.
uint last = 0;
for (int i = 0; i < offsets.Length; i++)
{
// If this is the last offset in the params list
// we need to return the T type requested.
if (i == (offsets.Length - 1))
{
return (T) _Read(offsets[i] + last, t);
}
// Keep reading from the last thing read + the next offset
// in the params list.
// This is the equivalent to: [[[0x404]+0x54]+0x2C]
last = (uint) _Read(last + offsets[i], typeof (uint));
}
// We should never hit this point
// The compiler bitches if we don't add this...
return default(T);
}
private object _Read(uint address, Type t)
{
switch (Type.GetTypeCode(t))
{
case TypeCode.SByte:
return GetReader.ReadSByte(address);
case TypeCode.Byte:
return GetReader.ReadByte(address);
case TypeCode.Int16:
return GetReader.ReadShort(address);
case TypeCode.UInt16:
return GetReader.ReadUShort(address);
case TypeCode.Int32:
return GetReader.ReadInt(address);
case TypeCode.UInt32:
return GetReader.ReadUInt(address);
case TypeCode.Int64:
return GetReader.ReadInt64(address);
case TypeCode.UInt64:
return GetReader.ReadUInt64(address);
case TypeCode.Single:
return GetReader.ReadFloat(address);
case TypeCode.Double:
return GetReader.ReadDouble(address);
default:
return GetReader.ReadObject(address, t);
}
}
/// <summary>
/// Reads a string from memory. The default length is 255. (MAX_LEN in C++)
/// </summary>
/// <param name="address">The address to read the string from.</param>
/// <param name="ascii">if set to <c>true</c> the string will be read as an ASCII string. Otherwise it will be read as Unicode.</param>
/// <returns></returns>
/// 12/22/2008 4:42 PM
public string ReadString(uint address, bool ascii)
{
return ReadString(address, ascii, 255);
}
/// <summary>
/// Reads a string from memory.
/// </summary>
/// <param name="address">The address to read the string from.</param>
/// <param name="ascii">if set to <c>true</c> the string will be read as an ASCII string. Otherwise it will be read as Unicode.</param>
/// <param name="length">The length of the string to read.</param>
/// <returns></returns>
/// 12/22/2008 4:43 PM
public string ReadString(uint address, bool ascii, int length)
{
return ascii
? GetReader.ReadASCIIString(address, length).Trim()
: GetReader.ReadUnicodeString(address, length).Trim();
}
public byte[] ReadBytes(uint address, int size)
{
return GetReader.ReadBytes(address, size);
}
#endregion
#region Write
public bool Write<T>(uint offset, T value)
{
return _Write(offset, value, typeof (T));
}
private bool _Write(uint address, object value, Type t)
{
switch (Type.GetTypeCode(t))
{
case TypeCode.SByte:
return GetWriter.WriteSByte(address, (sbyte) value);
case TypeCode.Byte:
return GetWriter.WriteByte(address, (byte) value);
case TypeCode.Int16:
return GetWriter.WriteShort(address, (short) value);
case TypeCode.UInt16:
return GetWriter.WriteUShort(address, (ushort) value);
case TypeCode.Int32:
return GetWriter.WriteInt(address, (int) value);
case TypeCode.UInt32:
return GetWriter.WriteUInt(address, (uint) value);
case TypeCode.Int64:
return GetWriter.WriteInt64(address, (long) value);
case TypeCode.UInt64:
return GetWriter.WriteUInt64(address, (ulong) value);
case TypeCode.Single:
return GetWriter.WriteFloat(address, (float) value);
case TypeCode.Double:
return GetWriter.WriteDouble(address, (double) value);
default:
return GetWriter.WriteObject(address, value);
}
}
/// <summary>
/// Reads a string from memory. The default length is 255. (MAX_LEN in C++)
/// </summary>
/// <param name="address">The address to read the string from.</param>
/// <param name="value"></param>
/// <param name="ascii">if set to <c>true</c> the string will be read as an ASCII string. Otherwise it will be read as Unicode.</param>
/// <returns></returns>
/// 12/22/2008 4:42 PM
public bool WriteString(uint address, string value, bool ascii)
{
return ascii
? GetWriter.WriteASCIIString(address, value)
: GetWriter.WriteUnicodeString(address, value);
}
public bool WriteBytes(uint address, byte[] value)
{
return GetWriter.WriteBytes(address, value);
}
#endregion
#region CreateCodeCave
public CodeCave CreateCodeCave(int size)
{
return CreateCodeCave(size, MemoryAllocType.MEM_COMMIT, MemoryProtectType.PAGE_EXECUTE_READWRITE);
}
public CodeCave CreateCodeCave()
{
return CreateCodeCave(Constants.DEFAULT_MEMORY_SIZE, MemoryAllocType.MEM_COMMIT,
MemoryProtectType.PAGE_EXECUTE_READWRITE);
}
public CodeCave CreateCodeCave(int size, MemoryAllocType memoryAllocType)
{
return CreateCodeCave(size, memoryAllocType, MemoryProtectType.PAGE_EXECUTE_READWRITE);
}
public CodeCave CreateCodeCave(int size, MemoryAllocType memoryAllocType, MemoryProtectType memoryProtectType)
{
return new CodeCave(this, size, memoryAllocType, memoryProtectType);
}
#endregion
CodeCave class. (See the comments for what it's used for. And yes, I purposely abstracted another layer on the FASM implementation. So when I use my Voodoo lib, I don't have to require the FASM reference on the main project. Again, see the comments.)
Code:
using System;
using System.Collections.Generic;
using Fasm;
using Voodoo.Native;
namespace Voodoo
{
/// <summary>
/// This class holds a simple wrapper for the FASM DLL provided by Shynd, and Tomasz Grysztar, with a small twist.
/// This class allows you to dynamically create a code cave, and release the allocated memory once the class loses
/// scope. So it is very valid for the following to happen:
/// using (CodeCave cc = myMemoryManager.CreateCodeCave()) { /* Code Here */ }
/// The required memory size is allocated in the constructor, and freed once the object is disposed.
/// There is no need to remember to allocate/free memory!
///
/// This class exposes the main pieces of the FASM DLL so that you will not need to add a reference
/// to it in your actual project. This is also to keep in compliance with .NET standards so if this library
/// is ever updated, we can simply pop in a different DLL, and not worry about having everyone update their
/// applications with the new API and references.
/// </summary>
/// 12/22/2008 10:50 PM
public class CodeCave : IDisposable
{
private readonly uint allocatedMemory;
private readonly int allocSize;
private readonly ManagedFasm fasm;
private readonly IntPtr memoryHandle = IntPtr.Zero;
private readonly MemoryManager mgr;
/// <summary>
/// Gets the address where this <see cref="CodeCave"/> starts.
/// </summary>
/// <value>The allocation address.</value>
/// 12/24/2008 2:47 PM
public uint AllocationAddress { get { return allocatedMemory; } }
#region Ctors
internal CodeCave(MemoryManager memoryManager, int size, MemoryAllocType allocationType,
MemoryProtectType protectType)
: this(memoryManager.ProcessHandle, size, allocationType, protectType)
{
mgr = memoryManager;
}
internal CodeCave(IntPtr processMemoryHandle, int size, MemoryAllocType memoryAllocType,
MemoryProtectType protectType)
{
memoryHandle = processMemoryHandle;
allocSize = size;
allocatedMemory = Win32.VirtualAllocEx(memoryHandle, 0, size, (uint) memoryAllocType, (uint) protectType);
fasm = new ManagedFasm(memoryHandle);
fasm.SetMemorySize(size);
}
internal CodeCave(IntPtr processMemoryHandle, int size, MemoryAllocType memoryAllocType)
: this(processMemoryHandle, size, memoryAllocType, MemoryProtectType.PAGE_EXECUTE_READWRITE) {}
internal CodeCave(IntPtr processMemoryHandle, int size, MemoryProtectType memoryProtectType)
: this(processMemoryHandle, size, MemoryAllocType.MEM_COMMIT, memoryProtectType) {}
internal CodeCave(IntPtr processMemoryHandle, int size)
: this(processMemoryHandle, size, MemoryAllocType.MEM_COMMIT, MemoryProtectType.PAGE_EXECUTE_READWRITE) {}
internal CodeCave(IntPtr processMemoryHandle)
: this(
processMemoryHandle, Constants.DEFAULT_MEMORY_SIZE, MemoryAllocType.MEM_COMMIT,
MemoryProtectType.PAGE_EXECUTE_READWRITE) {}
internal CodeCave(IntPtr processMemoryHandle, MemoryAllocType allocType, MemoryProtectType protectType)
: this(processMemoryHandle, Constants.DEFAULT_MEMORY_SIZE, allocType, protectType) {}
internal CodeCave(IntPtr processMemoryHandle, MemoryAllocType allocType)
: this(
processMemoryHandle, Constants.DEFAULT_MEMORY_SIZE, allocType, MemoryProtectType.PAGE_EXECUTE_READWRITE) {}
internal CodeCave(IntPtr processMemoryHandle, MemoryProtectType protectType)
: this(processMemoryHandle, Constants.DEFAULT_MEMORY_SIZE, MemoryAllocType.MEM_COMMIT, protectType) {}
~CodeCave()
{
Dispose();
}
#endregion
#region Implementation of IDisposable
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
Win32.VirtualFreeEx(memoryHandle, allocatedMemory, allocSize, (uint) MemoryFreeType.MEM_RELEASE);
GC.SuppressFinalize(this);
}
#endregion
#region FASM Wrapper
/// <summary>
/// Gets the underlying ManagedFasm object. Use this only if you plan on adding a
/// reference to the Managed FASM DLL in your main project!
/// </summary>
/// <value>The get asm.</value>
/// 12/22/2008 11:04 PM
public ManagedFasm GetAsm { get { return fasm; } }
/// <summary>
/// Gets or sets the size of the memory allocated for the FASM object.
/// </summary>
/// <value>The size of the get asm memory.</value>
/// 12/22/2008 11:05 PM
public int GetAsmMemorySize { get { return fasm.GetMemorySize(); } set { fasm.SetMemorySize(value); } }
/// <summary>
/// Gets or sets the process handle the FASM object is set to use.
/// </summary>
/// <value>The get asm process handle.</value>
/// 12/22/2008 11:05 PM
public IntPtr GetAsmProcessHandle { get { return fasm.GetProcessHandle(); } set { fasm.SetProcessHandle(value); } }
/// <summary>
/// Gets or sets the get asm pass limit.
/// </summary>
/// <value>The get asm pass limit.</value>
/// 12/22/2008 11:06 PM
public int GetAsmPassLimit { get { return fasm.GetPassLimit(); } set { fasm.SetPassLimit(value); } }
#region AddLine
/// <summary>
/// Adds a line of ASM to the current FASM buffer.
/// </summary>
/// <param name="line">The line.</param>
/// <param name="args">The args.</param>
/// 12/22/2008 11:06 PM
public void AsmAddLine(string line, params object[] args)
{
fasm.AddLine(string.Format(line, args));
}
public void AsmAddLine(params string[] lines)
{
foreach (string line in lines)
{
fasm.AddLine(line);
}
}
public void AsmAddLine(IList<string> lines)
{
foreach (string line in lines)
{
fasm.AddLine(line);
}
}
public void AsmAddLine(IEnumerable<string> lines)
{
foreach (string line in lines)
{
fasm.AddLine(line);
}
}
#endregion
#region Add
public void AsmAdd(string asm, params object[] args)
{
fasm.Add(asm, args);
}
#endregion
#region Assemble
public byte[] AsmAssemble()
{
return fasm.Assemble();
}
#endregion
#region Clear
public void AsmClear()
{
fasm.Clear();
}
#endregion
#region Inject
public bool AsmInject()
{
return AsmInject(allocatedMemory);
}
public bool AsmInject(uint address)
{
// FASM EXECUTOR
return fasm.Inject(address);
}
#endregion
#region Inesert InsertLine
public void AsmInsertLine(int index, string line, params object[] args)
{
fasm.InsertLine(string.Format(line, args), index);
}
public void AsmInsert(int index, string asm, params object[] args)
{
fasm.Insert(string.Format(asm, args), index);
}
#endregion
#region AsmInjectAndExecute
#region No address/param
public uint AsmInjectAndExecute()
{
return AsmInjectAndExecute(allocatedMemory, 0);
}
public uint AsmInjectAndExecute(params string[] lines)
{
AsmAddLine(lines);
return AsmInjectAndExecute();
}
public uint AsmInjectAndExecute(IList<string> lines)
{
AsmAddLine(lines);
return AsmInjectAndExecute();
}
public uint AsmInjectAndExecute(IEnumerable<string> lines)
{
AsmAddLine(lines);
return AsmInjectAndExecute();
}
#endregion
#region Address
public uint AsmInjectAndExecute(uint address)
{
return AsmInjectAndExecute(address, 0);
}
public uint AsmInjectAndExecute(uint address, params string[] lines)
{
AsmAddLine(lines);
return AsmInjectAndExecute(address);
}
public uint AsmInjectAndExecute(uint address, IList<string> lines)
{
AsmAddLine(lines);
return AsmInjectAndExecute(address);
}
public uint AsmInjectAndExecute(uint address, IEnumerable<string> lines)
{
AsmAddLine(lines);
return AsmInjectAndExecute(address);
}
#endregion
#region Address and Parameter
public uint AsmInjectAndExecute(uint address, uint parameter)
{
// FASM EXECUTOR
return fasm.InjectAndExecute(memoryHandle, address, parameter);
}
public uint AsmInjectAndExecute(uint address, uint parameter, params string[] lines)
{
AsmAddLine(lines);
return AsmInjectAndExecute(address, parameter);
}
public uint AsmInjectAndExecute(uint address, uint parameter, IList<string> lines)
{
AsmAddLine(lines);
return AsmInjectAndExecute(address, parameter);
}
public uint AsmInjectAndExecute(uint address, uint parameter, IEnumerable<string> lines)
{
AsmAddLine(lines);
return AsmInjectAndExecute(address, parameter);
}
#endregion
#endregion
#region AsmInjectAndExecuteEx
#region No Params
public IntPtr AsmInjectAndExecuteEx()
{
return AsmInjectAndExecuteEx(allocatedMemory, 0);
}
public IntPtr AsmInjectAndExecuteEx(params string[] lines)
{
AsmAddLine(lines);
return AsmInjectAndExecuteEx();
}
public IntPtr AsmInjectAndExecuteEx(IList<string> lines)
{
AsmAddLine(lines);
return AsmInjectAndExecuteEx();
}
public IntPtr AsmInjectAndExecuteEx(IEnumerable<string> lines)
{
AsmAddLine(lines);
return AsmInjectAndExecuteEx();
}
#endregion
#region Address
public IntPtr AsmInjectAndExecuteEx(uint address)
{
return AsmInjectAndExecuteEx(address, 0);
}
public IntPtr AsmInjectAndExecuteEx(uint address, params string[] lines)
{
AsmAddLine(lines);
return AsmInjectAndExecuteEx(address);
}
public IntPtr AsmInjectAndExecuteEx(uint address, IList<string> lines)
{
AsmAddLine(lines);
return AsmInjectAndExecuteEx(address);
}
public IntPtr AsmInjectAndExecuteEx(uint address, IEnumerable<string> lines)
{
AsmAddLine(lines);
return AsmInjectAndExecuteEx(address);
}
#endregion
#region Address and Param
public IntPtr AsmInjectAndExecuteEx(uint address, uint parameter)
{
// FASM EXECUTOR
return fasm.InjectAndExecuteEx(memoryHandle, address, parameter);
}
public IntPtr AsmInjectAndExecuteEx(uint address, uint parameter, params string[] lines)
{
AsmAddLine(lines);
return AsmInjectAndExecuteEx(address, parameter);
}
public IntPtr AsmInjectAndExecuteEx(uint address, uint parameter, IList<string> lines)
{
AsmAddLine(lines);
return AsmInjectAndExecuteEx(address, parameter);
}
public IntPtr AsmInjectAndExecuteEx(uint address, uint parameter, IEnumerable<string> lines)
{
AsmAddLine(lines);
return AsmInjectAndExecuteEx(address, parameter);
}
#endregion
#endregion
#endregion
#region Read/Write Stuff
#region Read
/// <summary>
/// Reads the specified offsets. TODO: Add proper comments...
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="offsets">The offsets.</param>
/// <returns></returns>
/// 12/22/2008 6:41 PM
public T Read<T>(params uint[] offsets)
{
return mgr.Read<T>(offsets);
}
/// <summary>
/// Reads a string from memory. The default length is 255. (MAX_LEN in C++)
/// </summary>
/// <param name="address">The address to read the string from.</param>
/// <param name="ascii">if set to <c>true</c> the string will be read as an ASCII string. Otherwise it will be read as Unicode.</param>
/// <returns></returns>
/// 12/22/2008 4:42 PM
public string ReadString(uint address, bool ascii)
{
return mgr.ReadString(address, ascii);
}
/// <summary>
/// Reads a string from memory.
/// </summary>
/// <param name="address">The address to read the string from.</param>
/// <param name="ascii">if set to <c>true</c> the string will be read as an ASCII string. Otherwise it will be read as Unicode.</param>
/// <param name="length">The length of the string to read.</param>
/// <returns></returns>
/// 12/22/2008 4:43 PM
public string ReadString(uint address, bool ascii, int length)
{
return mgr.ReadString(address, ascii, length);
}
public byte[] ReadBytes(uint address, int size)
{
return mgr.ReadBytes(address, size);
}
#endregion
#region Write
public bool Write<T>(uint offset, T value)
{
return mgr.Write(offset, value);
}
/// <summary>
/// Writes a string to memory.
/// </summary>
/// <param name="address">The address to read the string from.</param>
/// <param name="value"></param>
/// <param name="ascii">if set to <c>true</c> the string will be written as an ASCII string. Otherwise it will be written as Unicode.</param>
/// <returns></returns>
/// 12/22/2008 4:42 PM
public bool WriteString(uint address, string value, bool ascii)
{
return mgr.WriteString(address, value, ascii);
}
/// <summary>
/// Writes a string to memory. This writes to the <see cref="AllocationAddress"/> of this <see cref="CodeCave"/>.
/// </summary>
/// <param name="value"></param>
/// <param name="ascii">if set to <c>true</c> the string will be written as an ASCII string. Otherwise it will be written as Unicode.</param>
/// <returns></returns>
/// 12/22/2008 4:42 PM
public bool WriteString(string value, bool ascii)
{
return mgr.WriteString(allocatedMemory, value, ascii);
}
public bool WriteBytes(uint address, byte[] value)
{
return mgr.WriteBytes(address, value);
}
#endregion
#endregion
}
}
Properly laid out Win32 enums/structs.
Code:
using System;
using System.Runtime.InteropServices;
namespace Voodoo.Native
{
/// <summary>
/// Values to gain required access to process or thread.
/// </summary>
[Flags]
public enum AccessRights : uint
{
/// <summary>
/// Standard rights required to mess with an object's security descriptor, change, or delete the object.
/// </summary>
STANDARD_RIGHTS_REQUIRED = 0x000F0000,
/// <summary>
/// The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state. Some object types do not support this access right.
/// </summary>
SYNCHRONIZE = 0x00100000,
/// <summary>
/// Required to terminate a process using TerminateProcess.
/// </summary>
PROCESS_TERMINATE = 0x0001,
/// <summary>
/// Required to create a thread.
/// </summary>
PROCESS_CREATE_THREAD = 0x0002,
//public const uint PROCESS_SET_SESSIONID = 0x0004,
/// <summary>
/// Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory).
/// </summary>
PROCESS_VM_OPERATION = 0x0008,
/// <summary>
/// Required to read memory in a process using ReadProcessMemory.
/// </summary>
PROCESS_VM_READ = 0x0010,
/// <summary>
/// Required to write memory in a process using WriteProcessMemory.
/// </summary>
PROCESS_VM_WRITE = 0x0020,
/// <summary>
/// Required to duplicate a handle using DuplicateHandle.
/// </summary>
PROCESS_DUP_HANDLE = 0x0040,
/// <summary>
/// Required to create a process.
/// </summary>
PROCESS_CREATE_PROCESS = 0x0080,
/// <summary>
/// Required to set memory limits using SetProcessWorkingSetSize.
/// </summary>
PROCESS_SET_QUOTA = 0x0100,
/// <summary>
/// Required to set certain information about a process, such as its priority class (see SetPriorityClass).
/// </summary>
PROCESS_SET_INFORMATION = 0x0200,
/// <summary>
/// Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken, GetExitCodeProcess, GetPriorityClass, and IsProcessInJob).
/// </summary>
PROCESS_QUERY_INFORMATION = 0x0400,
/// <summary>
/// Required to suspend or resume a process.
/// </summary>
PROCESS_SUSPEND_RESUME = 0x0800,
/// <summary>
/// Required to retrieve certain information about a process (see QueryFullProcessImageName). A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted PROCESS_QUERY_LIMITED_INFORMATION.
/// </summary>
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000,
/// <summary>
/// All possible access rights for a process object. (Windows Vista/Server 2k8 Specific)
/// </summary>
PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF,
/// <summary>
/// All possible access rights for a process object. (Windows XP specific)
/// </summary>
PROCESS_ALL_ACCESS_WINXP = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x001F0FFF,
/// <summary>
/// Required to terminate a thread using TerminateThread.
/// </summary>
THREAD_TERMINATE = 0x0001,
/// <summary>
/// Required to suspend or resume a thread.
/// </summary>
THREAD_SUSPEND_RESUME = 0x0002,
/// <summary>
/// Required to read the context of a thread using GetThreadContext
/// </summary>
THREAD_GET_CONTEXT = 0x0008,
/// <summary>
/// Required to set the context of a thread using SetThreadContext
/// </summary>
THREAD_SET_CONTEXT = 0x0010,
/// <summary>
/// Required to read certain information from the thread object, such as the exit code (see GetExitCodeThread).
/// </summary>
THREAD_QUERY_INFORMATION = 0x0040,
/// <summary>
/// Required to set certain information in the thread object.
/// </summary>
THREAD_SET_INFORMATION = 0x0020,
/// <summary>
/// Required to set the impersonation token for a thread using SetThreadToken.
/// </summary>
THREAD_SET_THREAD_TOKEN = 0x0080,
/// <summary>
/// Required to use a thread's security information directly without calling it by using a communication mechanism that provides impersonation services.
/// </summary>
THREAD_IMPERSONATE = 0x0100,
/// <summary>
/// Required for a server thread that impersonates a client.
/// </summary>
THREAD_DIRECT_IMPERSONATION = 0x0200,
/// <summary>
/// All possible access rights for a thread object.
/// </summary>
THREAD_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF
}
/// <summary>
/// Values that determine how memory is allocated.
/// </summary>
[Flags]
public enum MemoryAllocType
{
/// <summary>
/// Allocates physical storage in memory or in the paging file on disk for the specified reserved memory pages. The function initializes the memory to zero.
///
///To reserve and commit pages in one step, call VirtualAllocEx with MEM_COMMIT | MEM_RESERVE.
///
///The function fails if you attempt to commit a page that has not been reserved. The resulting error code is ERROR_INVALID_ADDRESS.
///
///An attempt to commit a page that is already committed does not cause the function to fail. This means that you can commit pages without first determining the current commitment state of each page.
/// </summary>
MEM_COMMIT = 0x00001000,
/// <summary>
/// Reserves a range of the process's virtual address space without allocating any actual physical storage in memory or in the paging file on disk.
///
///You commit reserved pages by calling VirtualAllocEx again with MEM_COMMIT.
/// </summary>
MEM_RESERVE = 0x00002000,
/// <summary>
/// Indicates that data in the memory range specified by lpAddress and dwSize is no longer of interest. The pages should not be read from or written to the paging file. However, the memory block will be used again later, so it should not be decommitted. This value cannot be used with any other value.
///
///Using this value does not guarantee that the range operated on with MEM_RESET will contain zeroes. If you want the range to contain zeroes, decommit the memory and then recommit it.
/// </summary>
MEM_RESET = 0x00080000,
/// <summary>
/// Reserves an address range that can be used to map Address Windowing Extensions (AWE) pages.
///
///This value must be used with MEM_RESERVE and no other values.
/// </summary>
MEM_PHYSICAL = 0x00400000,
/// <summary>
/// Allocates memory at the highest possible address.
/// </summary>
MEM_TOP_DOWN = 0x00100000
}
/// <summary>
/// Values that determine how a block of memory is protected.
/// </summary>
[Flags]
public enum MemoryProtectType
{
/// <summary>
/// Enables execute access to the committed region of pages. An attempt to read or write to the committed region results in an access violation.
/// </summary>
PAGE_EXECUTE = 0x10,
/// <summary>
/// Enables execute and read access to the committed region of pages. An attempt to write to the committed region results in an access violation.
/// </summary>
PAGE_EXECUTE_READ = 0x20,
/// <summary>
/// Enables execute, read, and write access to the committed region of pages.
/// </summary>
PAGE_EXECUTE_READWRITE = 0x40,
/// <summary>
/// Enables execute, read, and write access to the committed region of image file code pages. The pages are shared read-on-write and copy-on-write.
/// </summary>
PAGE_EXECUTE_WRITECOPY = 0x80,
/// <summary>
/// Disables all access to the committed region of pages. An attempt to read from, write to, or execute the committed region results in an access violation exception, called a general protection (GP) fault.
/// </summary>
PAGE_NOACCESS = 0x01,
/// <summary>
/// Enables read access to the committed region of pages. An attempt to write to the committed region results in an access violation. If the system differentiates between read-only access and execute access, an attempt to execute code in the committed region results in an access violation.
/// </summary>
PAGE_READONLY = 0x02,
/// <summary>
/// Enables both read and write access to the committed region of pages.
/// </summary>
PAGE_READWRITE = 0x04,
/// <summary>
/// Gives copy-on-write protection to the committed region of pages.
/// </summary>
PAGE_WRITECOPY = 0x08,
/// <summary>
///Pages in the region become guard pages. Any attempt to access a guard page causes the system to raise a STATUS_GUARD_PAGE_VIOLATION exception and turn off the guard page status. Guard pages thus act as a one-time access alarm. For more information, see Creating Guard Pages.
///
///When an access attempt leads the system to turn off guard page status, the underlying page protection takes over.
///
///If a guard page exception occurs during a system service, the service typically returns a failure status indicator.
///
///This value cannot be used with PAGE_NOACCESS.
/// </summary>
PAGE_GUARD = 0x100,
/// <summary>
/// Does not allow caching of the committed regions of pages in the CPU cache. The hardware attributes for the physical memory should be specified as "no cache." This is not recommended for general usage. It is useful for device drivers, for example, mapping a video frame buffer with no caching.
///
///This value cannot be used with PAGE_NOACCESS.
/// </summary>
PAGE_NOCACHE = 0x200,
/// <summary>
/// Enables write-combined memory accesses. When enabled, the processor caches memory write requests to optimize performance. Thus, if two requests are made to write to the same memory address, only the more recent write may occur.
///
///Note that the PAGE_GUARD and PAGE_NOCACHE flags cannot be specified with PAGE_WRITECOMBINE. If an attempt is made to do so, the SYSTEM_INVALID_PAGE_PROTECTION NT error code is returned by the function.
/// </summary>
PAGE_WRITECOMBINE = 0x400,
}
/// <summary>
/// Values that determine how a block of memory is freed.
/// </summary>
[Flags]
public enum MemoryFreeType
{
/// <summary>
/// Decommits the specified region of committed pages. After the operation, the pages are in the reserved state.
///
///The function does not fail if you attempt to decommit an uncommitted page. This means that you can decommit a range of pages without first determining their current commitment state.
///
///Do not use this value with MEM_RELEASE.
/// </summary>
MEM_DECOMMIT = 0x4000,
/// <summary>
/// Releases the specified region of pages. After the operation, the pages are in the free state.
///
/// If you specify this value, dwSize must be 0 (zero), and lpAddress must point to the base address returned by the VirtualAllocEx function when the region is reserved. The function fails if either of these conditions is not met.
///
/// If any pages in the region are committed currently, the function first decommits, and then releases them.
///
/// The function does not fail if you attempt to release pages that are in different states, some reserved and some committed. This means that you can release a range of pages without first determining the current commitment state.
///
/// Do not use this value with MEM_DECOMMIT.
/// </summary>
MEM_RELEASE = 0x8000
}
/// <summary>
/// Values which determine the state or creation-state of a thread.
/// </summary>
[Flags]
public enum ThreadFlags
{
/// <summary>
/// The thread will execute immediately.
/// </summary>
THREAD_EXECUTE_IMMEDIATELY = 0,
/// <summary>
/// The thread will be created in a suspended state. Use ResumeThread to resume the thread.
/// </summary>
CREATE_SUSPENDED = 0x04,
/// <summary>
/// The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the commit size.
/// </summary>
STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000,
/// <summary>
/// The thread is still active.
/// </summary>
STILL_ACTIVE = 259,
}
/// <summary>
/// Values that determine the wait status of an object (thread, mutex, event, etc.).
/// </summary>
public enum WaitValues : uint
{
/// <summary>
/// The object is in a signaled state.
/// </summary>
WAIT_OBJECT_0 = 0x00000000,
/// <summary>
/// The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.
/// </summary>
WAIT_ABANDONED = 0x00000080,
/// <summary>
/// The time-out interval elapsed, and the object's state is nonsignaled.
/// </summary>
WAIT_TIMEOUT = 0x00000102,
/// <summary>
/// The wait has failed.
/// </summary>
WAIT_FAILED = 0xFFFFFFFF,
/// <summary>
/// Wait an infinite amount of time for the object to become signaled.
/// </summary>
INFINITE = 0xFFFFFFFF,
}
/// <summary>
/// Determines which registers are returned or set when using GetThreadContext or SetThreadContext.
/// </summary>
public enum CONTEXT_FLAGS
{
/// <summary>
/// DO NOT USE! For internal context settings!
/// </summary>
CONTEXT_i386 = 0x00010000,
/// <summary>
/// SS:SP, CS:IP, FLAGS, BP
/// </summary>
CONTEXT_CONTROL = (CONTEXT_i386 | 0x01),
/// <summary>
/// AX, BX, CX, DX, SI, DI
/// </summary>
CONTEXT_INTEGER = (CONTEXT_i386 | 0x02),
/// <summary>
/// DS, ES, FS, GS
/// </summary>
CONTEXT_SEGMENTS = (CONTEXT_i386 | 0x04),
/// <summary>
/// 387 state
/// </summary>
CONTEXT_FLOATING_POINT = (CONTEXT_i386 | 0x08),
/// <summary>
/// DB 0-3,6,7
/// </summary>
CONTEXT_DEBUG_REGISTERS = (CONTEXT_i386 | 0x10),
/// <summary>
/// cpu specific extensions
/// </summary>
CONTEXT_EXTENDED_REGISTERS = (CONTEXT_i386 | 0x20),
/// <summary>
/// Everything but extended information and debug registers.
/// </summary>
CONTEXT_FULL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS),
/// <summary>
/// Everything.
/// </summary>
CONTEXT_ALL = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS |
CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS |
CONTEXT_EXTENDED_REGISTERS),
}
}
And a quickie property for getting/setting the current working process' MainWindowTitle. (Note, you'll need the SendMessage stuff. That's what Sender is. Just a wrapper around SendMessage)
Code:
/// <summary>
/// Gets or sets the main window title of the process.
/// (Note: if the process' MainWindowHandle == IntPtr.Zero, setting this property does nothing!)
/// </summary>
/// <value>The main window title.</value>
/// 12/22/2008 4:46 PM
public string MainWindowTitle
{
get { return WorkingProcess.MainWindowTitle; }
set
{
if (WorkingProcess.MainWindowTitle != value && WorkingProcess.MainWindowHandle != IntPtr.Zero)
{
StringBuilder sb = new StringBuilder(value);
Sender.SendMessage(WorkingProcess.MainWindowHandle, (int) SendMessageParam.WM_SETTEXT, IntPtr.Zero, sb);
}
}
}
Quick SendMessage class and whatnot.
Code:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
namespace Voodoo.Native.SendMessageAPI
{
[StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
internal class Sender
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, StringBuilder lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, String lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
internal static extern void SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref RECT lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref Point lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
}
}
Enjoy folks.