Using ReadProcessMemory with process module base address and offsets - c#

How does one read memory using a process module's base address and offsets? I have grabbed the desired module's base address with the following:
Process process = Process.GetProcessesByName("process")[0];
ProcessModule bClient;
ProcessModuleCollection bModules = process.Modules;
IntPtr processHandle = OpenProcess(0x10, false, process.Id);
int firstOffset = 0xA4C58C;
int anotherOffset = 0xFC;
for (int i = 0; i < bModules.Count; i++)
{
bClient = bModules[i];
if (bClient.ModuleName == "module.dll")
{
IntPtr baseAddress = bClient.BaseAddress;
Console.WriteLine("Base address: " + baseAddress);
}
}
After that I added the first offset to the base address:
IntPtr firstPointer = IntPtr.Add(baseAddress, (int)firstOffset);
This gives me a pointer; 440911244 in this case.
I can use this pointer in Cheat Engine, for instance, to browse its memory region and find the value to which the anotherPointer points to but I don't find the proper way to add the offset to firstPointer, however.
My question is, do I have to use ReadProcessMemory just before adding the final anotherOffset to the pointer? If so, what is the proper way of using it in this case?
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
IntPtr lpBuffer,
int dwSize,
out IntPtr lpNumberOfBytesRead);

Change the ReadProcessMemory lpBuffer paramater to:
byte[] lpBuffer,
then
byte[] buffer = new byte[sizeof(float)];
IntPtr bytesRead = IntPtr.Zero;
IntPtr readAddress = IntPtr.Add(baseAddress, firstOffset);
readAddress = IntPtr.Add(readAddress, anotherOffset)
ReadProcessMemory(processHandle, readAddress, buffer, buffer.Length, out bytesRead);
float value = BitConverter.ToSingle(buffer, 0);

Related

C# - Accessing Raw Sectors in high offset (over 4G) on external HDD

I am using in my program "Kernel32.dll" functionality to access raw disk sectors on WinXP SP3 OS (external HDD).
Everything works fine till the program reaches sector number 8388607 - which means the bytes offset in SetFilePointer exceeds 32 bit (uint!).
But my code, as below, uses all variables as "long". What I am doing wrong?
The code (on "Dump" button click):
int drive = DRV.SelectedIndex; // DRV is the drive combo box
long bps = BytesPerSector(drive), spt = GetTotalSectors(drive);
string dr = DRV.SelectedItem.ToString();
int moveToHigh, read = 0;
uint GENERIC_READ = 0x80000000;
uint OPEN_EXISTING = 3;
SafeFileHandle handleValue = CreateFile(dr, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (handleValue.IsInvalid)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
// idx = Loop starting index
// FS = The starting sector index
// TS = The final sector index
long idx = (FS == -1) ? 0 : FS, tot = (TS == -1) ? spt : TS;
for ( ; idx < tot; idx++)
{
byte[] b = new byte[bps];
// HERE IS THE ISSUE!!!
SetFilePointer(handleValue, idx*bps), out moveToHigh, EMoveMethod.Current);
if (ReadFile(handleValue, b, bps, out read, IntPtr.Zero) == 0)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
if (this.IsDisposed == true) { handleValue.Close(); break; }
Application.DoEvents();
}
handleValue.Close();
The kernel32.dll external functions:
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint SetFilePointer(
[In] SafeFileHandle hFile,
[In] long lDistanceToMove,
[Out] out int lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32", SetLastError = true)]
internal extern static int ReadFile(SafeFileHandle handle, byte[] bytes,
int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);
I have tried many things, but no idea what is wrong, application just ending up with a fatal exception asking to send bug report
Thanks a lot
Your P/Invoke definition is wrong. The function takes a 32bit value in but you defined it as a 64bit value. It won't work properly and definitely not past the value range of 32bit variables.
See the definition and example on how to use at pinvoke.net:
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int SetFilePointer(IntPtr handle, int lDistanceToMove, out int lpDistanceToMoveHigh, uint dwMoveMethod);
int lo = (int)(offset & 0xffffffff);
int hi = (int)(offset >> 32);
lo = SetFilePointer(handle, lo, out hi, moveMethod);
So you need to split the 64bit value in two and provide both parts for the function.
Also don't use doubles for integers. You will get into trouble when the accuracy ends and there is no reason to use them.

Read memory with module base address

How can I read a memory with module base address?
For example how can I read this memory: "winCap64.dll"+0x123456 + offsets.
I have added an example code of what I could produce after some research but I still cant read anything in C#. However the addresses are absolutely fine since they return me the correct value when I add them on Cheat Engine.
Edit: added samle code
[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Boolean bInheritHandle, UInt32 dwProcessId);
[DllImport("kernel32.dll")]
static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
byte[] lpBuffer, UIntPtr nSize, uint lpNumberOfBytesWritten);
static IntPtr Handle;
static void Main(string[] args)
{
Process[] Processes = Process.GetProcessesByName("process");
Process nProcess = Processes[0];
Handle = OpenProcess(0x10, false, (uint)nProcess.Id);
IntPtr pointer = IntPtr.Add(nProcess.Modules[125].BaseAddress, 0x020C5150);
int curhp = ReadOffset(pointer, 0x4D8);
int curhp2 = ReadOffset((IntPtr)curhp, 0x0);
int curhp3 = ReadOffset((IntPtr)curhp2, 0x1c0);
Console.WriteLine(curhp3.ToString());
Console.ReadKey();
}
public static int ReadOffset(IntPtr pointer, uint offset)
{
byte[] bytes = new byte[24];
uint adress = (uint)ReadPointer(pointer) + offset;
ReadProcessMemory(Handle, (IntPtr)adress, bytes, (UIntPtr)sizeof(int), 0);
return BitConverter.ToInt32(bytes, 0);
}
public static int ReadPointer(IntPtr pointer)
{
byte[] bytes = new byte[24];
ReadProcessMemory(Handle, pointer, bytes, (UIntPtr)sizeof(int), 0);
return BitConverter.ToInt32(bytes, 0);
}
How about something like this?
IntPtr pointer = IntPtr.Add(nProcess.Modules[125].BaseAddress, BaseAddress);
Console.WriteLine("Final: " + pointer.ToString("X"));
int hp = ReadInt32(pointer, Handle);
string hexPrefix = "80" + hp.ToString("X"); //because int32 will cut some digits. I sugget using int64. Even UInt64.
long hexToint = long.Parse(hexPrefix, NumberStyles.HexNumber);
hp = ReadInt32((IntPtr)hexToint + 0x00, Handle);
hexPrefix = "80" + hp.ToString("X");
hexToint = long.Parse(hexPrefix, NumberStyles.HexNumber);
hp = ReadInt32((IntPtr)hexToint + 0x1c0, Handle);
hexPrefix = "80" + hp.ToString("X");
hexToint = long.Parse(hexPrefix, NumberStyles.HexNumber);
hp = ReadInt32((IntPtr)hexToint + 0x0, Handle);
IntPtr is the architecture agnostic way to store a pointer and pass it around, say to ReadProcessMemory:
IntPtr pointer = IntPtr.Add(nProcess.Modules[125].BaseAddress, 0x02093458);

How to call a CPU instruction from C#?

My processor (Intel i7) supports the POPCNT instruction and I would like to call it from my C# application. Is this possible?
I believe I read somewhere that it isn't, but the JIT will invoke it if it finds it available but what function would I have to call that may be substituted with such an instruction?
Popcount is being called millions of times in a loop so I'd like to be able to have this CPU optimization if possible.
You want to play with fire, and here we like to play with fire...
class Program
{
const uint PAGE_EXECUTE_READWRITE = 0x40;
const uint MEM_COMMIT = 0x1000;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
private delegate int IntReturner();
static void Main(string[] args)
{
List<byte> bodyBuilder = new List<byte>();
bodyBuilder.Add(0xb8); // MOV EAX,
bodyBuilder.AddRange(BitConverter.GetBytes(42)); // 42
bodyBuilder.Add(0xc3); // RET
byte[] body = bodyBuilder.ToArray();
IntPtr buf = VirtualAlloc(IntPtr.Zero, (IntPtr)body.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(body, 0, buf, body.Length);
IntReturner ptr = (IntReturner)Marshal.GetDelegateForFunctionPointer(buf, typeof(IntReturner));
Console.WriteLine(ptr());
}
}
(this small example of assembly will simply return 42... I think it's the perfect number for this answer :-) )
In the end the trick is that:
A) You must know the opcodes corresponding to the asm you want to write
B) You use VirtualAlloc to make a page of memory executable
C) In some way you copy your opcodes there
(the code was taken from http://www.cnblogs.com/netact/archive/2013/01/10/2855448.html)
Ok... the other one was as written on the site (minus an error on the uint -> IntPtr dwSize), this one is how it should be written (or at least it's a +1 compared to the original... I would encapsulate everything in a IDisposable class instead of using try... finally)
class Program
{
const uint PAGE_READWRITE = 0x04;
const uint PAGE_EXECUTE = 0x10;
const uint MEM_COMMIT = 0x1000;
const uint MEM_RELEASE = 0x8000;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);
private delegate int IntReturner();
static void Main(string[] args)
{
List<byte> bodyBuilder = new List<byte>();
bodyBuilder.Add(0xb8); // MOV EAX,
bodyBuilder.AddRange(BitConverter.GetBytes(42)); // 42
bodyBuilder.Add(0xc3); // RET
byte[] body = bodyBuilder.ToArray();
IntPtr buf = IntPtr.Zero;
try
{
// We VirtualAlloc body.Length bytes, with R/W access
// Note that from what I've read, MEM_RESERVE is useless
// if the first parameter is IntPtr.Zero
buf = VirtualAlloc(IntPtr.Zero, (IntPtr)body.Length, MEM_COMMIT, PAGE_READWRITE);
if (buf == IntPtr.Zero)
{
throw new Win32Exception();
}
// Copy our instructions in the buf
Marshal.Copy(body, 0, buf, body.Length);
// Change the access of the allocated memory from R/W to Execute
uint oldProtection;
bool result = VirtualProtect(buf, (IntPtr)body.Length, PAGE_EXECUTE, out oldProtection);
if (!result)
{
throw new Win32Exception();
}
// Create a delegate to the "function"
// Sadly we can't use Funct<int>
var fun = (IntReturner)Marshal.GetDelegateForFunctionPointer(buf, typeof(IntReturner));
Console.WriteLine(fun());
}
finally
{
if (buf != IntPtr.Zero)
{
// Free the allocated memory
bool result = VirtualFree(buf, IntPtr.Zero, MEM_RELEASE);
if (!result)
{
throw new Win32Exception();
}
}
}
}
}

c# readprocessmemory with Cheat Engine

I'm trying to get string value from address which i found using cheat engine. I found for example 0x01742A38 and this is main part of my program (regular windows form application):
Process[] processes = Process.GetProcessesByName("Tibia");
foreach (Process p in processes)
{
IntPtr windowHandle = p.MainWindowHandle;
byte[] bufor = new byte[50];
uint baseAddress = (uint)p.MainModule.BaseAddress.ToInt32();
IntPtr addr = ((IntPtr)(baseAddress + 0x01742A38));
uint o = 0;
UInt32 k = 30;
if (ReadProcessMemory(windowHandle, addr, bufor, k, ref o))
{
label3.Text = "Success!";
}
else
{
label3.Text = "Fail : (";
}
}
Assuming your static address is correct, you have to open the target process using the OpenProcess function with at least the right PROCESS_VM_READ (0x0010).
I also suggest you to use a more suitable pinvoke signature for the function ReadProcessMemory:
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead);

Why does my C#/pinvoke DeviceIoControl call return 0 bytes read with garbage data?

I have an unmanaged C++ Windows console app that works fine. I want it in C#. I have done DllImport statements for the necessary Kernel32.dll symbols:
[StructLayout(LayoutKind.Sequential)]
internal struct DiskGeometry
{
public long Cylinders;
public int MediaType;
public int TracksPerCylinder;
public int SectorsPerTrack;
public int BytesPerSector;
}
internal static class NativeMethods
{
internal const uint FileAccessGenericRead = 0x80000000;
internal const uint FileShareWrite = 0x2;
internal const uint FileShareRead = 0x1;
internal const uint CreationDispositionOpenExisting = 0x3;
internal const uint IoCtlDiskGetDriveGeometry = 0x70000;
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern SafeFileHandle CreateFile(
string fileName,
uint fileAccess,
uint fileShare,
IntPtr securityAttributes,
uint creationDisposition,
uint flags,
IntPtr template);
[DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
public static extern int DeviceIoControl(
SafeFileHandle device,
uint controlCode,
IntPtr inBuffer,
uint inBufferSize,
IntPtr outBuffer,
uint outBufferSize,
ref uint bytesReturned,
IntPtr overlapped);
}
I then have the following application code:
public static void Main()
{
SafeFileHandle diskHandle = NativeMethods.CreateFile(
"\\\\.\\PhysicalDrive0",
NativeMethods.FileAccessGenericRead,
NativeMethods.FileShareWrite | NativeMethods.FileShareRead,
IntPtr.Zero,
NativeMethods.CreationDispositionOpenExisting,
0,
IntPtr.Zero);
if (diskHandle.IsInvalid)
{
Console.WriteLine("CreateFile failed with error: {0}", Marshal.GetLastWin32Error());
return;
}
int geometrySize = Marshal.SizeOf(typeof(DiskGeometry));
Console.WriteLine("geometry size = {0}", geometrySize);
IntPtr geometryBlob = Marshal.AllocHGlobal(geometrySize);
uint numBytesRead = 0;
if (0 == NativeMethods.DeviceIoControl(
diskHandle,
NativeMethods.IoCtlDiskGetDriveGeometry,
IntPtr.Zero,
0,
geometryBlob,
(uint)geometrySize,
ref numBytesRead,
IntPtr.Zero))
{
Console.WriteLine("DeviceIoControl failed with error: {0}", Marshal.GetLastWin32Error());
return;
}
Console.WriteLine("Bytes read = {0}", numBytesRead);
DiskGeometry geometry = (DiskGeometry)Marshal.PtrToStructure(geometryBlob, typeof(DiskGeometry));
Marshal.FreeHGlobal(geometryBlob);
long bytesPerCylinder = (long)geometry.TracksPerCylinder * (long)geometry.SectorsPerTrack * (long)geometry.BytesPerSector;
long totalSize = geometry.Cylinders * bytesPerCylinder;
Console.WriteLine("Media Type: {0}", geometry.MediaType);
Console.WriteLine("Cylinders: {0}", geometry.Cylinders);
Console.WriteLine("Tracks per Cylinder: {0}", geometry.TracksPerCylinder);
Console.WriteLine("Sectors per Track: {0}", geometry.SectorsPerTrack);
Console.WriteLine("Bytes per Sector: {0}", geometry.BytesPerSector);
Console.WriteLine("Bytes per Cylinder: {0}", bytesPerCylinder);
Console.WriteLine("Total disk space: {0}", totalSize);
}
My C# app prints "Bytes read = 0" and the geometry member values are garbage. I am certainly no expert on DllImport and marshaling. Please help me understand what I am doing wrong. If I change the fifth parameter to DeviceIoControl to be "ref DiskGeometry" and just pass in one created right before the call (instead of IntPtr and alloc), all printed geometry member values are 0.
You have mistype, try this:
internal const uint IoCtlDiskGetDriveGeometry = 0x70000;
Try using one of those signatures for the DllImport: http://pinvoke.net/default.aspx/kernel32.DeviceIoControl

Categories

Resources