HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2

ANTICHAT — форум по информационной безопасности, OSINT и технологиям

ANTICHAT — русскоязычное сообщество по безопасности, OSINT и программированию. Форум ранее работал на доменах antichat.ru, antichat.com и antichat.club, и теперь снова доступен на новом адресе — forum.antichat.xyz.
Форум восстановлен и продолжает развитие: доступны архивные темы, добавляются новые обсуждения и материалы.
⚠️ Старые аккаунты восстановить невозможно — необходимо зарегистрироваться заново.
Вернуться   Форум АНТИЧАТ > ИНФО > Статьи
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 09.02.2013, 17:04
BlackIce
Участник форума
Регистрация: 10.01.2013
Сообщений: 100
Провел на форуме:
18665

Репутация: 27
По умолчанию

Интро


Сейчас актуально писать мелкий говнософт для разных социальных сетей. Обычно начинающие быдлокодеры пишут подобное с помощью процедурного подхода и если проект более-менее сложный начинают захлебываться в глобальных переменных и значениях процедур и функций. Я хочу продемонстрировать ООП подход и его приимущества. В статье будет ценен не код программы (скорее он то только для устрашения), а способ мышления при использовании ООП подхода.

Этап 1


ТЗ: Написать дампер сообщений социальной сети ВКонтакте с возможностью дампить переписку как по SID так и по логину/паролю.

Оговорюсь заранее, что при написании софта, я встретил много подводных камней, которые значительно усиливали запутанность программы. Я не стал вдаваться в безупречную реализацию, тк, пишу для демонстрации объектно ориентированного метода, но все-же я пометил комментариями участки кода, требующие доработки.

Что нам понадобится?

1) Язык поддерживающий ООП (Я пишу на Дэльфи)

2) Сниффер сетевого трафика (работать будем в основном с http поэтому httpAnalyzer вполне устроит).

Этап 2


По ООП есть куча разной литературы. Я попробую максимально доступно объяснить всю суть на конкретном примере. Итак, исходя из ТЗ мне нужно создать класс объекта, который смог бы проделывать определенные операции на сайте. Для начала происнифаем сайт и разберемся в алгоритмах запросов. Об этом я вообще писать не буду. По окончании у нас будет алгоритм примерно такой:

1 - Авторизуемся

2 - парсим корешей

3 - парсим месаги

Создаем новый класс объекта . Коротко немного теории : каждый класс что-то знает и что-то умеет делать. То что класс знает называется полями класса (если угодно переменные), а то что он умеет - называется методами класса (если угодно процедуры и функции)... В самомо начале проэктируется внешний вид класса (что знает умеет), а потом реализация (как он умеет). Чтож, давайте попробуем определиться, что необходимо знать и уметь нашему классу...


Знать: авторизационные данные (логин пароль), SID пользователя, количество друзей пользователя, список ID друзей, и он должен взаимодействовать с сетью по протоколу http, поэтому будет разумно запихнуть в него объект типа TidHTTP. Можно продолжать, но в учебных целях притормозим

Уметь: Авторизоваться, Парсить ID друзей, Парсить сообщения.

Также, каждый объект класса будет инициализирован под средством метода конструктора Create () . В нем удобно создавать объекту все условия для комфортной работы (создавать файлы/ соединяться с БД/ задавать настройки по умолчанию других объектов.)

Код:
//---------------Class for work with Vk.com--------- 
type
    TVKDump = Class
                Login, Password : String; // Данные для авторизации
                Link : String;            // Нужная шняга
                SID : String;             // Значение remixsid в кукисах
                HTTP : TidHTTP;           // Для работы с нетом
                FriendList : TStringList; // Список ИДшников друзей
                FriendCount : Integer;    //Количество друзей
                function ParseMessage (FriendID : String) : Boolean;   //Вытаскиваем сообщения со скритов
                function Authorize () : Boolean;                      //Авторизация
                function ParseFriends () : Integer;                   //Парсим ИД корешей
                constructor Create ();                                // Чето создаем и настраиваем
              end;
//-------------------------------------------------
Этап 3


Вот собственно и все! Осталось всего ничего описать реализацию каждой функции . Здесь в подробности я вдаваться не буду, просто выложу свой быдлокод .... Там в основном парсинг и танци с бубном вокруг запросов к ВК.

Код:
//------------function parse messages with a script--------------------------
function TVKDump.ParseMessage (FriendID : String) : Boolean;
  var Data, MsgList : TStringList;
      Name, Mess, tmp : String;
      i, j : Integer;
  begin
    Result := True;
try
 try
    HTTP.AllowCookies := False;
    HTTP.Request.CustomHeaders.Clear;
    HTTP.Request.CustomHeaders.Add('Cookie:remixsid=' + SID);
    MsgList := TStringList.Create;
    Data := TStringList.Create;

      for j := 0 to 5 do
        begin
          Data.Clear;
          Data.Add('act=a_history');
          Data.Add('al=1');
          // offset - параметр смещения сообщений, можно пробовать подставлять
          Data.Add('offset=' + IntTostr(j*50));
          Data.Add('peer=' + FriendID);
          Data.Add('whole=0');

          tmp := HTTP.Post('http://vk.com/al_im.php', Data);
          HTTP.AllowCookies := True;
          Sleep(200);
            for i := 1 to 100 do
              begin
                Delete(tmp, 1, Pos('class="mem_link" target="_blank">', tmp) + 32);
                Name := Copy(tmp, 1, Pos('', tmp) - 1);
                Delete(tmp, 1, Pos('', tmp) + 5);
                Mess := Copy(tmp,1, Pos('', tmp) - 1);
                MsgList.Add(Name + ':' +Mess);
              end;
       end;
       MsgList.SaveToFile(FriendID + '_damp.txt');
 except
  Result := False;
 end;
finally
    MsgList.Free;
    Data.Free;
end;
  end;

//----------------------------------------------------------

//-----------------authorization-----------------------------
function TVKDump.Authorize () : Boolean;    

//---------------parse link necessary to request-------------
function ParseLink ( Page : String) : Boolean;
  begin
    Result := false;
    Delete(page,1,Pos('action=',page)+15);
    link := Copy(page,1,pos('>',page)-2);
      if link <> ''
        then
          begin
            Link := 'http://' + Link;
            Result := true;
          end;
  end;
//--------------------------------------------------------------

var Data:TStringList;
    tmp: String;

  begin
    Result := False;
      try
        try
				  Data := TStringList.Create;
				  Data.Add('email='+Login);
				  Data.Add('pass='+Password);

//-----------  реализация быдлятская, но нет времени делать норм -----------------------
          ParseLink(HTTP.Get('http://m.vk.com/login'));
          HTTP.HandleRedirects := False;
          HTTP.AllowCookies := False;
          try
				    HTTP.Post(Link, Data);
          except
            try
              HTTP.Get(HTTP.Response.Location);
            except
              tmp := HTTP.Response.RawHeaders.Text;
              Delete(tmp, 1, Pos('remixsid=',tmp) + 8);
              SID :=Copy( tmp,1 ,Pos('expires=',tmp)-3);
            end;

          end;
//--------------------------------------------------------------------------------------
          HTTP.HandleRedirects := True;
          HTTP.AllowCookies := True;
          tmp := HTTP.Get(HTTP.Response.Location);

          
				    if Pos('logout',tmp) <> 0
					    then Result := True;
			except
				Result := False;
			end;
			finally
				Data.Free;
			end;

		end;

//-------------parsing function friends ID's -----------------------
// парсит вроде первых 20 чтобы парсило всех нужно допиливать

function TVKDump.ParseFriends () : Integer;
var tmp: String;
    i:integer;
  begin
    HTTP.AllowCookies := False;
    HTTP.Request.CustomHeaders.Add('Cookie:remixsid=' + SID);
    tmp := HTTP.Get('http://m.vk.com/friends');
    HTTP.AllowCookies := True;
    Delete(tmp,1,Pos(' ',tmp)+4);
    FriendCount :=StrToInt(Copy(tmp,1,Pos('',tmp)-1));
      for i:=1 to 18  do

        begin
          Delete(tmp,1,Pos('',tmp)-1));
        end;
    FriendList.SaveToFile('friends.txt');
  end;
//-----------------------------------------------------------

//-------------- Созаём нужные объекты и настраиваем HTTP ----------------
constructor TVKDump.Create ();

  begin
    FriendList := TStringList.Create;
    HTTP := TIdHTTP.Create(nil);
    HTTP.HandleRedirects := True;
      with HTTP.Request do
        begin
          UserAgent := 'Mozilla/5.0 (Windows NT 5.1; rv:16.0) Gecko/20100101 Firefox/16.0';
          ContentType := 'application/x-www-form-urlencoded';
          AcceptLanguage := 'ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3';
        end;

  end;
Этап 4


На 4 этапе необходимо создать объект нашего класса. Для этого его нужно инициализировать методом Create (). Также описывается поведение объекта и взаимодействие с другими компонентами программы. Дабы немного поизвращаться я не стал делать GUI. Программа получает необходимые данные ввиде параметров командной строки, а результаты пишет в файлы.

Код:
Var
      VK : TVKDump;
      i : Integer;
begin
  VK := TVKDump.Create ();

//-----------если без запущена параметров, тогда выходим -----------------
   if ((Paramstr(1) = '') and (Paramstr(2) = '')) then
    begin
      Exit;
    end;

//----------возможность указать SID---------------------------------------
 if ((Paramstr(1) = '0')  and (Paramstr(2)  = '0'))
  then
    begin
      VK.SID := Paramstr(3);
        VK.ParseFriends();
          for i := 1 to 3 do  // можно ставить VK.FriendsCount но нужно допилить функцию парсинга друзей
            VK.ParseMessage(VK.FriendList[i]);
    end

   else  //-----------иначе указываем логин и пароль------------------------

    begin
      VK.Login := Paramstr(1);
      VK.Password := Paramstr(2);
      VK.Authorize;
      VK.ParseFriends();
        for i := 1 to 5 do   // можно ставить VK.FriendsCount но нужно допилить функцию парсинга друзей
          VK.ParseMessage(VK.FriendList[i]);
    end;

end.
Чтобы автоизоваться с помощью логина и пароля нужно в консольке набрать

Цитата:
Сообщение от None  
D:\Delphi Projects\7\vkdumper\VKDump>VK_Dumper.exe pass login
А если по SID:

Цитата:
Сообщение от None  
D:\Delphi Projects\7\vkdumper\VKDump>VK_Dumper.exe 0 0 6dbed7eb6eb7e7d7bd6be76bd 76be76e6db7e6b7e67eb7b
Оутро


Моя программа является еще сырым приложением и используется в качестве наглядности, но если есть необходимость и руки = тру, то и интерфейс можно прикрутить и потоки и функции поправить...

Подобным образом создаются проекты побольше со сложной структурой. Мир ООП очень богат и при разумном использовании очень помогает упростить жизнь разработчику как професионального уровня так и мелкому фрилансеру. Надеюсь кому-то пригодиться. Спасибо за внимание. BlackIce.

Привожу код всего приложения:

Код:
program VK_Dumper;
Uses
IdHttp,IdCookieManager,Dialogs, IdHTTPHeaderInfo, Classes, SysUtils;

//---------------Class for work with Vk.com---------
type
    TVKDump = Class
                Login, Password : String; // Данные для авторизации
                Link : String;            // Нужная шняга
                SID : String;             // Значение remixsid в кукисах
                HTTP : TidHTTP;           // Для работы с нетом
                FriendList : TStringList; // Список ИДшников друзей
                FriendCount : Integer;    //Количество друзей
                function ParseMessage (FriendID : String) : Boolean;   //Вытаскиваем сообщения со скритов
                function Authorize () : Boolean;                      //Авторизация
                function ParseFriends () : Integer;                   //Парсим ИД корешей
                constructor Create ();                                // Чето создаем и настраиваем
              end;
//-------------------------------------------------

//------------function parse messages with a script--------------------------
function TVKDump.ParseMessage (FriendID : String) : Boolean;
  var Data, MsgList : TStringList;
      Name, Mess, tmp : String;
      i, j : Integer;
  begin
    Result := True;
try
 try
    HTTP.AllowCookies := False;
    HTTP.Request.CustomHeaders.Clear;
    HTTP.Request.CustomHeaders.Add('Cookie:remixsid=' + SID);
    MsgList := TStringList.Create;
    Data := TStringList.Create;

      for j := 0 to 5 do
        begin
          Data.Clear;
          Data.Add('act=a_history');
          Data.Add('al=1');
          // offset - параметр смещения сообщений, можно пробовать подставлять
          Data.Add('offset=' + IntTostr(j*50));
          Data.Add('peer=' + FriendID);
          Data.Add('whole=0');

          tmp := HTTP.Post('http://vk.com/al_im.php', Data);
          HTTP.AllowCookies := True;
          Sleep(200);
            for i := 1 to 100 do
              begin
                Delete(tmp, 1, Pos('class="mem_link" target="_blank">', tmp) + 32);
                Name := Copy(tmp, 1, Pos('', tmp) - 1);
                Delete(tmp, 1, Pos('', tmp) + 5);
                Mess := Copy(tmp,1, Pos('', tmp) - 1);
                MsgList.Add(Name + ':' +Mess);
              end;
       end;
       MsgList.SaveToFile(FriendID + '_damp.txt');
 except
  Result := False;
 end;
finally
    MsgList.Free;
    Data.Free;
end;
  end;

//----------------------------------------------------------

//-----------------authorization-----------------------------
function TVKDump.Authorize () : Boolean;    

//---------------parse link necessary to request-------------
function ParseLink ( Page : String) : Boolean;
  begin
    Result := false;
    Delete(page,1,Pos('action=',page)+15);
    link := Copy(page,1,pos('>',page)-2);
      if link <> ''
        then
          begin
            Link := 'http://' + Link;
            Result := true;
          end;
  end;
//--------------------------------------------------------------

var Data:TStringList;
    tmp: String;

  begin
    Result := False;
      try
        try
				  Data := TStringList.Create;
				  Data.Add('email='+Login);
				  Data.Add('pass='+Password);

//-----------  реализация быдлятская, но нет времени делать норм -----------------------
          ParseLink(HTTP.Get('http://m.vk.com/login'));
          HTTP.HandleRedirects := False;
          HTTP.AllowCookies := False;
          try
				    HTTP.Post(Link, Data);
          except
            try
              HTTP.Get(HTTP.Response.Location);
            except
              tmp := HTTP.Response.RawHeaders.Text;
              Delete(tmp, 1, Pos('remixsid=',tmp) + 8);
              SID :=Copy( tmp,1 ,Pos('expires=',tmp)-3);
            end;

          end;
//--------------------------------------------------------------------------------------
          HTTP.HandleRedirects := True;
          HTTP.AllowCookies := True;
          tmp := HTTP.Get(HTTP.Response.Location);

          
				    if Pos('logout',tmp) <> 0
					    then Result := True;
			except
				Result := False;
			end;
			finally
				Data.Free;
			end;

		end;

//-------------parsing function friends ID's -----------------------
// парсит вроде первых 20 чтобы парсило всех нужно допиливать

function TVKDump.ParseFriends () : Integer;
var tmp: String;
    i:integer;
  begin
    HTTP.AllowCookies := False;
    HTTP.Request.CustomHeaders.Add('Cookie:remixsid=' + SID);
    tmp := HTTP.Get('http://m.vk.com/friends');
    HTTP.AllowCookies := True;
    Delete(tmp,1,Pos(' ',tmp)+4);
    FriendCount :=StrToInt(Copy(tmp,1,Pos('',tmp)-1));
      for i:=1 to 18  do

        begin
          Delete(tmp,1,Pos('',tmp)-1));
        end;
    FriendList.SaveToFile('friends.txt');
  end;
//-----------------------------------------------------------

//-------------- Созаём нужные объекты и настраиваем HTTP ----------------
constructor TVKDump.Create ();

  begin
    FriendList := TStringList.Create;
    HTTP := TIdHTTP.Create(nil);
    HTTP.HandleRedirects := True;
      with HTTP.Request do
        begin
          UserAgent := 'Mozilla/5.0 (Windows NT 5.1; rv:16.0) Gecko/20100101 Firefox/16.0';
          ContentType := 'application/x-www-form-urlencoded';
          AcceptLanguage := 'ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3';
        end;

  end;

 Var
      VK : TVKDump;
      i : Integer;
begin
  VK := TVKDump.Create ();

//-----------если без запущена параметров, тогда выходим -----------------
   if ((Paramstr(1) = '') and (Paramstr(2) = '')) then
    begin
      Exit;
    end;

//----------возможность указать SID---------------------------------------
 if ((Paramstr(1) = '0')  and (Paramstr(2)  = '0'))
  then
    begin
      VK.SID := Paramstr(3);
        VK.ParseFriends();
          for i := 1 to 3 do  // можно ставить VK.FriendsCount но нужно допилить функцию парсинга друзей
            VK.ParseMessage(VK.FriendList[i]);
    end

   else  //-----------иначе указываем логин и пароль------------------------

    begin
      VK.Login := Paramstr(1);
      VK.Password := Paramstr(2);
      VK.Authorize;
      VK.ParseFriends();
        for i := 1 to 5 do   // можно ставить VK.FriendsCount но нужно допилить функцию парсинга друзей
          VK.ParseMessage(VK.FriendList[i]);
    end;

end.
 
Ответить с цитированием

  #2  
Старый 09.02.2013, 19:43
Kaimi
Познавший АНТИЧАТ
Регистрация: 23.08.2007
Сообщений: 1,237
Провел на форуме:
18127311

Репутация: 1676


По умолчанию

Цитата:
Сообщение от None  
пишут подобное с помощью процедурного подхода и если проект более-менее сложный начинают захлебываться в глобальных переменных и значениях процедур и функций
Цитата:
Сообщение от None  
способ мышления при использовании ООП подхода.
Цитата:
Сообщение от None  
Login, Password : String; // Данные для авторизации
Link : String; // Нужная шняга
SID : String; // Значение remixsid в кукисах
HTTP : TidHTTP; // Для работы с нетом
FriendList : TStringList; // Список ИДшников друзей
FriendCount : Integer; //Количество друзей
function ParseMessage (FriendID : String) : Boolean; //Вытаскиваем сообщения со скритов
function Authorize () : Boolean; //Авторизация
function ParseFriends () : Integer; //Парсим ИД корешей
constructor Create (); // Чето создаем и настраиваем
Т.е. берем класс, фигачим в нем всё то же разрозненное нечто, что в теории существовало бы в виде отдельных процедур и пары глобальных переменных и называем это ООП подходом, который обладает "приимуществами" в виде упрощенной поддержки ?
 
Ответить с цитированием

  #3  
Старый 09.02.2013, 20:28
DooD
Познавший АНТИЧАТ
Регистрация: 30.09.2010
Сообщений: 1,168
Провел на форуме:
257934

Репутация: 288


По умолчанию

Цитата:
Сообщение от Kaimi  
Т.е. берем класс, фигачим в нем всё то же разрозненное нечто, что в теории существовало бы в виде отдельных процедур и пары глобальных переменных и называем это ООП подходом, который обладает "приимуществами" в виде упрощенной поддержки ?
конечно это лишь просто пример работы с классами,и тут можно было бы спокойно обойтись процедурами(мне и самому ближе процедурно-функциональное программирование,ну не люблю я классы ёкрмн,писать по меньшей мере,юзать готовые-да ).Вот банальный пример, когда лучше применить класс:http://mrkto.com/oop_php_class_function/

а так ТС молодец,и идея прикольна
 
Ответить с цитированием

  #4  
Старый 09.02.2013, 20:41
B1t.exe
Постоянный
Регистрация: 06.11.2006
Сообщений: 865
Провел на форуме:
1977708

Репутация: 208


По умолчанию

Кстати, давно искал такой софт )) чтоб дампить переписку из акков, и в офф-лайне спокойно читать/разобрать.

Можете дать рабочую прогу?
 
Ответить с цитированием

  #5  
Старый 09.02.2013, 20:48
Spot
Новичок
Регистрация: 01.03.2007
Сообщений: 2
Провел на форуме:
3478

Репутация: 0
По умолчанию

Поправте меня, но на статью и близко не тянет. Что бы представить модель ООП не хватит написать только один класс-обертку. Суть ООП всё таки это взаимодействие между различными обьектами, а не работа с одним единственным классом-обьектом.

Как пример обьекта - годится, но не как представление модели ООП.
 
Ответить с цитированием

  #6  
Старый 09.02.2013, 21:07
BlackIce
Участник форума
Регистрация: 10.01.2013
Сообщений: 100
Провел на форуме:
18665

Репутация: 27
По умолчанию

2 Kaimi, DX вы же делфи не знаете?

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

Линк на файл : http://www.sendspace.com/file/dykm4i
 
Ответить с цитированием

  #7  
Старый 10.02.2013, 01:26
Unknown
Новичок
Регистрация: 21.06.2005
Сообщений: 1
Провел на форуме:
0

Репутация: 0
По умолчанию

В статье хорошо продемонстрирован антипаттерн "God object". Слишком много функционала возложено на один объект. Не обязательно знать делфи, чтобы не заметить такой ошибки.

Главная задача ООП - закрывать для изменения существующий и отлаженный код, и предоставить возможность добавлять к нему новую функциональность. За счет этого обеспечивается повторное использование.

В данном случае нет смысла в классе TVKDump; с тем же успехом можно было бы сделать все это модулем (delphi unit), а поля - просто переменными этого модуля.

Получение страницы с веб-сервера vk.com - в принципе задача для отдельного класса. Ведь можно грузить страницы как напрямую, так и через прокси или цепочки прокси. Если все это запихнуть в один класс, никакой выгоды от ООП не будет, т.к. такой код сложнее выдрать для использования где-либо еще. Страница может загружаться не полностью, а частями (для уменьшения трафика) + списки друзей и прочее могут быть реализованы на сайте постранично (следовательно для каждой страницы требуется отдельный запрос).

Аутентификацию тоже следует вынести в отдельный класс, зависящий от соединения с vk (а не просто от сферического TidHTTP, поскольку это внешняя зависимость). Предположим, что вконтакте спалил наш "многопоточный сканер" и решил показать каптчу, на абсолютно произвольном запросе. Теперь придется в код класса внедрять еще и каптчу. Это значит, что надо интегрировать все это дело с antigate и как альтернативу предоставить возможность вбивать их вручную.

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

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

P.S. Для программы уровня "написал и забыл" данный код хорошо годится, главное, чтобы работало. А поддерживать такое не пожелаю никому
 
Ответить с цитированием

  #8  
Старый 10.02.2013, 03:51
Chrome~
Постоянный
Регистрация: 13.12.2008
Сообщений: 354
Провел на форуме:
1747641

Репутация: 175
По умолчанию

Цитата:
Сообщение от BlackIce  
2 Kaimi, DX вы же делфи не знаете?
То есть ты хочешь сказать, что знаешь Delphi? Или даже ООП?

ТС, прочитай про атрибуты видимости методов, переменных, про свойства. Так как ты написал пишут только начинающие быдлокодеры. Ко всему этому ты еще создаешь объекты в конструкторе, но нигде их не освобождаешь. Зачем писать статью с такими ошибками? Чтобы сделать свой членский взнос в литературу для быдлокодеров?
 
Ответить с цитированием
Ответ





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.