|
Опкоды, Формулы, Клиент Разбор и изучение взаимодействия клиента с сервером |
|
Опции темы | Поиск в этой теме | Опции просмотра |
01.06.2010, 18:25 | #41 |
WowCore Dev
Регистрация: 31.03.2010
Сообщений: 468
Сказал(а) спасибо: 73
Поблагодарили 106 раз(а) в 70 сообщениях
|
прокси не будет работать с батлнетом, сколько не старайтесь. не тратьте время.
надо либо pcap, либо инжектор, либо lsp. pcap по проще. ну мы же раздавали сниферы, и снифы выкладывали. как показала практика пользы всем не будет. а только больше геморроя сниферописателям. все тупо садятся на шею и орут "дай еще, дай новую версию, дай дай дай". снифами никто не делится. а снифер подавай. увы, опыт отрицательный. но все это фигня легко переживаемая по сравнением с тем, что паблик сниффер может стать гвоздем в заднице. баном на оффе по меньшей мере. |
01.06.2010, 18:32 | #42 | ||
YTDB Dev
Регистрация: 01.02.2010
Сообщений: 288
Сказал(а) спасибо: 125
Поблагодарили 97 раз(а) в 53 сообщениях
|
Цитата:
Цитата:
|
||
01.06.2010, 18:41 | #43 |
Kobold Dev
|
мыы уже с константином обсудили все и каг
авось из нас всех выйдет толк а не сразу "баны" не там написал и читай правила шучу -) и с колидой тоже отписали всеровно в одной каше варимся
__________________
Вообще-то я не специалист по этим гравицаппам... |
01.06.2010, 18:43 | #44 | |
Kobold Dev
|
Цитата:
а потом нубо мега АДминчег кричат что он мега опупеный кулхацкер стянул всю базу офа с помощью снифа наслышаны сами -) "прокси не будет работать с батлнетом, сколько не старайтесь. не тратьте время. надо либо pcap, либо инжектор, либо lsp. pcap по проще." хз хз против лома нету приема если нету другого лома
__________________
Вообще-то я не специалист по этим гравицаппам... |
|
01.06.2010, 19:04 | #45 | |
Пользователь
Регистрация: 22.03.2010
Сообщений: 41
Сказал(а) спасибо: 7
Поблагодарили 25 раз(а) в 15 сообщениях
|
Цитата:
а под прокси мы наверное имеем в виду разные вещи. если речь идет об L7-прокси, который изображает для клиента близардовский сервер - то тут действительно ой. перспектив никаких не видно. а если о жутком кадавре, который для LSP-редиректора выглядит как L4-прокси (socks4/5), а по сути - реализует MITM-атаку. - то тут всё очень даже перспективно. + не нужно заморачиваться с реализацией LSP + не нужно заморачиваться с косяками сборки потока из пакетов. (4х потоков, точнее) + есть возмножность активно влиять на передаваемые данные. в том числе и данные, передаваемые варденом внутри дополнительного крипто-потока. + существенно меньший объем работ по реализации, в сравнении с pcap и своим lsp (насчет хуков - не уверен). + гораздо более легкая миграция на новые версии, по сравнению с хуками. |
|
03.06.2010, 11:30 | #46 | |||
RuDB Dev
Регистрация: 01.02.2010
Адрес: localhost
Сообщений: 592
Сказал(а) спасибо: 323
Поблагодарили 283 раз(а) в 122 сообщениях
Записей в дневнике: 2
|
хм... заставить трафик ходить через указанный адрес. Читал про это в интернете...
Цитата:
декриптовать -> внести свою лепту -> обратно зашифровать и пускай идет дальше. Цитата:
Неясным осталось только то, Цитата:
Что-то чем дальше тем сложнее все становится. |
|||
03.06.2010, 14:56 | #47 | ||
Пользователь
Регистрация: 22.03.2010
Сообщений: 41
Сказал(а) спасибо: 7
Поблагодарили 25 раз(а) в 15 сообщениях
|
Цитата:
1. идем на http://www.proxycap.com/download.html , скачиваем и устанавливаем этот "proxifier". (ну или любой другой по вкусу, они все практически одинаковые). ВСЁ!!! про LSP и связанные с ним заморочки можно забыть - эта программа занимается ими сама. 2. добавляем socks4 прокси с адресом 127.0.0.1:наш_порт. добавляем правила "wow.exe перекидывать на этот прокси, остальное не трогать". 3. идем на http://ftp.icm.edu.pl/packages/socks...OCKS4.protocol , читаем описание протокола. проще не придумать. реализуем сервер этого счастья хоть на C#, хоть на чём угодно другом. 4. добавляем логику типа такой: Код:
принять соединение соединиться с запрашиваемым адресом ответить ок принять первые 4 байта данных от клиента если 3-4 байты равны "\xed\x01"(SMSG_AUTH_SESSION) или "\x12\x05" (SMSG_AUTH_SECOND_SESSION): значит в этом соединении идут интересующие нас данные и его нада обрабатывать иначе: просто и тупо прокидывать данные между клиентом и сервером (battle.net / запрос новостей и т.п.) 6. прикидываем (ida в помощь) когда и где в памяти wow.exe образуются интересующие нас ключи и читаем их оттуда. Цитата:
это только в начале, потом легче пойдет. |
||
Пользователь сказал cпасибо: | Konctantin (03.06.2010) |
03.06.2010, 20:17 | #48 |
RuDB Dev
Регистрация: 01.02.2010
Адрес: localhost
Сообщений: 592
Сказал(а) спасибо: 323
Поблагодарили 283 раз(а) в 122 сообщениях
Записей в дневнике: 2
|
Спасибо, я вашем посте я получил почти все что меня интересовало.
Теперь, как немного освобожусь от роботы, попытаюсь все это дело реализовать. Еще раз спасибо. ЗЫ. Не вы случайно автор адской трупожерки? Последний раз редактировалось Konctantin; 03.06.2010 в 20:25. |
04.06.2010, 09:18 | #49 |
Пользователь
Регистрация: 12.03.2010
Сообщений: 85
Сказал(а) спасибо: 5
Поблагодарили 42 раз(а) в 17 сообщениях
|
|
04.06.2010, 09:35 | #50 |
Kobold Dev
|
__________________
Вообще-то я не специалист по этим гравицаппам... |
04.06.2010, 10:55 | #51 |
RuDB Dev
Регистрация: 01.02.2010
Адрес: localhost
Сообщений: 592
Сказал(а) спасибо: 323
Поблагодарили 283 раз(а) в 122 сообщениях
Записей в дневнике: 2
|
Вчера посидел немного, и сделал "прозрачный" прокси сервер,
С помощью проксификатора заставил клиент ходить через свой прокси. Теперь вот как будет время, перенесу все наработки по снифферу в прокси. Но, у меня такой вопрос: пакеты будут приходить ферментированные? ну скажем так: размер в заголовке 20 а длинна пакета 15, значить записать этот пакет в буффер и принять следующий пакет, объединить и обработать |
04.06.2010, 11:20 | #52 | |
Пользователь
Регистрация: 22.03.2010
Сообщений: 41
Сказал(а) спасибо: 7
Поблагодарили 25 раз(а) в 15 сообщениях
|
Цитата:
то, что пакеты будут фрагментироваться при приеме - бывает, но очень редко. а вот обратная ситуация - когда "одинм куском" приходит несколько пакетов - вполне себе нормальное явление. так что разбиение потока на пакеты делать обязательно. |
|
Пользователь сказал cпасибо: | Konctantin (04.06.2010) |
13.06.2010, 06:04 | #55 |
Гость
Сообщений: n/a
|
А я скучаю по временам адской трупожорки
Там всё так просто было и можно было снифить много-много чего. Сейчас, увы, такого удобного снифера нет |
13.06.2010, 08:40 | #56 | |
RuDB Dev
Регистрация: 01.02.2010
Адрес: localhost
Сообщений: 592
Сказал(а) спасибо: 323
Поблагодарили 283 раз(а) в 122 сообщениях
Записей в дневнике: 2
|
Ностальгия...
Мне вот интересно, кто-то уже реализовал проксю или сниффер, или все сделано только в теории? Вот лично мне, как человеку далекому от программирования в сфере сетевых протоколов очень трудно сделать то, чего до конца не понимаешь. Сами понимаете, все это хобби, и есть еще реальная жизнь, пока получается - делаешь, как только зашел в тупик проект сразу уходит с "рабочего стола" в "архив" до лучших времен. Бывает такое, что загвоздка в том самом "да" или "нет", и требуется мизерная подсказка, но увы... До сих пор. я не нашел в интернете никаких примеров "рабочих" прокси, чтобы изучить сам принцип действия. Максимум что у меня получилось, так это получения списка миров, дальше ничего не выходит Выше я писал: Цитата:
Так был рад, а оно оказалось лажа... И все таки, надо по чуть чуть по изучать все это и сделать то, что задумал. |
|
14.06.2010, 17:10 | #57 |
RuDB Dev
Регистрация: 01.02.2010
Адрес: localhost
Сообщений: 592
Сказал(а) спасибо: 323
Поблагодарили 283 раз(а) в 122 сообщениях
Записей в дневнике: 2
|
Давайте вернемся к нашим баранам и продолжим тему
ЗЫ. Естественно америку я не открою, но просто опишу суть. В даном случае использован проксификатор, с правилами следуещего содержания: Если приложение wow.exe соединяется с конечной точкой 213.248.127.130:1119, тогда перенаправить его на 127.0.0.1:9998 (Login - сервер) иначе если приложение wow.exe соеденяется (адресс не указан, тобиш 0.0.0.0:0), тогда перенаправляем его на 127.0.0.1:9999 (World - сервер) Значит, нам надо создать прокси, который бы создал 2 соединения, это соединение с клиентом и соединение с сервером: * Соединение с клиентом, прокси выступает в качестве сервера и общается с клиентом * Соединение с сервером, прокси выступает в качестве клиента и общается с сервером (Login - сервером) но это все у нас пока процесс общения сервером авторизации. (213.248.127.130:1119) Мы просто выступаем посредником и пересылаем пакеты при этом слушая их. Но, клиент же должен подключится к World - серверу. По этому, когда приходит пакет AUTH_REALM в котором приходит IPAdress:port сервера к которому надо подключится, запоминаем этот IPAdress:port. Создаем опять 2 подключения, аналогичные первым, только с адресом который мы прочитали и запомнили. И далее выполняем обмен сообщениями между World - сервером и клиентом. Для дальнейшей обработки пакетом их можно декриптовать и складывать, или делать с ними что захотим. Далее, по скольку ввели новую систему распределения нагрузки World - сервер может прислать пакет, который указывает, что нужно переподключится на новый World - сервер, и присылает данные: 1) SMSG_REDIRECT_CLIENT он присылает адрес нового сервера 2) SMSG_AUTH_CHALLENGE приходят новые сиды Не знаю, может я что-то упустил, если так, то поправьте пожалуйста. |
15.06.2010, 17:32 | #58 | |||
Пользователь
Регистрация: 22.03.2010
Сообщений: 41
Сказал(а) спасибо: 7
Поблагодарили 25 раз(а) в 15 сообщениях
|
Цитата:
у других, думаю, тоже есть. вот только делиться и тем более выкладывать в паблик тут "почему-то" непринято Цитата:
у меня, например, нет разделения на login/world. всё, что не начинается с нужного пакета - просто и тупо перекидывается без обработки. ну или можно на диск писать, если желание есть. Цитата:
для упрощения начать с такой конфигурации: 1. клиент у нас ровно одна штука, в начальный момент времени загружен, но не залогинен. 2. прокси запускается строго перед логином в таком случае - какая разница, какой там адрес отдал клиенту сервер авторизации??? интересующее нас соединение, один черт, начнется с SMSG_AUTH_CHALLENGE больше оно в нашем раскладе ни с чего начаться не может! значит: 0. открываем (bind) сокет на нужном порту и ждем подключений (listen) от проксификатора 1. принимаем (accept) соединение от проксификатора 2. разбираем socks4 запрос, подключаемся (connect) к указанному адресу, отдаем проксификатору socks4-ответ "ОК" 3. тут я прошлый раз неправильно написал. нужно делать так: ждем, пока клиент что-нибудь пошлет, проверяем у этого "чего-нибудь" 3й+4й байты - и если они не равны опкоду CMSG_AUTH_SESSION (а не SMSG_AUTH_SESSION - такого опкода вообще нету) - забиваем на это соединение. ничего интересного тут не предвидится. естественно продолжая прокидывать через него данные в обе стороны 5. если таки интересующие нас байты найдены - то ВЫВОДИМ НА КОНСОЛЬ МНОГО РАЗНОЦВЕТНЫХ БУКВ И РАДУЕМСЯ, ЧТО НАКОНЕЦ ЧТО-ТО ПОЛУЧИЛОСЬ. пишем поток на диск (естественно каждое направление в свой файл. разделять на отдельные пакеты не нужно.) 6. летим подальше от любимого даларана, желательно в сторону пристани Моа'ки а оттуда - на самую дальнюю льдину, какую получится найти. 7. выходим из игры и смотрим на то месиво, что записалось в файлы. ничего осмысленного, т.к. данные пошифрованы. и скорее всего запишется очень мало данных, т.к. SMSG_SECOND_CONNECTION приходит почти сразу. но прервый шаг уже сделан, в соединение вклинились!!! вот так выглядит функция, занимающаяся пересылкой данных: http://paste2.org/p/878723 (шаги 2-3) это, конечно, не C#, но представление дает на yield не смотреть, они для реализации со-процедур (самопальной и весьма корявой, но "и так работает"). на read_session_key() и вытаскивания сидов из SMSG_AUTH_CHALLENGE не смотреть, она осталась со времен, когда по этим сидам я генерил крипто-состояния сам, а не читал их готовыми из памяти. не судьба убрать, "и так работает". разбиение на пакеты, расшифровка пакетов, расшифровка вардена, логика, шифровка вардена, шифровка пакетов, сборка пакетов в поток - они все в WorldFilter код коряв и страшен, как моя жизнь. однако "и так работает" )) Последний раз редактировалось abdula123; 15.06.2010 в 18:32. |
|||
Пользователь сказал cпасибо: | Konctantin (15.06.2010) |
15.06.2010, 22:21 | #59 |
RuDB Dev
Регистрация: 01.02.2010
Адрес: localhost
Сообщений: 592
Сказал(а) спасибо: 323
Поблагодарили 283 раз(а) в 122 сообщениях
Записей в дневнике: 2
|
меня просто в большей сложности смущает то, что нужно из одного потока разделять на на 2 потока, тобиш приходят пакеты которые должны идти на LoginServer и WorldServer но как их потом разделять, чтоб определить куда какой перенаправлять???
надо или знать все опкоды бнет пакетов или сразу на стадии соединения определить куда они направлены клиентом. Просто я понимаю такую реализацию: получаем соединение от клиента, и соединяемся с сервером: но, чтобы соединится с сервером, надо знать конечную точку. Тобиш работать в так званом клиент серверном режиме. Или же можно реализовать "слепую прокси" которой не надо явно указывать куда подключатся, но я себе такое слабо представляю. Черт, я еще больше запутался, или может это так пиво повлияло... |
16.06.2010, 05:47 | #60 | |
Пользователь
Регистрация: 22.03.2010
Сообщений: 41
Сказал(а) спасибо: 7
Поблагодарили 25 раз(а) в 15 сообщениях
|
Цитата:
просто прокси, без всякой специфики wow. потом уже, когда будет не "понимание", а работающий код - к нему уже можно будет дописывать нужный функционал. |
|
16.06.2010, 12:38 | #61 |
RuDB Dev
Регистрация: 01.02.2010
Адрес: localhost
Сообщений: 592
Сказал(а) спасибо: 323
Поблагодарили 283 раз(а) в 122 сообщениях
Записей в дневнике: 2
|
вот тут я и застрял, я не могу понять как прокси будет знать куда перебрасывать соединение, если в сокете, конечный адресс уже выглядит как localhost:port
|
16.06.2010, 15:06 | #62 | |
Пользователь
Регистрация: 22.03.2010
Сообщений: 41
Сказал(а) спасибо: 7
Поблагодарили 25 раз(а) в 15 сообщениях
|
Цитата:
читать до просветления. |
|
Пользователь сказал cпасибо: | Konctantin (16.06.2010) |
16.06.2010, 18:40 | #63 |
RuDB Dev
Регистрация: 01.02.2010
Адрес: localhost
Сообщений: 592
Сказал(а) спасибо: 323
Поблагодарили 283 раз(а) в 122 сообщениях
Записей в дневнике: 2
|
Черт, биг сенкую. Наконец то мне дошло, в самом пакете все есть
Код:
+----+----+----+----+----+----+----+----+----+----+....+----+ | VN | CD | DSTPORT | DSTIP | USERID |NULL| +----+----+----+----+----+----+----+----+----+----+....+----+ # of bytes: 1 1 2 4 variable 1 |
16.06.2010, 20:21 | #64 | |
Пользователь
Регистрация: 22.03.2010
Сообщений: 41
Сказал(а) спасибо: 7
Поблагодарили 25 раз(а) в 15 сообщениях
|
Цитата:
что и было проделано мною в феврале, когда снова появился интерес копаться. понятно, что многие парсеры пакетов устарели и их нужно переписывать. (кстати, у меня теперь новый формат парсеров пакетов, ими теперь можно парсить + менять поля + кодировать обратно - одним и тем-же кодом) может быть потом выложу потом. тем более, что интерес снова куда-то уходит (бот написан и бегает, сниффер снифит) Последний раз редактировалось abdula123; 16.06.2010 в 20:28. |
|
16.06.2010, 21:58 | #65 |
WowCore Dev
Регистрация: 31.03.2010
Сообщений: 468
Сказал(а) спасибо: 73
Поблагодарили 106 раз(а) в 70 сообщениях
|
бот наверное имеется ввиду тот, который на запущенном и залогиненном клиенте кнопки нажимает и мышкой шевелит?
|
17.06.2010, 04:13 | #66 | |
Пользователь
Регистрация: 22.03.2010
Сообщений: 41
Сказал(а) спасибо: 7
Поблагодарили 25 раз(а) в 15 сообщениях
|
Цитата:
тем самым имеющий практически полную информацию об окружении и действующий в соответствии с ней. |
|
17.06.2010, 06:49 | #67 | |
Гость
Сообщений: n/a
|
Цитата:
А парсеры пакетов подгоним под новые билды и ревизии мангоса, не проблема |
|
17.06.2010, 16:26 | #68 | ||
Пользователь
Регистрация: 22.03.2010
Сообщений: 41
Сказал(а) спасибо: 7
Поблагодарили 25 раз(а) в 15 сообщениях
|
Цитата:
кстати, а что случилось с Trac'ом проекта? почему он пускает незалогиненых, дает им доступ к коду. и не дает логиниться. кагбе паблика не очень хочется. UPD: а, понятно, проклятые китайцы забили на opensvn Цитата:
Последний раз редактировалось abdula123; 17.06.2010 в 16:29. |
||
19.06.2010, 02:12 | #69 |
WowCore Dev
Регистрация: 31.03.2010
Сообщений: 468
Сказал(а) спасибо: 73
Поблагодарили 106 раз(а) в 70 сообщениях
|
решил тряхнуть стариной - переписал старый zLogger (который работает на pcap) на новый лад. следующую сессию видит и начинает новый снифф. пишет в raw, потом в оффлайне уже декриптую утилиткой. спасибо том_рус что подсказал где брать сиды для нового соединения.
|
Пользователь сказал cпасибо: | sven (20.06.2010) |
19.06.2010, 22:17 | #70 |
Kobold Dev
|
Хех -)) запахло порохом ? ))
решили все тряхнуть стариной ? -)
__________________
Вообще-то я не специалист по этим гравицаппам... |
22.06.2010, 19:48 | #72 | |
Новичок
Регистрация: 31.03.2010
Сообщений: 22
Сказал(а) спасибо: 2
Поблагодарили 23 раз(а) в 8 сообщениях
|
Цитата:
Так вот к нашим баранам: можно вообще делать под raw сокетами. Пакеты и правда могут приходить "всё в одном", с повторами, порезаные. Но логика сборки там простая. Я и такой сделал и он куда проще даже проксевого (с проксевым головняк лично у меня с критическими секциями, пока не отправлено надо ж что-то делать с новыми пакетами). У Ромки под PCap принцип тот-же, разве что ему влом пакеты собирать (какая-то у него либа проприетарно-тыреная этим занимается). Можно было б выложить основной код, но я так понимаю у девелоперов с кодом Дельфи еще хуже чем с СИ. |
|
Пользователь сказал cпасибо: | Konctantin (22.06.2010) |
23.06.2010, 00:24 | #73 |
Новичок
Регистрация: 31.03.2010
Сообщений: 22
Сказал(а) спасибо: 2
Поблагодарили 23 раз(а) в 8 сообщениях
|
обработка пакетов
Вот собсно raw сокеты в 2-х словах. Код на Дельфи, но винапи он и в Африке винапи. PChar соответственно в си char*. Элементарного типа WSAStartup не касаюсь.
Инициализация Код:
//декларация обработки ивента const WM_ListenSocketEvent = WM_User+1; .... procedure WMListenSocketEventHandler(var Msg:TMessage);message WM_ListenSocketEvent; .... function TfrmMain.InitSocket: Boolean; var PromiscuousMode: dword; temp: integer; BufSize: dword; begin result:=false; // создаем сокет hSocket := socket(AF_INET, SOCK_RAW, IPPROTO_IP); if hSocket = INVALID_SOCKET then begin DeInitSocket(WSAGetLastError); AddToLog('Raw sockets not supported'); Exit; end; FillChar(Addr_in, SizeOf(sockaddr_in), 0); Addr_in.sin_family:= AF_INET; // указываем за каким интерфейсом будем следить Addr_in.sin_addr.s_addr := inet_addr(PChar(Host)); // связываем сокет с локальным адресом if ScktErrorCheck(bind(hSocket, @Addr_in, SizeOf(sockaddr_in))) = SOCKET_ERROR then exit; BufSize:=MAX_PACKET_SIZE; if ScktErrorCheck(SetSockOpt(hSocket, SOL_SOCKET, SO_RCVBUF, PChar(@BufSize), sizeof(BufSize))) = SOCKET_ERROR then exit; temp:=sizeof(integer); if ScktErrorCheck(GetSockOpt(hSocket, SOL_SOCKET, SO_RCVBUF, PChar(@BufSize), temp)) = SOCKET_ERROR then exit else AddToLog('Buffer size = '+IntToHex(BufSize,4)); if ScktErrorCheck(WSAAsyncSelect(hSocket,frmMain.Handle,WM_ListenSocketEvent,FD_READ or FD_CLOSE)) = SOCKET_ERROR then exit; // Переключаем интерфейс на прием всех пакетов проходящих через интерфейс - promiscuous mode. PromiscuousMode := 1; if ScktErrorCheck(ioctlsocket(hSocket, SIO_RCVALL, PromiscuousMode)) = SOCKET_ERROR then exit; Result := True; end; Код:
procedure TfrmMain.WMListenSocketEventHandler(var Msg:TMessage); var Sock: TSocket; SockError,PacketSize: integer; begin Sock:=TSocket(Msg.WParam); SockError:=WSAGetSelectError(Msg.lParam); if SockError <> 0 then begin CloseSocket(Sock); Exit; end; case WSAGetSelectEvent(Msg.lParam) of FD_Read: begin CS.Enter; PacketSize := recv(hSocket, Packet, MAX_PACKET_SIZE, 0); // Если есть данные - производим их разбор ParcePacket(PacketSize); CS.Leave; end; FD_Close: begin AddToLog('FD_CLOSE'); end; end; end; Код:
if PacketSize <= SizeOf(TIPHeader) then exit; pIpHdr:=PIPHeader(@Packet[0]); ipHdrLen:=GetIPHeaderLen(pIpHdr); pTcpHdr:=PTCPHeader(@Packet[ipHdrLen]); // определяем тип протокола if pIpHdr.iph_protocol = IPPROTO_TCP then begin PacketType := 'TCP'; // Смотрим порт отправителя и получателя SrcPort := pTcpHdr.sourcePort; DestPort := pTcpHdr.destinationPort; end else exit; SrcPort := htons(SrcPort); DestPort := htons(DestPort); if (SrcPort <> frmMain.FListenPort)and(DestPort <> frmMain.FListenPort) then exit; // Пишем IP адрес отправителя с портом AddrSrc.S_addr := pIpHdr.iph_src; // Пишем IP адрес получателя с портом AddrDst.S_addr := pIpHdr.iph_dest; tcpHdrDataOffs:=ipHdrLen + GetTCPDataOffset(@Packet[ipHdrLen]); PacketFlags:=ntohs(pTcpHdr.flags); ... продолжение ниже... |
2 пользователя(ей) сказали cпасибо: | Konctantin (23.06.2010), zergtmn (23.06.2010) |
23.06.2010, 00:27 | #74 |
Новичок
Регистрация: 31.03.2010
Сообщений: 22
Сказал(а) спасибо: 2
Поблагодарили 23 раз(а) в 8 сообщениях
|
сама сборка пакетов (для пикапа тоже пригодится)
Код:
constructor TTcpBuffer.Create; begin FCS:=TCriticalSection.Create; setlength(FSeqArr, SIZE64); FSeqCount:=0; FCurrSeq:=0; //FNextSeq:=0; FDupCount:=0; FOorCount:=0; end; destructor TTcpBuffer.Destroy; var i: integer; begin FCS.Enter; // |--[ack|array] count,first // | |--[seq|wsabuf] // | |--[seq|wsabuf] // | |--[seq|wsabuf] for i:=0 to FSeqCount - 1 do FreeMem(FSeqArr[i].wsa_buf.buf); FSeqArr:=nil; FCS.Leave; FCS.Free; inherited; end; procedure TTcpBuffer.ASwap(Lo, Hi: integer); var temp: TSeqRec; begin move(FSeqArr[Lo],temp,sizeof(TSeqRec)); move(FSeqArr[Hi],FSeqArr[Lo],sizeof(TSeqRec)); move(temp,FSeqArr[Hi],sizeof(TSeqRec)); end; procedure TTcpBuffer.QuickSort(iLo, iHi: integer); var Lo, Hi: integer; pivot: dword; begin Lo := iLo; Hi := iHi; pivot:=FSeqArr[(Lo + Hi) div 2].swappedSeq; repeat while FSeqArr[Lo].swappedSeq < pivot do Inc(Lo); while FSeqArr[Hi].swappedSeq > pivot do Dec(Hi); if Lo <= Hi then begin if Lo <> Hi then ASwap(Lo,Hi); Inc(Lo); Dec(Hi); end; until Lo > Hi; if Hi > iLo then QuickSort(iLo, Hi); if Lo < iHi then QuickSort(Lo, iHi); end; {function TTcpBuffer.QuickFind(const looking_for: dword; iLo, iHi: integer):dword; var Mid: dword; pivot: dword; begin if (iHi-iLo-1) > 0 then begin Mid:=(iLo+iHi) div 2; pivot:=FSeqArr[Mid].swappedSeq; if pivot < looking_for then result:=QuickFind(looking_for,Mid,iHi) else result:=QuickFind(looking_for,iLo,Mid); end else if looking_for > FSeqArr[iLo].swappedSeq then result:=iHi else result:=iLo; end;} function TTcpBuffer.Match(Value: dword; ItemIndex: integer): integer; begin result:=0; if Value < FSeqArr[ItemIndex].swappedSeq then result:=-1 else if Value > FSeqArr[ItemIndex].swappedSeq then result:=1; end; function TTcpBuffer.QuickSearch(Value: dword; Count: integer; MatchFunction: TMatchFunction): integer; var L, M, C: integer; begin if Count > 0 then begin L := 0; Dec(Count); while L <= Count do begin M := (L + Count) shr 1; C := MatchFunction(Value, M); if C > 0 then L := M + 1 else if C <> 0 then Count := M - 1 else begin Result := M; Exit; end; end; end; Result := -1; end; { Add any match cap sequence to array } procedure TTcpBuffer.Add2Buffer(data: pointer; swappedSeq,len,dataOffs: dword; isFromServer: boolean); var prev: dword; dataLen: dword; i: integer; begin prev:=FSeqCount; inc(FSeqCount); if FSeqCount > length(FSeqArr) then setlength(FSeqArr, ((length(FSeqArr) shr 6) + 1) shl 6); //by 64 GetMem(FSeqArr[prev].wsa_buf.buf, len); move(data^, FSeqArr[prev].wsa_buf.buf^, len); FSeqArr[prev].wsa_buf.len:=len; FSeqArr[prev].swappedSeq:=swappedSeq; FSeqArr[prev].dataOffs:=dataOffs; dataLen:=len - dataOffs; FSeqArr[prev].dataLen:=dataLen; //if swappedSeq = FNextSeq then // FNextSeq:=FCurrSeq + dataLen; if FSeqCount > 1 then QuickSort(0, FSeqCount - 1); if FSeqCount = 10 then begin if isFromServer then AddToLog('SMSG') else AddToLog('CMSG'); AddToLog('current '+IntToHex(FCurrSeq,8)+' datalen '+IntToHex(dataLen,4)); AddToLog('expecting '+IntToHex(FCurrSeq + dataLen,8)); for i := 0 to 9 do AddToLog('seq['+IntToStr(i)+']='+IntToHex(FSeqArr[i].swappedSeq,8)); end; end; { Add any packet from current to current+MAX_DELTA_BROWSE_SEQUENCE } procedure TTcpBuffer.AddData(data: pointer; len: dword; isFromServer: boolean); var packetFlags: word; ipHdrLen,tcpHdrDataOffs,dataOffs: dword; pIpHdr: PIPHeader; pTcpHdr: PTCPHeader; pseudoHdr: TTCPPseudoHeader; pseudohdrCS,cs: word; swappedSeq,maxPossibleSeq: dword; label fin; begin FCS.Enter; pIpHdr:=PIPHeader(data); ipHdrLen:=GetIPHeaderLen(pIpHdr); pTcpHdr:=PTCPHeader(@TBytes(data)[ipHdrLen]); //check already in array swappedSeq:=ntohl(pTcpHdr.sequenceNumber); if FSeqCount > 1 then begin if QuickSearch(swappedSeq, FSeqCount, Match) >= 0 then begin //AddToLog(Format('skip duplicated seq: %.8x swseq: %.8x',[pTcpHdr.sequenceNumber,swappedSeq])); inc(FDupCount); goto fin; end; end else if FSeqCount > 0 then begin if FSeqArr[0].swappedSeq = swappedSeq then begin //AddToLog(Format('skip duplicated seq: %.8x swseq: %.8x',[pTcpHdr.sequenceNumber,swappedSeq])); inc(FDupCount); goto fin; end; end; //check CS cs:=GetChecksum(pIpHdr, ipHdrLen); if cs <> 0 then begin if isFromServer then AddToLog('wrong iphdr cs='+IntToHex(cs,4)+' src=server') else AddToLog('wrong iphdr cs='+IntToHex(cs,4)+' src=client'); if (checkCS)and(isFromServer) then goto fin; end; if isFromServer then begin pseudoHdr.iph_src:=pIpHdr.iph_src; pseudoHdr.iph_dest:=pIpHdr.iph_dest; pseudoHdr.reserved:=0; pseudoHdr.iph_protocol:=pIpHdr.iph_protocol; pseudoHdr.tcp_length:=ntohs(len - ipHdrLen); //ntohl shr 16; pseudohdrCS:=not(GetChecksum(@pseudoHdr, sizeof(pseudoHdr))); cs:=GetChecksum(pTcpHdr, len - ipHdrLen, pseudohdrCS); if cs <> 0 then begin if isFromServer then AddToLog('wrong iphdr cs='+IntToHex(cs,4)+' src=server') else AddToLog('wrong iphdr cs='+IntToHex(cs,4)+' src=client'); if (checkCS) then goto fin; end; end; packetFlags:=ntohs(pTcpHdr.flags); //initial sequences if (packetFlags and TCP_FLAG_SYN) <> 0 then begin //FNextSeq:= FCurrSeq:=swappedSeq + 1; //FNextSeq; goto fin; end; //if (packetFlags and TCP_FLAG_ACK) <> 0 then goto fin; maxPossibleSeq:=FCurrSeq + MAX_DELTA_BROWSE_SEQUENCE; if ((FCurrSeq < maxPossibleSeq)and((swappedSeq < FCurrSeq)or(swappedSeq > maxPossibleSeq))) //linear or ((FCurrSeq > maxPossibleSeq)and((swappedSeq < FCurrSeq)and(swappedSeq > maxPossibleSeq))) then begin //AddToLog(Format('skip out of range seq: %.8x swseq: %.8x FCurrSeq: %.8x',[pTcpHdr.sequenceNumber,swappedSeq,FCurrSeq])); inc(FOorCount); goto fin; end; tcpHdrDataOffs:=GetTCPDataOffset(@TBytes(data)[ipHdrLen]); dataOffs:=ipHdrLen+tcpHdrDataOffs; if len > dataOffs then Add2Buffer(data, swappedSeq, len, dataOffs, isFromServer); fin: FCS.Leave; end; procedure TTcpBuffer.RemoveAt(seqArrPos: integer); begin Assert(seqArrPos < FSeqCount); FreeMem(FSeqArr[seqArrPos].wsa_buf.buf); if seqArrPos < (FSeqCount - 1) then move(FSeqArr[seqArrPos+1], FSeqArr[seqArrPos], sizeof(TSeqRec)*(FSeqCount - seqArrPos - 1)); dec(FSeqCount); end; procedure TTcpBuffer.Release(swappedSeq: dword); var maxPossibleSeq: dword; i,spos: integer; begin FCS.Enter; if FSeqCount > 1 then begin //AddToLog(Format('TTcpBuffer.Release seq: %.8x swseq: %.8x FSeqCount: %d',[bswap(swappedSeq),swappedSeq,FSeqCount])); //for i := 0 to FSeqCount - 1 do // AddToLog(Format('FSeqArr[%d] swseq: %.8x wsa_buf.buf: %.8x wsa_buf.len: %d',[i,FSeqArr[i].swappedSeq,dword(FSeqArr[i].wsa_buf.buf),FSeqArr[i].wsa_buf.len])); spos:=QuickSearch(swappedSeq, FSeqCount, Match); if spos >= 0 then begin //AddToLog(Format('swseq found at %d',[spos])); FCurrSeq:=FCurrSeq + FSeqArr[spos].dataLen; RemoveAt(spos); end; //remove trash i:=0; while i < FSeqCount do begin maxPossibleSeq:=FCurrSeq + MAX_DELTA_BROWSE_SEQUENCE; if maxPossibleSeq > FCurrSeq then begin if (FSeqArr[i].swappedSeq < FCurrSeq)or(FSeqArr[i].swappedSeq > maxPossibleSeq) then begin //AddToLog(Format('FSeqCount: %d removing at: %d FCurrSeq: %.8x maxPossibleSeq: %.8x swseq: %.8x',[FSeqCount,i,FCurrSeq,maxPossibleSeq,FSeqArr[i].swappedSeq])); RemoveAt(i); end else inc(i); end else if (FSeqArr[i].swappedSeq < FCurrSeq)and(FSeqArr[i].swappedSeq > maxPossibleSeq) then begin //AddToLog(Format('FSeqCount: %d removing at: %d FCurrSeq: %.8x maxPossibleSeq: %.8x swseq: %.8x',[FSeqCount,i,FCurrSeq,maxPossibleSeq,FSeqArr[i].swappedSeq])); RemoveAt(i); end else inc(i); end; end else if FSeqCount > 0 then begin if FSeqArr[0].swappedSeq = swappedSeq then begin FCurrSeq:=FCurrSeq + FSeqArr[0].dataLen; RemoveAt(0); end; end; FCS.Leave; end; { Get next matched sequence } function TTcpBuffer.GetSequence: PSeqRec; var spos: integer; begin result:=nil; FCS.Enter; if FSeqCount > 1 then begin spos:=QuickSearch(FCurrSeq, FSeqCount, Match); if spos >= 0 then result:=@FSeqArr[spos]; end else if FSeqCount > 0 then begin if FSeqArr[0].swappedSeq = FCurrSeq then result:=@FSeqArr[0]; end; FCS.Leave; end; |
2 пользователя(ей) сказали cпасибо: | Konctantin (23.06.2010), zergtmn (23.06.2010) |
23.06.2010, 00:31 | #75 |
Новичок
Регистрация: 31.03.2010
Сообщений: 22
Сказал(а) спасибо: 2
Поблагодарили 23 раз(а) в 8 сообщениях
|
да, сама структура "номер пакета" - "пакет"
Код:
PSeqRec = ^TSeqRec; TSeqRec = packed record swappedSeq: dword; dataOffs,dataLen: dword; wsa_buf: WSABUF; end; TSeqArr = array of TSeqRec; Код:
function GetDWordDiff(aLo,aHi: dword):dword; begin if aHi >= aLo then result:=aHi - aLo else result:= maxdword - aLo + aHi; end; function GetIPHeaderLen(ih: PIPHeader): Word; // IP header length begin // multiply the low nibble by 4 // and return the length in bytes Result := (ih.iph_verlen and $F) shl 2; end; function GetTCPDataOffset(th: PTCPHeader): Word; begin // doff (data offset) stored in 32 bit words, // multiply the value by 4 to get byte offset Result := ((th.flags and $F0) shr 4) shl 2; end; function GetFlags(flags: word): string; begin result := '' ; if (flags AND TCP_FLAG_FIN) = TCP_FLAG_FIN then result := result + 'FIN '; if (flags AND TCP_FLAG_SYN) = TCP_FLAG_SYN then result := result + 'SYN '; if (flags AND TCP_FLAG_RST) = TCP_FLAG_RST then result := result + 'RST '; if (flags AND TCP_FLAG_PSH) = TCP_FLAG_PSH then result := result + 'PSH '; if (flags AND TCP_FLAG_ACK) = TCP_FLAG_ACK then result := result + 'ACK '; if (flags AND TCP_FLAG_URG) = TCP_FLAG_URG then result := result + 'URG '; if (flags AND TCP_FLAG_ECH) = TCP_FLAG_ECH then result := result + 'ECH '; if (flags AND TCP_FLAG_CWR) = TCP_FLAG_CWR then result := result + 'CWR '; result := trim (result); end; function GetChecksum(lpBuf: pointer; count: integer; initial_value: word = 0):word; var temp: integer; begin //http://www.faqs.org/rfcs/rfc1071.html temp:=initial_value; while count > 1 do begin temp:=temp + PWord(lpBuf)^; inc(integer(lpBuf),sizeof(word)); dec(count,sizeof(word)); end; if count > 0 then temp:=temp + PByte(lpBuf)^; while (temp shr 16) <> 0 do temp:=(temp and $ffff) + (temp shr 16); result:= not(temp); end; Последний раз редактировалось user456; 23.06.2010 в 00:33. |
Пользователь сказал cпасибо: | zergtmn (23.06.2010) |
23.06.2010, 08:55 | #76 | |
Пользователь
Регистрация: 22.03.2010
Сообщений: 41
Сказал(а) спасибо: 7
Поблагодарили 25 раз(а) в 15 сообщениях
|
Цитата:
и вся та простыня кода называется "проще"??? ё-маё. как-же всё-таки любят некоторые усложнять себе жизнь. у меня ВСЯ обработка соединений \ расшифровка \ лог \ зашифровка в разы меньше и проще, чем одно только это чтение и сборка tcp-пакетов. |
|
23.06.2010, 11:24 | #77 |
Новичок
Регистрация: 31.03.2010
Сообщений: 22
Сказал(а) спасибо: 2
Поблагодарили 23 раз(а) в 8 сообщениях
|
|
24.06.2010, 17:31 | #78 | |
Пользователь
Регистрация: 22.03.2010
Сообщений: 41
Сказал(а) спасибо: 7
Поблагодарили 25 раз(а) в 15 сообщениях
|
Цитата:
проще - имеется в виду проще в реализации, т.е. меньше затраты времени на нее, меньше кода в результате и вообще - меньше напрягов для реализующего. так что в данном случае, это не только другой вариант, но еще и проще |
|
02.07.2010, 12:41 | #79 |
Умный
Регистрация: 02.07.2010
Сообщений: 434
Сказал(а) спасибо: 27
Поблагодарили 73 раз(а) в 45 сообщениях
|
Приветствую,
решил написать свой сниффер, больше из спортивного интереса. В ВоВ играю на офе с 2006 года. По образованию программист, но уже достаточно давно не кодил ничего Долого выбирал каким способом перехватывать трафик, сперва была идея сделать свой TDI фильтр драйвер и перенаправлять весь трафик идущий от приложения wow.exe в пользовательское приложение. Почитав DDK на тему создания TDI фильтров - понял что такой подход это как из пушки по воробьям. Слишком сложно. использовать pcap мне почему-то не понравилось ... И с первого взгляда я не нашел как фильтровать трафик от конкретного приложения. RAW сокеты - неплохой вариант, один минус - слишком много рутинного кода по обработке сырого tcp потока. Хотя если один раз написать и отладить эту часть или воспользоваться какими-нибудь готовыми наработками, то тоже вполне достойный вариант. Однако у меня нет готовых решений, поэтому пропускаем. Так же проблема с определением к какому приложению относится трафик Больше всего понравился вариант предложеный abdula123. По сути это и есть первый вариант с TDI фильтром, только фильтр уже написан и отлажен хорошими людьми . Я использую proxifier (www.proxifier.com) Плюсом такого подхода так же является платформонезависимость, посколько этот проксификатор работает на всех версиях виндовс. К тому же у этого проксификатора есть portable версия, не требующая установки. Настраиваем правило, для приложения wow весь трафик перенаправлять на localhost, наш порт. И все, весь поток данных от wow.exe у нас. SOCKS4 - примитивнешйи протокол, имеющий всего две команды CONNECT и BIND. CONNECT - это запрос на установку соединения с удаленным хостом. BIND - запрос на открытие порта в режиме прослушивания (для принятия соединений) В нашем случае реализация поддержки BIND не требуется, вов ничего не слушает. В общем скачав VisualStudio2010, со скрипом вспоминал програмирование с использованием сокетов. Вчера много тупил, сегодня мой прокси отлично работает. Во всяком случае все приложения с использованием SOCKS4 прокси, и вов через проксифиер - работает без проблем. Если есть желание, могу показать код, всего 290 строк -) Двигаемся дальше, вставляем теперь непосредственно разбор трафика вов. В связи с этим вопрос по поводу получения ключа. Его можно считать на лету ? или только выдергивать из памяти роцесса ? Последний раз редактировалось Йоха; 02.07.2010 в 12:45. |
02.07.2010, 13:32 | #80 |
WowCore Dev
Регистрация: 11.03.2010
Сообщений: 112
Сказал(а) спасибо: 10
Поблагодарили 51 раз(а) в 25 сообщениях
|
|