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

MasterGH

Ветераны
  • Постов

    2 999
  • Зарегистрирован

  • Победитель дней

    129

Сообщения, опубликованные MasterGH

  1. Ясно..............

    Тогда скажите как писать скрипт для примера с этой инструкцией  movss xmm0,[edi+000005c4] что-бы знать как пишутся скрипты.

    Согласен с Xipho поищи на форуме. Почитай статьи. Если увижу старания, то я помогу.

  2. Здравствуйте, krocki

    TSearch старая программа и показывает инструкции не правильно. Используйте Cheat Engine (эта программа сложная не спорю, но иначе есть ещё сложнее MHS, OllyDBG). Найдите адрес, поставьте на него брейкпоинт на доступ и приведите вновь Ваши инструкции.

  3. Если вы что-то будите писать, то можете писать про любые другие платформы, эмуляторы и отладчике.

    В этом постей 2 части по созданию читов в игре M4K.

    Игра: M4K.

    Дебагер: fceux-2.1.4a-win32

    Исходник этого эмулятора и различная документация:

    fceu2.1.4a.rar

    Сайт этого отладчка:ссылка


    Часть1.Отключение таймера с помощью отладки.

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

    Сразу покажу к чему мы придём. 

    post-3-1291353608,27_thumb.png

    С помощью этой галочки мы с можем отключать и включать таймер теоритически на любом эмуляторе. Здесь русифицированная версия Cheat Engine, но на оригинальной версии скрипты тоже должны работать.

    Ну а теперь, о том как это было сделано.

    1. Обзор команд микропроцессора 6502 

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

    NOP   NoOperation

    DEC   Decrement Memory by One

    DEX   Decrement Index X by One

    DEY   Decrement Index Y by One

    INC   Increment Memory by One

    INX   Increment Index X by One

    INY   Increment Index Y by One

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

    6502.rar.

    Можете скачать у нас, а можно взять отсюда.

    Не очень плохой дебагер: fceux-2.1.4a-win32

    post-3-1291213918,14_thumb.png

    Как видим тут свои инструкции ассемблера, не тек к которым мы привыкли.

    2. Часть. Простой нопинг.

    Самый простой способ не выполнять какое-то действие это занопить инструкции работающие с адресами параметров на которые хотим повлиять.

     Подопытным кроликом будет M4K, т.е. не пользователь M4K, а игрушка +)

    post-3-1291353523,64_thumb.png

    Рис.1

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

    Для начала найдём адрес таймера.

    Поставим игру на паузу.

    Заходим сюда в RAM Search

    post-3-1291353528,79_thumb.png

    Рис.2

    Первый поиск.

    post-3-1291353532,77_thumb.png

    Рис.3

    Снимаем паузу с игры и вновь ставим, на экране 94 секунды.

    Второй поиск:

    post-3-1291353537,05_thumb.png

    Рис.4

    Как видим, осталось 4 результата. Каждый адрес последовательно выделяем и нажимаем кнопку Add Cheat, чтобы найти из них рабочий путём заморозки. Закрываем этоокно. Идём в другое.

    post-3-1291353541,54_thumb.png

    Рис.5

    Откроется окно

    post-3-1291353546,54_thumb.png

    Рис.6

    Там где звёздочки, там идёт заморозка адреса значением в HEX виде.Вновь снимем паузу с игры и увидим, что таймер не меняется. Наша задача узнать все ли адреса рабочие для заморозки. Для этого мы должны снимать звёздочки и проверять, не работает ли таймер.

    post-3-1291353550,58_thumb.png

    Рис.7

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

    Кликнем правой кнопкой мышки по первому адресу, чтобыперейти в hex редактор, а уже из него быстро попадём куда надо.

    post-3-1291353555,29_thumb.png

    Рис.8

    Ещё не забудьте снять заморозку (я забыл снять заморозку на рис.6) Перешли сюда, смотрим

    post-3-1291353560,48_thumb.png

    Рис.9

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

    post-3-1291353565,33_thumb.png

    Рис.10

    У вас появиться большое окно отладчика.

    post-3-1291353570,02_thumb.png

    Рис.11

    Снимаем паузу с игры и тут же прерываемся на знакомойинструкции вычитания.

    post-3-1291353574,94_thumb.png

    Рис.12

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

    Кликнем левой кнопкой мышки на место указанное стрелкой на рисунке 12.

    Появится интересное окно

    post-3-1291353579,99_thumb.png

    Рис.13

    Инструкция DEC состоит из 2 байтов, NOP - из одного. Значит нужно два NOP-а. Сколько байткакая инструкция занимает смотрите в документации или можете не смотреть, а узнать об этом прямо в этом окне на рис.13 

    Напишем nop и нажмем клавишу Enter. И ещё раз. Вот что вышло.

    post-3-1291353584,83_thumb.png

    Рис.14

    post-3-1291353589,71_thumb.png

    Рис.15

    На рис. 15 байты в главном окне ещё не перерисовались.  Итак мы видим, что мы запишем два нопа, тудагде  надо и не нарушим логику кода.

    Сохраним (Save)для возможной отмены.

    Нажмём Applay (обновить/подтвердить)

    Увидим следующие изменения.

    post-3-1291353593,94_thumb.png

    Рис.16

    Ага, значит мы стерли команду нопами. Закрываем окно нарис. 16 И видим изменение в коде.

    post-3-1291353599,37_thumb.png

    Рис.17

    Теперь нажмем на кнопку RUN и снимаем паузу.

    И видим, что таймер теперь застыл на 93 секундах.

    post-3-1291353603,85_thumb.png

    Рис.18

    Отлично, работает!

    Переходим к автоматизации активации и деактивации чита записью nop-ов и восстановлением оригинального кода

    07: C284:C6 B2 - таймер включен

    07: C284:EA EA - таймер выключен

    Есть множество инструментов, которыми можно это сделать: CE, MHS и в конце концов своим трейнером.  В Artmoney есть ручной поиск сигнатуры, его можно использовать для нахождения адреса, а затем записывать в него пару нопов или восстанавливать предыдущее значение. Но Artmoney меня не устроила темчто там надо делать многое вручную. Идеальный вариант писать свою программу, ноэто долго и поэтому я решил сделать всё на Cheat Engine.

    Итак, скопируем кусок сигнатуры в блокнот (шрифт Courier New, чтобы соблюдалась табуляция):


    07:C286:A5 B2     LDA $00B2 = #$5D
    07:C288:85 07     STA $0007 = #$00
    07:C28A:A9 00     LDA #$00
    07:C28C:85 08     STA $0008 = #$00
    07:C28E:85 09     STA $0009 = #$00
    07:C290:85 0D     STA $000D = #$00
    07:C292:20 BA D2  JSR $D2BA
    07:C295:AD 74 06  LDA $0674 = #$09
    07:C298:69 40     ADC #$40
    07:C29A:8D 3E 06  STA $063E = #$4A
    07:C29D:AD 73 06  LDA $0673 = #$03
    07:C2A0:69 41     ADC #$41
    07:C2A2:8D 3F 06  STA $063F = #$44
    07:C2A5:60        RTS
    07:C284:C6 B2     DEC $00B2 = #$5D

    Сигнатура представляет из себя байты кода:

    C6 B2 A5 B2 85 07 A9 00 85 08 85 09 85 0D 20 BA D2

     

    Здесь не все байты кода, но если нужно, т.е. если чти работать не будет, то возьмите другие байты.

    Пишем скрипт для CE:


    Игра NES: M4K (любой эмулятор)
    Чит-код: Остановка таймера
    Дата: 12.3.2010
    Автор скрипта: MasterGH
    Версия CE: Cheat Engine 5.6  RUS (v 2.0)
    }

    [ENABLE]
    aobscan(_faddress,C6B2A5B28507A90085088509850D20BAD2)
    _faddress:
    db EA EA

    [DISABLE]
    aobscan(_faddress,EAEAA5B28507A90085088509850D20BAD2)
    _faddress:
    db C6 B2
    {

    Запускаем Cheat Engine.

    В процессах подключаем эмулятор.

    Идём в автоассемблер, вставляем этот скрипт и связываем с основной таблицей.

    Переименовываем чит в «Остановка таймера»

    post-3-1291353608,27_thumb.png

    Рис.19

    Теперь очень удобно нажимать галочку для активации идеактивации таймера.

    Минусы, у этого метода следующие вручную придётсявыбирать процесс и вручную выбирать таблицу с читами. И ещё один минус вам нужно настроить поиск в настройках - сканировать память типа MEM_MAPPED.

    post-3-1291353613,88_thumb.png

    Рис.20

    Если вы теперь решите использовать CE для сканирования памяти Windows-игр, то Вам придется отключать эту настройку вручную, т.к. сканирование замедляется с этой настройкой.

    На этом пока всё.


    Часть2 . Продолжение.... 

    Точнее это черновик. К сожалению чит не доделан из-за не удобного отладчика в эмуляторе (пока нет времени времени доделать чит)

    post-3-1291718894,77_thumb.png

    Черновик приводить в нормальный вид некогда. Просто вот скрипт CE на постоянное здоровье в игре M4K


    aobscan(addres1,F6 B8 A9 20 8d 06 20 b5 b8 38 e9 01 4a 4a 4a)
    aobscan(addres2,02 04 00 02 04 00 02 04 00 02 04 00 02 04 00 02 04)

    addres1:
    db 4c 0b cb ea

    addres2:
    db F6 B8 8D 16 CB A9 00 85 B8 AD 16 CB 4C FB C1 02 04


    [DISABLE]
    aobscan(addres1, 4c 0b cb ea 8d 06 20 b5 b8 38 e9 01 4a 4a 4a)
    aobscan(addres2, F6 B8 8D 16 CB A9 00 85 B8 AD 16 CB 4C FB C1 02 04)

    addres1:
    db F6 B8 A9 20

    addres2:
    db 02 04 00 02 04 00 02 04 00 02 04 00 02 04 00 02 04
    [ENABLE]

  4. Цель данной темы понять как работает Windows OS (от устройств до программ пользовательского уровня)...

    Итак пока вот две стати:

    1) Цикл статей «Драйверы режима ядра»

    2) Статья про API hooking revealed (ENG):

    Скрин из статьи:

     post-3-1291230732,17_thumb.jpg

    3) На следующем рисунке показаны основные внутренние компоненты операционной системы Windows (подробнее в MSDN)

    post-3-1291230830,24_thumb.png

    Многих тонкостей нет, например тогокак попасть в ring 0 из ring 3 (статьи про это дело в интернете)... Также в ring 0 нельзя выполнять операции WInAPI, но зато можно пользоваться VxD - сервисами...

  5. Здесь выкладываются проекты по системному программированию на С#. Т.е. программирование всего, что связано с процессами, потоками, хуками, драйверами, работа с памятью и т.п. всё-то что характерно для Windows операционных систем. У С# есть много проблем с WinAPI и решаются они маршалингом, вот его-то и можно найти в этой теме.


    Ниже нет таковых трейнеров, здесь механизм создания модов, который можно будет применить в геймхакинге.

    Файлы по игре Grand Theft Auto 4

    (Скачайте ещё SlimDX SDK, который потребуется при компиляции)

    Grand Theft Auto 4.rar

    Вот что можно сделать:

    post-3-1291199159,72_thumb.jpg

    Болле подробно читайте темы:

    1) Автор:HazardX [bETA] GTAIV .Net ScriptHook

    2) Автор: aru [GTAIV|REL|SRC] C++ Script Hook

    3) Там же почитайте темы Alexander Blade по тому что он мутил с asi лоадером, и почитайте про обходы Windows - LIVE

    Файлы по игре Mass Effect 2

    Подробноестей не понмю (поищите в интернете)

    Mass Effect 2.rar

  6. CheatEngine56src.rar

    SVN (на теущий момнет там валяется 5.6.1 и 6.0)

    Скомпилированный вариант CE 5.6.1 (установщик, включает справку)

    CheatEngine561.rar

    Также у нас есть  тема по модернизации CE RUS (возможно вы там найдете что-то для себя, русскую версию, темы модернизации и т.п.)

    CE обычно обновляется в Новый год или после него. Те кто не хотят ждать могут компилировать вариант из SVN.

     

    Update: Рекомендую использовать Delphi 7. Точную версию не помню

  7. Здесь выкладываются проекты по системному программированию на С++. Т.е. программирование всего, что связано с процессами, потоками, хуками, драйверами, работа с памятью и т.п. всё-то что характерно для Windows операционных систем. 


    Известный MHS от L.Spiro

    Очень много примеров для различных задач находится в этом проекте. Просто рай для изучения С++.

    Ссылки с нашего форума:

    MHS (исходники)

    Stars.rar

    Kerner драйвер(исходники)

    StockReport2008.rar

    MHS6.1.rar (скомпилированный вариант)

    MHS6.1.rar

    Справка по MHS

    MHS Help.rar


    Установка хуков (wtlui.sln)

    SVN (на текущей момент ревизия 39, Visual Studio 2010),

    Исхдоник (с примером tracedll)

    wtlui.rar

    Пример (пример установки хука на запись в память):


    #include <stdio.h>
    #include <detours.h>

    typedef BOOL (__cdecl *WPMProc) (HANDLE,LPVOID,LPVOID,DWORD,LPVOID);
    WPMProc WPM;

    BOOL MyWPM(HANDLE hProc, LPVOID lpAddress, LPVOID lpBuffer, DWORD dwSize, LPVOID shit) {
        char szText[512];

        sprintf(szText, "WriteProcessMemory Call (Write to process %d at address %x bytes %x)\nAllow WriteProcessMemory to be executed?", GetProcessId(hProc), lpAddress, lpBuffer);

        if(MessageBox(0, szText, "WPM Call", MB_YESNO) == IDYES)
            return WPM(hProc,lpAddress,lpBuffer,dwSize,shit);

        return 0;
    }

    void lpMain(){
        DWORD dwWPM;
        HMODULE hKernel;

        if(hKernel = GetModuleHandle("kernel32.dll")){
            dwWPM = (DWORD)GetProcAddress(hKernel, "WriteProcessMemory");
            WPM = (WPMProc)DetourFunction((PBYTE)WriteProcessMemory, (PBYTE)MyWPM);
        }
    }

    BOOL WINAPI DllMain(HINSTANCE hInst, DWORD ul_reason, LPVOID lpReserved){
        if (ul_reason == DLL_PROCESS_ATTACH) {
            DisableThreadLibraryCalls(hInst);
            CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&lpMain, 0, 0, 0);
        }
        return 1;
    }
    #include <windows.h>

    Это код старого проекта, в новом проекте DetourFunction изменился на DetourAttach (см. detours.h)

  8. Хочу обратить внимание на пример из  MSDN по удобной работе с LINQ запросами.

    Представьте, что у нас есть список студентов (который можно удобно импортировать из различных баз данных, в том числе и xml...). Этот список в стиле C# описывается вот так:

               new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 72, 81, 60}},
               new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
               new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {99, 89, 91, 95}},
               new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {72, 81, 65, 84}},
               new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {97, 89, 85, 82}}

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

      Low averages

       Omelchenko, Svetlana:77.5

       O'Donnell, Claire:72.25

       Garcia, Cesar:75.5

      High averages

       Mortensen, Sven:93.5

       Garcia, Debra:88.25

    Человек не знающий LINQ пошёл "ай да наяривать циклы"   :grin: чтобы вывести результат. А вот элегантное решение с LINQ:

            var booleanGroupQuery =
                from student in students
                group student by student.Scores.Average() >= 80; //pass or fail!

    Ну и вот весь код


    {
        // The element type of the data source.
        public class Student
        {
            public string First { get; set; }
            public string Last { get; set; }
            public int ID { get; set; }
            public List<int> Scores;
        }

        public static List<Student> GetStudents()
        {
            // Use a collection initializer to create the data source. Note that each element
            //  in the list contains an inner sequence of scores.
            List<Student> students = new List<Student>
            {
               new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 72, 81, 60}},
               new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
               new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {99, 89, 91, 95}},
               new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {72, 81, 65, 84}},
               new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {97, 89, 85, 82}}
            };

            return students;

        }

        static void Main()
        {
            List<Student> students = GetStudents();
            var booleanGroupQuery =
                from student in students
                group student by student.Scores.Average() >= 80; //pass or fail!

            foreach (var studentGroup in booleanGroupQuery)
            {
                Console.WriteLine(studentGroup.Key == true ? "High averages" : "Low averages");
                foreach (var student in studentGroup)
                {
                    Console.WriteLine("   {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());
                }
            }

            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
    }
    class GroupSample1

  9. Что-то я потыркался, потыркался и ни хрена не вышло всё равно не компилит

    f9daef607d1e.jpg

    Мастер

    если не трудно, отредактируй мой скрипт чтоб компилися

    и укажи на места ошибок!!!!!!!!!!!!!!!!!!!!!!!!!

    Ты ещё забыл попросить сделать трейнер ) Не.  У нас на форуме есть множество примеров как писать скрипты по ним можно научиться. 

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

  10. Когда пишешь ассемблерные инструкции нужно писать не в круглых скобках, а в квадратных.

    mov (_Player),ecx

    нужно заменить на 

    mov [_Player],ecx

    А также необходимо заменить остальные скобки под "_newmem:"

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

    Hacking flash games with CE

    This is a small description on how to find values in flash games generally. It does not cover the tutorial on how to find values, only the part which is unique to flash games.

    First of all, flash games are working differently from other games, so the usual pointer, code injection methods etc will not work here (or at least not as You would expect). CE is by far not the best choice to hack a flash game, that is why universal flash trainers were created. I rarely play and hack flash games, so this is not a professional tutorial, just some methods that You may try if You are stuck.

    Because most of the users are thinking about Flash games that they work as normal games, I will explain it in a few words what is the difference. If You hack a normal game, You just start the exe file, than You do the usual hacks and when You get back, the code will remain the same. The exe file is not changing. However if You update the game, of course the exe file will change in the new version and You will have to make another trainer based on the new codes (or use AOBscan but that is a "special" method). So how are flash games working? Usually You start the browser, the browser will load the flash player plugin and the flash player plugin will run the swf file. So when You try to hack the game, You try to hack the browser or flash player, which is using the swf file. Now if You try to make a trainer, You will obviously have to think about this question: will other people use exactly the same browser and flash player plugin as me not to mention browser updates and other kind of plugins and system components which is related to the browser? Well, not. Their browser will be different at least in one little thing, the codes and pointers will be different on their computers so the idea of making a working trainer which is based on code injection or pointers is generally screwed. It is just like everyone would use a special version of the game which is different from Yours. All You can do is to make some pointers which will work with Your browser on Your computer at least until You don't update or install anything in it, or You can use AOBscan to write a script which is searching for specific codes and change them with code injection. Using code injection with flash games is much harder so if You choose that method, You have to be really good. Now lets continue...

    Important note from CE's creator (DarkByte):

    If you're using firefox and want to use Cheat Engine on a browser game, then open plugin-container.exe instead of the firefox process. (That process will only exist when the game has already been started)

    If You want to find a value in a flash game with CE, these are the main methods that are usually working:

    1. Search for the value as a "4 byte" value. This is simple enough and it is working with most of the new games which has been written in AS3.

    2. Search for the value as a "Double type" value. Some older flash games are using double type values to store the variables.

    3. Search for the value as a "4 byte" value, but multiply the value with 8 when You search for it. For example You have 100 gold in the game, then You need to search for 800. If You have found it and You want 10000 gold, You need to change it to 80000. If You type in a value which cannot be divided with 8, most likely You will crash the game.

    4. Remember there is an option in CE to search for ALL value types, so if You don't have a clue, try it out. It may be Double, 4 byte, whatever.

    5. Some games are always changing the address of the values, in this case You need to find the value from 1 search. Most of this games are multiplying the value with 8, so You need to use the 3rd method, but You have only one shot at it to find it and the address will be moved. You also need to pause the game with CE to prevent the game from moving the address elsewhere until You find it and change it. To pause the process, click on "Advanced options" at the bottom of CE and click on the pause button. Then search for the value and if You find it, change it. If not, or You have too many results, try it again. Generally the bigger the number that You search for, the less results will be. For example if You search for 8, You will have tons of results. If You search for 3635384, You will have far less, most likely only a few (or maybe only one result which is the best).

    6. Some games are using encryptions to protect the game from hackers. In this case, You can still search for unknown value and changed/unchanged values. Maybe You will find what You seek.

    That is all I can recommend for now.

    Peace!

    Geri

    -

    Источник: szemelyesintegracio.hu

  12. Написать эту тему меня подтолкнуло то, что о C# у нас мало информации. Это просто безобразие. Надо о нём обязательно поговорить особенно в контексте advanced gamehaking.

    Сразу перейдем к этому контексту без нудного вступления о C#. C# (Си-шарпу) успел найти применение некоторый человек (не помню имени) над проектом создания модов к GTA 4. Я так понял, что он изучил код игры и написал главный модуль и заголовочные описания к нему на VC++ 2005. Далее он написал на C# описания того как взаимодействовать с модулем, а дальше самое интересное. Пользователи могут писать свои скрипты на .NET используя последние упомянутые описания.

    Итак что сделал автор

    1) Изучил код игры

    2) Написал главный модуль и заголовочные описания к нему на VC++ позволяющие изменять поведения игры (писал конечно же с ассемблерными вставками)

    3) Написал на C# описания работы с этим модулем.

    4) Теперь пользователь может писать свои скрипты на NET языках (C#, VB.NET, F#, Delphi.NET и т.п.)

    Прежде всего .NET языки очень удобны для прикладных задач, т.е. работе с данными и бизнес-процессами (короче процессами по управлению чего-то). Автор уже написал костяк описаний того чем можно управлять и теперь очень удобно управлять, т.е. писать код чтобы в игровом процессе что-то происходило.

    Разработчиками .NET очень многое уже написано и вам остаётся это использовать. Короче на C# логику удобнее писать чем на VC++. Например, очень легко на C# написать различные условия каких-то игровых процессов. Среда разработки на каждом шагу подсказывает вам, то что вы могли бы забыть и что вы могли бы применить. Открывает вам список методов и интерфейсов и тут же дает краткое справочное описание...

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

    Короче самое важное, это то что на .NET мы пишем меньше и яснее чем на VC++, делаем всё быстро и видим в коде меньше лишнего, а документация нам подсказывает очень многое, что писать самим нам не надо, а использовать уже готовое. В голове мы сразу строим то, что дольше будем строить на VC++. Идеальный современный вариант для решения прикладных задач как для новичков, так и для профессионалов различных областей.

    Ходят много споров о том какая программа C# или VC++ работает быстрее. Если вас интересует моё мнение, то я скажу, что скорость следует обсуждать тогда, когда её нужно обсуждать. В наших задачах скорость работы программ не плохая, даже хорошая. Пока скажу только одно. При настройках по умолчанию при первом запуске .программы написанной на .NET, JIT-компилятор компилирует CIL код ("код языка .NET, аналогичный ассемблеру") в машинный код и это занимает время. А далее если этот код будет работать постоянно на приемлемой скорости...

    ------------

    На cheatengine форуме я нашёл тему, в которой парень хочет научиться C# и не знает с чего начать и ему посоветовали написать программу решающую прикладную простую задачу показывать знаки зодиака по введенной информации.

    Я написал эту программу остальное оставляю желающим исправить. Весь написанный код нужно расположить в Program.cs - генерированном файле при создании консольного приложения

    post-3-1299491697,68_thumb.png

    Тоже самое для того чтобы скопировать в проект:


    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;

    namespace Zodiak
    {
    class Program
    {
    const string InfoZodiak = @"
    Овен March 21 April 20
    Телец April 21 May 20
    Близнецы May 21 June 21
    Рак June 22 July 22
    Лев July 23 August 23
    Дева August 24 September 23
    Весы September 24 October 23
    Скорпион October 24 November 22
    Стрелец November 23 December 21
    Козерог December 22 January 20
    Водолей January 21 February 20
    Рыбы February 21 March 20";


    static DateTime SpecialParsing(int year, string mount, string day)
    {
    // Шаблон 2008-11-01
    string tempString = String.Format("{0}-{1}-{2}", year, mount, day);
    return DateTime.Parse(tempString);
    }

    public static string GetZodiakName(DateTime current)
    {
    //если дата больше 22 декабря и не больше 21 января, то это козерог
    if (
    (current.Month == 12 && current.Day >= 22 && current.Day <= 31) ||
    (current.Month == 1 && current.Day <= 20)
    )
    return "Козерог";

    string pattern = @"\b(\w+?)\s*\b(\w+?)\s*\b(\w+?)\s*\b(\w+?)\s*\b(\w+?)\s*\b";
    foreach (Match match in Regex.Matches(InfoZodiak, pattern,
    RegexOptions.IgnoreCase))
    {
    string nameZodiak = match.Groups[1].Value; // Aries
    string leftMounth = match.Groups[2].Value; // March
    string leftDay = match.Groups[3].Value; // 21
    string rigthMounth = match.Groups[4].Value; // April
    string rigthDay = match.Groups[5].Value; // 19

    var leftDate = SpecialParsing(current.Year, leftMounth, leftDay);
    var rigthDate = SpecialParsing(current.Year, rigthMounth, rigthDay);

    if (leftDate <= current && current <= rigthDate)
    return nameZodiak;
    }
    return "input error";
    }

    static int GetUserInputToInt(string message)
    {
    Console.WriteLine(message);
    return int.Parse(Console.ReadLine());
    }

    static void Main()
    {
    Console.WriteLine("Введите дату и я покажу знак зодикака");
    Console.WriteLine("");
    // Test it input is "April 18" (output "Aries") and "April 21" (output "Taurus")
    do
    {
    try
    {
    // Получить от пользователя значение даты
    int mounth, day, year = DateTime.Now.Year;
    mounth = GetUserInputToInt("Введите месяц (числом):");
    day = GetUserInputToInt("Введите день:");
    var date = new DateTime(year, mounth, day);

    // Вывести знак зодика
    string sign = GetZodiakName(date);
    Console.WriteLine("Знак зодиака: {0}", sign);
    Console.WriteLine("");
    }
    catch { continue; }

    // Желает ли пользователь закончить работу с программой
    Console.WriteLine("Выйти? (Y или NO):");
    string questionExit = Console.ReadLine();
    if (string.Compare(questionExit, "Y", true) == 0)
    return;
    Console.WriteLine("");

    } while (true);
    }
    }
    }
    using System;

    Вводим числом месяц, дату и получаем ответ. Здесь использовались регулярные выражения, работа с датами. Всё описывается в MSDN...

    Может быть позже я напишу ещё что-нибудь.

  13. Прочитал я статью полностью и не со всем соглашусь.

    1. Здесь нужно участие typedef для enum, чтобы kind объявить не как int, а как описанный тип множества.

     struct game_object_t
    {
    int kind; //это код типа объекта
    int x,y;
    int health;
    int score;
    int anger;
    };

    enum game_object_kinds
    {
    kind_Player,
    kind_Monster,
    kind_Missle,
    kind_Explosion,
    };
     

    2. В базовом классе нельзя открывать так доступ через public. Следовало сделать через "protect" 

        

    class GameObject
        {
            public:
                int x,y;
                int health;
                virtual int GetType() { return -1; }
                virtual void Think() {}
        };

    3.

    После серии опытов в написании системы игровых объектов, можно прийти к выводу, что хранить координаты и размеры объекта внутри самого объекта — неправильно т.к. эти данные требуются, чтобы проверять столкновения объектов и только при обнаружении столкновения должен вызываются соответствующий метод объекта (Push, Damage или др.).

    Я с этим не согласен. Координаты должны находиться внутри игровых объектов и должны быть закрыты.

    "Мир" не может двигать объекты, их могут двигать(оказывать влияние) только другие объекты в этом мире. "Мир" это абстрактная оболочка, она сама никак не влияет на объекты, она только связывает единым контекстом что объекты находятся в одном мире внутри неё. Когда мы смотрим в "мир" каждый объект в нём "передаёт" информацию о своё положении. И только сам игровой объект должен "решать" как ему передвигаться в зависимости от его природы, т.е. объект мир не должен двигать объект, а только другие объекты могут это делать.

  14. В этой теме не будет вопроса по программированию, а будет просто статья.

    Ссылка на оригинал (статья из RDSN)

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

    Объектная система игры (игровой "движок")

    Каким бы хорошим не был "движок" графический — сама игра работает благодаря "движку" игровому т.е. той части кода игры, которая отвечает за хранение и обработку разнообразных игровых объектов. В этой статье я бы хотел описать некоторую ретроспективу видов игровых "движков", начиная со времен "древних" игровых систем.

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

    Любая диалоговая программа, не исключая, конечно же, и игры, строиться на основе цикла (обычно — одного цикла). Краткая схема такого цикла выглядит так:


        Цикл:
        {
            Ввод
            Обработка
            Вывод
        }
        Инициализация

    На этапе Инициализации производится подготовка к работе цикла — задаются начальные состояния объектов игры, запускается графическая, звуковая и другие подсистемы программы игры. Кроме того, инициализация может встречатся и внутри цикла (на этапе Обработки), если требуется, например, загрузить новый уровень или восстановить работоспособность графической подсистемы после переключения на другую задачу по Alt+Tab (в Windows).

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

    На этапе Обработки происходит свмое интересное — здесь "думают" монстры, обрабатывается физика, а также создаются и уничтожаются разнообразные игровые объекты — т.е. работает игровой "движок". Кроме того, очень важно сделать так, чтобы независимо от скорости выполнения всего цикла программы на разных компьютерах, объекты игры всегда работали именно с той скоростью, на которую раситаны по замыслу создателей игры.

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

    Таким образом видно, что для игрового "движка" необходимо задать:

    а) какие бывают объекты (типы объектов)

    б) как они создаются/уничтожаются, обрабатываются, взаимодействуют

    в) как они получают ввод от игрока (интерфейс системы ввода)

    г) как они отображают себя для игрока (интерейс системы вывода)


    Ретроспектива видов игровых "движков":

    1. Хранение и обработка отдельных единичных объектов

    Итак, самым простым и понятным способом задать объекты игры в программе является объявление отдельных переменных.

    Пример:


        int monsterX, monsterY, monsterHealth, monsterAnger;

        playerX = playerY = 10;
        playerHealth = 100;
        playerScore = 0;

        monsterX = 190; monsterY = 90;
        monsterHealth = 1000;
        monsterAnger = 10;
        int playerX, playerY, playerHealth, playerScore;

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

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

    Примерно так:


        {
            int x,y;
            int health;
            int score;
        };

        struct monster_t
        {
            int x,y;
            int health;
            int anger;
        };
            
        player_t  player;
        monster_t monster;
            
        player.x = player.y = 10;
        player.health = 100;
        player.score = 0;

        monster.x = 190; monster.y = 90;
        monster.health = 2500;
        monster.anger = 100;
    struct player_t

    2. Множества однотипных объектов

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

    Пример:


        monster_t monsters[ max_monsters ];
        
        for(int j = 0; j < max_monsters; j++)
        {
           monsters[j].x = i * 10;
           monsters[j].y = 90 - i;
           monsters[j].health = 1000 + (random() % 1000);
           monsters[j].anger = 10;
        }
        const int max_monsters = 10;

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

    Однако проблемы начинаются тогда, когда количество типов объектов становиться большим, а от игры требуется еще большая реалистичность. Код просто напросто превращается в нечто такое:


        ControlPlayer();                       //обрабатываем управление игрока
        ThinkMonsters();                       //монстры "думают"
        MovePlayer();                          //двигает игрока
        MoveMonsters();                        //двигаем монстров
        CheckCollisions_Player_Monsters();     //проверяем, если монстр поймал игрока
        MoveMissles();                         //двигаем ракеты
        CheckCollisions_Player_Missles();      //проверяем, если ракета попала в игрока (ракета взорвется)
        CheckCollisions_Monsters_Missles();    //проверяем, какие ракеты в каких монстров попали (ракеты взрываюся)
        AnimateExplosions();                   //анимируем взрывы, которые оставляют ракеты
        CheckCollisions_Player_Explosions();   //проверяем, если игрока задел взрыв (уменьшаем здоровье и т.д.)
        CheckCollisions_Monsters_Explosions(); //проверяем, каких монстров какие взрывы задели (...)
        ...
        //Этап обработки объектов

    И так далее — чем больше типов объектов, тем сложнее код.

    3. Единая структура для всех объектов

    Чтобы упростить программирование объектов, можно задать одну структуру для всех объектов игры. Тогда внутри этой структуры необходимо будет хранить код типа объекта, чтобы проверив этот код можно было однозначно сказать — что же, собственно, задает этот объект (игрока, монстра, ракету, взрыв и др.).


        {
            int kind; //это код типа объекта
            int x,y;
            int health;
            int score;
            int anger;
        };

        enum game_object_kinds
        {
            kind_Player,
            kind_Monster,
            kind_Missle,
            kind_Explosion,
        };
        struct game_object_t

    Также видно, что в таком случае приходится объявлять все виды полей, которые могут потребоваться объекту, если его поле kind будет принимать то или иное значение.

    Чтобы избежать таких затрат памяти можно объединить поля разных объектов в безымянные union'ы.


        {
            int kind; //это код типа объекта
            int x,y;
            int health;
            union
            {
                int score;
                int anger;
            };
        };
        struct game_object_t

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

    Однако где-же здесь упрощение при обработке объектов?

    А упрощение состоит в том, что мы можем написать обработчик объектов, в котором будет проверяться поле kind объекта и будут выполняться соответствующие именно этому типу объектов действия.

    Пример:


        {
            switch(p->kind)
            {
                case kind_Player:
                    ...
                    break;
                case kind_Monster:
                    ...
                    break;
                case kind_Missle:
                    ...
                    break;
                case kind_Explosion:
                    ...
                    break;
                default:
                    //ошибка - тип объекта неверен
                    ...
                    break;
            }
        }
        void Think( game_object_t *p )

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

    Пример:


        {
            int kind; //это код типа объекта
            int x,y;
            int health;
            union
            {
                int score;
                int anger;
            };
            void (* Think)( game_object_t *self );
        };
        struct game_object_t

    Затем в программе, при инициализации объекта надо будет заполнить это поле определенным значением, либо нулем (ноль — отсутствие обрабочика)


        ...
        void Monster_Think( game_object_t *self )
        {
            //здесь "думает" монстр
        }
        ...
        void Missle_Think( game_object_t *self )
        {
            //здесь "думает" ракета
        }
        ...
           objects[0].Think = Monster_Think;
           objects[1].Think = Missle_Think;
        ...
        game_object_t objects[ max_game_objects ];

    Теперь можно вызывать обработчики "дум" объектов единообразным образом.


        {
            void (* proc)() = objects[j].Think;
            if(proc) proc( &objects[j] );
        }
        for(int j = 0; j < num_game_objects; j++)

    Причем для каждого объекта будет вызван именно тот обработчик, который был задан ему в поле Think.

    Может возникнуть вопрос — а зачем после этого нужно поле kind объекта? Очень просто — чтобы можно было идентифицировать объект по номеру его типа. Для чего? Например, для того, чтобы можно было сохранять игровые объекты в файл (ведь в файле нельзя хранить адрес обработчика "думания" т.к. этот адрес может поменяться при новом запуске программы, номер же не изменится пока мы этого не захочем).

    4. Класс объекта, наследование и виртуальные методы

    Следующей ступенью на пути совершенстования игрового "движка" будет решение заменить структуру на класс т.к. в языке С++ классы лучше соответствуют ООП (объектно-ориентированному подходу в программировании), чем "чистые" структуры в стиле pure С.

    Пример:


        {
            public:
                int x,y;
                int health;
                virtual int GetType() { return -1; }
                virtual void Think() {}
        };
        class GameObject

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

    Примеры:


        {
            private:
                int score;

            public:
                int GetType() { return kind_Player; }
                void Think()  {}
        };

        class GameObject_Monster: public GameObject
        {
            private:
                int anger;

            public:
                int GetType() { return kind_Monster; }
                void Think()  {}
        };
        class GameObject_Player: public GameObject

    Чтобы любой объект класса-потомка GameObject "подумал" нужно все лишь написать:


                             //в том числе можно подставить адрес объекта,
                             //класс которого - класс-потомок класса GameObject
        p->Think();          //здесь вызывается метод Think того класса, к
                             //которому пренадлежит объект
        GameObject *p = ...; //здесь подставляется адрес конкретного объекта

    Чтобы получить код типа объекта можно написать:

       ... = p->GetType();

    Таким образом в С++ уже встроены те средства, которые помогают в создании системы игровых объектов.

    Как правило в классе-родителе (таком как GameObject) не должно быть никаких полей данных — только объявление общих для всех объектов _виртуальных_ методов.

    Пример:


        {
            public:
                virtual int GetType() { return -1; }

                virtual void Think  ()                               {}
                virtual void Push   ( float force_x, float force_y ) {}
                virtual void Damage ( float damage )                 {}
                ...
        };
        class GameObject

    Таким образом, если надо толнуть объект, то достаточно лишь вызвать его метод Push(...), независимо от того, к какому классу-потомку пренадлежит этот объект:


        p->Push( force_x, force_y );
        GameObject *p = GetAnyDerivedClassObject();

    Если в классе-потомке метод Push(...) не будет описан, то будет вызван метод класса-родителя т.е. в данном случае пустой метод.

    5. Вынос физики за рамки объекта

    После серии опытов в написании системы игровых объектов, можно прийти к выводу, что хранить координаты и размеры объекта внутри самого объекта — неправильно т.к. эти данные требуются, чтобы проверять столкновения объектов и только при обнаружении столкновения должен вызываются соответствующий метод объекта (Push, Damage или др.).

    Можно реализовать игровой "движок" так, что объекты не будут "знать" своего точного положения и размеров в том "мире", в котором они находяться. Эта информация будет храниться отдельно от объектов самим "миром". "Мир" будет заведовать физикой объектов т.е. находить какие объекты пересекаются и вызывать соответствующие методы объектов. Если объекту потребуется узнать какую-то физическую информацию, создать другой объект или подвинуть себя — он должен будет вызвать соответствующий метод "мира".

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

    6. Продолжение банкета

    Про следующий шаг улучшения игрового "движка" я, как и обещал, напишу в следующей статье. А пока — комментарии, дополнения, размышления, критика — are welcome.


    Объектная система игры (игровой "движок")

    © Германов "EyeGem" Евгений, 2003 г.

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

  15.  

    Ну Visual Studio это все-таки уже явное определение платформы (в основном из-за встроенных MS-классов-велосипедов), а Страуструп - это все ж теория голого С++ в общем виде. Конечно, сайт тематический, геймхакинг, что уже определяет платформу (это как в том анекдоте про PC и Mac)..

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

    Тем не менее, для написания трейнера вполне хватит и WinAPI (в Рихтера, к слову, пару раз заглядывал, но там мне не понравился слог).И, мм.. Как таковых COM-объектов в Dx и Opngl с гулькин нос. Буквально, полторы функции. Да и зачем там это? Динамических библиотек в %windir% и корне достаточно за глаза, чтобы их еще и регистрировать в виде компонентов.

    От того какая у тебя цель зависит то чем ты будешь пользоваться. Win-API и язык программирования это минимальный набор "трейнеров по умолчанию", которых большинство людей делают.  В моих целях "полный вариант" включая устройства, драйвера, управление com-объектами, которые игра использует и многое другое.

    У Рихтера надо читать, только, то что тебя интересует. В случае трейнеров это в первую очередь механизмы работы Windows (процессы, потоки,защита памяти, работа потоков, очереди сообщений,  и др).

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

    А вот для этого просто необходима VS C++. На ней можно писать приложения аналогичные игровым, дизассемблировать и понимать свои догадки. + IDA и hex-array, OllyDbg или иные программы.

    Я, собсно, че к вам заглянул-то :) Хочется порыться в ресурсах игр, для этого стоит познакомиться с WinAsm'ом, а то у нас только и было что один семестр по микроконтроллерам (то есть специфический, не под 8086), с кривой методичкой; там, помнится, даже сегменты были только общего назначения, а-ля DOS. Хотя могу ошибаться, нам явно не все начитали :) Надеюсь, в такой вот обстановке радости и веселья, по пути почитывая cracklab, приду к тому, к чему стремлюсь :)

    Под ресурсами игры обычно подразумевают: картинки, текстуры,  музыка, модели, различные конфиги... Хотя последние могут пригодиться для создания читов, но мы как-то не занимались распаковкой/запаковкой ресурсов и у нас нет по этому информации (хотя жаль). Если тебе нужно копаться с игровыми ресурсами, то тебе надо на сайты по модингу., а если нет, то Welcome  :)  

  16. Правильно, Страуструпа нужно обязательно прочитать, тем кто не читал (даже тем кто читал Шилдта). 

    Так же замечу, что хорошо бы понимать новую Visual Studio для C++: ее возможности, типы проектов которые можно, нужно или не нужно создавать...  Для этого нужны книги по новее датируемые выше 2008 года. В частности нужны ещё книги (статьи или информация) как писать совместно с WinAPI от создания простых окон, работы с файлами до сложных задач. Классикой в последнем случае будет книга Рихтера (Windows для профессионалов). Также не забыть про архитектуру Windows (она есть у того же Рихтера и в некоторых книгах + в хелпах DDK: "Kernel-Mode Driver Architecture" и т.п. ). 

    Также не забыть про ассемблер, который можно делать как вставками в VS C++ коде.

    И многое многое другое (программирование COM  (DirectX, opneGL), PE формат (статьи в Wasm-а), работа с дизассемблирами и отладчиками (так же с Wasma и др. сайтов)). Короче знать надо все, всё от устройств, контроллеров и драйверов от которых зависит запуск игры... до процессов и механизмов позволяющие играть в эту игру.  Только узнав всё это на полную катушку можно заниматься геймхакингом.

    Основные направления всё же это:

    1) очень хорошие навыки дизассемблирования и отладки + такие же знания того как работают "механизмы" Windows

    2) создание инъекций кода путём ассемблера и языка программирования

    3) создание трейнеров как отдельных программ так и встроенных в саму игру (в том числе и интерфейс трейнера должен быть прямо в окне игры)

    4) остальное по мелочам и в зависимости от целей.

    По С++ советую изучить указатели на адреса и функции, структуры, множества, классы (функции), операция привидения. Это поможет понять суть того как например вам в вашем трейнере работать с адресом здоровья и как игра с этим адресом работает через множество структур и классов и массивов данных. Позже изучить как выглядит при отладке инкапсуляция, наследование, полиморфизм и множественное виртуальное наследование. Т.е. надо понять как увидеть связь данных и функций привязанных к классу. Увидеть таблицу виртуальных методов, таблицу базовых классов (при множественном наследовании). Увидеть как в дизассемблере происходит привидение чего-то к какому-то типу: динамик касты, статик касты. Как работают конструкторы и деструкторы в отладке. Должны научиться видеть границы функции в дизассемблере, видеть и "догадываться" как используется эта функция например работающая со здоровьем: она используется одним объектом (вашим героем), множествами объектов (вашим героем и врагами) или эта функция настолько полиморфна, что используется не только для здоровья вашего героя и врагов, но ещё и для адреса патронов, усталости и маны также для вашего героя и врагов. Или же только для вашего героя или же только для ваших врагов... Все перечисленное мне кажется должен уметь каждый, т.к. это базовые моменты при создании ин]екции кода. Остальное например может быть таким. Если вам интересно собирать статистику о том что происходит в игре и как вы на эту игру влияете вот тут-то очень даже пригодятся знания языка программирования. Возможно это вам поможет автоматизировать некоторые процессы (я имею ввиду для сингловых игр, а не для многопользовательских)...

    Другие моменты касаются создания трейнера. В интернете можно найти уже "вылизанные" функции поиска процесса и "механизмы" чтения, записи в адрес, снятие протекции со страницы памяти если в неё нельзя записывать байты. Создание окна на Win API тоже есть. Всё это очень просто.

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

  17. Статья Oboema про создание трейнера (2008 г.)

    "How To Create A Game Trainer Using C/C++"

    Дата статьи: Oct 4 2008

    Chapters.... 

    1) Introduction... Programs needed... objective...

    2) Api calls we will be using

    3) header file of CProcess

    4) methods of CProcess

    5) An example: Mortal Kombat 4 trainer

    6) the end

    CHAPTER 1: Introduction... Programs needed... objective...

    ***************************************************

    While answering questions on the gamehacking webboard, I noticed a lot 

    people out there want to develop trainers themselves instead of using

    standard kits. Although you can use just about any programming language

    for the job, I figure the best option is C/C++. The main advantages of

    C/C++ is that its fast enough and that it produces neat, small executables.

    You need a C/C++ compiler (duh). What also needs to be included is: a

    windows resource editor, text editor and access to Windows API. If you must

    know, I use Microsoft Visual C++ for the job.

    The objective of this tutorial is to create a small, working trainer

    of course, but in school I also learned how to develop reusable code.

    Since we all want to release a trainer more than once, I developed a C++

    class which just about does it all. The usage of this class looks

    something like this (in pseudo-code):


    {
    Find the process
    if (process is loaded)
    if (key is pressed)
    Read/Write memory
    }
    void timer_or_thread_function () 

     

    I won't teach you how the project should be created, how windows messages work,

    how C++ classes work or what data types are available... there are plenty of

    resources on that available on the net.

    Also note that the method of gamehacking presented here is *a* method; not

    *the* method

    Lets get into some code...

    CHAPTER 2: API calls we will be using

    ***************************************

    First, lets list all the Windows APIS we're gonna need to develop the CProcess class. 

    ---------------------------------------------------------------------

     


    LPCTSTR lpClassName, // pointer to class name
    LPCTSTR lpWindowName // pointer to window name
    );
    HWND FindWindow( 

    details All programs started in windows have a window <duh>

    This API call finds the window handle for a running process.

    ---------------------------------------------------------------------


    HWND hWnd, // handle to window
    LPDWORD lpdwProcessId // address of variable for process identifier
    );
    DWORD GetWindowThreadProcessId( 

     

    details We can't do much with only the Window handle, we need to have

    the process id to be able to get the process handle.

    ---------------------------------------------------------------------

     

     


    DWORD dwDesiredAccess, // access flag
    BOOL bInheritHandle, // handle inheritance flag
    DWORD dwProcessId // process identifier
    );
    HANDLE OpenProcess( 

    details And you guessed, this one gets the process handle based on

    the process ID.

    ---------------------------------------------------------------------


    HWND hwnd, // handle of window for timer messages
    UINT idTimer, // timer identifier
    UINT uTimeout, // time-out value
    TIMERPROC tmprc // address of timer procedure
    );
    UINT SetTimer( 

     

    details This API is used to generate a timer message at a certain interval.

    We'll use it to check whether or not keys have been pressed and

    if so to read or write values to the game's memory.

    ---------------------------------------------------------------------


    int vKey // virtual-key code
    );
    SHORT GetAsyncKeyState( 

    details This API checks to see if a key has been pressed since last call to

    the API. We need to call this one over and over again (see SetTimer)

    ---------------------------------------------------------------------



    HANDLE hProcess, // handle of process whose memory is written to
    LPVOID lpBaseAddress, // address to start writing to
    LPVOID lpBuffer, // address of buffer to write data to
    DWORD cbWrite, // number of bytes to write
    LPDWORD lpNumberOfBytesWritten // actual number of bytes written
    );
    BOOL WriteProcessMemory( 

     

    details I'm not religious, but we really have to thank God to have Billy-boy

    include this API into Windows. This is the heart of every trainer.

    It can write values to memory.

    ---------------------------------------------------------------------

     



    HANDLE hProcess, // handle of process whose memory is read
    LPVOID lpBaseAddress, // address to start reading
    LPVOID lpBuffer, // address of buffer to read data to
    DWORD cbRead, // number of bytes to read
    LPDWORD lpNumberOfBytesWritten // actual number of bytes read
    );
    BOOL ReadProcessMemory( 

    details And of course, this is WriteProcessMemory's twin. It can read

    values from memory.

    --------------------------------------------------------------------


    UINT uExitCode // exit code for all threads
    );
    VOID ExitProcess( 

    details Windows closes all handles and cleans just about everything, but

    its a good programming practise to close it yourself. This one

    closes a process.

    -------------------------------------------------------------------

    Ok... take a second look at the all APIs. Notice all the ugly parameter datatypes like HWND,

    UINT, LPVOID, HANDLE and HPROCESS. Personally I hate to use these types, so what I'll do is

    put all these APIS and variables in the C++ class, so I won't be bothered with them while

    programming the trainer.

    ( Thanx to RECLAIM for the explaination of the APIs )

    CHAPTER 3: Header file of CProcess

    ************************************

    The header file of our CProcess class is relatively easy... here it is: 


    {
    public:
    CProcess();
    virtual ~CProcess();

    bool IsRunning(); // checks if process was found already
    bool FindProcess(char *p_WindowTitle); // finds a process
    BYTE ReadByte(DWORD p_Address); // reads 1 byte from memory
    bool WriteByte(DWORD p_Address, BYTE p_Value); // writes 1 byte to memory
    bool IsKeyPressed(int p_iKey); // checks for a key-press
    bool IsSpyRunning(char *p_WindowTitle); // checks for trainer spy


    private:
    HANDLE OpenProcess(char *p_ClassName, char *p_WindowTitle);

    HANDLE m_hProcess;
    bool m_bGameRunning;
    };
    class CProcess 

    CHAPTER 4: Methods of CProcess

    ********************************

    Lets develop each method one by one... here goes. 

    Constructor/Destructor

    Every C++ class has a constructor and a destructor. These methods are used for

    initializing resp. deinitializing of local variables. Since we only have 2 local

    variables these methods are straightforward:


    {
    m_hProcess = NULL;
    m_bGameRunning = false;
    }

    CProcess::~CProcess()
    {
    if (m_bGameRunning)
    CloseHandle(m_hProcess);
    }
    CProcess::CProcess() 

    Note the m_hProcess will contain the handle of the process and m_bGameRunning

    is a flag to see if we opened the process already.

    Private method: OpenProcess

    This method will find and open a process.


    {
    HWND hWindow;
    DWORD pid;

    hWindow = FindWindow(p_ClassName, p_WindowTitle);
    if (hWindow) {
    GetWindowThreadProcessId(hWindow, &pid);
    return ::OpenProcess(PROCESS_ALL_ACCESS, false, pid);
    }
    return NULL;
    }
    HANDLE CProcess::OpenProcess(char *p_ClassName, char *p_WindowTitle) 

    Notice that this method is private, which means it can only be used by other members

    of the CProcess class. What it does... it looks for the window handle (FindWindow)

    based on the window title of the game (the p_Classname parameter should be NULL!).

    Then it retrieves the Process ID (GetWindowThreadProcessId), opens the process

    (OpenProcess) and returns the handle of that process.

    If the game isn't loaded or if the window title isn't correct(!), it will return NULL

    indicating failure.

    This method is used by FindProcess() and IsTrainerSpyRunning().

    Public method: FindProcess

    This method will find and open a process and on top of that it'll store everything

    in the class' private members.


    {
    if (m_hProcess == NULL) {
    m_hProcess = this->OpenProcess(NULL, p_WindowTitle);
    if (m_hProcess)
    m_bGameRunning = true;
    return m_bGameRunning;
    }
    else
    return false;
    }
    bool CProcess::FindProcess(char *p_WindowTitle) 

    The trainer program will call this method to find and open the process of the game.

    This method tries to open the process and store the handle in the class' private

    member. It also sets a flag to indicate success or failure.

    Public method: WriteByte


    //This method will write 1 byte to the specified memory addy.
    bool CProcess::WriteByte(DWORD p_Address, BYTE p_Value)
    {
    DWORD bytes;

    if (m_bGameRunning)
    return (WriteProcessMemory(m_hProcess, (void*)p_Address,
    (void *)&p_Value, 1, &bytes) != 0);
    return false;
    }

     

    The method returns true if and only if writing the byte to the mem addy was

    successful. False indicates the game isn't running (call FindProcess first!)

    or writing the value simply failed.

    Public method: ReadByte


    {
    DWORD bytes;
    BYTE tmpValue;

    if (m_bGameRunning) {
    if (ReadProcessMemory(m_hProcess, (void*)p_Address,
    (void *)&tmpValue, 1, &bytes) == 0)
    return 0;
    else
    return tmpValue;
    }
    return 0;
    }
    BYTE CProcess::ReadByte(DWORD p_Address) 

     

    The method returns the byte value that has been read for the game's memory.

    Public method: IsRunning

    We need a method to expose the m_bGameRunning variable, so the trainer can tell

    whether or not the process was already found and opened successfully.


    {
    return m_bGameRunning;
    }

    No further explaination needed, I figure


    Public method: IsKeyPressed
    This function detects a key press.

    bool CProcess::IsKeyPressed(int iKey)
    {
    return ((GetAsyncKeyState(iKey) & 1) == 1);
    }
    bool CProcess::IsRunning() 

    This might look strange to you. It just so happens GetAsynchKeyState sets the

    least significant bit of the returned value to indicate the key has been pressed.

    True or False would have worked fine for me, by the way

    Public method: IsTrainerSpyRunning

    Don't you just hate it when people are trying to rip off your mem addy?


    {
    HANDLE hTmp = this->OpenProcess(NULL, "TRAINER SPY");
    if (hTmp) {
    CloseHandle(hTmp);
    return true;
    }
    return false;
    }
    bool CProcess::IsSpyRunning(char *p_WindowTitle) 

     

    This method tries to open the Trainer Spy process. If it can be opened the

    handle of trainer spy (trainer spy will keep on running!) is closed and the method

    returns true indicating trainer spy is running and something needs to be done

    about it!

    Thats it... those are all the methods we need.

    CHAPTER 5: An example: Mortal Kombat 4 +3 trainer

    ***************************************************

    Lets develop a trainer for Mortal Kombat 4. 

    With GameHack I found these mem addies:

    Health player 1 0x00534A9D 1 byte

    Health player 2 0x005322ED 1 byte

    timer 0x00534AD8 1 byte

    Ohw, before we start.. I'm not gonna explain how to use the resource editor

    to develop the actual window of the trainer since its different for every

    development tool.


    // Include all header files for the VC++ project
    //
    #include <stdio.h>
    #include "stdafx.h"
    #include "Process.h"

    /* ------------------------------------------ */
    /* -- Identification for dialog, controls, -- */
    /* -- timers & such -- */
    /* ------------------------------------------ */
    #define DLG_MAIN 200 // ID for dialog
    #define DLG_ICON 30000 // IDs for icons
    #define DLG_ICON_S 30000
    #define IDC_QUIT 1011 // ID for "quit"-button
    #define IDC_INFO 2000 // ID for "info"-button
    #define ID_TIMER 1 // ID for timer
    #define IDC_STATIC -1 // ID for all labels
    #define TIMER_INTERRUPT 500 // timer msg interval in msec

    /* ---------------------------------------- */
    /* -- The mem addies found with GameHack -- */
    /* ---------------------------------------- */
    #define HEALTH_PL1_ADDRESS 0x00534A9D
    #define HEALTH_PL2_ADDRESS 0x005322ED
    #define TIMER_ADDRESS 0x00534AD8


    /* ------------------------------------------ */
    /* -- Global variables... oh well... -- */
    /* ------------------------------------------ */
    HINSTANCE TheInstance = 0; // instance handle of this trainer
    CProcess gameProcess; // instance of the CProcess class


    /* ------------------------------------------------------------- */


    //
    // Windows passes messages to application windows to indicate "something"
    // needs to be done
    //
    BOOL CALLBACK DialogProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    switch (message) {
    case WM_INITDIALOG:
    //
    // set the time to generate a timer message (WM_TIMER)
    // at a small interval
    //
    SetTimer(hwnd, ID_TIMER, TIMER_INTERRUPT, NULL);
    return TRUE;

    case WM_TIMER:
    //
    // a timer msg was received so call our main function!
    //
    WriteMem(hwnd);
    return TRUE;

    case WM_COMMAND:
    switch (LOWORD(wParam)) {
    case IDC_INFO:
    //
    // the info button on the window was pressed
    //
    MessageBox(hwnd, "<show some info>", "Mortal Kombat 4 +3 trainer", MB_OK);
    return TRUE;
    case IDC_QUIT:
    //
    // the quit button on the window was pressed
    //
    PostQuitMessage(0);
    return TRUE;
    }
    return TRUE;

    case WM_DESTROY:
    //
    // this app is about to be closed so kill the timer
    //
    KillTimer(hwnd, ID_TIMER);
    PostQuitMessage(0);
    return TRUE;

    case WM_CLOSE:
    //
    // destroy the window
    //
    DestroyWindow (hwnd);
    return TRUE;

    case WM_PAINT:
    //
    // paint msg so we can show a bmp on the screen (or something else)
    //
    PaintIt(hwnd);
    return TRUE;
    }
    return FALSE;
    }


    //
    // the main function.. this one was generated by Visual C++ (talk about ugly code!
    //
    int WINAPI WinMain
    (HINSTANCE hInst, HINSTANCE hPrevInst, char * cmdParam, int cmdShow)
    {
    TheInstance = hInst;
    HWND hDialog = 0;

    hDialog = CreateDialog (hInst, MAKEINTRESOURCE (DLG_MAIN), 0, (DLGPROC)DialogProc);
    if (!hDialog)
    {
    char buf [100];
    wsprintf (buf, "Error x%x", GetLastError ());
    MessageBox (0, buf, "CreateDialog", MB_ICONEXCLAMATION | MB_OK);
    return 1;
    }

    HICON hIcon = LoadIcon (TheInstance, MAKEINTRESOURCE (DLG_ICON));
    SendMessage (hDialog, WM_SETICON, WPARAM (TRUE), LPARAM (hIcon));
    hIcon = LoadIcon (TheInstance, MAKEINTRESOURCE (DLG_ICON_S));
    SendMessage (hDialog, WM_SETICON, WPARAM (FALSE), LPARAM (hIcon));


    MSG msg;
    int status;
    while ((status = GetMessage (&msg, 0, 0, 0)) != 0)
    {
    if (status == -1)
    return -1;
    if (!IsDialogMessage (hDialog, &msg))
    {
    TranslateMessage ( &msg );
    DispatchMessage ( &msg );
    }
    }

    return msg.wParam;
    }


    //
    // This is our main function that does the job! Remember this function
    // is called every time the timer msg is received.
    //
    void WriteMem(HWND hwnd)
    {
    //
    // find out if we already found the game before
    //
    bool bOk = gameProcess.IsRunning();

    //
    // if not then try to find it
    //
    if (!bOk)
    bOk = gameProcess.FindProcess("Mortal Kombat 4");

    //
    // if and only if game is running -> write mem
    //
    if (bOk) {
    if (gameProcess.IsSpyRunning("TRAINER SPY"))
    //
    // someone is trying to rip us off! Close this trainer
    //
    PostQuitMessage(0);

    //
    // if F10 was pressed, max the timer!
    //
    if (gameProcess.IsKeyPressed(VK_F10))
    if (!gameProcess.WriteByte(TIMER_ADDRESS, 100))
    PostQuitMessage(0);

    //
    // if F11 was pressed, max player 1's health!
    //
    if (gameProcess.IsKeyPressed(VK_F11))
    if (!gameProcess.WriteByte(HEALTH_PL1_ADDRESS, 0xFF))
    PostQuitMessage(0);
    //
    // if F12 was pressed, max player 2's health!
    //
    if (gameProcess.IsKeyPressed(VK_F12))
    if (!gameProcess.WriteByte(HEALTH_PL2_ADDRESS, 0xFF))
    PostQuitMessage(0);

    }
    }


    void PaintIt(HWND hwnd)
    {
    //
    // To do (or not to do
    // = show a neat pic on your trainer's window
    //
    }
    // 

    CHAPTER 6: The End

    *********************

    You can use the CProcess class or the main program code in any way you want. 

    If you experience any problems with it, don't hesitate to contact me.

    You can also ask for me to send you the complete MS Visual C++ project.

    Happy Hunting,

    Oboema

  18. Есть вариант, что игра обладает защитой от модификации кода. Как Left4Dead 2, к примеру. Там тоже можно взломать что угодно, но при включенном VAC игра крашится через пару минут, когда отрабатывают проверки античита.

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

  19. MasterGH

    Твой скрипт почему-то просто не компилится, все твои варианты перепробовал.

    SER[G]ANT уже объяснил почему.

    Как у тебя получилось все мои варианты перепробовать: один явно не компилируется, два других не доделаны. Сомневаюсь, что ты правильно последних два сделал.

    Снова обращаю внимание на то, что все ошибки со скриптами узнаются в отладке при трассировке. Можно делать её в дизассемблере CE поставив бряк перед в ходом на инъекцию.

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

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

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