Перейти к содержанию

C# ReadProcessMemory и сохранение на диск


Рекомендуемые сообщения

Всем привет. 
читаю из памяти 


все прекрасно работает. lpBuffer пополняться от 0 до 255
Хочу все это сохранить в файл на диск 
сохраняю так:

 


Теперь в чем вопрос когда смотрю в память процесса через Cheat Engine я нахожу свою сигнатуру "3C 2F 69 74 65 6D 3E 3C 2F 63 6F 6D 6D 6F 64 69 74 69 65 73 3E 3C 2F 64 61 74 61 3E"
но когда просматриваю в сохранённом файле на диске ее там нет.
В чем может быть причина?


как сделать дамп памяти запущенного процесса правильно?

static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,[Out] byte[]lpBuffer,int dwSize,        out int lpNumberOfBytesRead);
 protected bool SaveData(byte[] Data)        {            BinaryWriter Writer = null;            string Name = @"C:\buffer.txt";            try            {                // Create a new stream to write to the file                Writer = new BinaryWriter(File.OpenWrite(Name));                // Writer raw data                                Writer.Write(Data);                Writer.Flush();                Writer.Close();            }            catch            {                //...                return false;            }            return true;        }
Изменено пользователем alexmarch
Ссылка на комментарий
Поделиться на другие сайты

Попробуй сделать по аналогии. Тут запись текста в файло. Пара пирмеров

 

using System;using System.IO;using System.Text;class Test {    public static void Main()     {        string path = @"c:\temp\MyTest.txt";        // Open the stream and write to it.        using (FileStream fs = File.OpenWrite(path))         {            Byte[] info =                 new UTF8Encoding(true).GetBytes("This is to test the OpenWrite method.");            // Add some information to the file.            fs.Write(info, 0, info.Length);        }        // Open the stream and read it back.        using (FileStream fs = File.OpenRead(path))         {            byte[] b = new byte[1024];            UTF8Encoding temp = new UTF8Encoding(true);            while (fs.Read(b,0,b.Length) > 0)             {                Console.WriteLine(temp.GetString();            }        }    }}
using System;using System.Windows.Forms;using System.IO;using System.Text;namespace WindowsApplication1{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        private void button1_Click(object sender, EventArgs e)        {            FileStream writeStream ;            try            {                writeStream = new FileStream("c:\\csharp.net-informations.dat", FileMode.Create);                BinaryWriter writeBinay = new BinaryWriter(writeStream);                writeBinay.Write("CSharp.net-informations.com binary writer test");                writeBinay.Close();            }            catch (Exception ex)            {                MessageBox.Show (ex.ToString());            }        }    }}
Ссылка на комментарий
Поделиться на другие сайты

Привет!

 

Нельзя просто так взять и записать массив байт туда, куда нужно записывать тип string. Нужно сначала смотреть в документацию. Можно сделать, например, вот так:

 

 

В данном случае я использовал класс BitConverter, чтобы привести тип byte[] к типу string. Есть и другие способы. Подробнее - в поисковике по запросу "C# byte array to string".

 

using System;using System.IO; namespace fileio_bytearray_test{    class Program    {        static void Main(string[] args)        {            var data = new byte[] { 11, 22, 33 };            try            {                using (var bw = new BinaryWriter(File.OpenWrite(@"test.txt")))                {                    bw.Write(BitConverter.ToString(data));                    bw.Flush();                }            }            catch (Exception e)            {                Console.Out.WriteLine(e.InnerException.ToString());            }        }    }}
Ссылка на комментарий
Поделиться на другие сайты

Keng твой вариант приводит к такому результату

4D-5A-90-00-03-00-00-00-04-00-00-00-FF-FF

а должно быть  приблизительно так:

MZ !This program cannot be run in DOS mode.

Я прекрасно отдаю себе отчет разницу между string и byte

Этот наверно подходит File.WriteAllBytes(@"C:\buffer.txt", buffer);

Если честно я уже все перепробовал и не понимаю на какой стадии ошибка

Это все твой же код я мучаю по поиску сигнатур

вот пример

 

ReadProcessMemory(handle, (IntPtr)startAddress, buffer, sizeToAllocate, out bytesread); //Читаем, с начала адресса, в буфер, весь файл, и заглушка

тут переменные 

int startAddress = 0; // Начало файла
int sizeToAllocate = 0; // Размер файла
byte[] buffer; // Буфер для записи всей игры из памяти
и вот когда я ищу свою сигнатуру я не могу ее там найти вот я и решил ее слить на диск и посмотреть в Cheat Engine, вдруг думаю я что то упустил
так вот в сохраненном buffer тоже нет моей сигнатуры. Если быть точнее есть ее куски но не целиком.
Я непониманию где БАГ помогите 
Ссылка на комментарий
Поделиться на другие сайты

Если ты прекрасно понимаешь разницу, то тогда почему ты пытаешься скормить массив байт методу, который ждет string? Сканер сигнатур возвращает адрес памяти, причем первый найденный. Если он тебе возвращает что-то не то, а код ты подсмотрел у меня, то проблема не в моем коде, а в сигнатуре - попробуй сделать другую в этой же игре.
Ссылка на комментарий
Поделиться на другие сайты

ты пытаешься скормить массив байт методу, который ждет string?

Покажи где я пытаюсь это сделать?

 

то проблема не в моем коде

Спасибо за твой код все чудесно

Единственно я его сделал несколько удобнее

 string hexValues = "3C 63 6F 6D 6D 6F 64 69 74 69 65 73 3E 3C 69 74 65 6D 3E 3C 69 64 3E";            hexValues = hexValues.Replace(" ", string.Empty); //Удалим пробелы  //Преобразуем из HEX в DEC16   int[] signature = Enumerable.Range(0, hexValues.Length / 2).Select(x => Convert.ToInt32(hexValues.Substring(x * 2, 2), 16)).ToArray();   //Посик сигнатуры
Ссылка на комментарий
Поделиться на другие сайты

Гм, шапка темы, 2-й спойлер, 16-я строка:

 

Writer.Write(Data);

 

То, что ты сохранишь N байт на диск вряд ли даст что-то полезное. Я еще раз повторю, что сканер сигнатур возвращает адрес памяти, по которому было найдено первое вхождение сигнатуры, или же код ошибки на выбор разработчика. Адрес можно посмотреть в твоей программе, а что по адресу находится - в отладчике. Если же что-то работает не так, что, прежде всего, надо попробовать другую сигнатуру.

Ссылка на комментарий
Поделиться на другие сайты

У меня не стоит задача записи на диск всей памяти. Делал я это от безысходности так как хотел увидеть что хранит в себе buffer.

buffer если я все правильно вижу хранить массив байт, с который можно  проводить int сравнение в пределах 0 до 255

Я думал что я неправильно конверчу  свою сигнатуру все проверил там все ОК. потом я понял что что то не так с buffer-ом и поэтому начал его сохранять на диск что бы посмотреть Cheat Engine-ом


сейчас я так данные сохраняю

File.WriteAllBytes(@"C:\buffer.txt", buffer);

Но это не решило проблемы


могу видео записать 

Ссылка на комментарий
Поделиться на другие сайты

Как я уже писал выше, способов перевода из массива байт в текстовую строку существует довольно много. Подробнее можно почитать об этом, например, [тут]. Я все еще не совсем понимаю, как это может помочь в отладке работы сканера сигнатур, если всю необходимую информацию можно посмотреть в отладчике.
Ссылка на комментарий
Поделиться на другие сайты

Нет, погоди-ка. Что значит "в буфере нет сигнатуры"? Вот пример:

 

0x0000001: A+B

0x0000002: C+E

0x0000003: F+Z

 

Представим, что буквы - это опкоды ассемблерных инструкций, а 16-ричные цифры - адреса памяти, по которым находится этот псевдокод. Пишем такую сигнатуру:

 

"ABCEFZ"

 

Что делает сканер? Он берет адрес исполняемого модуля, его размер в байтах, а затем бежит по этому массиву байт и ищет в нем первое вхождение сигнатуры, то есть совпадения с ней. И возвращает адрес, по которому это совпадение нашел, то есть адрес модуля + смещение. Типа вот так:

 

0x0000011: A+B

0x0000022: C+E

0x0000033: F+Z

 

В первом случае сканер вернет адрес 0x0000001, а во втором - 0x0000011. Если не найдет ничего - то и вернет 0 или -1. Что дальше с этим адресом делать? Например, инъекцию кода, или просто записать на его место нужное количество команд NOP.

 

В свете вышенаписанного, что означает "в буфере нет сигнатуры"?

Ссылка на комментарий
Поделиться на другие сайты

Отвечая на твой вопрос: в буфере ее нет.

Я ищу в памяти набор байт определенной последовательности. Когда нахожу записываю и храню переменной

Вот твой почти не переделанный код.

Я все понимаю о чем ты говоришь, что он ищет начало сигнатуры меня это все устраивает, я никак не могу обьяснить что по какой то блин ФАНТАСТИЧЕСКОЙ, ЗАГАДОЧНОЙ, причине в Буффере НЕТ этой сигнатуре, когда как я ее явно, отчетливо, в упор вижу через отладчик! ЧУДО, которое я не могу никак объяснить.

Поэтому и прошу Вас многоуважаемые подсказать, ткнуть носом где ошибка.

        public int FindSignature(string hexValues)        {            hexValues = hexValues.Replace(" ", string.Empty); //Удалим пробелы            //Преобразуем из HEX в DEC16            int[] signature = Enumerable.Range(0, hexValues.Length / 2).Select(x => Convert.ToInt32(hexValues.Substring(x * 2, 2), 16)).ToArray();            //Посик сигнатуры            File.WriteAllBytes(@"C:\buffer.txt", buffer);                      var counter = 0; // обьявляем переменную счетчик             if (signature.Length <= buffer.Length) //Проверим что бы сигнатура была меньше буфера            {                for (var i = 0; i < buffer.Length; i++) //Цыкл гонит по всему массиву                {                    if (buffer[i] == signature[0] | signature[0] == -1) //Если первый символ сигнатуры равен или равен -1, тогда ...                     {                        for (var j = 0; j < signature.Length; j++) //вхождение в сигнатуру                        {                            if (buffer[i + j] == signature[j] | signature[j] == -1) //Если свопадает с сигнатурой или равен -1, тогда ...                            {                                counter++; // Считаем совпадения                                                              if (counter == signature.Length) // Если  сигнатура найдена                                {                                                                      return xmlStart = i + startAddress; //Вернем найденый адрес                                }                            }                            else                            {                                counter = 0;                            }                        }                    }                }            }            return -1;        } 
Ссылка на комментарий
Поделиться на другие сайты

Вы хотите сказат что на ЧитЭнжине находит последвательност байтов(сигнатуру), код каторый на С# не находит так?.

Просто суть вопроса не могу понять.

 

П.С. Вы

Изменено пользователем Laziz
  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

Ты хочеш сказат что на ЧитЭнжине находит последвательност байтов(сигнатуру), код каторый на С# не находит так?.

Просто суть вопроса не могу понять.

Абсолютно точно. Именно это я и говорю.

Ссылка на комментарий
Поделиться на другие сайты

попробуйте этим поискать, потом скажете. находит ли вообше.

http://forum.gamehacklab.ru/topic/3567-videourok-kenga-poisk-signatury-signaturu/?p=26679

  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

Может просто CE ищет сигнатуру в модуле, а ты в исполняемом файле или наоборот? :)

может быть, я уже не знаю куда посмотреть все по 100 перепроверил.

вот код как я ищу

 

 

попробуйте этим поискать, потом скажете. находит ли вообше.

http://forum.gamehacklab.ru/topic/3567-videourok-kenga-poisk-signatury-signaturu/?p=26679

ща попробую

Тип поиска массив байт? мне в int перевести надо?

у меня HEX или стринг!

3C 3F 78 6D 6C 20 76 65 72 73 69 6F 6E 3D 22 31 2E 30 22 20 65 6E 63 6F 64 69 6E 67 3D 22 75 74 66 2D 38 22 3F 3E 0A 3C 64 61 74 61 3E 3C 69 6E 76 65 6E 74 6F 72 79 3E <?xml version="1.0" encoding="utf-8"?><data><inventory>
 public int GetProcessID(string nameProc) //Поиск Id процесса        {            foreach (Process proc in Process.GetProcessesByName(nameProc))            {                pID = proc.Id; // запомним ID процесса                return proc.Id;            }            return -1;        }        public int FindModulesAddress(string nameProc) // Поиск по модулям         {            if (pID !=0) // если ID процесса найден            {                foreach (var p in Process.GetProcesses())                {                     if (p.Id == pID ) // Ищем процеес с нашим ID                    {                        foreach (ProcessModule m in p.Modules) // Находим базовый модуль                        {                            if (m.ModuleName == nameProc + ".exe") // Имя модуля должно совпадать с именим exe-файла                            {                                string srtA = m.BaseAddress.ToString();//Удалить экперемент                                UInt32 Base = (UInt32)m.BaseAddress.ToInt32(); //Удалить экперемент                                startAddress = (int)m.BaseAddress; // Берем базовый адрес                                sizeToAllocate = m.ModuleMemorySize; // Размер модуля                                return 1;                                                            }                        }                    }                }                            }            return -1;        }
Изменено пользователем alexmarch
Ссылка на комментарий
Поделиться на другие сайты

Тип поиска массив байт? мне в int перевести надо?

у меня HEX или стринг!

3C 3F 78 6D 6C 20 76 65 72 73 69 6F 6E 3D 22 31 2E 30 22 20 65 6E 63 6F 64 69 6E 67 3D 22 75 74 66 2D 38 22 3F 3E 0A 3C 64 61 74 61 3E 3C 69 6E 76 65 6E 74 6F 72 79 3E 
Тип: массив байт

По поводу сигнатуры: пробелы просто убери, и вставь в программу.

Ссылка на комментарий
Поделиться на другие сайты

Тип: массив байт

По поводу сигнатуры: пробелы просто убери, и вставь в программу.

3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D227574662D38223F3E0A3C646174613E3C696E76656E746F72793E 

Ругается благим матом, говорит непонятный символ 

Изменено пользователем alexmarch
Ссылка на комментарий
Поделиться на другие сайты

3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D227574662D38223F3E0A3C646174613E3C696E76656E746F72793E 

Ругается благим матом, говорит непонятный символ 

 

В конце пробел стоит наверно, у меня не ругается.

Ссылка на комментарий
Поделиться на другие сайты

Да нашел!!!!

УРА действительно в конце пробел был.  o_0

По модулям поиск не находит!

Но поиск очень медленный

В любом случаи спасибо, это хоть какое то решение.

Но почему  тогда в поиске по модулям в буфере оказывается не то!

Зачем его тогда вообще использовать, если в нем нет нужных значений!

Изменено пользователем alexmarch
Ссылка на комментарий
Поделиться на другие сайты

Да нашел!!!!

УРА действительно в конце пробел был.  o_0

По модулям поиск не находит!

Но поиск очень медленный

В любом случаи спасибо, это хоть какое то решение.

Но почему  тогда в поиске по модулям в буфере оказывается не то!

Зачем его тогда вообще использовать, если в нем нет нужных значений!

На все эти вопросы ответ придет со временем, если усердно потрудитесь, и тогда скажете БИНГО! :-D А пока скажу так.

Модуль - по сути, те ж файлы на диске, а современнный игры, да и старые использует еще дополнительный памят. Поиск по модулям там не ищет. Как то так.

 

Но почему тогда в поиске по модулям в буфере оказывается не то!

не знаю, или вы так думаете или вам кажется так. во всяком случае там ничего не оказываеться.

 

поиск медленный - потому что не С++.

Ссылка на комментарий
Поделиться на другие сайты

Виртуальное адресное пространство процесса или как найти свою сигнатуру.
1. В 32-битных системах процессор может сгенерировать 32-битный адрес. Это означает, что каждому процессу выделяется диапазон виртуальных адресов от 0x00000000 до 0xFFFFFFFF
Эти 4 Гб адресов система делит примерно пополам, и для кода и данных пользовательского режима отводятся 2 Гб в нижней части памяти. Если быть более точным, то речь идет об виртуальных адресах, начиная с 0x00010000 и конечная 0x07FFEFFFF
vm1.png
Источник тут >>
2. В большинстве современных операционных систем виртуальная память организуется с помощью страничной адресации. Оперативная память делится на страницы: области памяти фиксированной длины (например, 4096 байт), которые являются минимальной единицей выделяемой памяти (то есть даже запрос на 1 байт от приложения приведёт к выделению ему страницы памяти).
Источник тут >>
 
3.Так же, как и в Win32, размер страницы на платформе x64 равен 4 Кб. Первые 64 Кб адресного пространства никогда не проецируются на физическую память, поэтому младший допустимый адрес - 0x10000. В отличие от Win32 системные DLL по умолчанию не загружаются по адресу в верхней части адресного пространства пользовательского режима. Вместо этого они загружаются после 4 Гб, обычно по адресам, близким к 0x7FF00000000.
Источник тут >>
Так как нам правильно сканировать память чужого процесса на C#?
Windows запуская любой процесс, выделят память из кучи, стека и областей - однако Windows не будет выделять "весь блок" памяти целиком. Она пытается выделить любой свободной кусок памяти, доступной для так называемой User-Mode – таким образом выделенная память не будет непрерывной. Так же, Windows не скажет нам диапазон адресов, где мы можем найти данные программы. Таким образом, нам придется сканировать почти каждый возможный адрес ( с помощью GetSystemInfo ()) и проверять,  принадлежит ли он к нашему процессу (с VirtualQueryEx ()): если это произойдет, будем читаем значения с помощью (ReadProcessMemory () )

 

код взял тут

using System;using System.Diagnostics;using System.IO;using System.Runtime.InteropServices;namespace MemoryScanner{    class Program    {        // REQUIRED CONSTS        const int PROCESS_QUERY_INFORMATION = 0x0400;        const int MEM_COMMIT = 0x00001000;        const int PAGE_READWRITE = 0x04;        const int PROCESS_WM_READ = 0x0010;        // REQUIRED METHODS        [DllImport("kernel32.dll")]        public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);        [DllImport("kernel32.dll")]        public static extern bool ReadProcessMemory(int hProcess, int lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);        [DllImport("kernel32.dll")]        static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo);        [DllImport("kernel32.dll", SetLastError=true)]        static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength);        // REQUIRED STRUCTS        public struct MEMORY_BASIC_INFORMATION        {            public int BaseAddress;            public int AllocationBase;            public int AllocationProtect;            public int RegionSize;            public int State;            public int Protect;            public int lType;        }        public struct SYSTEM_INFO        {            public ushort processorArchitecture;            ushort reserved;            public uint pageSize;            public IntPtr minimumApplicationAddress;            public IntPtr maximumApplicationAddress;            public IntPtr activeProcessorMask;            public uint numberOfProcessors;            public uint processorType;            public uint allocationGranularity;            public ushort processorLevel;            public ushort processorRevision;        }                // finally...        public static void Main()        {            // getting minimum & maximum address            SYSTEM_INFO sys_info = new SYSTEM_INFO();            GetSystemInfo(out sys_info);              IntPtr proc_min_address = sys_info.minimumApplicationAddress;            IntPtr proc_max_address = sys_info.maximumApplicationAddress;            // saving the values as long ints so I won't have to do a lot of casts later            long proc_min_address_l = (long)proc_min_address;            long proc_max_address_l = (long)proc_max_address;            // notepad better be runnin'            Process process = Process.GetProcessesByName("notepad")[0];            // opening the process with desired access level            IntPtr processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_WM_READ, false, process.Id);            StreamWriter sw = new StreamWriter("dump.txt");            // this will store any information we get from VirtualQueryEx()            MEMORY_BASIC_INFORMATION mem_basic_info = new MEMORY_BASIC_INFORMATION();            int bytesRead = 0;  // number of bytes read with ReadProcessMemory            while (proc_min_address_l < proc_max_address_l)            {                // 28 = sizeof(MEMORY_BASIC_INFORMATION)                VirtualQueryEx(processHandle, proc_min_address, out mem_basic_info, 28);                                // if this memory chunk is accessible                if (mem_basic_info.Protect == PAGE_READWRITE && mem_basic_info.State == MEM_COMMIT)                {                    byte[] buffer = new byte[mem_basic_info.RegionSize];                    // read everything in the buffer above                    ReadProcessMemory((int)processHandle, mem_basic_info.BaseAddress, buffer, mem_basic_info.RegionSize, ref bytesRead);                    // then output this in the file                    for (int i = 0; i < mem_basic_info.RegionSize; i++)                        sw.WriteLine("0x{0} : {1}", (mem_basic_info.BaseAddress+i).ToString("X"), (char)buffer[i]);                }                // move to the next memory chunk                proc_min_address_l += mem_basic_info.RegionSize;                proc_min_address = new IntPtr(proc_min_address_l);            }            sw.Close();            Console.ReadLine();        }    }}
Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.