Get Adobe Flash player



Доход от игр робота:
сайт $ -14'860,43
игроки $ +36'555,85




Майнеры вход

Заказы для бота

Казино рейтинги

Проверка теорий

Рабочие группы

Скачать бот CMP

Правила работы


[Delphi] На базе CheatEngine 6.3 сканируем память онлайн приложений (flash-игр) казино

Трейнеры, хаки и читы для игр онлайн казино Идеальная система распознавания номеров статистики на рулетке в онлайн казино, необходима для корректной игры ботом Casino-Mining Pool. Для бота CMP очень важно правильно распознавать статистику, ведь от этого напрямую зависят прогнозы следующей ставки и расчет текущего кредита игрока.

Все предыдущие наши системы OCR были построены на анализе графического материала, полученного через захват участка экрана. Но огромное число комбинаций версий интернет-браузеров, флеш-плееров, видеокарт и разрешений экрана делают невозможным создать универсальную схему OCR.

На сегодняшний день, мы переходим на принципиально новый алгоритм OCR. Бот для игры в рулетку будет вытягивать данные о выпадающих номерах прямо из памяти программы казино. Это позволит добиться 100% точности работы бота.

Важно!

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

CheatEngine, ArtMoney и другие трейнеры

Такие программы как ArtMoney, Cheat Engine, Wpe Pro работают во всех играх, просто необходимо знать систему шифрования данных и адреса переменных. С их помощью пользователь может свободно влиять на любые параметры любых игровых объектов.

Эти программы входят в международную пятерку программ, от которых серьезные разработчики игр часто создают защитные механизмы. Если пул столкнется с похожей проблемой:

а) Поможет переименование и повторная сборка всех модулей бота. См. http://zhyk.anihub.ru/viewtopic.php?id=20  (Делаем свой Cheat Engine).

б) Hidetools - это утилита для скрытия каких-либо программ и процессов. В результате программу и ее процессы не будет видеть диспетчер программ.

Как работают трейнеры - сканирование памяти запущенных приложений и поиск в ней адресов переменных [Delphi]

Пример использования Cheat Engine: http://www.youtube.com/watch?v=Rr3WBF1yNy8

В качестве жертвы эксперимента возьмём winmine.exe – игра Сапёр, версия под XP.
Править мы будем количество мин на поле.

Для внесения изменений в чужой процесс нам необходимо узнать его ID.

Накидаем небольшую функцию:


function GetProcessID(Const ExeFileName: string; var ProcessId: integer): boolean;
var
ContinueLoop: BOOL;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
result := false;
FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize := Sizeof(FProcessEntry32);
ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
while integer(ContinueLoop) <> 0 do begin
if (StrIComp(PChar(ExtractFileName(FProcessEntry32.szExeFile)), PChar(ExeFileName)) = 0)
or (StrIComp(FProcessEntry32.szExeFile, PChar(ExeFileName)) = 0)  then begin
ProcessId:= FProcessEntry32.th32ProcessID;
result := true;
break;
end;
ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;


Тип у функции булевый, поэтому ID процесса будет возвращаться в переменную, указанную в качестве второго параметра (ProcessId).

Пример использования:


var
PidId: integer;
begin
if GetProcessID('winmine.exe', PidId) then
begin
//исполняемый код
end;
end;


Значения всех переменных храниться в определённой ячейки памяти в шестнадцатеричной системе. Для того чтобы изменить определённое значение нам необходимо знать адрес ячейки. Чтобы вычислить его можно воспользоваться ArtMoney, но я буду использовать CheatEngine.

Запустим нашу «Жертву».
Далее откроем CheatEngine и жмём на кнопку «Select a process to open»:
В появившемся списке выберем элемент оканчивающийся на winmine.exe и нажмём кнопку «Open»
Теперь можно осуществлять поиск значений:
На уровне сложности «Новичек» у нас 10 мин, поэтому в поле Value вводим число 10.
Жмём «First Scan».
В сапёре переходим на уровень сложности «Профессионал».
В CheatEngine в поле Value вводим 99.
Жмём «NextScan».

Видим 3 значения, дважды кликая по ним мы добавляем их в список в нижней части окна, если выделить элемент из этого списка и нажать клавишу Enter то откроется окно редактирования значения. Это может быть необходимо для определения какая именно переменная нам нужна.
Опытным путём я определил что за количество мин отвечает номер три, находящийся по адресу 10056A4.


Теперь нам необходимо написать функцию, которая могла бы изменить кол-во мин на более выгодное для нас Пусть это будет одна мина. в шестнадцатеричной системе 01 (в делфи при указании числа в шестнадцатеричной системе перед ним необходимо ставить знак $, например $01).

Код:



var
byteArr : Array of byte;
begin
//пытаемся найти процесс Сапёра   
if GetProcessID('winmine.exe', PidId) then
begin
//Открываем процесс для полного доступа (в том числе и редактирования памяти)   
PidHandle  :=  OpenProcess(PROCESS_ALL_ACCESS,False,PidId);
//указываем размер массива, в нашем случае 4 байта
SetLength(byteArr, 4);
//заполняем массив
byteArr[0] := $01;
byteArr[1] := $00;
byteArr[2] := $00;
byteArr[3] := $00;
//вносим изменения в память процесса
pokeX($10056A4, byteArr);
//отчищаем память, занимаемую массивом
SetLength(byteArr, 0);
//закрываем процесс
closehandle(PidHandle);
//Выводим сообщения о том, что всё ОК
SHOWMESSAGE('Изменения внесены, для их применения необходимо перезапустить игру на текущем уровне сложности');
end
else
begin
MessageDlg('Сначала запустите Сапёр!', mtwarning, [mbOK],0);
end;



Хочется обратить ваше внимание на то, что занося данные в массив в качестве первого элемента мы указываем последний (при счёте слева на право) байт числа. Такова особенность работы ЭВМ.
В принципе мы могли установить размер массива на 1 и записать только один элемент массива (остальные байты автоматически бы обнулились):

Код:


SetLength(byteArr, 1);
byteArr[0] := $01;



Но первый вариант корректней, так как мы работаем с 4х байтовой ячейкой памяти.

Теперь рассмотрим функцию записи данных в память процесса:

Код:



procedure pokeX(Address: Cardinal; Data: Array of Byte);
var
Written: Cardinal;
begin
WriteProcessMemory(PidHandle, Pointer(Address), @Data, SizeOf(Data), Written);
end;



Она сделана для удобства, т.к. ей мы передаём только 2 переменные, после чего функция сама заполняет оставшиеся параметры функции WriteProcessMemory (стандартная функция WinAPI ничего сверхъестественного).
Первым атрибутом для неё служит адрес памяти, который мы вычислили в CheatEngine, вторым – массив с данными.

Посмотрим на полный исходник:

Код:



unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, TLhelp32;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
PidHandle: integer;
PidID : integer;
byteArr : Array of byte;
Const
ProgramName = 'winmine.exe';


implementation

uses Unit1;

{$R *.dfm}

function GetProcessID(Const ExeFileName: string; var ProcessId: integer): boolean;
var
ContinueLoop: BOOL;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
result := false;
FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize := Sizeof(FProcessEntry32);
ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
while integer(ContinueLoop) <> 0 do begin
if (StrIComp(PChar(ExtractFileName(FProcessEntry32.szExeFile)), PChar(ExeFileName)) = 0)
or (StrIComp(FProcessEntry32.szExeFile, PChar(ExeFileName)) = 0)  then begin
ProcessId:= FProcessEntry32.th32ProcessID;
result := true;
break;
end;
ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;

procedure pokeX(Address: Cardinal; Data: Array of Byte);
var
Written: Cardinal;
begin
WriteProcessMemory(PidHandle, Pointer(Address), @Data, SizeOf(Data), Written);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
byteArr : Array of byte;
begin
if GetProcessID(ProgramName, PidId) then
begin
PidHandle  :=  OpenProcess(PROCESS_ALL_ACCESS,False,PidId);
SetLength(byteArr, 4);
byteArr[0] := $01;
byteArr[1] := $00;
byteArr[2] := $00;
byteArr[3] := $00;
pokeX($10056A4, byteArr);
SetLength(byteArr, 0);
closehandle(PidHandle);
SHOWMESSAGE('Изменения внесены, для их применения необходимо перезапустить игру на текущем уровне сложности');
end
else
begin
MessageDlg('Сначала запустите Сапёр!', mtwarning, [mbOK],0);
end;
end;

end.

 

Вот и всё! Запускаем Сапёра, выбираем режим сложности "Профессионал", жмём в нашей программе на кнопку изменения памяти. В сапёре нажимаем на рожицу - запускаем новую игру. Всё у вас одна мина на поле!

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

Все серьезные онлайн игры выше 3-4 категории сложности имеют скрытый трафик (данные постоянно сверяются с базой на сервере). Для начала поработаем с браузерными версиями игр казино, т.к. у них принцип работы намного проще (все выполняется в контейнере, нет скрытого трафика, нет доступа к функциям WIN API, нет серьезных защитных механизмов и т.д.). Мы можем видеть данные только клиентской оболочки казино и этого вполне достаточно.

Пример работы с "чужими" процессами — компонент TMemoryInspector (2004-2005)

авт. - Юрий Писарев, см. http://www.delphikingdom.com/asp/viewitem.asp?catalogid=788


Введение
Компонент предназначен для доступа к адресному пространству чужого процесса. Позволяет читать память процесса, записывать данные любой длины в память процесса и замораживать данные любой длины в памяти процесса. Можно работать одновременно с любым количеством запущенных на компьютере процессов.

Принцип работы компонента

Чтобы получить доступ к процессу, компонент использует динамическую библиотеку. Устанавливается ловушка типа WH_CALLWNDPROC, которая реагирует на сообщения, посылаемые функцией SendMessage. После установки ловушки, компонент посылает сообщение WM_NULL целевому окну и, библиотека отображается на адресное пространство процесса (если не была отображена раньше), которому принадлежит целевое окно.

Эта технология подробно описывается в книге Джеффри Рихтера (как и ряд других технологий для тех же целей), поэтому особо подробно останавливаться не буду. Для того чтобы активировать компонент, предназначен метод:

function Activate: Boolean; virtual;

который устанавливает ловушку, создает информационный файл, отображаемый в память, в общем, делает некоторую подготовительную работу. Для того чтобы деактивировать компонент, предназначен метод:

function Deactivate: Boolean; virtual;

который убирает ловушку и закрывает все отображаемые в память файлы. Впрочем, активировать и деактивировать компонент, а также проследить его состояние можно, используя свойство:

property Active: Boolean;

Явно вызывать метод Activate не обязательно, так как при вызове методов компонента проверяется статус компонента и, если надо, производится его активация. Метод:

function UpdateWndData: Boolean; virtual;

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

property ProcessId_: THandles;

содержит дескрипторы процессов;

property ProcessSize: TIntArray;

содержит размеры процессов;

property WndHandle: THandles;

содержит дескрипторы окон процессов;

property WndClassName: TStrings;

содержит имена классов окон;

property WndText: TStrings;

содержит заголовки окон;

property ModuleFileName: TStrings;

содержит имена исполняемых файлов окон; Вышеперечисленные свойства представляет собой массивы данных, где любой элемент массива соответствует элементу любого другого массива с тем же индексом. Таким образом, все вышеперечисленные свойства имеют одинаковую длину, а элементы свойств с одинаковыми индексами относятся к одному и тому же процессу. Свойство компонента:

property Selected: Integer;

обозначает индекс выбранного элемента вышеперечисленных массивов. Это свойство можно установить исходя из, например, заголовка окна:


var
Index: Integer;
begin
Index := 10;
with MemoryInspector do if WndText[Index] = ‘Microsoft Internet Explorer’ then
Selected := Index;
end;


или это свойство можно установить исходя из имени класса окна:


var
Index: Integer;
begin
Index := 10;
with MemoryInspector do if WndClassName[Index] = ‘IEFrame’ then
Selected := Index;
end;


Зная дескриптор окна, можно получить индекс, соответствующий свойству Selected:

function GetWindowIndex(Window: THandle): Integer; virtual;

Чтение памяти процесса

Чтение памяти процесса осуществляется функцией:

function PeekData: Boolean; virtual;

Перед тем, как считывать данные процесса, необходимо установить некоторые свойства компонента. Первым делом, необходимо обновить информацию обо всех доступных в системе процессах и их окнах. После этого выбрать какое-нибудь окно целевого процесса и установить свойство Selected. В результате вызова функции PeekData данные записываются в поток памяти. Этот поток вы должны создать сами и установить ссылку на объект потока в свойстве компонента:

property StreamRef: TMemoryStream;

После того, как заданы свойства Selected и StreamRef, можно вызывать функцию PeekData. Работа функции PeekData зависит от свойства:

property UpdateMemory: Boolean;

Это свойство обозначает, будет ли перед считыванием памяти обновляться информация о регионах памяти и их блоках в выбранном процессе. Если это свойство истинно, то размер считываемой памяти будет, вероятно, изменяться. Когда память считывается первый раз, это свойство значение не имеет, библиотека обновляет информацию о памяти процесса в любом случае. В последующих вызовах функции PeekData можно либо заново обновить информацию (UpdateMemory = True), либо использовать ту информацию о памяти, которая была получена в первый раз (UpdateMemory = False). Работа функции PeekData также зависит от свойства компонента, которое определяет правила чтения памяти или записи в память:

property ReadOptions: TReadOptions;

где

TProtect = (apPageReadOnly, apPageReadWrite, apPageWriteCopy,
apPageExecute, apPageExecuteRead, apPageExecuteReadWrite,
apPageExecuteWriteCopy, apPageNoAccess);

TProtectSet = set of TProtect;

определяет набор атрибутов защиты страниц памяти;

TSpecial = (spPageGuard, spPageNoCache);

TSpecialProtect = set of TSpecial;

определяет набор специальных атрибутов защиты страниц памяти;

TPageType = (ptMemImage, ptMemMapped, ptMemPrivate);

TPageTypeSet = set of TPageType;

определяет тип физической памяти страниц

TReadOptions = record
ChangeProtect: Boolean;
ProhibitedProtect, PermittedProtect: TProtectSet;
ProhibitedSpecialProtect: TSpecialProtect;
ProhibitedPageType: TPageTypeSet;
end;

Описание атрибутов защиты страниц памяти:

apPageReadOnly: Разрешено только чтение страницы
apPageReadWrite: Разрешены только чтение страницы и запись на странице
apPageWriteCopy: Разрешена только запись на странице, которая приводит к предоставлению копии страницы, после чего этот флаг убирается
apPageExecute: Разрешено только исполнение содержимого страницы
apPageExecuteRead: Разрешены только чтение страницы и исполнение содержимого страницы
apPageExecuteReadWrite: Нет ограничений
apPageExecuteWriteCopy: Нет ограничений, любые операции приводят к предоставлению копии страницы, после чего этот флаг убирается
apPageNoAccess: Нет доступа

Описание специальные атрибутов защиты страниц памяти:

spPageGuard: Попытка доступа к содержимому страницы вызывает исключение, после чего этот флаг убирается
spPageNoCache: Отключает кэширование группы страниц памяти

Тип страниц регионов памяти:

ptMemImage: Указывает что страницы региона памяти отображены на EXE или DLL файл, спроецированный в память
ptMemMapped: Указывает что страницы региона памяти отображены на файл данных, спроецированный в память
ptMemPrivate: Указывает что страницы региона памяти отображены на страничный файл памяти

Структура TReadOptions:

Поле ChangeProtect обозначает будут ли производиться попытки получить доступ к защищенным блокам памяти. Защищенными считаются те блоки памяти, атрибуты которых не определены полями ProhibitedProtect, PermittedProtect, ProhibitedSpecialProtect и ProhibitedPageType
Поле ProhibitedProtect определяет запрещенный набор атрибутов страниц памяти. Любой блок памяти, имеющий страницы с один из таких атрибутов, будет проигнорирован
Поле PermittedProtect определяет разрешенный набор атрибутов страниц памяти
Поле ProhibitedSpecialProtect определяет запрещенный набор специальных атрибутов страниц памяти. Любой блок памяти, имеющий страницы с один из таких атрибутов, будет проигнорирован
Поле ProhibitedPageType определяет запрещенные типы страниц памяти. Любой блок памяти, имеющий страницы таких типов, будет проигнорирован

Значение свойства ReadOptions по умолчанию настроено оптимальным образом.

Блоки памяти

Как уже было сказано, вся память редактируемого процесса разбита на регионы и блоки. Когда библиотека читает память, она берет ее по кусочкам из каждого блока, а потом склеивает воедино и передает в компонент. Таким образом, каждый байт полученной памяти принадлежит какому-то блоку в том процессе, где он был взят. Так вот, если у вас есть, например, память какого-то процесса размером, скажем, в 10 мегабайт, и вы обнаружили в этой памяти нужное вам число, адрес которого 100 байт, то вы, естественно, хотите изменить его. Можно поступить несколькими способами:

Первый способ – это передать соответствующим методам записи адрес этого числа – 100 байт, то есть локальный адрес, а также новое число, на которое вы хотите изменить старое. Этот способ рассмотрим несколько позже.
Второй способ – это получить блок памяти в редактируемом процессе, которому соответствует число по локальному адресу 100, и использовать соответствующие методы записи. Этот способ имеет преимущество, так как он выполняется быстрее.

Для получения блока памяти используется функция:

function TMemoryInspector.GetMemoryRegion(LocalAddress: Longword): Boolean;

Ее параметр LocalAddress это и есть адрес числа в нашем примере, по которому мы хотим получить соответствующий блок в редактируемом процессе. В результате вызова этой функции изменяются некоторые свойства компонента:

property Beginning: Integer;

Используется библиотекой и обозначает сумму размеров разрешенных блоков памяти, предшествующих полученному блоку. Значение этого свойства необходимо для некоторых методов записи.

property MemoryRegion: TRegion;

TRegion = record
AllocationBase, BaseAddress: Pointer;
AllocationProtect, Protect: TProtect;
SpecialProtect: TSpecialProtect;
PageState: TPageState;
RegionSize: Longword;
PageType: TPageType;
end;

Это и есть нужный нам блок памяти. Отдельные значения полей записи TRegion вряд ли вам понадобятся, так как свойство MemoryRegion нужно только для методов записи. Тем не менее, я кратко опишу эти поля:

AllocationBase: Начальный адрес региона памяти
BaseAddress: Начальный адрес блока памяти
AllocationProtect: Атрибуты защиты региона памяти, присвоенные ему по время резервирования
Protect: Атрибуты защиты блока памяти
SpecialProtect: Специальные атрибуты защиты блока памяти
PageState: Состояние страниц блока памяти
RegionSize: Размер блока памяти
PageType: Тип физической памяти страниц блока

Все подготовительные работы для записи числа по адресу 100 завершены. Теперь можно приступать к записи:

function Write(MemoryRegion: TRegion; Start, Beginning: Longword;
Buffer: TShareBuffer; Length: Longword = 0): Boolean; overload; virtual;
function WriteByte(MemoryRegion: TRegion; Start, Beginning: Longword;
Value: Byte): Boolean; overload; virtual;
function WriteWord(MemoryRegion: TRegion; Start, Beginning: Longword;
Value: Word): Boolean; overload; virtual;
function WriteLongword(MemoryRegion: TRegion; Start, Beginning: Longword;
Value: Longword): Boolean; overload; virtual;
function WriteInt64(MemoryRegion: TRegion; Start, Beginning: Longword;
Value: Int64): Boolean; overload; virtual;
function WriteSingle(MemoryRegion: TRegion; Start, Beginning: Longword;
Value: Single): Boolean; overload; virtual;
function WriteDouble(MemoryRegion: TRegion; Start, Beginning: Longword;
Value: Double): Boolean; overload; virtual;
function WriteExtended(MemoryRegion: TRegion; Start, Beginning: Longword;
Value: Extended): Boolean; overload; virtual;
function WriteString(MemoryRegion: TRegion; Start, Beginning: Longword;
Value: ShortString): Boolean; overload; virtual;
function WriteBuffer(MemoryRegion: TRegion; Start, Beginning: Longword;
Value: Pointer; Length: Longword): Boolean; overload; virtual;
function WriteBuffer(MemoryRegion: TRegion; Start, Beginning: Longword;
Value: TByteArray): Boolean; overload; virtual;
function WriteBuffer(MemoryRegion: TRegion; Start, Beginning: Longword;
Value: string): Boolean; overload; virtual;

Осталось выбрать наиболее подходящую функцию для записи. Несколько слов об общих параметрах функций. Параметры MemoryRegion и Beginning это то, о чем мы только что говорили. Параметр Start это адрес начала записи в масштабе блока памяти: Start = LocalAddress – Beginning. Базовый метод записи Write требует параметр Buffer, который имеет тип:

TShareBuffer = record
case Byte of
0: (ByteArray: TSmallByteArray);
1: (CharArray: TSmallCharArray);
2: (ValueRecord: TValueRecord);
3: (Float80: Extended);
end;

где

TSmallByteArray = array[Byte] of Byte;

TSmallCharArray = array[Byte] of Char;

TValueRecord = record
case Byte of
0: (ByteArray: array[0..7] of Byte);
1: (Signed8: Shortint);
2: (Unsigned8: Byte);
3: (Signed16: Smallint);
4: (Unsigned16: Word);
5: (Signed32: Longint);
6: (Unsigned32: Longword);
7: (Signed64: Int64);
8: (Float32: Single);
9: (Float64: Double);
end;

Как видно, параметром Buffer может быть представлено практически любое значение, имеющее наиболее распространенный тип и небольшой размер. Если требуется записать значение, длина которого превышает размер структуры TShareBuffer, следует использовать методы типа WriteBuffer. Такие методы могут записывать значения неограниченной длины. Параметры Value методов WriteBuffer имеют тип:

Pointer; ссылка на величину записи
TByteArray = array of Byte; массив байт неограниченной длины
String; длинная строка

В итоге я приведу полный код примера, в котором требуется записать в память процесса число по локальному адресу 100: …

const
Value: Int64 = 1000;
var
LocalAddress, Start: Integer;
MemoryInspector: TMemoryInspector;
Stream: TMemoryStream;
begin
MemoryInspector := TMemoryInspector.Create(Self);
MemoryInspector.Parent := Self;
with MemoryInspector do
begin
// Получаем информацию обо всех процессах и их окнах:
UpdateWndData;
// Выбираем самый первый процесс:
Selected := 0;
// Устанавливаем адрес:
LocalAddress := 100;
// Получаем блок памяти:
GetMemoryRegion(LocalAddress);
// Устанавливаем начало записи:
Start := LocalAddress - Beginning;
// Запись:
WriteInt64(MemoryRegion, Start, Beginning, Value);
// Память процесса можно загрузить в поток и сохранить в файл:
Stream := TMemoryStream.Create;
try
StreamRef := Stream;
PeekData;
Stream.SaveToFile('stream.dat');
finally
Stream.Free;
end;
end;


Простые методы записи

Второй метод записи был только что подробно рассмотрен. Теперь пришла очередь описать первый метод, наиболее простой. Он работает немного медленнее предыдущего, но все же обладает некоторым преимуществом. Представьте себе ситуацию, вы собираетесь записать число размером, скажем 10 байт. Тот блок, в котором будет производиться запись, имеет размер, например 4096 байт, запись начинается с 4092 байта. Получается, что в регион может быть записано только 4 байта, а нужно записать 10 байт. Функции второго типа, которые были рассмотрены в предыдущей главе, в такой ситуации запишут только 4 байта из 10. Функции первого типа ведут себя иначе и в рассматриваемой ситуации сначала найдут следующий блок памяти, запишут в него неуместившиеся 6 байт, после чего запишут первые 4 байта в исходный блок памяти. Ниже приведен список функций первого типа:

function Write(LocalAddress: Longword; Buffer: TShareBuffer; Length: Longword = 0): Boolean; overload; virtual;
function WriteByte(LocalAddress: Longword; Value: Byte): Boolean; overload; virtual;
function WriteWord(LocalAddress: Longword; Value: Word): Boolean; overload; virtual;
function WriteLongword(LocalAddress: Longword; Value: Longword): Boolean; overload; virtual;
function WriteInt64(LocalAddress: Longword; Value: Int64): Boolean; overload; virtual;
function WriteSingle(LocalAddress: Longword; Value: Single): Boolean; overload; virtual;
function WriteDouble(LocalAddress: Longword; Value: Double): Boolean; overload; virtual;
function WriteExtended(LocalAddress: Longword; Value: Extended): Boolean; overload; virtual;
function WriteString(LocalAddress: Longword; Value: ShortString): Boolean; overload; virtual;
function WriteBuffer(LocalAddress: Longword; Value: Pointer; Length: Longword): Boolean; overload; virtual;
function WriteBuffer(LocalAddress: Longword; Value: TByteArray): Boolean; overload; virtual;
function WriteBuffer(LocalAddress: Longword; Value: string): Boolean; overload; virtual;

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


const
Value: Int64 = 1000;
var
LocalAddress: Integer;
MemoryInspector: TMemoryInspector;
Stream: TMemoryStream;
begin
MemoryInspector := TMemoryInspector.Create(Self);
MemoryInspector.Parent := Self;
with MemoryInspector do
begin
// Получаем информацию обо всех процессах и их окнах:
UpdateWndData;
// Выбираем самый первый процесс:
Selected := 0;
// Устанавливаем адрес:
LocalAddress := 100;
// Запись:
WriteInt64(LocalAddress, Value);
// Память процесса можно загрузить в поток и сохранить в файл:
Stream := TMemoryStream.Create;
try
StreamRef := Stream;
PeekData;
Stream.SaveToFile('stream.dat');
finally
Stream.Free;
end;
end;


Заморозка значений

Технология заморозки значений практически ничем не отличается от технологии записи на уровне блока памяти:

function Freeze(Elapse: Longword; MemoryRegion: TRegion; Start, Beginning: Longword; Buffer: TShareBuffer; Length: Longword = 0): Boolean; overload; virtual;
function FreezeByte(Elapse: Longword; MemoryRegion: TRegion; Start, Beginning: Longword; Value: Byte): Boolean; virtual;
function FreezeWord(Elapse: Longword; MemoryRegion: TRegion; Start, Beginning: Longword; Value: Word): Boolean; virtual;
function FreezeLongword(Elapse: Longword; MemoryRegion: TRegion; Start, Beginning: Longword; Value: Longword): Boolean; virtual;
function FreezeInt64(Elapse: Longword; MemoryRegion: TRegion; Start, Beginning: Longword; Value: Int64): Boolean; virtual;
function FreezeSingle(Elapse: Longword; MemoryRegion: TRegion; Start, Beginning: Longword; Value: Single): Boolean; virtual;
function FreezeDouble(Elapse: Longword; MemoryRegion: TRegion; Start, Beginning: Longword; Value: Double): Boolean; virtual;
function FreezeExtended(Elapse: Longword; MemoryRegion: TRegion; Start, Beginning: Longword; Value: Extended): Boolean; virtual;
function FreezeString(Elapse: Longword; MemoryRegion: TRegion; Start, Beginning: Longword; Value: ShortString): Boolean; virtual;
function FreezeBuffer(Elapse: Longword; MemoryRegion: TRegion; Start, Beginning: Longword; Value: Pointer; Length: Longword): Boolean; overload; virtual;
function FreezeBuffer(Elapse: Longword; MemoryRegion: TRegion; Start, Beginning: Longword; Value: TByteArray): Boolean; virtual;
function FreezeBuffer(Elapse: Longword; MemoryRegion: TRegion; Start, Beginning: Longword; Value: string): Boolean; virtual;

Как видно, список этих функций отличается от списка функций записи только одним дополнительным параметром. Параметр Elapse обозначает частоту обновления в миллисекундах. После вызова любой из этих функций, изменяется свойство компонента, которое обозначает состояние заморозки:

property Frozen: Boolean;

В любой момент времени может быть заморожено только одно значение одного процесса. Для разморозки предназначена функция:

function Unfreeze: Boolean; virtual;

Ниже приведен код пример, который рассматривался в предыдущих главах, где вместо записи мы замораживаем значение:


const
Value: Int64 = 1000;
var
LocalAddress, Start: Integer;
MemoryInspector: TMemoryInspector;
Stream: TMemoryStream;
begin
MemoryInspector := TMemoryInspector.Create(Self);
MemoryInspector.Parent := Self;
with MemoryInspector do
begin
// Получаем информацию обо всех процессах и их окнах:
UpdateWndData;
// Выбираем самый первый процесс:
Selected := 0;
// Устанавливаем адрес:
LocalAddress := 100;
// Получаем блок памяти:
GetMemoryRegion(LocalAddress);
// Устанавливаем начало заморозки:
Start := LocalAddress - Beginning;
// Заморозка с интервалом обновления 500 мс:
FreezeInt64(500, MemoryRegion, Start, Beginning, Value);



// Разморозка:
Unfreeze;
// Память процесса можно загрузить в поток и сохранить в файл:
Stream := TMemoryStream.Create;
try
StreamRef := Stream;
PeekData;
Stream.SaveToFile('stream.dat');
finally
Stream.Free;
end;
end;


Установка компонента

Компонент состоит из нескольких частей. Первая часть это, собственно, сам компонент и набор необходимых вторичных компонентов. Вторая часть это используемая компонентом библиотека. Несколько слов о вторичных компонентах и файлах:

Компонент TMemoryManager предназначен для получения информации о доступных процессах и их окнах, а также для чтения памяти и записи в память
Компонент TFileManager предназначен для создания файла, отображаемого в память и дальнейшей работы с таким файлом
Файл MemUtils содержит некоторые общие типы и данные

Порядок установки компонента:

Установить компоненты TMemoryManager, TFileManager, файл MemUtils
Получить файл Mi.dll и переместить его в директорию, где находится пакет с установленными компонентами
Установить компонент TMemoryInspector

Необходимо, чтобы еще одна копия файла Mi.dll находилась в одной директории с исходными файлами программы, использующей компонент.

Ресурсы

MemUtils.zip (209 K; обновление от 31.05.04)
Архив содержит:

компонент TMemoryInspector
компонент TMemoryManager
компонент TFileManager
файл MemUtils
библиотеку Mi

А так же, дополнительную информацию и пример по использованию этого компонента.

 

 

free download Cheat Engine и программ для создания трейнеров, читтеров, хаков, сканеров памяти

В качестве жертвы возьмём winmine.exe – игра Сапёр, версия под XP

Править мы будем количество мин на поле.
Для внесения изменений в чужой процесс нам необходимо узнать его ID.
Накидаем небольшую функцию:

Код:
function GetProcessID(Const ExeFileName: string; var ProcessId: integer): boolean;
var
  ContinueLoop: BOOL;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  result := false;
  FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize := Sizeof(FProcessEntry32);
  ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
  while integer(ContinueLoop) <> 0 do begin
	if (StrIComp(PChar(ExtractFileName(FProcessEntry32.szExeFile)), PChar(ExeFileName)) = 0)
	   or (StrIComp(FProcessEntry32.szExeFile, PChar(ExeFileName)) = 0)  then begin
	   ProcessId:= FProcessEntry32.th32ProcessID;
	   result := true;
	   break;
	end;
	ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;
Тип у функции булевый, поэтому ID процесса будет возвращаться в переменную, указанную в качестве второго параметра (ProcessId).

Пример использования:

Код:
var
  PidId: integer;
begin
  if GetProcessID('winmine.exe', PidId) then
    begin
      //исполняемый код
    end;
end;
Значения всех переменных храниться в определённой ячейки памяти в шестнадцатеричной системе. Для того чтобы изменить определённое значение нам необходимо знать адрес ячейки. Чтобы вычислить его можно воспользоваться ArtMoney, но я буду использовать CheatEngine.

Запустим нашу «Жертву»:


Далее откроем CheatEngine и жмём на кнопку «Select a process to open»:

В появившемся списке выберем элемент оканчивающийся на winmine.exe и нажмём кнопку «Open»
Теперь можно осуществлять поиск значений:

На уровне сложности «Новичек» у нас 10 мин, поэтому в поле Value вводим число 10
Жмём «First Scan»
В сапёре переходим на уровень сложности «Профессионал»
В CheatEngine в поле Value вводим 99
Жмём «NextScan»

Видим 3 значения, дважды кликая по ним мы добавляем их в список в нижней части окна, если выделить элемент из этого списка и нажать клавишу Enter то откроется окно редактирования значения. Это может быть необходимо для определения какая именно переменная нам нужна.
Опытным путём я определил что за количество мин отвечает номер три, находящийся по адресу 10056A4.


Теперь нам необходимо написать функцию, которая могла бы изменить кол-во мин на более выгодное для нас Пусть это будет одна мина. в шестнадцатеричной системе 01 (в делфи при указании числа в шестнадцатеричной системе перед ним необходимо ставить знак $, например $01).

Код:
var
  byteArr : Array of byte;
begin
//пытаемся найти процесс Сапёра    
if GetProcessID('winmine.exe', PidId) then
  begin
    //Открываем процесс для полного доступа (в том числе и редактирования памяти)    
    PidHandle  :=  OpenProcess(PROCESS_ALL_ACCESS,False,PidId);
	  //указываем размер массива, в нашем случае 4 байта
	  SetLength(byteArr, 4);
	  //заполняем массив
 	  byteArr[0] := $01;
 	  byteArr[1] := $00;
 	  byteArr[2] := $00;
 	  byteArr[3] := $00;
	  //вносим изменения в память процесса
	  pokeX($10056A4, byteArr);
	  //отчищаем память, занимаемую массивом
 	  SetLength(byteArr, 0);
	  //закрываем процесс
	  closehandle(PidHandle);
    //Выводим сообщения о том, что всё ОК
    SHOWMESSAGE('Изменения внесены, для их применения необходимо перезапустить игру на текущем уровне сложности');
  end
else
  begin
	  MessageDlg('Сначала запустите Сапёр!', mtwarning, [mbOK],0);
  end;
Хочется обратить ваше внимание на то, что занося данные в массив в качестве первого элемента мы указываем последний (при счёте слева на право) байт числа. Такова особенность работы ЭВМ.
В принципе мы могли установить размер массива на 1 и записать только один элемент массива (остальные байты автоматически бы обнулились):

Код:
SetLength(byteArr, 1);
byteArr[0] := $01;
Но первый вариант корректней, так как мы работаем с 4х байтовой ячейкой памяти.

Теперь рассмотрим функцию записи данных в память процесса:

Код:
procedure pokeX(Address: Cardinal; Data: Array of Byte);
var
Written: Cardinal;
begin
  WriteProcessMemory(PidHandle, Pointer(Address), @Data, SizeOf(Data), Written);
end;
Она сделана для удобства, т.к. ей мы передаём только 2 переменные, после чего функция сама заполняет оставшиеся параметры функции WriteProcessMemory (стандартная функция WinAPI ничего сверхъестественного).
Первым атрибутом для неё служит адрес памяти, который мы вычислили в CheatEngine, вторым – массив с данными.

Посмотрим на полный исходник:

Код:
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;
 
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
  PidHandle: integer;
  PidID : integer;
  byteArr : Array of byte;
Const
  ProgramName = 'winmine.exe';
 
 
implementation
 
uses Unit1;
 
{$R *.dfm}
 
function GetProcessID(Const ExeFileName: string; var ProcessId: integer): boolean;
var
  ContinueLoop: BOOL;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  result := false;
  FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize := Sizeof(FProcessEntry32);
  ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
  while integer(ContinueLoop) <> 0 do begin
	if (StrIComp(PChar(ExtractFileName(FProcessEntry32.szExeFile)), PChar(ExeFileName)) = 0)
	   or (StrIComp(FProcessEntry32.szExeFile, PChar(ExeFileName)) = 0)  then begin
	   ProcessId:= FProcessEntry32.th32ProcessID;
	   result := true;
	   break;
	end;
	ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;
 
procedure pokeX(Address: Cardinal; Data: Array of Byte);
var
Written: Cardinal;
begin
  WriteProcessMemory(PidHandle, Pointer(Address), @Data, SizeOf(Data), Written);
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  byteArr : Array of byte;
begin
if GetProcessID(ProgramName, PidId) then
  begin
    PidHandle  :=  OpenProcess(PROCESS_ALL_ACCESS,False,PidId);
	  SetLength(byteArr, 4);
 	  byteArr[0] := $01;
 	  byteArr[1] := $00;
 	  byteArr[2] := $00;
 	  byteArr[3] := $00;
	  pokeX($10056A4, byteArr);
 	  SetLength(byteArr, 0);
	  closehandle(PidHandle);
    SHOWMESSAGE('Изменения внесены, для их применения необходимо перезапустить игру на текущем уровне сложности');
  end
else
  begin
	  MessageDlg('Сначала запустите Сапёр!', mtwarning, [mbOK],0);
  end;
end;
 
end.
Вот и всё! Запускаем Сапёра, выбираем режим сложности "Профессионал", жмём в нашей программе на кнопку изменения памяти. В сапёре нажимаем на рожицу - запускаем новую игру. Всё у вас одна мина на поле

На последок могу сказать, что у вас наврятли получиться сразу взламывать сложные игры и программы, так как там многие массивы данных создаются динамично и при каждом новом запуске программы имею разные адреса в памяти.
Вложения:
Скачать файл (Bandicam.rar)BandiCam 1.7 (CRC)[Программа для записи видео с экрана монитора + звук. Без ограничения времени записи и лого www.bandicam.com на видео-роликах.]6882 Kb29.06.2015 00:03
Скачать файл (CheatEngine62src.rar)CEngine_src[скачать исходники программы CheatEngine 6.2 (download Delphi's source files)]2027 Kb18.06.2013 12:18
Скачать файл (CheatEngine63.exe)CheatEngine63[скачать известный трейнер для сканирования памяти, поиска сигнатуры и редактирования переменных из других приложений]7882 Kb18.06.2013 12:16
Скачать файл (ProcessExplorer.zip)ProcessExplorer[скачать ProcessExplorer (Microsoft) для отслеживания нитей запущенных в памяти процессов]1149 Kb18.06.2013 12:11
Скачать файл (WinDebugTools.exe)WinDebugTools[скачать Windows Debug Tools SDK (Microsoft) - пакет, расширяющий режим Threads в ProcessExplorer]968 Kb19.06.2013 01:11
Комментарии
Антон |2016-08-03
avatar Битые ссылки: не качается CheatEngine63 :nea:
LikaZ |2016-10-19
Все нормально качает
Андрей |2014-07-03
Тема класс :clap: :clap: :clap: :clap: :clap: :clap: :clap: :clap:
ADM13 |2014-06-28
avatar Нормальная подборка для сканирования памяти разных программ.
Только зарегистрированные пользователи могут оставлять комментарии!
 
 

Архивы CMP

Статистика

Анализ спинов

Частые вопросы

Тренажер игры


- Нет денег для старта?
Помощь от профсоюза игроков: Ежедневно на страницах сайта появляются три бриллианта. Любой зарегистрированный майнер, который найдет такое изображение и сделает мышкой клик по нему, получит 25$ на свой WMZ-кошелек. Бонус может находиться в любом месте - в тексте статьи, в рабочих группах, в обсуждениях, в комментариях к фото или просто на стене профиля любого майнера. деньги для начала работы

Профессиональная игра в казино:

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

Отличные две стратегии, которые имеют длинные волны устойчивого роста кредита. Попробуем выделить и соединить значимые компоненты обеих методик в обобщенную......


Азартные игры могут вызывать зависимость, пожалуйста, отнеситесь ко всему, что Вы далее станете узнавать и применять на практике, очень ответственно ! ......


Отзывы игроков:

Anna
ИПМ: 0.9
Я вам даже больше скажу, как человек, который знает кухню изнутри. Даже если представить невозможное, и допустим Тестер придумал систему, по которй МО изменится в +. Так казиношники проанализировав это - сразу урежут лимиты ставок, внесут изменения в правила, где будет ограничение по "ботам" и системам. Если это не поможет - будут тупо не выплачивать выигрыши по таким аккаунтам, сославшись на какой то пункт в правилах. И им будет абсолютно по фиг, что кто то будет исходить пеной на форумах. Вы как дети, честное слово. :) Ну не будет казино оплачивать жизнь Тестера, поймите это наконец то.

Азартные игры могут вызывать зависимость, пожалуйста, сами не играйте - все сделает CMP бот для игры в казино!

Freeroll

Только в лицензионных играх у вас всегда есть шанс поймать x1000 и больше.
Ежедневные freeroll-турниры на лицензионных слотах. Казино дает 2000$ реалом для старта в каждой игре.

E pluribus unum


Марафоны игр в разных казино от Шпилевого.

Рулетка

Интернет казино Profit
  Зеркало 1       Зеркало 2 
Казино Profit. Лучшая рулетка с треком и контролем честности. Турниры 500$.


игровые автоматы

Copyright 2011-2018 © casino-mining.com © All Rights Reserved