using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using WeifenLuo.WinFormsUI.Docking; using RomCheater.PluginFramework.Interfaces; using System.Diagnostics; using System.IO; using RomCheater.Logging; using System.Reflection; using Sojaner.MemoryScanner.MemoryProviers; namespace RomCheater.Docking { public partial class FloatingRamDumperDialog : DockContent, IAcceptsPlugin, IAcceptsProcess, IAcceptsProcessAndConfig { #region sub-classes private const int BYTE_CORRECTION_VALUE = 23; public enum DumpSize { Bytes, KiloBytes, MegaBytes, GigaBytes, } #endregion private DumpSize dumpSize = DumpSize.Bytes; public FloatingRamDumperDialog() { InitializeComponent(); this.AcceptedPlugin = null; this.AcceptedProcess = null; } public FloatingRamDumperDialog(IConfigPlugin config) : this() { this.AcceptedPlugin = config; } public FloatingRamDumperDialog(IConfigPlugin config, Process process) : this() { this.AcceptedPlugin = config; this.AcceptedProcess = process; } private void FloatingRamDumperDialog_Load(object sender, EventArgs e) { txtStart.Value = 0; txtEnd.Value = int.MaxValue; } #region IAcceptsProcess Members public Process AcceptedProcess { get; set; } #endregion #region IAcceptsPlugin Members public IConfigPlugin AcceptedPlugin { get; set; } #endregion #region ram-dump specific private void radioBTNBytes_CheckedChanged(object sender, EventArgs e) { dumpSize = DumpSize.Bytes; } private void radioBTNKiloBytes_CheckedChanged(object sender, EventArgs e) { dumpSize = DumpSize.KiloBytes; } private void radioBTNMegaBytes_CheckedChanged(object sender, EventArgs e) { dumpSize = DumpSize.MegaBytes; } private void radioBTNGigaBytes_CheckedChanged(object sender, EventArgs e) { dumpSize = DumpSize.GigaBytes; } private void btnCalcEndAddr_Click(object sender, EventArgs e) { ulong start = 0; ulong end = 0; start = txtStart.Value; switch (dumpSize) { case DumpSize.Bytes: end = (ulong)(Convert.ToDouble(txtDumpSize.Text) * 1.0 + (double)start) + BYTE_CORRECTION_VALUE; txtEnd.Value = end; break; case DumpSize.KiloBytes: end = (ulong)(Convert.ToDouble(txtDumpSize.Text) * 1000.0 + (double)start) + BYTE_CORRECTION_VALUE; txtEnd.Value = end; break; case DumpSize.MegaBytes: end = (ulong)(Convert.ToDouble(txtDumpSize.Text) * 1000000.0 + (double)start) + BYTE_CORRECTION_VALUE; txtEnd.Value = end; break; case DumpSize.GigaBytes: end = (ulong)(Convert.ToDouble(txtDumpSize.Text) * 1000000000.0 + (double)start) + BYTE_CORRECTION_VALUE; txtEnd.Value = end; break; } } private void btnCalcStartAddr_Click(object sender, EventArgs e) { long start = 0; long end = 0; end = txtEnd.ToInt64(); switch (dumpSize) { case DumpSize.Bytes: start = (long)((double)end - (Convert.ToDouble(txtDumpSize.Text) * 1.0)) + BYTE_CORRECTION_VALUE; txtStart.Value = (ulong)start; ; break; case DumpSize.KiloBytes: start = (long)((double)end - (Convert.ToDouble(txtDumpSize.Text) * 1000.0)) + BYTE_CORRECTION_VALUE; txtStart.Value = (ulong)start; ; break; case DumpSize.MegaBytes: start = (long)((double)end - (Convert.ToDouble(txtDumpSize.Text) * 1000000.0)) + BYTE_CORRECTION_VALUE; txtStart.Value = (ulong)start; ; break; case DumpSize.GigaBytes: start = (long)((double)end - (Convert.ToDouble(txtDumpSize.Text) * 1000000000.0)) + BYTE_CORRECTION_VALUE; txtStart.Value = (ulong)start; break; } } private void btnCalcDumpSize_Click(object sender, EventArgs e) { ulong start = txtStart.Value; ulong end = txtEnd.Value; ulong byte_diff = (end - start) + BYTE_CORRECTION_VALUE; switch (dumpSize) { case DumpSize.Bytes: txtDumpSize.Text = string.Format("{0:n2}", (double)byte_diff); break; case DumpSize.KiloBytes: txtDumpSize.Text = string.Format("{0:n3}", (double)byte_diff / 1000.0); break; case DumpSize.MegaBytes: txtDumpSize.Text = string.Format("{0:n6}", (double)byte_diff / 1000000.0); break; case DumpSize.GigaBytes: txtDumpSize.Text = string.Format("{0:n9}", (double)byte_diff / 1000000000.0); break; } } private void btnDumpRam_Click(object sender, EventArgs e) { if (this.AcceptedProcess == null) { MessageBox.Show("Please select a process to dump memory from", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } DialogResult result = dumpsaver.ShowDialog(); if (result != DialogResult.OK) return; DumpRam(txtStart.Value, txtEnd.Value, dumpsaver.FileName); } #endregion #region memory support private void DumpRam(ulong start, ulong end, string filename) { uint byte_count = (uint)(end - start); string arch = ProcessorAssemblyArchitecture.GetProcessorArchitecture(typeof(FloatingRamDumperDialog).Assembly); if (arch == ProcessorAssemblyArchitecture.x86) { // intptr is 4 bytes on x86 if (end > int.MaxValue) logger.Warn.WriteLine("Warning: DumpRam(): ending address is greater than 0x{0:x8} and we are running x86, this will exceed the max value for IntPtr", int.MaxValue); } else if (arch == ProcessorAssemblyArchitecture.x64) { // inptr is 8 bytes on x64 if (end > uint.MaxValue) logger.Warn.WriteLine("Warning: DumpRam(): ending address is greater than 0x{0:x8} and we are running x64, this will exceed the max value for UIntPtr", int.MaxValue); } else if (arch == ProcessorAssemblyArchitecture.AnyCpu) { if (IntPtr.Size == 4) //x86 { if (end > int.MaxValue) logger.Warn.WriteLine("Warning: DumpRam(): ending address is greater than 0x{0:x8} and we are running x86, this will exceed the max value for IntPtr", int.MaxValue); } else if (IntPtr.Size == 8) //x64 { } else // unknown { if (end > uint.MaxValue) logger.Warn.WriteLine("Warning: DumpRam(): ending address is greater than 0x{0:x8} and we are running x64, this will exceed the max value for UIntPtr", int.MaxValue); } } else { throw new InvalidProgramException(string.Format("Unexcepted processor aritecture: expected x86, x64, or AnyCpu(Msil) but we have: {0}", arch)); } DumpRam(start, byte_count, filename); } private void DumpRam(ulong start, uint count, string filename) { if (this.AcceptedProcess == null) return; GenericMemoryProvider provider = new GenericMemoryProvider((IAcceptsProcessAndConfig)this); provider.OpenProvider(); int bytesReadSize; if (provider.WriteProcessMemoryToFile(filename, (uint)start, count, out bytesReadSize)) { MessageBox.Show(string.Format("Succefully dumped memory (0x{0:x8}-0x{1:x8}) from pid=({3}) to file {2}", start, start + count, filename, string.Format("0x{0:x4} {1}.exe", this.AcceptedProcess.Id, AcceptedProcess.ProcessName)), "", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { MessageBox.Show(string.Format("Failed to dump memory (0x{0:x8}-0x{1:x8}) from pid=({3}) to file {2}", start, start + count, filename, string.Format("0x{0:x4} {1}.exe", this.AcceptedProcess.Id, AcceptedProcess.ProcessName)), "", MessageBoxButtons.OK, MessageBoxIcon.Error); } provider.CloseProvider(); } #endregion } }