Показаны сообщения с ярлыком C#. Показать все сообщения
Показаны сообщения с ярлыком C#. Показать все сообщения

20130803

IT'S ALIVE! ALIVE!!

Привет всем, кто это читает! Ещё не забыли моё имя и тему этого блога? (:

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

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

1. Я смотрю последние видео и пробую продолжить от них (d3d, хуки, воллхаки и прочая прелесть на C++). Плюсы я знаю средне, d3d - ещё более средне, так что это будет медленно и, скорее всего, корявенько, но я учусь и исправляюсь.
2. Мы садимся и с нуля пишем движок для трейнеров на C++. Или на ассемблере. Или на C#. С фичами, которые предложите вы, или до которых не догадаюсь я. Весь код я буду заливать на GitHub, конечно же.
3. С нуля пишем какую-нибудь простенькую игру на d3d, потом - компаемся отладчиком в её потрохах и понимаем, как и что работает. Ещё более медленный вариант, но сулит много интересного.
3. Что-нибудь повеселее - то, что вы предложите в комментариях.

20120817

Direct3D - Часть 0: Вступительная

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

Ребята, если вы до этого никогда не писали на плюсах (а я и сам почти никогда на них не писал) - не переживайте, он сильно похож на C# - оба имеют синтаксис, очень похожий на их далёкого предка - С.

Ну, тем хардкорщикам, которые до этого писали только на ассемблере, придётся немного попривыкнуть. :D

Его и будем ломать в дальнейшем. :)

[Ссылка] на видеоурок.
[Ссылка] на исходный код + скомпилированную программу.

PS: Всё-таки выложу исходник ещё и тут - прокомментирую:


#include //Подключаем необходимые заголовочные файлы, чтобы оно соображало,
#include //где какие функции, что какие структуры обозначают и всё такое

#pragma comment(lib, "d3d9.lib") //До кучи добавляем библиотечку d3d

LPDIRECT3D9 d3d; //Объявляем глобальную переменную для объекта d3d
LPDIRECT3DDEVICE9 d3ddev; //Такую же, но для устройства d3d

void CleanD3D() //Функция, завершающая работу D3D
{
d3ddev->Release(); //У обоих объектов вызываем функцию "УбитьСебя"
d3d->Release();
}

void RenderFrame() //Функция, рисующая что-нибудь на экране
{
        //Говорим нашему устройству d3d очистить наше окно цветом FF0000 - красным!
d3ddev->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 0, 0), 1.0f, 0);
d3ddev->BeginScene(); //Типа начинаем рисовать
d3ddev->EndScene(); //Сразу заканчиваем, так ничего и не нарисовав
d3ddev->Present(0, 0, 0, 0); //Меняем местами буфер на экране и тот, который мы заполнили цветом
}

//Функция, инициализирующая D3D
void InitD3D(HWND hWnd) //hWnd - аргумент, идентификатор нашего окна
{
d3d = Direct3DCreate9(D3D_SDK_VERSION); //Создаём объект d3d, запихиваем в переменную
D3DPRESENT_PARAMETERS d3dpp; //Объявляем переменную со структурой настроек
ZeroMemory(&d3dpp, sizeof(d3dpp)); //Очищаем выделенную под неё память
d3dpp.Windowed = 1; //Говорим, что рисовать будем в окне
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; //В один буфер рисуем, когда первый уже отобразили
        //Создаём устройство d3d, скармливая ему идентификатор нашего окна
        //Результат тоже записываем в глобальную переменную
d3d->CreateDevice(0, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);
}

//Функция, управляющая нашим окном. Аргументы:
//hWnd - идентификатор окна
//message - сообщение для обработки
//wParam и lParam - дополнения к сообщению
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message) //Смотрим, что за сообщение
{
case WM_DESTROY: //Если "Убить окно"
{
PostQuitMessage(0); //Пишем завещание, говорим что окно умирает
return 0; //Возвращаем 0
}
}
return DefWindowProc(hWnd, message, wParam, lParam); //Иначе - возвращаем значение по умолчанию
}

//Точка входа в программу. Аргументы:
//hInstance - идентификатор процесса в системе
//hPrevInstance - идентификатор процесса-родителя (если есть)
//Оставшиеся два устарели и не используются, так что там всегда 0
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc; //Объявляем переменную под структуру описания нашего окна
ZeroMemory(&wc, sizeof(WNDCLASSEX)); //Очищаем под неё память
wc.cbSize = sizeof(WNDCLASSEX); //Задаём её размер
wc.style = CS_HREDRAW | CS_VREDRAW; //Говорим, как окно будет рисоваться
wc.lpfnWndProc = WindowProc; //Говорим, какая функция будет окном управлять
wc.hInstance = hInstance; //Указываем идентификатор процесса-родителя окна
wc.hCursor = LoadCursor(0, IDC_ARROW); //Использовать будем этот курсор-стрелочку
wc.lpszClassName = L"WindowClass"; //Имя структуры, описывающей окно
RegisterClassEx(&wc); //Регистрируем структуру в системе
HWND hWnd = CreateWindowEx(0, L"WindowClass", L"Test D3D9", 0, 0, 0, 640, 480, 0, 0, hInstance, 0); //Создаём окно с заголовком "Test D3D9" в верхнем левом углу экрана (0:0) размером в 640х480 пикселей, получаем его идентификатор
ShowWindow(hWnd, nCmdShow); //Показываем окно на экране
InitD3D(hWnd); //Инициализируем d3d
MSG msg; //Объявляем переменную под хранение сообщений для окна
while(1) //Делаем бесконечный цикл
{
while(PeekMessage(&msg, 0, 0, 0, 1)) //В нём в цикле получаем сообщения
{
TranslateMessage(&msg); //Переводим их в понятный окну формат
DispatchMessage(&msg); //Отправляем на растерзание процедуре окна
}
if(msg.message == WM_QUIT) //Если получили сообщение к выходу
{
break; //Прерываем цикл
}
RenderFrame(); //Иначе - рисуем при помощи d3d
}
CleanD3D(); //Если цикл прервался - завершаем работу d3d
return msg.wParam; //И выходим
}

20120704

Дописываем наш трейнер на C#. Инъекции кода. Часть 1.

Один мой зритель на ютубе подметил, что трейнер наш не совсем полноценен. Исправим это недоразумение!

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

[Ссылка].


Исходный код:

static void MakeCave()
{
   if (pID != 0)
   {
      Console.WriteLine("Process Id: " + pID);
      var handle = OpenProcess(ProcessAccessFlags.All, false, pID);
      if (handle != IntPtr.Zero)
      {
         Console.WriteLine("Process handle: " + handle.ToString());
         var caveAddress = 0x004002A8;                    
         var valueon = new byte[] { 0xD9, 0x9E, 0x5C, 0x43, 0x0F, 0x00 };
         var valueoff = new byte[] { 0xD9, 0x9E, 0x5C, 0x43, 0x0F, 0x00 };
         var addressFrom = 0x00416494;
         var addressTo = addressFrom + valueoff.Length;
         var buffer = new byte[valueoff.Length];
         buffer[0] = 0xE9;                    
         var f = BitConverter.GetBytes(caveAddress-addressFrom-5);                    
         Array.Copy(f, 0, buffer, 1, f.Length);
         for (var i = 5; i < valueoff.Length; i++)
         {
            buffer[i] = 0x90;
         }
         var dummy = new UIntPtr();
         WriteProcessMemory(handle, (IntPtr)addressFrom, buffer, (uint)buffer.Length, out dummy);
         var caveBuffer = new byte[valueon.Length + 5];
         Array.Copy(valueon, caveBuffer, valueon.Length);
         caveBuffer[valueon.Length] = 0xE9;
         var retAddress = BitConverter.GetBytes(addressFrom-caveAddress-valueoff.Length);
         Array.Copy(retAddress, 0, caveBuffer, valueon.Length + 1, retAddress.Length);
         WriteProcessMemory(handle, (IntPtr)caveAddress, caveBuffer, (uint)caveBuffer.Length, out dummy); 
         CloseHandle(handle);
         Console.WriteLine("Handle closed.");
         Console.ReadKey();
      }
   }
}

ВНИМАНИЕ! В коде допущена логическая ошибка - сначала нужно записывать кейв, а только потом - прыжок на него. Ошибка допущена сознательно и исправляется простой перестановкой нескольких строчек, так что это будет домашним заданием.

20120630

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

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

Но за этими словами кроется довольно громоздкая надстройка в виде горячих клавиш, таймеров, окошек, сканеров сигнатур и прочего сахара, сделанного исключительно из расчёта на удобство использования для конечного пользователя. Как бы, нам-то с вами известно, что надо всего-то по адресу 0x12345 поменять mov eax,ebx на nop,  но вот людям, качающим и использующим трейнеры абсолютно до лампочки - им надо, чтобы нажал кнопку - стал бессмертным.

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

А что может быть круче? Может!

Как мы знаем, почти 90% информации в наши черепушки поступает посредством глаз - т.е. посредством того, что мы видим. Пользователь может взять и не запомнить комбинации клавиш для всех 30-ти опций нашего трейнера, а ведь опций может быть и 50, и 150.

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

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

Вот.

Мы уже немного освоили графику под винду с использованием ассемблера (покрутите блог вниз - там была статья с картинками и рисованием прямоугольничка), следующий шаг - DirectX, но писать мы будем уже на C++, потому что на C# это всё будет довольно криво выглядеть. Не пугайтесь, если не знаете плюсов - нам понадобится исключительно общая концепция работы, а синтаксис там и без этого очень похожий.

20120605

Ещё чуток по поводу программирования напишу. Что-то из этого я в блоге уже писал, что-то - не писал, но повторение - это, как известно, зашибись, поэтому пусть будет. Итак!

Вы совершенно ни хрена не понимаете в чёрной магии, но очень хотите научиться. Кто согласен - читаем дальше.

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

1. [Рассылку Калашникова] - объясняет с самых основ, просто, понятно, со вкусом и юмором.
2. [Дневники чайника] - длинный, но интересный дневник о том, как один парень изучил ассемблер с нуля. Отладчиком он там пользуется довольно древним - вы можете использовать любой другой, например [OllyDbg].

Если же вы в принципе не представляете, как всё это происходит и в жизни не видели даже Бейсика - добро пожаловать [сюда] и [сюда]. Пусть и не ассемблер, но основы программирования поданы отлично. Предупреждаю! - необходимо знание английского хотя бы на уровне чтения, средненькое.

В принципе, используя СЕ, можно создавать трейнеры и без навыков программирования (помимо ассемблера, который нужен для самого взлома), но если очень приспичит и захочется разгуляться - придётся писать трейнеры самому.

Трейнеры (под Windows, конечно же) пишутся с использованием [WinAPI], прочитав статью, можно понять, что писать при этом можно на любом языке, лишь бы он умел с этими самыми винапи работать. Поэтому - C, C#, C++, Pascal - список можно долго продолжать.

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

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

20120528

[Видеоурок] И что же, всё-таки, делать с указателями?

[Ссылочка].

Смотрим ещё раз, как ищутся указатели, подробно разбираем код из [статьи].

PS: Совсем забыл! Чтобы узнать именно адрес значения (например, чтобы затем записать туда что-нибудь) - просто остановитесь на предпоследнем шаге - не читайте значение адреса, прочитайте последний уровень указателя - результатом будет адрес значения, куда можно писать, используя уже готовые процедуры.

20120524

Ну очень важно.

Внимание, вопрос!
Про что мне всё-таки записать третью часть видеоурока по трейнерам? Что ещё научимся делать?

Пилим дальше трейнер на C# - учимся работать с указателями.

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

Задача у нас такая - есть указатель вида 0x12345+0x1+0x5+0x7, надо суметь его прочитать. Что такое указатель - все помнят? Смотрите:

0x12345 - по этому адресу будет лежать другой адрес (это ведь указатель!). Допустим, 0xA.
Прибавляем к результату первое смещение, получаем 0xA+0x1. Читаем получившийся адрес:

[0xA+0x1] = второй адрес, скажем, 0xB

[0xB+0x2 (второе смещение)] = 0xC.

...
...

[0xD+0x7] = 123 - нужное нам значение, на которое указатель и указывает. Вот код:


public int ReadBytes()
        {          
            if (pID != 0) //Проверяем, что игра найдена
            {
                var dwAddress = 0x55D804; //Базовый адрес указателя
                byte[] buffer = new byte[4]; //Буфер, массив из четырёх байт, куда будут читаться значения
                int bytesread; //Переменная-заглушка, хранящая количество прочитанных байт
                var handle = OpenProcess(0x001F0FFF, false, pID); //Получаем хэндл процесса игры
                ReadProcessMemory(handle, (IntPtr)dwAddress, buffer, 4, out bytesread); //Читаем значение базового адреса
                var result = BitConverter.ToInt32(buffer, 0); //Конвертируем массив байт в циферки
                result += 0x70; //Прибавляем первое смещение
                ReadProcessMemory(handle, (IntPtr)result, buffer, 4, out bytesread); //Читаем получившийся адрес
                var temp = BitConverter.ToSingle(buffer, 0); //Конвертируем результат во float
                CloseHandle(handle); //Закрываем хэндл игры
                return temp; //Возвращаем результат
            }
            return -1; //Если не нашли игру - возвращаем -1.
        }

Тут у нас указатель такой - 0x55D804 + 0x70 = Значение, причём это float. Читаем значение базового адреса, конвертируем из массива байт в цифры, прибавляем смещение, читаем получившийся адрес, конвертируем во float - вуаля! Всё просто. Но код можно улучшить, если у нас много смещений. Смотрите:

//В аргументах присылаем базовый адрес указателя + массив смещений
public int ReadBytes(int baseAddress, byte[] offsets)
        {          
            if (pID != 0 && baseAddress != 0 && offsets.Length != 0) //Проверяем, что всё на месте
            {              
                byte[] buffer = new byte[4]; //Буфер для чтения
                int bytesread; //Заглушка
                var handle = OpenProcess(0x001F0FFF, false, pID); //Получаем хэндл
                ReadProcessMemory(handle, (IntPtr)baseAddress, buffer, 4, out bytesread); //Читаем базовый адрес
                for (var i = 0; i < offsets.Length; i++) //Бежим в цикле, пока не кончатся смещения
                {
                    baseAddress = BitConverter.ToInt32(buffer, 0); //Конвертируем результат в циферки
                    baseAddress += offsets[i]; //Прибавляем смещение
                    ReadProcessMemory(handle, (IntPtr)baseAddress, buffer, 4, out bytesread); //Читаем
                }
//Как только смещения в массиве закончились
CloseHandle(handle); //Закрываем хэндл
                var result = BitConverter.ToSingle(buffer, 0); //Конвертируем результат во float               
                return result; //Возвращаем результат
            }
            return -1; //Иначе - ошибка
        }



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


var address = 0x55D804; //Базовый адрес
var offsets = new byte[] {0x70}; //Массив со смещениями
var myFloat = ReadBytes(address, offsets); //Читаем!





20120406

Улучшаем внешний вид трейнера - C#.

Второй видеоурок по созданию трейнера на C# - используем только голую Microsoft Visual Studio Express 2010, пишем на C#, узнаём, как работать с мышкой\клавиатурой, понимаем, что такое события (и ещё разок освежаем память), придаём трейнеру больше индивидуальности.

[Тык].

20120327

Делаем трейнер на C# - часть первая.

Название говорит само за себя. :)

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

Visual Studio, которая в уроке использовалась, можно скачать [вот отсюда]. А меня можно найти ещё и [вот тут].

20120321

Трейнеры на HLL.

Сейчас я малость простыл (весна же!), но скоро начну выкладывать первые видеоуроки по созданию трейнеров на HLL - Highlevel Language - языках высокого уровня. Думаю начать с C# и C++. Научимся рисовать формочки, подключать нужные нам WinAPI-функции (возможностями .NET-фреймворка я буду стараться не использовать - только чистые WinAPI), само собой - будет показан процесс отладки кода, потому что это очень полезное и увлекательное занятие.

В качестве IDE (это такая штука, где пишется код - некий навороченный блокнот) буду использовать Microsoft Visual Studio. Редакция Express бесплатна для некоммерческого использования и её можно радостно скачать с сайта этих самых Microsoft - ссылку я дам.

Подумываю о том, нужно ли выкладывать исходный код куда-нибудь помимо блога - например, на [GitHub]. Напишите в комментариях, что вам удобней будет. (: