Интересный опыт. Человек на сайт создавал контент с помощью ИИ (chatGPT 4.0). Всего за 5 месяцев сайт получил следующие результаты:
- 1,12 млн SEO-трафика (поисковый, органика)
- 33 тыс. конверсий
По этой ссылке (https://www.reddit.com/r/pSEOnewsletter/comments/19aa766/how...) детали на английском. Получается, что Google вполне себе "переваривает" такие материалы. В общем стоит задуматься... А мы, например, платим за переводы и публикации 20 000 руб. в месяц. Может стоит создавать автоматически? :) Сразу возникает желание начать делать некий сервис, ведь если платим мы, значит платят и другие. За 20 000 р. мы получаем 20 статей. И я готов платить 20 000 р. за 2000 статей, созданных с помощью ИИ :)
Если потратите время и почитаете опыт автора, то удивитесь скорости роста трафика:
↳ 1 месяц, чтобы достичь трафика 6K в месяц
↳ 2 месяца, чтобы получить 17 тыс. трафика в месяц
↳ 3 месяца, чтобы получить 40 тыс. трафика в месяц
↳ 4 месяца, чтобы получить 120 тыс. трафика в месяц
↳ 5 месяцев, чтобы получить 222 тыс. трафика в месяц
В итоге он получил ~5000 клиентов (если не хитрит, хотя пишет довольно детально).
Напомню, два месяца назад мы заловились с товарищем @Stich.626 чтобы сделать единообразное + бесплатное мобильное приложение и сайт для расчета ценников в магазинах, которое решили не бросать, любить и лелеять, насколько это возможно.
В этом посте пойдет речь про обновление мобильной программы, и технические аспекты ее написания (все таки сообщество для разработчиков). Поехали!
Недооцененный баннер в Goggle Play
0 - Че там по отзывам
Перед выпуском обновления мы разумеется лезем в обе консоли разработчиков (приложение есть как в Google Play, так и в RuStore), и занимаемся вычитыванием того, что вы там понарасказывали в них, и какие хотелки запрашиваете.
Лично я придерживаюсь мнения, что разработчик (сайта, приложения, не важно) уже сам должен хорошо понимать, чего в приложении хватает (или не хватает), и на основе отзывов должна формироваться картина того, что должно ускорятся, или что добавлять в ту или иную итерацию.
А для всего остального есть MasterCard система тестирования и многочисленные метрики.
Так вот, среди отзывов уже давно проскакивали запросы на добавление списка с историей, сохранение результатов, сравнение нескольких выбранных показателей, и смена валют.
Сегодня вопросом списка с историей мы и займемся.
1 - Нарисуй меня полностью!
Первичный вход в приложение
Перед тем, как что-то наговнокодить написать, нам нужно сформировать в файлах макетов новые сущности для функционирования списка. В нашей основной деятельности появляется один новый блок, основанный на MaterialCardView из библиотеки поддержки M3, который содержит в себе:
Заглушку на основе RelativeLayout, которая показывается, когда еще не было произведено ни одного расчёта;
Сам список ListView, который находится внутри карточки, но невидим до тех пор, пока мы не начнем что либо считать.
Вариация макета при наличии расчетов
Визуально выглядит неплохо, но еще есть над чем поработать.
Дело в том, что ListView (древнейший из компонентов андроида, кста) в своем базовом варианте очень плохо выглядит. Настолько плохо, что если использовать его "как есть", то потом можно выхватить от пользователей лучи поноса:
Чтобы не повторять мем из картинки выше, мы создаем новый файл макета, в котором сверстаем 1 единственный пункт меню, который в дальнейшем будет повторятся, и добавляться к списку каждый раз при его заполнении данными.
Этот же файл, кстати, мы потом переопределим в адаптере, когда доберемся до кода.
В нашем случае получилась довольно простая адаптация, в которой:
Был добавлен корневой LinearLayout, позиционирующий дочерние элементы по горизонтали, с суммарным весом 9
Внутренние (дочерние) блоки, два из которых тоже на основе LinearLayout (но уже вертикально ориентированные), и еще один TextView, который нуждается только в центрировании
И уже внутри наши текстовые переменные, которым мы назначаем айдишки, и будем использовать в коде.
Но перед этим пойдем посмотрим, как это выглядит без учета логики на эмуляторе:
2 - Пишем внутренности
На виртуальном телефоне неожиданностей не произошло, отображается все так как хотелось, поэтому двигаемся в кодильню файл основной активности:
Перво - наперво, нам нужно уяснить несколько логических моментов:
При открытии приложения список уже есть, и поэтому он создается в onCreate. Но он пустой, так как мы еще не наполняли его данными.
Список уже знает, какими данными он будет наполняться (проставлены id и назначен наш кастомный слой), поэтому для него также создан адаптер, базирующийся на SimpleAdapter, который берет данные из HashMap. Он очень удобен (лично для меня), т.к. его можно в дальнейшем наполнять чем угодно: картинками, другими слоями, чекбоксами, и т.д.
Пока пользователь (ты) не начал ничего вводить, смысла показывать его тоже нет, поэтому мы изначально установили заданную видимость заглушки и списка в макете (не в коде). Заглушку видно, список нет.
Из хорошего, когда мы писали приложение в первый раз, то определили подсчет результата через switch - приложение знает, какой показатель мы считаем, поэтому нам просто нужно дать адаптеру сведения из того или иного метода расчёта.
Для этого мы добавляем две строчки кода для каждого из режимов. В первой добавляем данные, а второй говорим приложению, что список обновился (и тебе по-хорошему надо перерисовать список).
Например, для расчета по килограммам это будет выглядеть так:
Проверяем на телефоне, и неожиданностей опять нет - расчет прошел по тому показателю, который мы запрашивали.
3. Доделываем
Всего то 48 предупреждений.
Нам остается пройтись по инспектору, чтобы приложение выглядело не как гавно в глазах IDE более менее сносным (студия сама может проверить, что нужно улучшить или доправить):
Забиваем строковые ресурсы в string;
Раскладываем код по полочкам. Активности переносим в пакет activities, адаптеры в adapters;
Убираем код, который не использовали, или комментим его в TODO
Меняем индексы в приложении, добавляем информацию что мы там накрутили;
Обновляем пакеты, проверяем что из-за них ничего не поломалось.
Формируем AppBundle для Google Play, APK для RuStore (вторые еще толком не научились, а первые уже требуют).
И еще напоследок расшифрую некоторые моменты, которые я не упомянул до этого:
В приложении нет специального параметра (типа boolean до объявления в onCreate, или иного в SharedPrefs, например) для отображения или скрытия блока с заглушкой, так как мы полагаемся на жизненный цикл Android. Другими словами, если приложение было выгружено из памяти, или закрыто, нам не надо сохранять состояние списка, он все равно пересоздаст себя вместе с активностью. Если приложение разворачивается после скрытия (onResume), то все восстановится.
Список изначально не занимает всю площадь экрана, или не раздувается при наполнении (у него фиксированная высота). Это сделано специально, т.к. у нас еще не весь функционал реализован, и ниже будут дополнительные блоки/карточки.
ListView сам по себе является вертикально прокручиваемым по типу ScrollView, поэтому мы сохранили логику прокрутки внутри карточки, и заблаговременно сообщили слою Coordinator через параметр android:nestedScrollingEnabled="true", что вот ты, собака, должен (и будешь) прокручиваться. И даже ничего не сломали в плане юзабилити, пользователю понятно, что там внутри прокручивается список, т.к. есть соответствующая полоса прокрутки.
4 - Что дальше?
Дальше хотелось бы добавить оставшиеся вещи, в той очередности как я их вижу сейчас:
Сохранение результатов в свой собственный список + назначение названия. Например, хлеб в пятерке и в ашане;
Сравнение показателей по выбору их из истории, или из сохраненного списка;
Смена валюты через настройки, т.к. приложение опубликовано в 15 странах.
Публикую ссылки без зазрения совести, так как денег не прошу, а приложение бесплатное, каковым и останется. Ссыль на сайт опционально, для потенциальных вопросов по андроиду, предложений и всего такого.
Всю жизнь я был так или иначе связан со спортом. Сначала занимался им профессионально, затем стал тренировать, а некоторое время писал публикации в СМИ. В 2020 году мне стрельнула в голову гениальная мысль - нет в рунете того сайта, в котором я нуждаюсь, а значит его нужно сделать самому. Концепция была максимально простая: в мире проходят сотни матчей в день, а все обзоры на них раскиданы по разным ютуб-каналам, поэтому было принято решение создать своеобразный агрегатор на эту тему.
Первые шаги и первое разочарование
Эта идея казалась мне беспроигрышной, вот только было несколько нюансов:
До этого момента я и понятия не представлял, что из себя представляет сайтостроение.
У меня было ровно ноль знаний о SEO. Я даже не знал, что это такое.
Я банально не проверил спрос на подобный контент, что стало самым важным, как выяснилось позже.
Я выбрал хостинг, зарегистрировал домен и начал медленно, но упорно выстраивать сайт через WordPress. По началу все было настолько плохо, что мне даже с трудом удавалось быстро найти панель управления сайтом. Через несколько месяцев я собрал простенький сайт, даже настроил граббер, но всплыла та самая проблема - не было такого количества спроса, который бы я хотел. Это было очевидно даже из Яндекс Вордстата, но я слишком поздно узнал об этом инструменте.
Перестройка сайта, счастье, и оглушительное падение
Просто так бросать сайт не хотелось, а потому начал искать пути развития. В России всегда была актуальна тема пиратских спортивных трансляций, и я стал изучать эту нишу. Внезапно обнаружил, что многие сайты живут годами, хотя транслируют матчи, защищенные авторскими правами со всех сторон. Так чем хуже мой сайт?
Я настроил потоки, оптимизировал страницы под поиск и почувствовал себя самым настоящим царем, ведь трафик сайта взлетел примерно до 5 тысяч уников в день, а AdSense, которым я монетизировал сайт, стал приносить примерно по 15-30 долларов в день. И это все практически на полном пассиве.
В голове стали генерироваться новые идеи, я строил грандиозные планы, но в один день все умерло. Я не смог зайти на сайт, на почте увидел сообщение от хостинга о требовании заблокировать сайт по решению Роскомнадзора. Еще позже я увидел сообщение от «Матч ТВ», в котором мне мягко намекнули, что я охренел и ворую их контент. Были попытки писать напрямую в Роскомнадзор, «Матч ТВ» и другие структуры, но ни одна из них не ответила.
Выводы
В день блокировки эмоции переваливали через край, я дико злился на хостинг, вещателей и другие сайты, которые промышляли аналогичным контентом, но спустя время очевидно, что виноват только я сам. Заниматься подобным серым трафиком морально тяжело, так как каждый день ожидаешь какую-нибудь претензию или блокировку. Я бы мог продолжить, постоянно переклеивать домены и работать дальше, но нервы важнее.
В качестве благодарности, если не сложно, подключайтесь к моей телеге, где на этот раз все безопасно: statsandmaps
Предыстория, один клиент в компании попросил проверить пк сотрудника после упадка продаж, он реально думал что сливали заказы копированием или как то доступом через crm в общем упадок был, а понять как и отследить было сложно. Так для тех кто в теме, скрипт я переделал под exe прятался он под pdf прайсом. а в диспетчере скрыт. И пост не для программистов.
Попросили меня проверить, результат порадовал, но причастность доказать нереально кто из менеджеров запустил данный софт. Схема проста, покупается зарубежный виртуальный номер на который регистрируется аккаунт телеграмм и через которого создаётся бот.
Рекомендую всем проверять отправки на порты телеги возможно вы тот самый за кем шпионит жена, муж, начальник или конкурент.
Находку я немного переписал, потому что она была зашита под файлом но выполняла почто такой же функционал как на видео.
Кто такие “White hats - Белы шляпы” ?
“White hats - Белы шляпы” - это термин, используемый для обозначения этичных хакеров, которые используют свои навыки для улучшения кибербезопасности.
Они работают на благо общества, помогая организациям обнаруживать и устранять уязвимости в их системах безопасности.
Белые шляпы проводят тестирование на проникновение и другие проверки безопасности, чтобы обнаружить потенциальные угрозы.
В отличие от “Black hats”, белые шляпы действуют законно и с разрешения владельцев систем.
Работа белых шляп важна для поддержания безопасности в интернете и защиты данных пользователей от злоумышленников. Всё тестировалось в среде на виртуальных машинах и ведео не в коем образом не пропагандирует взлом или как то его рекламирует. Видео несёт информационный характер в сфере Pentest. Tg@Windall
Прежде чем начать знакомство с более сложными программами, рассмотрим ряд опций, доступных для клиентских операций. Встроенный в Go пакет net предлагает обширную функциональность и поддерживает большинство, если не все типы записей. Преимущество этого пакета — в простоте его API. Например, LookupAddr(addr string) возвращает список имен хостов для заданного IP-адреса. Недостаток же его заключается в невозможности указывать целевой сервер. Вместо этого пакет использует настроенный в операционной системе механизм распознавания. К недостаткам можно отнести также отсутствие возможности выполнения углубленного анализа результатов.
Для обхода этих недочетов мы задействуем отличный сторонний пакет Go DNS, написанный Миком Гибеном (Miek Gieben). Предпочесть этот DNS-пакет всем прочим стоит из-за его высокой модульности и грамотно написанного и протестированного кода. Вот команда для его установки:
Установив пакет, вы будете готовы к проработке последующих примеров кода. Начнем с выполнения поиска А-записей для получения IP-адресов из имен хостов.
Извлечение А-записей:
Сперва познакомимся с поиском для полностью уточненного имени домена (fully qualified domain name, FQDN), которое указывает точное расположение хоста в иерархии DNS. Затем попробуем интерпретировать это FQDN в IP-адрес с помощью DNS-записи А. Эта запись связывает имя домена с IP-адресом. (Все листинги кода находятся в корневом каталоге /exist репозитория GitHub https://github.com/blackhat-go/bhg/.)
Код на языке Golang
Сначала создается msg , после чего идет вызов fqdn(string) для преобразования этого домена в FQDN, которым можно обменяться с DNS-сервером . Далее нужно изменить внутреннее состояние Msg на вызов SetQuestion(string, uint16)
с помощью значения TypeA, указывающего, что нужно искать А-запись. (В пакете она определена как const. Другие поддерживаемые значения можно найти в документации.) В завершение мы помещаем вызов Exchange(*Msg, string) , чтобы отправить сообщение на предоставленный адрес сервера, в данном случае являющегося DNS-сервером, обслуживаемым Google.
Нетрудно заметить, что данный код не особо полезен. Несмотря на то что мы отправляем запрос к DNS-серверу и запрашиваем А-запись, ответ мы не обрабатываем, то есть с результатом ничего не делаем. Но прежде чем реализовать нужную функциональность в Go, давайте рассмотрим, как выглядит ответ DNS, чтобы лучше понять этот протокол и различные типы запросов.
Перед выполнением программы которая написана выше запустите анализатор пакетов, например Wireshark или tcpdump, чтобы просмотреть трафик. Вот пример возможного использования tcpdump на хосте Linux:
$ sudo tcpdump -i eth0 -n udp port 53
В отдельном окне терминала скомпилируйте и выполните программу:
$ go run main.go
После выполнения кода в выходных данных перехвата пакетов должны отобразиться подключение к 8.8.8.8 через UDP 53, а также детали DNS-протокола:
Две из получаемых при перехвате пакетов строчек нуждаются в дополнительном пояснении. Сначала запрос отправляется с 192.168.7.51 к 8.8.8.8 с помощью UDP 53, при этом происходит запрос А-записи. В ответе от DNS-сервера Google 8.8.8.8 содержится интерпретированный из имени домена IP-адрес 104.131.56.170.
С помощью анализатора пакетов можно преобразовать имя домена stacktitan.comв IP-адрес. Теперь посмотрим, как извлечь эту информацию, используя Go.
Отработка ответов от структуры Msg:
В качестве значения Exchange(*Msg, string) возвращает (*Msg, error). Возврат типа error имеет смысл и является стандартным для идиом Go, но почему в ответе приходит также изначально отправленная *Msg? Чтобы это понять, нужно взглянуть на определение этой struct в исходном коде:
Код на языке Golang
Как видите, Msgstruct содержит как вопросы (question), так и ответы (answer). Это позволяет объединять все DNS-вопросы и ответы на них в единую унифицированную структуру. Тип Msg располагает различными методами, упрощающими работу с данными. Например, срез Question изменяется с помощью метода setQuestion(). Это срез можно изменять напрямую, используя append(), и получать тот же результат. Срез Answer содержит ответ на запросы и имеет тип RR. Ниже будет показано, как эти ответы обрабатывать.
Обработка DNS-ответов:
Пример начинается с сохранения возвращенных от Exchange значений и их проверки на наличие ошибок. Если ошибка обнаружена, вызывается panic() для остановки программы. Функция panic() позволяет быстро просмотреть трассировку стека и определить место возникновения ошибки. Далее проверяется длина среза Answer. Если она меньше 1, это означает, что записей нет, и происходит возврат — бывают случаи, когда имя домена не может быть интерпретировано.
Тип RR является интерфейсом, имеющим всего два определенных метода, ни один из которых не дает доступа к IP-адресу, хранящемуся в ответе. Для доступа к этим адресам нужно применить утверждение типа, чтобы создать экземпляр данных в качестве нужного типа.
Сначала выполняем перебор ответов. Далее применяем в ответе утверждение типа, чтобы гарантировать работу с типом *dns.A. При выполнении этого действия можно извлечь два значения: данные в виде утвержденного типа и bool, отражающее успешность утверждения. После проверки успешности утверждения происходит вывод IP, сохраненного в a.A. Несмотря на тип net.IP, он реализует метод String(), поэтому его можно легко вывести на экран.
Поработайте с этим кодом, изменяя DNS-запрос и обмен (exchange) для поиска дополнительных записей. Утверждение типа может оказаться для вас незнакомым, но по своему принципу оно аналогично приведению типов в других языках.
Перечисление поддоменов:
Теперь, научившись использовать Go в качестве DNS-клиента, вы можете создавать полезные инструменты. В этом разделе мы создадим утилиту подбора поддоменов. Подбор поддоменов цели и других DNS-записей — основополагающий шаг в процессе разведки, так как чем больше поддоменов вам известно, тем обширнее поле атаки. Наша утилита будет угадывать их на основе передаваемого списка слов (файла словаря).
Используя DNS, можно отправлять запросы настолько быстро, насколько быстро система сможет обрабатывать пакеты данных. Узким местом здесь станут не язык или среда выполнения, а сервер назначения. При этом, как и в предыдущих главах, будет важно управление многопоточностью программы.
Сначала нужно создать в GOPATH каталог под названием subdomain_guesser, а затем файл main.go. После этого в начале создания нового инструмента необходимо решить, какие аргументы эта программа будет получать. В данном случае это будет несколько аргументов, включая целевой домен, имя файла, содержащего поддомены для подбора, используемый DNS-сервер, а также количество запускаемых воркеров. В Go для парсинга опций командной строки есть полезный пакет flag, который мы будем применять для обработки аргументов командной строки. Несмотря на то что мы используем этот пакет не во всех примерах кода, в данном случае он служит для демонстрации более надежного и изящного парсинга аргументов. Код этого процесса будет приведен ниже.
Создание программы подбора поддоменов на языке Golang
В начале строка кода, объявляющая переменную flDomain, получает аргумент String и объявляет пустое строковое значение для того, что будет парситься как опция domain. Следующая связанная строка — это объявление переменной flWorkerCount. Здесь в качестве опции командной строки c нужно предоставить значение Integer. В данном случае мы устанавливаем 100 воркеров. Но это значение можно счесть консервативным, так что в процессе тестирования смело экспериментируйте с увеличением их числа. В завершение вызов flag.Parse() заполняет переменные, задействуя предоставленный пользователем ввод.
ПРИМЕЧАНИЕ:
Вы могли обратить внимание на то, что этот пример идет вразрез с правилами Unix в том, что определяет необязательные аргументы, которые на деле являются обязательными. Можете свободно использовать здесь os.Args. Просто нам быстрее и удобнее поручить всю работу пакету flag.
При сборке данной программы должна возникнуть ошибка, указывающая на неиспользованные переменные. Добавьте приведенный далее код сразу после вызова flag.Parse(). Это дополнение выводит в stdout переменные наряду с кодом, гарантируя передачу пользователем -domain и -wordlist:
Чтобы ваш инструмент сообщал, какие имена оказались интерпретируемыми, указывая при этом соответствующие им IP-адреса, нужно создать для хранения этой информации тип struct. Определите его над функцией main():
Для этого инструмента вы будете запрашивать два основных типа записей — А и CNAME. Каждый запрос будет выполняться в отдельной функции. Стоит создавать эти функции максимально небольшими и поручать каждой выполнение только одной задачи. Такой стиль разработки позволит в дальнейшем писать менее объемные тесты.
Запрос записей A и CNAME:
Для выполнения запросов мы создадим две функции: одну для А-записей, вторую для записей CNAME. Они обе будут получать FQDN в качестве первого аргумента и адрес DNS-сервера в качестве второго. Каждая из них должна возвращать срез строк и ошибку. Добавьте эти функции в код, который начали определять, расположив вне области main():
Этот код должен показаться вам знакомым, так как он практически идентичен коду, который мы писали в самом начале главы. Первая функция, lookupA, возвращает список IP-адресов, а lookupCNAME возвращает список имен хостов.
Записи CNAME (канонические имена) сопоставляют одно FQDN с другим, которое служит псевдонимом для первого. Предположим, что владелец организации example.com хочет разместить WordPress-сайт с помощью сервиса хостинга WordPress. У этого сервиса могут быть сотни IP-адресов для балансировки всех пользовательских сайтов, в связи с чем предоставить IP для отдельного сайта просто невозможно. Вместо этого данный хостинг может предоставить каноническое имя (CNAME), на которое и будет ссылаться example.com. В итоге адрес www.example.com получит CNAME, указывающее на somewhere.hostingcompany.org, которое, в свою очередь, будет иметь А-запись, указывающую на IP-адрес. Это позволит владельцу example.com разместить свой сайт на сервере, для которого у него нет IP-данных.
Зачастую это означает, что вам нужно проследить целый хвост из канонических имен, чтобы в итоге добраться до действительной А-записи. Мы говорим хвост, потому что из подобных имен может выстраиваться бесконечная цепочка. Добавьте приведенный далее код функции в область за пределами функции main(), чтобы понаблюдать, как использовать череду CNAMES для нахождения А-записи:
Сначала определяется срез для хранения результатов. Далее создается копия FQDN, переданного в качестве первого аргумента. В итоге вы не только не теряете исходный угаданный FQDN, но и можете задействовать его в первой попытке запроса. Начав бесконечный цикл, мы пробуем получить CNAME для этого FQDN. В случае отсутствия ошибок и возвращения не менее одного CNAME устанавливаем cfqdn равным этому возвращенному CNAME, используя continue для возврата к началу цикла. Данный процесс позволяет проследить череду CNAME до возникновения сбоя. Последний будет означать, что конец цепочки достигнут и можно искать А-записи. Но если возникнет ошибка, означающая, что при поиске записи возникли проблемы, то выход из цикла произойдет раньше. В случае обнаружения действительных А-записей каждый возвращенный IP-адрес добавляется в срез результатов, а цикл прерывается. В завершение results возвращается вызывающему.
Наша связанная с интерпретацией имен логика выглядит гладко, однако мы не учли производительность. Давайте совместим этот пример с горутинами, добавив в него многопоточность.
Переход к воркер-функции:
Мы создадим пул горутин, которые будут передавать работу воркер-функции, выполняющей единицу работы. Для распределения работы и сбора ее результатов задействуем каналы. Напомним, что нечто подобное мы уже делали в главе 2, когда создавали многопоточный сканер портов.
Продолжим расширять код Создание программы подбора поддоменов. Сначала создадим функцию worker(), разместив ее вне области функции main(). Она будет получать три аргумента каналов: канал для воркера, чтобы он сигнализировал о своем закрытии, канал доменов, в которых нужно получать работу, и канал для отправки результатов. Этой функции потребуется заключительный строковый аргумент для указания используемого DNS-сервера. Далее приведен пример кода для функции worker():
Прежде чем вводить функцию worker(), определим тип empty для отслеживания завершения выполнения воркера. Это будет структура без полей. Мы задействуем пустую struct, так как она имеет размер 0 байт и практически не создаст нагрузку при использовании. Далее в функции worker() происходит перебор канала доменов, используемый для передачи FQDN. После получения ответа от функции lookup() и проверки наличия не менее одного результата мы отправляем его в канал gather, который собирает все результаты обратно в main(). После того как канал закрывается и цикл совершает выход, структура empty отправляет в канал tracker сигнал вызывающему о завершении всей работы. Отправка пустой struct в канал отслеживания — это важный последний шаг. Если этого не сделать, возникнет состояние гонки, так как вызывающий компонент может выйти до получения каналом gather результатов.
Поскольку вся необходимая структура теперь настроена, можно переключиться обратно на main() и закончить программу, которую мы начали писать в Создание программы подбора поддоменов.
Определите переменные, которые будут содержать результаты и каналы, передаваемые в worker(), после чего добавьте в main() следующий код:
Создайте канал fqdns как буферизованный на основе предоставленного пользователем количества воркеров. Это позволит воркерам запускаться быстрее, поскольку канал сможет вместить больше одного сообщения до блокировки отправителя.
Создание сканера с помощью bufio:
Далее откройте файл, предоставленный пользователем в качестве списка слов, и создайте в нем новый scanner с помощью пакета bufio. Добавьте в main() код
Если возвращаемая ошибка не равна nil, используется встроенная функция panic(). При написании пакета или программы для применения другими людьми следует постараться представить эту информацию более ясно.
Мы будем применять новый scanner для захвата строки текста из переданного списка слов и создания FQDN путем совмещения этого текста с предоставленным пользователем доменом. Результат будет отправляться в канал fqdns. Но сначала нужно запустить воркеры, так как порядок важен. Если отправить работу в канал fqdns, не запустив их, этот буферизованный канал в итоге заполнится и функции-производители будут заблокированы. В main() нужно добавить приведенный далее код, чья задача — запускать горутины воркеров, читать вводный файл и отправлять работу в канал fqdns.
Создание воркеров с помощью этого паттерна похоже на то, что мы уже делали при построении многопоточного сканера портов: задействовали цикл for до момента достижения числа, переданного пользователем. Для захвата каждой строки в цикле используется scanner.Scan(). Этот цикл заканчивается, когда в файле не остается строк для считывания. Для получения строкового представления текста из отсканированной строки мы применяем scanner.Text().
Работа запущена! Отвлекитесь на секунду и ощутите свое величие. Прежде чем читать следующий код, подумайте, где вы находитесь в программе и что уже успели сделать за время чтения книги. Попробуйте самостоятельно закончить эту программу и затем перейти к следующему разделу, где мы поясним ее оставшуюся часть.
Сбор и отображение результатов
Проработку последней части мы начнем с запуска анонимной горутины, которая будет собирать результаты воркеров. Добавьте в main() следующее:
Перебирая канал gather, мы добавляем полученные результаты в срез results. Поскольку мы добавляем срез в другой срез, нужно использовать синтаксис … . После закрытия канала gather и завершения перебора, как и прежде, происходит отправка пустой struct в канал отслеживания. Это делается для предотвращения состояния гонки на случай, если append() не завершится к моменту итогового предоставления результатов пользователю.
Остается только закрыть каналы и представить результаты. Для этого добавьте следующий код в конец main():
Первым можно закрыть канал fqdns, так как мы уже отправили по нему всю работу. Далее нужно выполнить получение результатов в канале tracker по одному разу для каждого воркера, что позволит им обозначить свое полное завершение. После этого можно закрыть канал gather, потому что результатов для получения не остается. В завершение нужно выполнить еще одно получение результатов на канале tracker, чтобы позволить горутине окончательно завершиться.
Эти результаты пользователю еще не представлены. Нужно это исправить. При желании можно просто перебрать срез results и вывести поля Hostname и IPAddress, используя fmt.Printf(). Тем не менее мы предпочитаем задействовать для представления данных один из нескольких прекрасных пакетов Go, а именно tabwriter. Он позволяет выводить данные в красивых ровных столбцах, разбитых на вкладки. Для его применения добавьте в конец main() следующий код:
На этом наша программа для подбора поддоменов готова. Теперь вы можете собрать и запустить этот инструмент. Опробуйте его на списках слов или словарях из открытых репозиториев (можете найти множество через Google). Поэкспериментируйте с количеством воркеров. Вы можете заметить, что при слишком быстрой обработке результаты получаются неоднозначные. Вот пример выполнения с использованием ста воркеров:
Вы увидите, что вывод показывает несколько FQDN и их IP-адреса. Мы смогли угадать значения поддоменов для каждого результата на основе списка слов, переданного в качестве вводного файла.
Теперь, когда вы создали собственный инструмент для подбора поддоменов и научились интерпретировать имена хостов в IP-адреса для перечисления разных DNS-записей, можно переходить к написанию собственного DNS-сервера и прокси.
Дело в том, что я неоднократно сталкивался с одной и той же проблемой, а именно с тем, что на мою страницу в ВК были зафиксированы входы, которые не отображались в панели безопасности. Это как?
Скриншот с телефона:
Фото через браузер в тот день
Т.е. я в тот день не заходил в ВК. Даты нет, но данные у поддержки ВК есть. Ибо они бы на это сразу внимание обратили.
Естественно, что я спросил у поддержки ВК, и ответ был типичным:
В общем я решил уничтожить пиратский сайт - Лордфильм. Надоел он мне! со своей вечной рекламой казино-лохотрон.
Это не так то просто будет сделать, так как создатели этого ресурса создают колоссальное количество зеркал с разными DNS IP адресами.
Как я понял весь их агрегат само разворачивается на javascript коде который ссылается на их базу данных где они хранят свой пиратский контент.
Жаловаться в РКН нет смысла, черные хакеры поправят скрипт в течении часа и тот адрес который я отошлю к тому времени как в РНК его начнут проверять скорее всего адреса уже не будет существовать.
Раз так! Значит с ними надо бороться ихними же методами. Что я сделаю:
1. Создаем фейк сайт Лордфильм который наберет на себя все поисковые запросы от яндекса и гугла.
2. Выведу фейк сайт в топовые позиции, тем самым перетяну всю их аудиторию на себя.
3. Легализуют сайт под брендом "Лордфильм"
4. Я разорю их, и сделаю их вложения нерентабельными.
Я уже вел переговоры с майл чтоб те предоставили мне сертифицированный видео контент. Таким образом у меня будет легальный сайт под названием "Лордфильм" поэтому РКН на мой сайт ругаться не будет. Алгоритмы Яндекса это поймут и все поисковые запросы будут вести на мой сайт. Так же я запущу рекламу. Пираты казино-лохотрон потеряют абсолютно всю свою аудиторию, им уже ничего не поможет.
Если моя методика сработает, то та же самая участь постигнет и других пиратов интернета. Бойтесь меня!
Удаче мне в не легком пути! Да прибудет со мной сила белого хакера!
Где же найти сайт Лордфильм вот вам ответ! Сайт можно найти по поисковому запросу "Лордфильм"
(P/S Да ладно это шутка, просто написал чтоб рассмешить вас! Любые совпадения в реальной жизни случайны и ко мне и моим действиям никакого отношения не имеют, я даже не умею программировать, я работаю двориком.)