using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Threading; using System.Runtime.InteropServices; using RomCheater.Logging; using RomCheater.Core; using System.IO; namespace Sojaner.MemoryScanner { // code borrowed from: http://www.codeproject.com/KB/cs/sojaner_memory_scanner.aspx #region ProcessMemoryReader class //Thanks goes to Arik Poznanski for P/Invokes and methods needed to read and write the Memory //For more information refer to "Minesweeper, Behind the scenes" article by Arik Poznanski at Codeproject.com public class ProcessMemoryReader { public ProcessMemoryReader() { } /// /// Process from which to read /// public Process ReadProcess { get { return m_ReadProcess; } set { m_ReadProcess = value; } } private Process m_ReadProcess = null; private static IntPtr m_hProcess = IntPtr.Zero; public void OpenProcess() { // m_hProcess = ProcessMemoryReaderApi.OpenProcess(ProcessMemoryReaderApi.PROCESS_VM_READ, 1, (uint)m_ReadProcess.Id); ProcessMemoryReaderApi.ProcessAccessType access; access = ProcessMemoryReaderApi.ProcessAccessType.PROCESS_VM_READ | ProcessMemoryReaderApi.ProcessAccessType.PROCESS_VM_WRITE | ProcessMemoryReaderApi.ProcessAccessType.PROCESS_VM_OPERATION; m_hProcess = ProcessMemoryReaderApi.OpenProcess((uint)access, 1, (uint)m_ReadProcess.Id); } public void CloseHandle() { try { int iRetValue; iRetValue = ProcessMemoryReaderApi.CloseHandle(m_hProcess); if (iRetValue == 0) { throw new Exception("CloseHandle failed"); } } catch (Exception ex) { //System.Windows.Forms.MessageBox.Show(ex.Message, "error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning); throw ex; } } #region WriteProcessMemoryToFile public bool WriteProcessMemoryToFile(string filename, uint MemoryAddress, uint bytesToRead, out int bytesRead) { RamDumper dumper = new RamDumper(); return dumper.DumpMemoryToFile(ReadProcess, filename, MemoryAddress, bytesToRead, out bytesRead); } #endregion #region ReadProcessMemory public byte[] ReadProcessMemory(uint MemoryAddress, uint bytesToRead, out int bytesRead) { RamDumper dumper = new RamDumper(); return dumper.DumpMemoryToByteArray(ReadProcess, MemoryAddress, bytesToRead, out bytesRead); } #endregion #region WriteProcessMemory public void WriteProcessMemory(UIntPtr MemoryAddress, byte byteToWrite, out int bytesWritten) { WriteProcessMemory(MemoryAddress, new byte[] { byteToWrite }, out bytesWritten); } public void WriteProcessMemory(UIntPtr MemoryAddress, byte[] bytesToWrite, out int bytesWritten) { IntPtr ptrBytesWritten; ProcessMemoryReaderApi.WriteProcessMemory(m_hProcess, MemoryAddress, bytesToWrite, (uint)bytesToWrite.Length, out ptrBytesWritten); bytesWritten = ptrBytesWritten.ToInt32(); } #endregion #region RamDumper private interface IRamDumper { bool DumpMemoryToFile(Process ppid, string filename, uint MemoryAddress, uint bytesToRead, out int bytesRead); byte[] DumpMemoryToByteArray(Process ppid, uint MemoryAddress, uint bytesToRead, out int bytesRead); } private class RamDumper : IRamDumper { public RamDumper() { } private void InitMemoryDump(out uint byte_alignment) { byte_alignment = 102400; // get memory in 100mb chunks } #region IRamDumper members #region DumpMemoryToFile public bool DumpMemoryToFile(Process ppid, string filename, uint MemoryAddress, uint bytesToRead, out int bytesRead) { //logger.Info.WriteLine("Dumping memory (0x{0:x8}-0x{1:x8}) from pid=({3}) to file {2}", MemoryAddress, MemoryAddress + bytesToRead, filename, string.Format("0x{0:x4} {1}.exe", ppid.Id, ppid.ProcessName)); bytesRead = 0; uint byte_alignment = 0; // get common init parameters InitMemoryDump(out byte_alignment); uint address = MemoryAddress; uint _bytesToRead = bytesToRead; byte[] buffer = new byte[] { }; try { FileInfo fi = new FileInfo(filename); if (fi.Exists) fi.Delete(); using (FileStream fs = new FileStream(filename, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.ReadWrite)) { BinaryWriter bw = new BinaryWriter(fs); //foreach (byte b in data) { bw.Write(b); } for (uint i = 0; i <= bytesToRead; ) { if (_bytesToRead < byte_alignment) { _bytesToRead = bytesToRead; buffer = new byte[_bytesToRead]; } else { _bytesToRead = byte_alignment; buffer = new byte[byte_alignment]; } IntPtr ptrBytesRead; ProcessMemoryReader.ProcessMemoryReaderApi.ReadProcessMemory(m_hProcess, (UIntPtr)address, buffer, _bytesToRead, out ptrBytesRead); bytesRead = ptrBytesRead.ToInt32(); bw.Write(buffer); bw.Flush(); if (_bytesToRead < byte_alignment) { i += _bytesToRead; address += _bytesToRead; } else { i += byte_alignment; address += byte_alignment; } } bw.Close(); } logger.Info.WriteLine("Succefully dumped memory (0x{0:x8}-0x{1:x8}) from pid=({3}) to file {2}", MemoryAddress, MemoryAddress + bytesToRead, filename, string.Format("0x{0:x4} {1}.exe", ppid.Id, ppid.ProcessName)); return true; } catch (OutOfMemoryException ex) { logger.Error.WriteLine("Failed to dump memory (0x{0:x8}-0x{1:x8}) from pid=({3}) to file {2}", MemoryAddress, MemoryAddress + bytesToRead, filename, string.Format("0x{0:x4} {1}.exe", ppid.Id, ppid.ProcessName)); logger.Error.WriteLine("DumpMemory(): OutOfMemoryException"); logger.Error.WriteLine(ex.ToString()); } catch (Exception ex) { logger.Error.WriteLine("Failed to dump memory (0x{0:x8}-0x{1:x8}) from pid=({3}) to file {2}", MemoryAddress, MemoryAddress + bytesToRead, filename, string.Format("0x{0:x4} {1}.exe", ppid.Id, ppid.ProcessName)); logger.Error.WriteLine("DumpMemory(): Exception"); logger.Error.WriteLine(ex.ToString()); } return false; } #endregion #region DumpMemoryToByteArray public byte[] DumpMemoryToByteArray(Process ppid, uint MemoryAddress, uint bytesToRead, out int bytesRead) { //logger.Info.WriteLine("Dumping memory (0x{0:x8}-0x{1:x8}) from pid=({2})", MemoryAddress, MemoryAddress + bytesToRead, string.Format("0x{0:x4} {1}.exe", ppid.Id, ppid.ProcessName)); bytesRead = 0; uint byte_alignment = 0; // get common init parameters InitMemoryDump(out byte_alignment); uint address = MemoryAddress; uint _bytesToRead = bytesToRead; byte[] buffer = new byte[] { }; try { using (MemoryStream ms = new MemoryStream()) { BinaryWriter bw = new BinaryWriter(ms); //foreach (byte b in data) { bw.Write(b); } for (uint i = 0; i <= bytesToRead; ) { if (_bytesToRead < byte_alignment) { _bytesToRead = bytesToRead; buffer = new byte[_bytesToRead]; } else { _bytesToRead = byte_alignment; buffer = new byte[byte_alignment]; } IntPtr ptrBytesRead; ProcessMemoryReader.ProcessMemoryReaderApi.ReadProcessMemory(m_hProcess, (UIntPtr)address, buffer, _bytesToRead, out ptrBytesRead); bytesRead = ptrBytesRead.ToInt32(); bw.Write(buffer); bw.Flush(); if (_bytesToRead < byte_alignment) { i += _bytesToRead; address += _bytesToRead; } else { i += byte_alignment; address += byte_alignment; } } bw.Close(); return ms.ToArray(); } //logger.Info.WriteLine("Succefully dumped memory (0x{0:x8}-0x{1:x8}) from pid=({2})", MemoryAddress, MemoryAddress + bytesToRead, string.Format("0x{0:x4} {1}.exe", ppid.Id, ppid.ProcessName)); } catch (OutOfMemoryException ex) { logger.Error.WriteLine("Failed to dump memory (0x{0:x8}-0x{1:x8}) from pid=({2})", MemoryAddress, MemoryAddress + bytesToRead, string.Format("0x{0:x4} {1}.exe", ppid.Id, ppid.ProcessName)); logger.Error.WriteLine("DumpMemory(): OutOfMemoryException"); logger.Error.WriteLine(ex.ToString()); } catch (Exception ex) { logger.Error.WriteLine("Failed to dump memory (0x{0:x8}-0x{1:x8}) from pid=({2})", MemoryAddress, MemoryAddress + bytesToRead, string.Format("0x{0:x4} {1}.exe", ppid.Id, ppid.ProcessName)); logger.Error.WriteLine("DumpMemory(): Exception"); logger.Error.WriteLine(ex.ToString()); } return new byte[]{}; } #endregion #endregion } #endregion /// /// ProcessMemoryReader is a class that enables direct reading a process memory /// public class ProcessMemoryReaderApi { // constants information can be found in [Flags] public enum ProcessAccessType { PROCESS_TERMINATE = (0x0001), PROCESS_CREATE_THREAD = (0x0002), PROCESS_SET_SESSIONID = (0x0004), PROCESS_VM_OPERATION = (0x0008), PROCESS_VM_READ = (0x0010), PROCESS_VM_WRITE = (0x0020), PROCESS_DUP_HANDLE = (0x0040), PROCESS_CREATE_PROCESS = (0x0080), PROCESS_SET_QUOTA = (0x0100), PROCESS_SET_INFORMATION = (0x0200), PROCESS_QUERY_INFORMATION = (0x0400) } // function declarations are found in the MSDN and in // HANDLE OpenProcess( // DWORD dwDesiredAccess, // access flag // BOOL bInheritHandle, // handle inheritance option // DWORD dwProcessId // process identifier // ); [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId); // BOOL CloseHandle( // HANDLE hObject // handle to object // ); [DllImport("kernel32.dll")] public static extern Int32 CloseHandle(IntPtr hObject); // BOOL ReadProcessMemory( // HANDLE hProcess, // handle to the process // LPCVOID lpBaseAddress, // base of memory area // LPVOID lpBuffer, // data buffer // SIZE_T nSize, // number of bytes to read // SIZE_T * lpNumberOfBytesRead // number of bytes read // ); [DllImport("kernel32.dll")] public static extern Int32 ReadProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead); // BOOL WriteProcessMemory( // HANDLE hProcess, // handle to process // LPVOID lpBaseAddress, // base of memory area // LPCVOID lpBuffer, // data buffer // SIZE_T nSize, // count of bytes to write // SIZE_T * lpNumberOfBytesWritten // count of bytes written // ); [DllImport("kernel32.dll")] public static extern Int32 WriteProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesWritten); } } #endregion }