Работа с антикапчей на ассемблере

По просьбам некоторых людей, да и просто для себя, решил написать функции для работы с антикапчей (anti-captcha.com) на ассемблере.
Если кто не знает, anti-captcha – это сервис, позволяющий распознавать капчи за небольшую плату (1$ за 1000 штук). Качество распознавания, как правило, 90%, время ожидания обычно не превышает 20 секунд.
Функции для работы с сервисом сразу решил проектировать таким образом, чтобы они могли нормально без конфликтов работать во много потоков одновременно.
Для этого необходимо использовать локальные переменные для чтения и записи, а глобальные переменные (из секции данных) можно только читать, но не изменять.
Кроме того, при работе с общими переменными или ресурсами необходимо применять какой-нибудь механизм, помогающий избегать конфликтов. Я использовал мьютексы (что это такое, объясню дальше).
Программу для тестирования я сделал таким образом – можно открыть несколько файлов (от 1 до 40) с картинками и одновременно послать их на распознавание (по одной картинке на поток).
Получилось следующее:

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

Итак, начнем писать программу:

Теперь рассмотрим следующий код, в котором создаются мьютексы. Что же такое мьютекс? Представим, что у нас есть программа, в которой работает два потока одновременно.
Пусть 1й поток считал переменную, увеличил ее на единицу и хочет записать ее новое значение. В это время второй поток тоже считал переменную, до того, как 1й успел ее записать, и тоже увеличил ее значение на 1.
Тогда после того, как 1й и 2й поток запишут изменения, учтено будет только одно.
Можно взглянуть на такой псевдокод:

1: read A
1: A+1
2: read A //тут еще старое значение A!
2: A+1
1: write A //стало A+1
2: write A //стало A+1, а не A+2, как должно было быть!

С помощью мьютекса можно избежать такого конфликта. Можно заблокировать переменную A и освободить ее только после того, как первый поток закончит с ней работать:

block A <-теперь A доступна только первому потоку 1: read A 1: A+1 1: write A //стало A+1 unblock A <-теперь A доступна всем, и она уже инкрементирована на 1 2: read A //тут уже новое значение A 2: A+1 2: write A //стало A+2, как и должно было быть.

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

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

Далее идет основная часть - обработка нажатия кнопок:

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

Теперь я опищу процедуру GetCaptchaError - эта процедура по номеру ошибки, возвращенному процедурами распознавания капчи, выдаст текст ошибки.

Теперь - описание процедуры вывода нового сообщения в лог. Здесь тоже используется мьютекс, так как поле - общее.

Еще одна вспомогательная процедура - процедура для объединения любого количества строк в одну:

Наконец, осталось разобрать самые важные процедуры - те, которые я написал для работы с сервисом антикапчи.
Начнем с процедуры, которая осуществляет закачку картинки на сервер и получает ID закачанной картинки.
В случае ошибки будет возвращен код ошибки в ebx, а если все нормально, то ebx будет равен 0.

Картинку с капчей на сервер отправили, ID её получили, теперь остается только делать регулярные запросы на сервер в ожидании ответа.
Для этого я написал процедуру AntiCaptchaAnswer.

Ну и наконец последнее - процедура инициализации для работы с антикапчей. Её нужно вызывать всего один раз после инициализации сокетов.
Она вернет в eax 0 в случае успеха или 2 в случае ошибки.

Всё. Программа написана, можно ее скомпилировать и использовать. Как можно компилировать программы в MASM32, описано в предыдущих статьях.
Напоследок приведу лог теста программы - я открывал 5 капч и одновременно их распознавал. Программа выдала следующее:

Начинаем...
THR4: Got ID: 2117276
THR4: Распознавание...
THR3: Got ID: 2117279
THR3: Распознавание...
THR5: Got ID: 2117280
THR5: Распознавание...
THR2: Got ID: 2117283
THR2: Распознавание...
THR1: Got ID: 2117277
THR1: Распознавание...
THR4: Капча пока не готова
THR3: Капча пока не готова
THR5: Капча пока не готова
THR2: Капча пока не готова
THR1: Капча пока не готова
THR4: Готово: 8031
THR3: Капча пока не готова
THR5: Капча пока не готова
THR2: Готово: qwsdv
THR1: Капча пока не готова
THR3: Готово: dqgs5
THR5: Готово: 770857
THR1: Готово: 905955

THR и номер - это номер потока, который выводит сообщение в лог.

Теперь создадим dll - библиотеку с функциями для работы с антикапчей. В исходном коде библиотеки поместим три процедуры - AntiCaptcha, AntiCaptchaInit и AntiCaptchaAnswer. Кроме того, создадим функцию инициализации dll:

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

В основной программе, чтобы использовать эту dll, определим переменные для хранения адресов загруженной dll и функций в ней:

Потом загрузим библиотеку и получим адреса функций в длл сразу после запуска программы:

В остальном программа не изменилась, кроме того, что при выходе необходимо освободить библиотеку:

В саму dll добавил на всякий случай еще две вспомогательные функции - SocketInit и SocketCleanup - это просто переходники к WinApi-функциям WSAStartup и WSACleanup.

Описание функций, экспортируемых dll:
AntiCaptchaInit - вызывается для инициализации работы с антикапчей, ей не надо передавать параметры, вернет 0 в случае успеха.

AntiCaptcha - вызывается для отправки изображения на сервер. Вернет 0 в случае успеха или код ошибки.
Параметры:

AntiCaptcha PROC,
[указатель на память, куда записывать ID капчи - буфер не менее 30 байт,
туда будет записана строка],
[указатель на строку с ключом антикапчи],
[1 или 0 - состоит ли капча из нескольких слов],
[1 или 0 - регистрозависима ли капча],
[1 или 0 - состоит ли капча только из цифр],
[минимальная длина капчи],
[максимальная длина капчи],
[указатель на строку с расширением, например, "jpg"],
[указатель на строку с типом, например "image/jpeg"],
[размер картинки в байтах],
[указатель на память, где загружена картинка]

Все параметры - DWORD.

AntiCaptchaAnswer - вызывается для получения распознанного варианта или статуса распознавания. Вернет 0 в случае успеха или код ошибки.
Параметры:

AntiCaptchaAnswer PROC,
[указатель на память, куда записать ответ],
[указатель на память с ID капчи, полученный с помощью предыдущей функции],
[указатель на строку с ключом антикапчи]

Все параметры - DWORD.

Коды возвращаемых ошибок:

1 - ошибка при создании сокета
2 - ошибка при подключении
4 - ошибка при создании запроса
5 - ошибка при отправке данных
6 - ошибка при получении данных
7 - слишком большой ответ сервера
10 - капча пока не распознана
11 - неверный ключ
12 - все работники пока заняты
13 - нулевой баланс на аккаунте
14 - несуществующий ID капчи
20 - неопределенная ошибка

Пример прототипа функции AntiCaptcha для c++:

Скачать исходники программы, саму программу в собранном виде, а также ее версию с dll можно тут: ZIP

Работа с антикапчей на ассемблере: 2 комментария

  1. хочу спросить программа работает по распознования капча ? или как её настроить ? добавляйся в скайп мой ник usausa629 есть пару вопросиков по программе . Спасибо

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *