Просмотр полной версии : [FASM] Хук DispatchNetworkQueue
И так всем привет!
Столкнулся с проблемой...
Если с сервер приходит пакет (например если на сервере сделать новый пакет, которого нету в клиенте по умолчанию) мы его анализируем и выполняем какой то код..
В общем что есть...
Структура NetworkPacket
по идеи так. (не знаю правильно или нет, так как до этого только рисованием в клиенте занимался)
struct NetworkPacket
union
id db ?
align_ dd ?
ends
cb dd ?
data db ?
ends
Так же по каком то примере от GoldFish на С++ был какой то хук
Я его попытался переделать в ФАСМ
proc DispatchNetworkQueueHook
push esp+04h
call [pDispNetwork]
test eax,eax
jz skip_
mov edx,[esp+4]
push eax
push edx
stdcall DrawPackets
pop eax
skip_:
ret 4
endp
Что делать дальше?
Этот хук надо сплайсить с
szDispNetwork db '?DispatchNetworkQueue@UNetworkHandler@@UAEHPAPAUN etworkPacket@@@Z',0
...
..
GetProcAddress([pEngine],szDispNetwork) ; pDispNetwork:=GetProcAddress(pEngine,szDispNetwork );
mov dword [pDispNetwork], eax
Подскажите пожалуста алгоритм что за чем, и если можете примеры....
Заранее спасибо
Честно, не вникал в код, что ты там пытаешься сделать, но самый простейший способ перехватить метод - заменить его адрес в таблице вызова(хотя если дела касаются руоффа, то это наверно самый палевный способ)
В кратце логика подмены в таблице имен такая:
1) находим адрес объекта "?AddNetworkQueue@UNetworkHandler@@UAEHPAUNetworkPa cket@@@Z"
2) находим адрес объекта "??_7UNetworkHandler@@6BUObject@@@"
3) начиная с адреса из пункта 2 организуем поиск ячейки со значением адреса (п.1)
4) затем заменяем там найденный адрес на адрес своей функции и радуемся жизни (и мб. ждем банан)))
Так это же тогда надо будет полностью писать функцию свою...
А как то же сплайсингом нельзя?
Просто в начале вызова ?AddNetworkQueue@UNetworkHandler@@UAEHPAUNetworkPa cket@@@Z
Поставить какой то call (E8) или же jmp (E9) на свою функцию а там Проверять какой id пакета.?
Вот я сделал отдельно функцию для сплайсинга
proc Splaising Adr,Hook
mov eax, [Adr]
mov ebx, eax
mov edx, [Hook]
add ebx, 05h
sub edx, ebx ; calc (hook - (orig + 5))
mov byte [eax], 0E8h ; call
mov dword [eax+1], edx ; rel32
ret
endp
Сплайсингом можно и даже лучше по сути)))
Про таблицу - просто проще (как мне кажется), если на начальном этапе)) Функцию свою надо будет писать ровно настолько, сколько тебе нужно выполнить в ней, а в конце уже вызывать реальную функцию AddNetworkQueue
То есть просто потом jmp [Original]?
А как тут получить параметр.. А именно айди пакета.
То есть просто потом jmp [Original]?
А как тут получить параметр.. А именно айди пакета.
1) jmp на функцию, объявленную так же как и перехватываемая (у которой будет один параметр - указатель на пакет)
2) в своей функции надо сразу сохранить содержимое ecx
3) перед вызовом оригинала восстановить переписанные 5 байт (джамп) запихнуть с ecx то что оттуда сохраняли, и уже теперь вызывать оригинал
4) снова поставить хук (так как для вызова мы его снимали)
зы: тут нету волшебных 5 байт в начале ф-ии которые можено переписать без последствий
По поводу id пакета и т.п. дам тебе тот же совет, что когда-то дали мне, берешь пакетхак и там есть инишники с описанием большинства (мб и всех, хотя врядли) пакетов))
ЗЫ Сначала хотел сказать, что Морфик наркоман, потом выпил кофе проснулся, и понял что похоже на правду)))
ЗЫЫ Морфик, ты сейчас кстати полностью извне работаешь с клиентом или все-таки инжетишься и юзаешь экспортируемые функции без перехвата?
Сплайс неочень хорошая идея так как востанавливать и перезаписывать функцию не лушее решение. Защита хукающая вмт тоже наивное решение. Дестр имхо твою защиту там перехукает быстрее чем ты это реализуеш) нада гдето из сокета брать пакет желательно юзая другую шифрацию недоводя даже до адднетворка и покрыть код фимой. Правда хз как такой пакет будет слать сервер и в каком виде у тя серверная часть защиты.
По поводу id пакета и т.п. дам тебе тот же совет, что когда-то дали мне, берешь пакетхак и там есть инишники с описанием большинства (мб и всех, хотя врядли) пакетов))
ЗЫ Сначала хотел сказать, что Морфик наркоман, потом выпил кофе проснулся, и понял что похоже на правду)))
ЗЫЫ Морфик, ты сейчас кстати полностью извне работаешь с клиентом или все-таки инжетишься и юзаешь экспортируемые функции без перехвата?
полностью из вне работать никак не выйдет, если канешна не знаешь алгоритмов фроста =) ингжект и работа без перехватов - возможностей мало, но зато максимум безопасности
В общем суть такова
Сервер на клиент отправляет пакет
(айди допустим 0x99, структура cSSSSS)
в 5 строк.... Имена чаров)
Потом методами клиента рисуем эти ники (топ пвп которые в игре)
Ну рисовалку я уже знаю как сделать)
А вот с пакетиками (клиент часть) пока что туговато)
Добавлено через 1 час 1 минуту
P.S. А как именно определить, какой айди приходит?
Вот при вызове UNetworkHandler::DispatchNetworkQueue функции передается в аргумент пакет (DispatchNetworkQueue(np:NetworkPacket)
Структура NetworkPacket выглядит както так
struct NetworkPacket
union
id db ?
align_ dd ?
ends
cb dd ?
data db ?
ends
Зная __thiscall аргументы передаются по стеку.
Очевидно что можно оттуда достать и сам пакет и проанализировать его... Только вот как.....
полностью из вне работать никак не выйдет, если канешна не знаешь алгоритмов фроста =) ингжект и работа без перехватов - возможностей мало, но зато максимум безопасности
ок, спс)) А то я стал уже голову ломать, зачем тебе нужен был РидПроцессМемори) уж думал, что ты полностью извне с памятью линейки работаешь))
Добавлено через 22 минуты
В общем суть такова
Сервер на клиент отправляет пакет
(айди допустим 0x99, структура cSSSSS)
в 5 строк.... Имена чаров)
Потом методами клиента рисуем эти ники (топ пвп которые в игре)
Ну рисовалку я уже знаю как сделать)
А вот с пакетиками (клиент часть) пока что туговато)
Добавлено через 1 час 1 минуту
P.S. А как именно определить, какой айди приходит?
Вот при вызове UNetworkHandler::DispatchNetworkQueue функции передается в аргумент пакет (DispatchNetworkQueue(np:NetworkPacket)
Структура NetworkPacket выглядит както так
struct NetworkPacket
union
id db ?
align_ dd ?
ends
cb dd ?
data db ?
ends
Зная __thiscall аргументы передаются по стеку.
Очевидно что можно оттуда достать и сам пакет и проанализировать его... Только вот как.....
Ну структура пакета рабочая вот: (на АСМе хз как оно)
struct NetworkPacket
{
unsigned char id, _padding1, exid, _padding2;
unsigned short size, _padding3;
unsigned char* data;
};
Соответственно первый параметр и есть id пакета.
Теперь про то как это выдернуть...
Смотри, если ты vmt хукаешь (про что говорил я), тогда как раз эта структура и передается твоей функции (точнее указатель), поэтому ничего выдергивать не надо...
Если Сплайсом(как Морфик говорил), тогда дергаешь из стека адрес, и по этому адресу уже лежит структура...
pop eax сохранит стек в EAX?
Туплю что то я со стеком(
Закинуть в стек - вроде понятно всё)
А вытолкнуть со стека какой то 1 параметр... В то время когда их там огого)
Или там будет указатель на сам пакет?)
pop eax сохранит стек в EAX?
Туплю что то я со стеком(
Закинуть в стек - вроде понятно всё)
А вытолкнуть со стека какой то 1 параметр... В то время когда их там огого)
Или там будет указатель на сам пакет?)
указатель)
Хм... Сейчас попробую..
Сделаю переменную по типу структуры
Ну то есть
a: NetworkPacket
потом
pop eax
mov [a], eax
...
по идеи по
a.Id будет айди пакета...
Сейчас посмотрим)))
Я когда изучал, получал тупо адрес, и читал несколько байт после него и пытался понять что это)))
Ахахах
Ппц докатился)
Смотри сколько инклудов )))
include 'win32a.inc'
include 'encoding\win1251.inc'
include 'macro\if.inc'
include 'hll.inc'
include 'main.inc'
include 'Function.inc'
include 'Guard.inc'
include 'Structures.inc'
include 'NetWork.inc'
Добавлено через 4 минуты
Хз пойдут или нет... Еще не проверял но думаю делать так
proc DispatchNetworkQueueHook
pop eax
mov [pk],eax
push ebp
mov ebp, esp
pushad
; какието stdcall
popad
push 0ffffffffh
push eax
ret
endp
Причем на это будет не JMP а CALL
Не будет это работать)
в pk у тебя будет адрес возврата из процедуры.
Нада чето типа того:
push ebp
mov ebp, esp
mov eax,[ebp+8]
pop ebp
mov pk, eax
где в [ebp+8] пропускаем в стеке адрес возврата 4 байта и еще 4 сохраненого нами ебп. Если вызываеш через call то придетса отступить еще на один адрес возврата [ebp+12]
Добавлено через 6 минут
И разумеетса после этих хуков ты обязан восстановить указатиль стека в соответствии с соглашениями вызова cdecl
Добавлено через 10 минут
Ах и да, если хукашеш диспатч то там еще и проверка нужна) она вызываетса в тике клиента около 100 раз в секунду в активном режиме и намного менше в неактивном, при этом в зависимости от плотности траффика от 99% до 10% она вызываетса вхолостую. Тоесть в ней пакета нет :) и нада проверять есть ли там пакет чтоб сразуже не словить генерал протекшн фолт
Кстати... Видел код для дампа пакетов...
push [esp+4]
call [OriginalDispatchNetworkQueuePtr]
test eax,eax
jz skip_
mov edx,[esp+4]
push eax
push [edx]
call NetworkPacketDump
pop eax
skip_:
ret 4
Может с него что то взять?
Я просто не совсем разобрался в нем(
Кстати... Видел код для дампа пакетов...
push [esp+4]
call [OriginalDispatchNetworkQueuePtr] // вызываем оригинал
test eax,eax // проверяем не вернул ли вызов ноль
jz skip_ // вернул ноль - значит холостой вызов, ниче не делаем
mov edx,[esp+4] // чето типа суем указатель на пакет в ЕДХ
push eax // сохраняем ЕАХ
push [edx] // передаем указатель на пакет в функцию дампа
call NetworkPacketDump // вызываем функцию дампа
pop eax // восстанавливаем ЕАХ
skip_:
ret 4 // воостанавливаем стек исходя из соглашения cdecl
Может с него что то взять?
Я просто не совсем разобрался в нем(
незнаю откуда этот кусок но я его понимаю примерно так )
pop eax ; Выталкиваем со стека Адрес Возврата в EAX (4 байта)
push ebp ; Толкаем в стек Адрес , которого начинаются аргументы (глубина стека)
mov ebp, esp ; в ebp теперь "Вершина" стека. Туда будут идти аргументы
mov ebx,[ebp+4] ; тут 4 или 8? мы же вытолкали адрес возврата (4 байта)
pop ebp ; Выталкиваем то стека значения в регистр EBP.
mov NetPk, ebx ; в NetPk у нас будет указатель на пакет
pushad
; какието операции с пакетами типа stdcall
popad
push 0ffffffffh
push eax ; востанавливаем адрес возврата
ret
Проверьте)
Добавлено через 8 часов 34 минуты
Сейчас сделал вот так...
;================================================= ================================
proc DispatchNetworkQueueHook
pop eax ; Выталкиваем со стека Адрес Возврата в EAX (4 байта)
push ebp ; Толкаем в стек Адрес , которого начинаются аргументы (глубина стека)
mov ebp, esp ; в ebp теперь "Вершина" стека. Туда будут идти аргументы
pushad
mov ebx,dword[ebp+08h] ; тут 4 или 8? мы же вытолкали адрес возврата (4 байта)
test ebx,ebx
jz skip
mov [pNetPk], ebx ; в NetPk у нас будет указатель на пакет
skip:
popad
push 0ffffffffh
push eax ; востанавливаем адрес возврата
ret
endp
mov eax, dword[pNetPk]
movzx eax, [eax+NetworkPacket.id]
Всё работает, по идеи в EAX должен быть ID пакета. Но у меня там его Размер почему то...)
Структура у меня такая
struct NetworkPacket
id db ?
pad1 db ?
exid db ?
pad2 db ?
_size dd ?
pad3 dd ?
pdata dd ?
ends
Movzx eax,[eax+пакет.id]
оо?
Добавлено через 8 минут
Movzx eax, [eax] это будет точно ид =)
AddMetworkQueue(p : pNetworkPacket)
203C6090: 55 push ebp
203C6091: 8BEC mov ebp, esp
203C6093: 6AFF push FFFFFFFFh //какието константы (переменные)
203C6095: 68ACF84120push 2041F8ACh //какието константы (переменные)
//тут ставитса обработчик исключения типа try-except
203C609A: 64A100000000mov eax, fs:[00h]
203C60A0: 50 push eax
203C60A1: 64892500000000mov fs:[00000000h], esp
203C60A8: 83EC0C sub esp, 0000000Ch
203C60AB: 53 push ebx
203C60AC: 56 push esi
203C60AD: 57 push edi
203C60AE: 8965F0 mov [ebp-10h], esp
203C60B1: 8BF9 mov edi, ecx
203C60B3: C745FC00000000mov [ebp-04h], 00000000h
203C60BA: 8DB76C010000lea esi, [edi+0000016Ch]
//entercriticalsection
203C60C0: 56 push esi
203C60C1: 90 nop
203C60C2: E839AF535C call 7C901000h (ntdll.dll rtlentercriticalsection)
//какаято функция core возвращающая свободный индекс массива
203C60C7: 83C73C add edi, 0000003Ch
203C60CA: 6A04 push 00000004h
203C60CC: 6A01 push 00000001h
203C60CE: 8BCF mov ecx, edi
203C60D0: 90 nop
203C60D1: E84AB4C3F4call 15001520h
//ложим в массив пакет
203C60D6: 8BD8 mov ebx, eax
203C60D8: 8B07 mov eax, [edi]
203C60DA: 8B4D08 mov ecx, [ebp+08h]
203C60DD: 890C98 mov [eax+ebx*4], ecx
//LeaveCriticalSection
203C60E0: 56 push esi
203C60E1: E8FAAF535Ccall 7C9010E0h (ntdll.dll rtlLeaveCriticalSection)
203C60E6: 90 nop
//восстанавливаем обработчик исключений и спасаем регистры
203C60E7: 8BC3 mov eax, ebx
203C60E9: 8B4DF4 mov ecx, [ebp-0Ch]
203C60EC: 64890D00000000mov fs:[00000000h], ecx
203C60F3: 5F pop edi
203C60F4: 5E pop esi
203C60F5: 5B pop ebx
203C60F6: 8BE5 mov esp, ebp
203C60F8: 5D pop ebp
203C60F9: C20400 retn 0004h
никаму ничего странным тут не кажетса?)
хз...
Кстати
у нас же
DispatchNetworkQueue(struct NetworkPacket * *)
Звёздочка обозначает операцию взятия адреса. Т.к. звёздочки две, то в функцию передаётся указатель на указатель на структуру.
вызываю PaketDump вот так
stdcall PaketDump,[ebp+08h]
proc PaketDump uses ebx, ppnp:DWORD
mov ebx, [ppnp] ; NetworkPacket **
mov ebx, [eax] ; NetworkPacket *
movzx eax, [ebx+NetrowkPacket.id]
...
endp
Но в итоге у меня рисуется все равно адрес... Пробовал не только сплайсингом хукать.... Но и подменой адреса (ну то есть сначало вызывается моя, потом я вызываю оригинал)
Пробовал перед
movzx eax, [ebx+NetrowkPacket.id]
дописать
mov ebx, [ebx]
В итоге клиент критует...
я тебе давал же пример как работает у меня..
нада вызывать вперед оригинал, и еще раз учите ассемблер)
supernewbie
25.04.2011, 02:19
//какаято функция core возвращающая свободный индекс массива
?Add@FArray@@QAEHHH@Z
Ну ее название мне стало искать лень среди тонны экспортов коре. Достаточно что я понял ее смысл)
supernewbie
25.04.2011, 10:41
пусть фрост ставят на серв, хоть весело будет, а то сср ппц какой-то непродвинутый)
и не доказать ниче)
Да не в этом дело
где бы инфу взять по хроникам памагите!
Рабочий код. Я добился чего хотел)
Спасибо всем за помощь.
;================================================= ================================
proc DispatchNetworkQueueHook
pop eax ; Выталкиваем со стека Адрес Возврата в EAX (4 байта)
push ebp ; Толкаем в стек Адрес , которого начинаются аргументы (глубина стека)
mov ebp, esp ; в ebp теперь "Вершина" стека. Туда будут идти аргументы
pushad
mov edx, [ebp+8]
.if edx > 0
stdcall PaketDump,[ebp+08h]
.endif
popad
push 0ffffffffh
push eax ; востанавливаем адрес возврата
ret
endp
;================================================= ================================
proc PaketDump uses ebx, ppnp:DWORD
mov eax, [ppnp] ; NetworkPacket **
mov ebx, [eax] ; NetworkPacket *
.if ebx > 0
movzx eax, [ebx+NetworkPacket.id]
stdcall IntToStr,eax,10,MAXHPBuff
.endif
ret
endp
;================================================= ================================
И в чем был косяк?) вроде все тоже
Косяк был в том что проверять надо было 2 раза.
Так как там идет указатель на указатель.
Тик дает указатель, на указатель который нулл.
Я сделал проверку 1 и 2 указателя))
Сплайсингом кстати хукаю)
Я же писал что нужна проверка еще в теме галухи вроде код.
Сплайсинг не есть хорошо) но работать будет если кроме тика другой поток это не вызовет. Если вдруг еще чтото захочет ее вызвать может кончитса плохо
supernewbie
25.04.2011, 15:54
как бэ там крит секции есть, можно хук после входа в них ставить
Добавлено через 45 минут
блин, как ж ты заставляешль его не рисовать не фризя весь поток полностью)
Добавлено через 36 минут
кажеца понял :)
как бэ там крит секции есть, можно хук после входа в них ставить
Добавлено через 45 минут
блин, как ж ты заставляешль его не рисовать не фризя весь поток полностью)
Добавлено через 36 минут
кажеца понял :)
я не уверен что у альфа после них =)
У меня (судя с твоего сообщения).
Место
203C6090: 55 push ebp
203C6091: 8BEC mov ebp, esp
203C6093: 6AFF push FFFFFFFFh //какието константы (переменные)
Идет call на мою функцию.
В ней уже то что тут.
Вот скрины
оригинал
http://cs5643.vkontakte.ru/u23837494/131637796/y_c0056804.jpg
сплайсинг
http://cs5643.vkontakte.ru/u23837494/131637796/y_85957810.jpg
Ну вот я и говорю что до секции :)
vBulletin® v3.6.11, Copyright ©2000-2024, Jelsoft Enterprises Ltd. Перевод: zCarot