DevDoc - статьи для разработчика ПО под Windows Невидимый софт
Доброго времени суток. Ресурс www.devdoc.ru
потихоньку развивается, и начали появляться статьи других авторов. Ниже будет
рассказано, как сделать программу-невидимку. А сейчас хочу сделать несколько
объявлений. Во-первых, статья о виртуальных списках, которую я обещал уже готова
и будет доступна для просмотра через пару дней. Во-вторых, от читателей получено
несколько конструктивных замечаний по отладке приложений. Мне приятно видеть,
что моя работа приносит пользу. Все пожелания будут учтены.
Автор: Абанов
Георгий
Последняя модификация: 2007-02-02 17:06:08
Статья опубликована с разрешения автора. Оригинал здесь.
Невидимый софт
В последнее время интерес к программам-невидимкам снова возрос. В первую очередь
это связано с появлением у рядовых пользователей WinXP. Эта ОСь, как известно,
обладает всеми защитными особенностями линейки NT. И поэтому левые процессы
стало “немножко” сложнее прятать от пользователя. Но и появление новых методов
сокрытия присутствия существенно прибавилось ;). В данной статья я расскажу
о новом способе “невидимости” (причём этот способ хорошо работает как в 9x,
так и в XP). Суть его заключается в следующем: мы берём какую-либо программу,
которая есть у более чем 90% пользователей и немножко изменяем её. (Из представленного
ниже каркаса можно сделать всё что угодно!) Плюсы этого метода очевидны – раз
заражённой нами прогой пользуются почти (а лучше без “почти”) все, то на неё
никто ничего плохого не подумает, к тому же наш кусок кода НИГДЕ НЕ БУДЕТ ВИДЕН.
Это актуально особенно для XP, так как в ней куча недокументированных функций
(в том числе и для работы с процессами) и NtQuerySystemInformation не самая
“опасная” для нас в данной ОСи. Так что осталось только выбрать прогу приступить
:).
Мой выбор пал на Explorer :). Он есть почти у всех счастливых обладателей виндовОза.
Какую его часть мы будем мучить? Ну, например, посмотрим в левый нижний угол
:). Да, именно часы станут нашей жертвой.
Для начала немного теории. Наша программка будет состоять из 3-х файлов. (Exe
– 1 штука, DLL – 2 штука :)). Нашей задачей будет какая-либо вставка кода в
“механизм часов”. Лучшее для этого дела место это оконная процедура окна класса
TrayClockWClass. После выбора жертвы всё становиться просто. Получается так:
Exe будет всё это запускать, одна из ДЛЛок будет содержать хук и проникать в
процесс Explorer’а, другая же – будет содержать его новую оконную процедуру.
Для проникновения мы воспользуемся SetWindowsHookEx с параметром WH_GETMESSAGE…
Но сначала посмотрим на экзэшник. Его целью будет загрузка ДЛЛки с хуком, затем
мы подождём немного (sleep(1000)), и пошлём часам мессагу, чтобы попасть в их
процесс.
uses
windows,messages,shellapi;
{$R *.res}var h:integer;
FI:NOTIFYICONDATA;
i:integer;
procedure RunStopHook(b:boolean);stdcall;external 'hdll.dll'; // проца в нашей DLL’ке с хуком. begin
RunStopHook(true);
h := FindWindowEx(0, 0, 'Shell_TrayWnd', nil);
h := FindWindowEx(h, 0, 'TrayNotifyWnd', nil);
h := FindWindowEx(h, 0, 'TrayClockWClass', nil);
sleep(1000); // что бы наша Dll’ка успела загрузиться.
postmessage(h,wm_paint,0,0);
zeromemory(@FI,sizeof(FI));
FI.cbSize:=sizeof(FI);
FI.szTip:='Hello temp';
FI.uFlags:=NIF_TIP;
FI.Wnd:=GetDeskTopWindow;
Shell_NotifyIcon(NIM_ADD,@FI); // у часов мы в дальнейшем поменяем отрисовку (для наглядности) //Shell_NotifyIcon(NIM_DELETE,@FI);end.
Так-с. Теперь подумаем о реализации ДЛЛки с хуком. Процедура перехвата должна
сверять хэндл часов с хэндлом перехватываемого message’а. Если они равны, то
ДЛЛка в процессе Explorer’а. И тут мы уже можем менять процедуру окна часов.
Но всё по порядку :).
library hdll;
library hdll;
uses
SysUtils,
Classes,
windows,
messages;
{$R *.res}var syshook:hhook; // переменная для хука // процедура из 2-ой ДЛЛки, которая заменит оконную процедуру часов. procedure GetAndSet(h:integer);stdcall; external 'gas.dll';
function CallWndProc(
nCode:integer ; // hook code
wParam: WPARAM ; // current-process flag
lParam: LPARAM // address of structure with message data):LRESULT;stdcall;
var h:integer;
// переменная влияющая на снятие хука. (т.е. показывающая, что оконная процедура часов изменена)
ok:boolean;
begin
ok:=false;
H := FindWindowEx(0, 0, 'Shell_TrayWnd', nil);
H := FindWindowEx(H, 0, 'TrayNotifyWnd', nil); // все пэрэнты часов можно узнать с помощью Spy++ //(а любителей кодинга отсылаю к MSDN GetParent & WindowFromPoint)if tmsg(pointer(lparam)^).hwnd=H thenbegin
h := FindWindowEx(H, 0, 'TrayClockWClass', nil); // получаем хэндл часов
loadlibrary('gas.dll'); // загружаем 2-ую ДЛЛку (чтобы она висела в процессе Explorer’а)
GetAndSet(h); // меняем ему процедуру
Invalidaterect(h,nil,false); //sendmessage(h,wm_paint,0,0);
ok:=true;
end;
result:=CallNextHookex(syshook,ncode,wparam,lparam);
if ok then UnHookWindowsHookEx(syshook); // отключаем хукend;
procedure RunStopHook(b:boolean);export;stdcall;
beginif b then SyShook:=Setwindowshookex(WH_GETMESSAGE,@callWndProc,Hinstance,0)else unhookwindowshookex(syshook); if(syshook=cardinal(-1))or(syshook=cardinal(0))then messagebox(0,'Suxx','',mb_ok);
end;
exports RunStopHook;
beginend.
Теперь самое интересное – оконная процедура часов. Её можно модифицировать
для чего угодно: это может быть и героический житель трои, и клавиатурный шпион,
и просто фенка (её, то, я и покажу) . При замене оконной процедуры мы создадим
шрифт и им будем выводить время ежесекундно. Так же мы не должны забывать и
о старой оконной процедуре, ведь она тоже выполняет не мало функций! (например
вызов окна по двойному щелчку на часах и popup по правой кнопке…)
library gas;
library gas;
uses
SysUtils,
Classes,windows,messages,shellapi;
{$R *.res}var SavedProc:pointer;
f:integer;
procedure MyDraw(h:hwnd); // процедура “канвасинья”var s:array[0..20]ofchar;
time:_systemtime;
begin
s:='hh'':''mm'':''ss'; // маска времени
SetTextColor(h,$ff0100); // установка цвета текста
selectObject(h,f);
GetLocalTime(time);
// форматируем строку со временем
GetTimeFormat(LOCALE_USER_DEFAULT,TIME_FORCE24HOURFORMAT,@time,s,s,21);
TextOut(h,0,0,@s[0],8); // Выводим строку end;function WinProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var http:integer;
pp:PAINTSTRUCT;
begincase msg of
WM_PAINT:begin// перехват и обработка
http:=beginPaint(hwnd, pp);
MyDraw(http);
endpaint(hwnd,pp);
result:=0;
end;
wm_timer:
begin
http:=getdc(hwnd);
MyDraw(http);
releasedc(hwnd,http);
result:=0;
end;
// эта фишка оконной процедуры часов. При этом message’е винда ожидает получить ответ о размере часов.
WM_USER+100:result:=195 +(20shl16);
else// если мессага не наша, то пусть её обработает старый обработчик
result:=CallWindowProc(SavedProc,hwnd,msg,wparam,lparam);
end;
end;
procedure GetAndSet(h:integer);stdcall; var p,p2:Trect;
hand,h2:integer;
begin// эта фишка, служет для того чтобы не наделать лишних проц. :]ifpointer(getwindowlong(h,GWL_WNDPROC))<>@winProc thenbegin
SavedProc:=pointer(SetWindowLong(h,GWL_WNDPROC,cardinal(@Winproc)));
SetTimer(h,0,1000,nil); // создаём таймер
f:=CreateFont(20,25,0,0,FW_THIN,1,1,0,RUSSIAN_CHARSET,OUT_CHARACTER_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY ,FF_MODERN ,nil); // Создаём шрифтend;
end;
exports GetAndSet;
beginend.
Приведённую выше процедуру отрисовки хорошо бы использовать для работы с асинхронными
сокетами :). На этом пока всё. (to be continued…)
Copyright
(C) Kudinov Alexander, 2006-2007
Перепечатка материалов с данного сайта запрещена без писменного
разрешения автора. При перепечатке обязательно указывать ссылку на оригинал.