PDA

Просмотр полной версии : [Информация] PWI / Rus / Indo удаление красного спама, поиск оффсетов, инжект патча в ОЗУ


t212
18.11.2011, 12:36
Сокращённый перевод , оригинал тут ([Ссылки могут видеть только зарегистрированные и активированные пользователи])

Краткое описание

В программу заложена возможность выбора окна клиента по имени .персонажа.
Возможность установки патча в процесс запущенный в ОЗУ.
Возможность управлять фильтрами чата через интерфейс программы, настройки при этом сохраняются после релога и использования внутриигровой панэли настроек.
Автоматический поиск нужных оффсетов в запущеном процессе.

Инструкция к программе, и исходные материалы - тут. ([Ссылки могут видеть только зарегистрированные и активированные пользователи])

Интерфейс программы -

[Ссылки могут видеть только зарегистрированные и активированные пользователи]

Итак, для начала необходимо определить, что именно изменяется (адреса в ОЗУ ) в момент использования внутриигровой панели настроек.
Запускаем Cheat Engine , прикрепляем к процессу клиента.
На внутриигровой панели настроек имеются 6 каналов чата ( Основной, Группа, Клан .... ) и 11 опций фильтра (Общий, Группа, Обьявления ... )
Напрашивается вывод о том что в памяти должна присутствовать область, сохраняющая 66 значений настроек фильтров. Так же , легко предположить что в целях экономии ресурсов ОЗУ , настройки сохраняются в виде отдельных байтов, при этом 1- означает что фильтр включен, 0 - выключен.

После прикрепления СЕ к клиенту , открываем внутриигровую панель настроек, выбираем Основной чат , ставим галочку в Общее. В СЕ запускаем поиск байтов со значением 1 .

[Ссылки могут видеть только зарегистрированные и активированные пользователи]

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

Далее выключаем фильтр основного чата в игре, изменяем параметр поиска в СЕ на 0, нажимаем Next Scan. Колличество найденных адрессов сократится до несколльких тысяч. Ничего не меняя в настройках клиента и СЕ продолжаем нажимать Next Scan еще несколько раз. Колличество адрессов будет резко сокращаться с каждым сканированием.

Заново включаем фильтр, и записываем 1 в строку поиска СЕ, сканируем. Продолжаем менять значения и сканировать до тех пор пока в окне поиска не останется 2 - 3 адресса.
Для просмотра памяти выбираем адресс ПКМ, в открывшемся меню выбираем browse memory region.
Адресс который нам нужен будет иметь вид - 100100011000101 ...
Теперь изменяя значения байтов, мы можем изменять настройки фильтров в клиенте, однако следует заметить что порядок настроек в фильтре и в ОЗУ могут отличаться.

[Ссылки могут видеть только зарегистрированные и активированные пользователи]

порядок фильтров в памяти ( для ПВИ ) следующий -

мessageTypes (see chatObj->msgScope)
Local // 0
World // 1
Squad // 2
Faction // 3
Whisper // 4
5 // 5
6 // 6
Trade // 7
Notification // 8
System // 9
Gen. Info // 0xa
Local info(b) // 0xb
Local info(c) // 0xc



Видно, что фильтров на самом деле не 11 а 14, при чем 3 последних - скрыты, в скрытых фильтрах и сохранены настройки для горнов и красного чата.
Итак, мы имеем 13*6 = 78 фильтров. Их оффсеты для каждой области чата (ПВИ ) следующие -

Common -> Normal = 0
Squad -> Normal = 0xD
Faction -> Normal = 0x1A
Whisper -> Normal = 0x27
Trade -> Normal = 0x34
General -> Normal = 0x41

Теперь когда обнаружены адреса фильтров в ОЗУ , проведем эксперимент. В окне СЕ browse memory region изменим значнеие байта отвечающего за известный нам первый фильтр - Основной - Общий. при этом галочка в окне внутриигровой панели не отреагирует на изменение.
Однако, если мы переключим область чата, например на группу и вернёмся в Основной, мы увидим что галочка появилась (если в СЕ 0 заменён на 1 ) или ищезла. Теперь если нажать Применить , белый чат появится/ пропадёт в основном канале. Попробуем найти ячейку для красного или желтого чата, и проделать то же самое . Чат пропадёт, при записи 0 в ячейку, но если закрыть и заново открыть панель настроек в игре, и галочка и чат вернутся на своё место.
Это наводит на мысль о том, что настройки фильтров храняяся еще гдето.
Есть несколько способов найти у область в памяти.
Первый - искать адресс с набором ячеек , значения в которых бы совпадали с прежде найденным адрессом. (Ищем после нажатия применить в панели игры )
Либо найти фрагмент кода, который из вне транслирует информацию по найденому нами адресу . Этот способ и рассмотрим.
Можно воспользоватся встроенным дебагером СЕ, но лучше выбрать инструмент более проффесиональный - OllyDbg

Запускаем OllyDbg , прикрепляем к клиенту ( СЕ если был прикреплён, отсоединяем ) Как только дебагер сообщает о соеденении с процессом нажимаем F9 - разблокируем клиент.
В списке "Executable modules" (Alt+E) двойным ЛКМ выбираем "ElementClient" 2 раза. Далее обращаемся к таблице memory dump area и вызываем функцию перехода по заданному адресу Ctrl+G (Goto address) , вводим адрес найденый с помощю СЕ, выбираем ячейку сохраняющую настройку фильтра Основной - Общий. ПКМ по ячейке, в меню выбираем set a memory breakpoint on write access (брек пойнт при записи памяти )

[Ссылки могут видеть только зарегистрированные и активированные пользователи]

Примечание - в зависимости от версии дебагера интерфейс и меню могут отличаться.

В игре открываем настройки, окно игры будет заморожено, активируется окно дебагера, который покажет нам следующий фрагмент кода

00569167 - 8D 85 1C020000 - lea eax,[ebp+0000021C]

F9 - разблокируем клиент.

При рассмотрении прилегающих строк программного кода мы видим

00569151 |. 8B40 18 MOV EAX,DWORD PTR DS:[EAX+18] ; settings base address
00569154 |. 8DBD 14020000 LEA EDI,[EBP+214]
0056915A |. B9 3A000000 MOV ECX,3A ; Number of integers to copy
0056915F |. B2 01 MOV DL,1
00569161 |. 8DB0 55010000 LEA ESI,[EAX+155] ; ** static filters offset **
00569167 |. 8D85 1C020000 LEA EAX,[EBP+21C] ; points to the filters byte array we found
0056916D |. F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS

Удаляем брекпойнт из памяти, и ставим конвенциональный брекпойнт на строку

00569151 |. 8B40 18 MOV EAX,DWORD PTR DS:[EAX+18] ; settings base address

Снова открываем настройки в игре. В EAX запишется значение baseCall static offset ( &baseCall = 0xAFF144, *baseCall = AFF7E8) (ПВИ)

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

А так же легко вычислить оффсет для постоянной области , он будет равен

[[[baseCall]+0x18]+0x155]

Добавим найденные ранее значения в таблицу оффсетов СЕ как показано на иллюстрации (Выбераем тип 'Array of bytes' , длинна 78) -

[Ссылки могут видеть только зарегистрированные и активированные пользователи]

также добавим Array of bytes для адресса найденного ранее . теперь мы можем сравнить содержимое по этим адресам памяти визуально.

[Ссылки могут видеть только зарегистрированные и активированные пользователи]

Бросается в глаза смещение на 4 байта . Эти 4 байта использубтся для настроек Отказа от группы и торговли , A.D. инверсии осей мышки.

Таким образом , необходимо прибавить 4 к найденному выше оффсету, и окончательный вид оффсетов для чата -

[[[baseCall]+0x18]+0x159]

теперь после настройки фильтров и нажатия применить обе строки должны совпадать


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

Итак , адрес наш адрес -адрес base динамических фильтров + 1, ( адрес динамических фильтров ПВИ [[[[[baseCall]+0x18]+0x8]+0x4B0]+0x218]).
Ставим брекпойнт на 1 байт выше этого адреса ( для желтого чата) .
В игре открываем настройки, дебагер покажет прежний адрес, жмём F9 , и останавливаемся на строке

00569186 |. 8895 19020000 MOV BYTE PTR SS:[EBP+219],DL

Что происходит -
при открытии панели настроек
1 настройки из статических фильтров копируются в динамические фильтры
2 некоторые динамические фильтры включаются принудительно ( красный и желтый чат ,шепот, рупоры )
3 настройки из динамических фильтров возвращаются в статические фильтры , и открывается сам интерфейс панели настроек.

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

Рассмотрим далее найденный нами участок программного кода

00569186 |. 8895 19020000 MOV BYTE PTR SS:[EBP+219],DL ; Common -> World On
0056918C |. 889D 5A020000 MOV BYTE PTR SS:[EBP+25A],BL ; General -> World off
00569192 |. 889D 62020000 MOV BYTE PTR SS:[EBP+262],BL ; General -> System off (red)
00569198 |. 889D 5D020000 MOV BYTE PTR SS:[EBP+25D],BL ; General -> Whisper off
0056919E |. 889D 65020000 MOV BYTE PTR SS:[EBP+265],BL ; General -> Horn? off

Всё это касается только Основного чата. Далее при рассмотрении кода находим обьяснение


00569174 |> 8850 05 /MOV BYTE PTR DS:[EAX+5],DL
00569177 |. 8810 |MOV BYTE PTR DS:[EAX],DL
00569179 |. 8850 08 |MOV BYTE PTR DS:[EAX+8],DL
0056917C |. 83C0 0D |ADD EAX,0D
0056917F |. 49 |DEC ECX
00569180 |.^ 75 F2 \JNE SHORT 00569174

Фрагмент кода обращается (посредством ADD EAX, 0D) ко всем областям чата и устанавливает некоторые фильтры .
Как мы помним щффсет динамических фильтров [[[[[baseCall]+0x18]+0x8]+0x4B0]+0x218] , однако на несколько строк выше мы видим

00569167 |. 8D85 1C020000 LEA EAX,[EBP+21C]

начинаем с 5 го фильтра в Общем чате (шёпот ) видим что фрагмент кода включает фильтры в последовательности

00569174 |> 8850 05 /MOV BYTE PTR DS:[EAX+5],DL ; Red system
00569177 |. 8810 |MOV BYTE PTR DS:[EAX],DL ; Whisper
00569179 |. 8850 08 |MOV BYTE PTR DS:[EAX+8],DL ; Horn? (filter 13 or 0xC)


Единственный способ прервать принудительное включение фильтров красного , желтого , и канала горна - с помощью патча устранить фрагменты кода ответственные за принудительное включение фильтров в клиенте , либо в файле на диске , либо процессе клиента в ОЗУ .

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

программа сканирует запущенный процесс клиента в ОЗУ, и отыскивает строки -

CPU Disasm
Address Hex dump Command Comments
00569174 |> /8850 05 /MOV BYTE PTR DS:[EAX+5],DL
00569177 |. |8810 |MOV BYTE PTR DS:[EAX],DL
00569179 |. |8850 08 |MOV BYTE PTR DS:[EAX+8],DL
0056917C |. |83C0 0D |ADD EAX,0D
0056917F |. |49 |DEC ECX
00569180 |.^\75 F2 \JNE SHORT 00569174
00569182 |. 33DB XOR EBX,EBX
00569184 |. 8BCD MOV ECX,EBP
00569186 |. 8895 19020000 MOV BYTE PTR SS:[EBP+219],DL
0056918C |. 889D 5A020000 MOV BYTE PTR SS:[EBP+25A],BL
00569192 |. 889D 62020000 MOV BYTE PTR SS:[EBP+262],BL
00569198 |. 889D 5D020000 MOV BYTE PTR SS:[EBP+25D],BL
0056919E |. 889D 65020000 MOV BYTE PTR SS:[EBP+265],BL

Далее , запускается патч, который замещает их на

CPU Disasm
Address Hex dump Command Comments
00569174 |> /90 /NOP
00569175 |. |90 |NOP
00569176 |. |90 |NOP
00569177 |. |90 |NOP
00569178 |. |90 |NOP
00569179 |. |90 |NOP
0056917A |. |90 |NOP
0056917B |. |90 |NOP
0056917C |. |83C0 0D |ADD EAX,0D
0056917F |. |49 |DEC ECX
00569180 |.^\75 F2 \JNE SHORT 00569174
00569182 |. 33DB XOR EBX,EBX
00569184 |. 8BCD MOV ECX,EBP
00569186 |. 90 NOP
00569187 |. 90 NOP
00569188 |. 90 NOP
00569189 |. 90 NOP
0056918A |. 90 NOP
0056918B |. 90 NOP
0056918C |. 90 NOP
0056918D |. 90 NOP
0056918E |. 90 NOP
0056918F |. 90 NOP
00569190 |. 90 NOP
00569191 |. 90 NOP
00569192 |. 90 NOP
00569193 |. 90 NOP
00569194 |. 90 NOP
00569195 |. 90 NOP
00569196 |. 90 NOP
00569197 |. 90 NOP
00569198 |. 90 NOP
00569199 |. 90 NOP
0056919A |. 90 NOP
0056919B |. 90 NOP
0056919C |. 90 NOP
0056919D |. 90 NOP
0056919E |. 90 NOP
0056919F |. 90 NOP
005691A0 |. 90 NOP
005691A1 |. 90 NOP
005691A2 |. 90 NOP
005691A3 |. 90 NOP

Больше принудительно включать флуд нечем.

В продолжении - оригинальная реализация функции Применить настройки из интерфейса программы .

По материалам [Ссылки могут видеть только зарегистрированные и активированные пользователи]

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

По причине того, что как сказанно выше , настройки копируются из статической области хранения в динамическую ( GUI игры ) , затем обратно, был разработан следующий алгоритм для активации изменений настроек -

1 Закрыть внутриигровую панель если она открыта.
2 Записать настройки в постоянную область хранения
3 ОВызвать функцию ткрытия интерфейса настроек в игре , и открыть внутриигровую панель настроек
4 Вызвать функцию эмулирующую нажатие Применить во внутриигровом интерфейсе
5 Закрыть внутриигровой интерфейс

В Оlly - в окне с кодом выбираем любую строку, ЛКМ, в мею выбираем 'Search for' -> 'All referenced strings'
Должно появится окошко, со списком всех констант используемых в приложении. ПКМ , в этом окне, и в меню выбираем 'Search for text' (Ctrl+F) . Ищем "Dlg_Building" , эта строка должна быть 1 , и место нахождения её должно быть единственным. 2 раза щёлкаем по ней ЛКМ, и дебагер показывает нам фрагмент кода связанного со строкой. На этом этапе можно открыть IDA disassembler , ввести найденный только что адрес начала функции. Код в этом месте достаточно запутан, придется отмотать несколько страниц его вверх, пока не пойдет последовательность NOP ов. Начало функции - первая строка после NOP ов. В текущей версии ПВИ , она находится по адресу 0x604B30 , а код выглядит так -

CPU Disasm
Address Hex dump Command Comments
00604B30 /. 53 PUSH EBX
00604B31 |. 8B5C24 08 MOV EBX,DWORD PTR SS:[ARG.1]
00604B35 |. 56 PUSH ESI
00604B36 |. 8B7424 10 MOV ESI,DWORD PTR SS:[ARG.2]
00604B3A |. 57 PUSH EDI
00604B3B |. 56 PUSH ESI ; /Arg2 => [ARG.2]
00604B3C |. 53 PUSH EBX ; |Arg1 => [ARG.1]
00604B3D |. E8 EE221E00 CALL 007E6E30 ; \ElementClient.007E6E30
00604B42 |. 84C0 TEST AL,AL
00604B44 |. 74 24 JE SHORT 00604B6A



2 и 4 инструкции сдесть загружают внутриигровой интерфейс, и указатель gui object соответственно. Ставим брекпойнт на 5 строку (PUSH EDI ), на внутриигровом интерфейсе нажимаем кнопку Применить.
Когда брекпойнт сработает, мы увидим значение в ESI, которое будет объектом gui и ссылкой последовательности в EBX, которая будет командой. Команда для кнопки применять - просто текстовая строка, "apply".

Если Вы cделаете это несколько раз для некоторых других элементов, то есть, откроете интерфейс параметров настройки игры или закроете его (X) , Вы получите командные строки для них также. Они - "gamesetting" и "Btn_Close" соответственно.

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

Оффсет для внутриигровой панели настроек имеет вид

[[[[[baseCall]+0x1C]+0x18]+0x8]+0x4B0]

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

Наша функция guiCommand() будет выглядеть примерно так

void guiCommand(string * command, guiObjectPointer)

в результате чего, получаем код

If gameSettingsTab is open
{
guiCommand("Btn_Close", gamesettingTabObject) // close the tab
Wait until it's closed
}
setChatFilters() // Write our preferred filters to the static filter array
guiCommand("gamesetting", gamesettingTabObject) // Open the tab again
guiCommand("apply", gamesettingTabObject) // Hit apply
guiCommand("Btn_Close", gamesettingTabObject) // close the tab again


файл PW_ChatFilter.au3 содержит инжект нашей функции управления в приложение, там с ним и можно ознакомится .

ENDS. ;)

Сокращённый ручной перевод выполнен по поросбе Nitrogen

t212
20.11.2011, 01:12
Ап, статья закончена.