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

MasterGH

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

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

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

    129

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

  1. Ребята, обращаюсь к тем, кто имел\имеет опыт написания своего отладчика или работы с бряками. Представим себе ситуацию:

    В гипотетической игре у игрока есть оружие, стреляющее с интервалом в 0.5 сек. Разработчики этот интервал знают, а вот кто-то посторонний - нет. Как чаще всего ищется значение этого таймера? Что-то типа:

    1. Находим адрес патронов

    2. Ставим на него бряк

    3. Трассируем вверх, пока не найдём нужное значение таймера

    Я подумал, что это как-то слишком долго

    Не долго, если знать как. Займёт 10 -15 минут. Второй (твой способ ниже) ещё труднее :)

    ... так что возникла идея автоматизировать процесс. Конкретно - делаем всё то же самое, но программно:

    1. Скармливаем проге адрес патронов

    2. Прога ставит на адрес int3

    3. Включает у себя таймер

    4. Шлёт игре несколько LMouseClick-событий, заставляя её пострелять. Или за неё это делает юзер.

    5. Замеряет таймером время между int3-срабатываниями

    Собственно, если у кого-нибудь есть сорцы по установке int3 - поделитесь, а? :)

    Идея по описанию не плохая.

    Задержки могут быть как уменьшающийся счётчик. Например, от 1200 до 0. И никакого понятия не будет, сколько в мс единиц этого счётчика. Допустим за 300 мс, счётчик уменьшился с 1200 до 0.

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

    В общем, как я очень надеюсь, есть решение попроще - в Olly 2.00+ версии есть логгирование бряков (в том числе и бряков на память), а вот для версии 1.10 есть плагин, позволяющий писать скрипты. Завёл сначала посмотреть на логгирование - довольно уныло, голый лог-файл и больше ничего, так что сейчас пишу скрипт - там всё уже веселее. :]

    Это довольно муторно. Даже на CE Lua-Engine будет попроще.

    Вот мой пример как я искал таймер при выстреле оружия (заняло меньше 10 минут)

    1) В CE Находим адрес патронов дробовика

    2) Ставим бряк на запись

    3) Автотрейсим (есть такая опция в CE) по 10000 инструкций, получаем дерево вызовов

    4) На каждый вызов сверху вглубь ставим бряки. Если прерываемся, то этот бряк не нужен и идём вглубь к следующему. Так мы отсеем участки кода, которые срабатывают без ввода(без кликов) от пользователя. Как только прерываться перестали, то теперь ставим бряки и кликаем, но уже правой кнопкой мышки. Дело в том что мы таким образом дойдём до участка кода, который распознаёт какой-либо ввод отличный от левого клика - выстрела.

    Наконец нашли такой бряк на адресе, где распознаётся ввод. В глубину ещё остаётся три бряка до бряка записи патронов.

    5) Теперь надо выяснить какой из оставшихся бряков реагирует только на левый клик и не реагирует когда клики идут очень быстро. Я использовал Lua-код для ведения лога в отладчике. И установил что следующий в глубь участок кода, как раз не работает при очень быстрых кликах


    {
    делать выстрелы
    }
    иначе
    {
    продолжать задерживать выстрелы
    }
    если ((таймер остановился для выстрела) и (т.п.))

    Ну, а если в псевдокоде IDA, то


    {
    int v1; // esi@1
    int v2; // eax@1
    signed int v3; // eax@4
    int v4; // eax@8
    double v5; // ST10_8@13

    v1 = a1;
    v2 = (*(int (__stdcall **)(_DWORD))(**(_DWORD **)(a1 + 40) + 488))(*(_DWORD *)(a1 + 372));
    if ( v2
    && (*(_DWORD *)(v2 + 32) > 0 || (*(int (__thiscall **)(int))(*(_DWORD *)(v2 + 44) + 132))(v2 + 44) == -1)
    && (v3 = *(_DWORD *)(v1 + 48), v3 != 2)
    && v3 != 3
    && (v3 < 4 || v3 > 6)
    || (v4 = *(_DWORD *)(v1 + 48)) == 0
    || v4 == 3
    || v4 == 5 && (unsigned __int8)sub_104CB430() )
    {
    sub_104C6150(*(float *)&v1, 0); // shot 2
    *(_DWORD *)(v1 + 112) = 3;
    *(_BYTE *)(v1 + 116) = 0;
    }
    else
    {
    if ( *(_DWORD *)(v1 + 48) == 2 )
    {
    v5 = IGSObject::GetTime(v1) - *(float *)(v1 + 52);
    if ( sub_104C5C10() - 0.1 < v5 )
    {
    if ( !*(_BYTE *)(v1 + 116) )
    *(_BYTE *)(v1 + 116) = 1;
    }
    }
    }
    }
    void __usercall sub_104CB1E0(int a1<eax>)

    Соответственно там где первый if,т.е. там где первый условный прыг пишем жёсткий JMP на код с комментарием "Shot2". Делаем это скриптом CE с сигнатурой кода, чтобы скрипт работал и на другой версии файла game_x86_rwdi.dll


    // MasterGH 2011
    [ENABLE]
    aobscan(address,74xx83xxxxxx7Fxx8Bxxxx8Dxxxx8BxxxxxxxxxxFFxx83xxxx75xx8Bxxxx83)
    label(injectAddress)
    registersymbol(injectAddress)

    address: // "game_x86_rwdi.dll"+4CB1FC = 0x030DB1FC
    injectAddress:
    db E9 83 00 00 00 // jmp game_x86_rwdi.dll+4CB284
    nop


    [DISABLE]
    injectAddress:
    db 74 30 //je game_x86_rwdi.dll+4CB22E
    db 83 78 20 00 // cmp dword ptr [eax+20],00
    unregistersymbol(injectAddress)
    // Fast Shot

    В этом случае все задержки пропали. Дальше копать не стал, т.к. мне лень. Если патроны бесконечные, можно стрелять очень быстро нажимая на мышку без конца. Правда прицел скачет как бешеный. Бесконечные патроны делал заморозив адрес патронов дробовика на 14 патронах.

  2. Версия игры (Update3); версия таблицы 1.0; +1; дата создания 22.09.2011

    Описание:

    1) Стрельба без задержек

    Таблица:

    DeadIslandGame.rar

    Дополнительная информация:

    1) Запустить и свернуть игру

    2) Подключиться к процессу игры из CE (значок компьютера)

    3) Поставить опции сканирования памяти в главном окне. На английском это: "-Writeable; -CopyOnWrite; +Executable". (минусы - ничего стоять не должно, плюс - галочка)

    4) Активировать чит и играть.

    Если у Вас кончаются патроны, то поищите трейнеры или таблицы, которые делают их бесконечными.

    Сам скрипт:


    // MasterGH 2011
    [ENABLE]
    aobscan(address,74xx83xxxxxx7Fxx8Bxxxx8Dxxxx8BxxxxxxxxxxFFxx83xxxx75xx8Bxxxx83)
    label(injectAddress)
    registersymbol(injectAddress)

    address: // "game_x86_rwdi.dll"+4CB1FC = 0x030DB1FC
    injectAddress:
    db E9 83 00 00 00 // jmp game_x86_rwdi.dll+4CB284
    nop


    [DISABLE]
    injectAddress:
    db 74 30 //je game_x86_rwdi.dll+4CB22E
    db 83 78 20 00 // cmp dword ptr [eax+20],00
    unregistersymbol(injectAddress)
    // Fast Shot

    • Плюс 2
  3. Эту тему я хотел написать во флудильне как простое задание для любителей и думал сам не решу до конца. На своё удивления следуя своей логики уже опытного программиста я расколол эту задачку как орех за 15 минут.

    Кто желает исследуем Dead Island.

    Цель:

    1) найти место в коде в котором идёт логическое условие -

    если пользователь (играет) и (может стрелять) и (нажал на левую кнопку мышки), то произвести выстрел.

    2) После нахождения этого условия найти функцию "Выстрела для некотрого героя"

    типа void Shot(pHero * objHero)

    3) Написать скрипт, который делает выстрел.

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

    Решение того что успел.

    1) Ищу адрес потронов для дробовика

    2) Ставлю бряк на запись

    3) Прерываюсь на


    02E86D9C - 50 - push eax
    02E86D9D - FF D2 - call edx
    02E86D9F - FF 48 20 - dec [eax+20] <<
    02E86DA2 - 83 C0 20 - add eax,20
    02E86DA5 - E8 4666C7FF - call 02AFD3F0

    EAX=34289F70
    EBX=199CD788
    ECX=34F10F88
    EDX=02D389E0
    ESI=199CD788
    EDI=0000000C
    ESP=0018F1C8
    EBP=0018F2B8
    EIP=02E86DA2

    4) Иду по инструкции в дизассемблер Cheat Engine. И ставлю трейс на 10000 тыс инструкций. У меня он проходит меньше чем за 15 секунд.

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

    5) На каждом участке вхождения в дереве сверху вглубь ставлю бряк в дизассемблере на выполнение (нажимаю F5). При это совершаю нажатие на правую, а не на левую кнопку мышки. Если бряк срабатывает, то эта инструкция не та, которая нужна. В итоге я наконец нашёл учаток:


    game_x86_rwdi.dll+4C5F38 - 8B C7 - mov eax,edi
    game_x86_rwdi.dll+4C5F3A - E8 A1520000 - call game_x86_rwdi.dll+4CB1E0
    game_x86_rwdi.dll+4C5F3F - 5D - pop ebp // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    game_x86_rwdi.dll+4C5F40 - 5E - pop esi
    game_x86_rwdi.dll+4C5F41 - 5F - pop edi

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

    6) Декомпилируем.

    Оказались не в огромном switch-e, а сразу после него:



    if ( a2 == sub_104CC9C0() && (!*(_BYTE *)(*(_DWORD *)(v4 + 40) + 4820) || sub_10435B80() != 2) )
    {
    if ( 1.0 == a3 )
    sub_104CB1E0(v4); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< где-то внутри будет выстрел
    }

    v4 = 199CD788 - здесь указатель на что? Пока не понятно. Но он есть в регистрах (см. выше) где был бряк при выстреле.

    А что если вызвать функцию sub_104CB1E0(v4) новым потоком и в eax передать 199CD788 ?

    [ENABLE]

    alloc(newmem,1024)
    createthread(newmem)

    newmem:
    mov eax, 199CD788
    call game_x86_rwdi.dll+4CB1E0
    ret


    [DISABLE]
    dealloc(newmem)

    О, Боже я выстрел.. Черт, я даже не думал, что получится, т.к. пишу в режиме ран-тайм... Как же всё просто оказалось smile.gif

    Участок кода, если кому надо:

    game_x86_rwdi.dll+4C5F2D - D8 5C 24 14  - fcomp dword ptr [esp+14]
    game_x86_rwdi.dll+4C5F31 - DFE0 - fnstsw ax
    game_x86_rwdi.dll+4C5F33 - F6 C4 44 - test ah,44
    game_x86_rwdi.dll+4C5F36 - 7A 0F - jp game_x86_rwdi.dll+4C5F47
    game_x86_rwdi.dll+4C5F38 - 8B C7 - mov eax,edi
    game_x86_rwdi.dll+4C5F3A - E8 A1520000 - call game_x86_rwdi.dll+4CB1E0
    game_x86_rwdi.dll+4C5F3F - 5D - pop ebp
    game_x86_rwdi.dll+4C5F40 - 5E - pop esi
    game_x86_rwdi.dll+4C5F41 - 5F - pop edi

  4. В дизайнере форм создаёшь форму.

    Бросаешь на неё компоненты 3 Image и 5 Label-ов.

    Делаешь по три иконки для первого и второго Image (это будут кнопки). Пишешь поведения смены иконок в зависимости от работы курсора: курос над картинкой, удерживание и отпускание.

    Для третьего Image делаешь задний фон с панелью. Если хочешь можешь делать панель отдельно.

    Пишешь обработчики для игры музыки/остановки и показа Info

    Делаешь окно с Info

    Делаешь главную форму нужного типа и размера.

    Дописываешь нужные свойства в лайблы.

    Пишешь ещё какие-то свои поведения для работы трейнера по горячим клавишам и поиска процесса игры.

    Вот и всё. Более подробно смотри учебники по Дельфи или Лазаря по работе с визуальными компонентами (VCL)

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

    В статье кажется речь идёт о СТАЛКЕР-е Зов припяти 1.6 К сожалению не помню точно для какой это версии игры, может быть это для Тени Чернобыля.

    Оформлять некогда. Вот архив

    ЧАСТЬ 1_Взлом патронов в СТАЛКЕР.rar

  6. keng, если Masm нужен для трейнеров, то я рекомендую вместо этого способа создания трейнеров использовать сценарии Lua в CE и AA-скрипты.

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


    captionWindow = 'My first Lua-trainer'

    function OnClose(sender)
    closeCE()
    return caFree
    end

    trainerForm = createForm()
    form_onClose(trainerForm, OnClose)
    control_setCaption(trainerForm, captionWindow)
    form_centerScreen(trainerForm)

    Более подробно здесь. Я очень жду официального появления CE Lua Engine 6.2, потому что в ней (в SDK) уже исправлены многие ошибки и появились новые возможности.

  7. Использование getProcessIDFromProcessName(name) не разумно в цикле таймера. Эта функция перебирает все процессы сравнивая их имена и возвращает id. Этот цикл можно применить один раз, ну два или три... но не постоянно в таймере. Это ненужные расходы ресурсов процессорного времени.

    Чтобы ещё меньше код тормозил нужно пользоваться не getProcessIDFromProcessName("DX2Main.exe"), а другим кодом с getOpenedProcessID(). Последняя возвратит ноль если процесс не подключен.

    А ещё лучше использовать автоаттач процессов (код с getAutoAttachList() ) и обработку события подключения процессов onOpenProcess(processid)...

  8. >>Не нужно так, я же в конце смайлик поставил - значит написал не совсем серьезно, а с неким юмором

    Да, действительно я грубо написал. Извиняюсь. В следующий раз буду по деликатнее. Наверно, из-за того что я с Акамой пообщался в течении недели по личной переписке. Видимо "заразился" его хамством и грубостью.

    Мне просто хотелось уточнить, что за функции сделаны. Теперь понятно.

    • Плюс 1
  9. MasterGH, Старфорс конечно же хорошо, выходит что я тогда делаю невозможное, потому что некоторые функции уже работают )))

    Хм...какие "функции уже работают" и что невозможное ты делаешь? Разве ты снял старфорс с игры? Я немного удивлен. Судя по статье с драйверами Страрфорса мы и не связываемся, а работаем через ринго3.... Насколько я помню были огромные статьи по распаковке других протекторов и они были гораздо и граздо длиннее. Странно что эта статья была такой короткой. И ещё у Старфорса могут быть разные функции защиты, возможно рассмотренная не была настолько сложной во взломе. Может быть решили защиту сделать хуже, чтобы игра меньше тормозила.

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

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

  10. Вообще да, файл перевода должен быть в UTF-8. Также насколько я помню фигурировали только две кодировки ANSI и UTF8. В исходниках ревизий ты можешь увидеть функции типа utf8toansi(...) и ansitoutf8(...). Последняя должна использоваться при выводе сообщений об ошибках.

    Я отрапартовал в форум бета версий. Посматривай за ответом, если у тебя есть доступ.

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

    Там надо Старфорс снимать через виртуалку или через удалённый отладчик ядра. Не сняв Старфорс никак отладку не провести: не узнать указателей и т.п. Никогда этим не занимался и времени нету.

  12. Я подумал что ты ответил "ничего удивительного", потому что обычно всегда в играх вылазят много инструкций. Поэтому я написал, к сожалению, несколько не в той форме "Наверно, привык видеть по 20-50 инструкций и более" ... :)

  13. Xipho, это из 23 мест! Ты можешь себе представить такую рутину...для чего считывать адрес здоровья (наверно это он). Да хоть патронов. Если это адрес здоровья то достаточно 1-2 инструкций чтения mov для отображения в GUI данных. Одной sub для отнятия, одной inc для увлечения, одной cmp для сравнения. А тут аж 23 одних только mov для чтения. Впрочем я знаю почему ты относишься к этому как к обычному делу. Наверно, привык видеть по 20-50 инструкций и более.

  14. Как я уже читал на этом форуме, были предложения встраивать ссылку на этот ресурс в трейнеры.

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

    Банера нет. Если кто-то хочет сделать, то можете сделать и предложить в отдельной теме. Администрация потом решит его судьбу.

  15. r1030 (обновлённая последняя на текущий момент)

    В Lua поддержку добавлены:

    canvas_lineTo(canvas, destinationx, destinationy)

    canvas_rect(canvas, x1,y1,x2,y2)

    canvas_fillRect(canvas, x1,y1,x2,y2)

    canvas_textOut(canvas, x,y, text)

    ---

    d3dhook_setOverlayAsMouse(overlayid):

    Sets the specific overlay image as the mouse cursors.

    This is useful in case you are in a situation with no visible mousecursor this can be used to render one with more performance as the x,y coordinates are updated inside the target app itself on each frame

    To disable the automatic updating of the overlay set as overlayid 0

    To make the mouse invisible, use d3dhook_setOverlayVisibility for that

    Note: The top left part of the overlay is the position of the mouse

    ---

    control_doClick(control): 6.2+: Executes the current function under onclick

    ---

    wincontrol_getControlCount(wincontrol) Returns the number of Controls attached to this class

    wincontrol_getControl(wincontrol,index) : Returns a WinControl class object

    wincontrol_getControlAtPos(wincontrol, x,y): 6.2: Gets the control at the given x,y position relative to the wincontrol's position

    wincontrol_canFocus(wincontrol): returns true if the object can be focused

    wincontrol_focused(wincontrol): returns boolean true when focused

    wincontrol_setFocus(wincontrol): tries to set keyboard focus the object

    wincontrol_onEnter(wincontrol, function) : Sets an onEnter event. (Triggered on focus enter)

    wincontrol_onExit(wincontrol, function) : Sets an onExit event. (Triggered on lost focus)

    ---

    Замена d3dhook_initializeHook(overlaystoragesize) на

    d3dhook_initializeHook(overlaystoragesize, hookmessages)


    Hooks direct3d and allocates a buffer with given size for storage of for the overlay images
    (for one screen stretching overlay sized 1920x1080 you need at least 6220800 bytes)


    hookmessages defines if you want to hook the windows message handler for the direct3d window. The d3dhook_onClick function makes use of that


    If no size is provided 16MB is is used and hookmessages is true


    Note: You can call this only once for a process
    d3dhook_initializeHook(overlaystoragesize, hookmessages):

    --

    d3dhook_onclick(function):

    Registers a function to be called when clicked on an visible overlay (excluding the mouse)

    function definition: function d3dclick(overlayid, x,y)

    x and y are coordinates in the overlay. If overlays overlap the last added overlay will be given

    Note: This can slow cause a slowdown in the game if there are a lot of overlays and you press the left button a lot

    ---

    form_printToRasterImage(form, rasterimage): Draws the contents of the form to a rasterimage class object

    ---

    d3dhook_getWidth(): Returns the width of the direct3d window. Note: At least one frame must have been rendered in the game for this to return anything useful

    d3dhook_getHeight(): Returns the height of the direct3d window. ""

    ---

    Изменены:

    d3dhook_createOverlay(Picture, x,y)

    Sets the Picture object to be used for the overlay.

    Call this each time you have made a change to the bitmap and want to update it in the game.

    About the bitmap. The collor 255,255,255 (white) is used for transparency. If you wish white try 255,255,254 or something similar

    This functions returns an ID you can use with the d3dhook_updateOverlay function

    If out of memory or the initialization failed, this returns nil

    Setting the position to -1,-1 will make it so the overlay will be at the center of the screen

    d3dhook_updateOverlayPosition(overlayid, x,y)

    Call this function when you wish to change the position this overlay has on the screen

    Setting the position to -1,-1 will make it so the overlay will be at the center of the screen

    ---

    d3dhook_setOverlayTransparency(overlayid, percentage): Sets the percentage in visibility of the overlay. 100 is fully visible, 0 is invisible.

  16. r1021 (обновлённая последняя на текущий момент)

    Поменялся "цвет прозрачности":

    d3dhook_createOverlay(Picture, x,y)

    Sets the Picture object to be used for the overlay.

    Call this each time you have made a change to the bitmap and want to update it in the game.

    About the bitmap. The collor 255,255,255 (white) is used for transparency. If you wish white try 255,255,254 or something similar

    Было:

    d3dhook_createOverlay(Picture, x,y)

    Sets the Picture object to be used for the overlay.

    Call this each time you have made a change to the bitmap and want to update it in the game.

    About the bitmap. The collor 0,0,0 (black) is used for transparency. If you wish black, try 0,0,1 or something similar

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

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

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