C#Bruteforce-多线程固定长度密码

本文关键字:密码 多线程 C#Bruteforce- | 更新日期: 2023-09-27 17:58:44

我一直在研究一种算法来执行Brute Forcing。这更多的是个人利益,而不是任何恶意使用tbh。我一直对密码学和安全感兴趣。我在应用程序上有一个模式,它将创建工作线程来练习给定长度(每个长度1个线程)的可能组合。

例如:你开始这个过程,然后它将以长度1,2,3,4,5,6,7,8开始,依此类推。当较低长度的线程完成时,它将把可疑密码长度增加1,并生成一个新线程。限制因素是ProcessorCount-1(为了避免线程锁定或GUI线程被冻结:通常发现系统使用自由内核更稳定)

因此,在一个4核系统上,您将处理密码长度1-3,当完成1,2和3时,它将转到4,5,6,依此类推。长度1-5几乎立即完成。在3-4秒内达到6-7。长度8可能需要30-45秒。(这些时间取决于是数字还是字母数字等)更多可能的字符会增加我们需要检查的键空间。

好的,这是一种多线程的方法。但我想介绍的另一种方法有点复杂。它涉及使用多个线程来使用固定长度的可疑密码的全部密钥空间。例如:我们知道它有8位数的长度,所以使用我们所有的线程可以更快地通过8位数的密码密钥空间。

我不确定该怎么办。

例如:假设我们的密码是100(1000个组合?)我们的处理器有8个核心所以这是7个潜在的线程——如果我们采用我的-1方法。每个线程大约要测试143个组合。我只是想知道如何有效地计算每个线程的起始位置。

例如:

线程1将以000开始,以142结束线程2将以143开始,以285结束等

数字听起来很容易,但当您使用一组可能的字符时-"abcdefghijklmnopqrstuvxyz1234567890"
如何计算起点和终点?该字符串中有36个可能的字符。3个字母的密码是36 x 36 x 36=46556个字符的组合吗?

好的,如果我有7个线程,每个线程处理6666个组合。如何获取这些起始位置和结束位置,并将它们转换为比较字符串。

我想我的主要问题是:如何将组合索引转换为由可用字符构造的字符串?

例如:

  • 1可能是"a"
  • 2应该是"b"
  • 37可能是"ab"等

C#Bruteforce-多线程固定长度密码

我不会建议你这样做,但如果这是你想要的方式,那么就像这个一样考虑它

字符1上有36种可能性,字符1上的每种可能性在字符2上都有36种。第三个角色也是如此
所以…
取第一个角色的可能性,并将其除以6(线程)(7将是混乱的)
每个线程给你6个
这是字符1的6种不同可能性,具有36X36种可能性

这意味着线程1执行所有以a、b、c、d、e和f开头的操作
线程2将执行g、h、i、j、k和l
依此类推

与其让每个线程只搜索搜索空间的1/n,不如考虑将其分割成"逻辑"部分(即对有意义)。这意味着你将创建比核心更多的作业,并且你的每个线程在完成前一个作业后,都可以只拾取其中一个作业。

例如,对于数字8位密码,您可以创建0到9的任务,其中任务n是"搜索所有以数字n开头的8位密码"。对于字母数字密码,您可以创建36个任务:"搜索所有以‘a’开头的密码","…以‘b’开头"。。。,"从"0"开始"。

将所有任务放入一个池中,根据需要启动任意多个线程,然后从池中给它们一个任务。一旦任务完成,就让线程从池中获取一个新任务,直到用完为止。

您可以使用线程池来实现这一点,但坦率地说,我只想自己创建一个简单的机制,其中工作池是List<Action>,您可以使用一个简单lock机制在上一个操作完成后从列表中提取任务。


编辑:快速生成一个示例。它看起来像很多代码,但相当简单。没有经过真正的测试,但应该能让你明白我的意思。

private List<Action> jobs = new List<Action>();
private object jobsLock = new object();
// This is the CPU-intensive function that does the actual work of checking passwords
private void TestPasswords(int length) {
    for(int i = 0; i < (1 << length); i++)
    {
        // Simulate testing the password.
        Thread.Sleep(100);
    }
}
// Each thread is dispatched with this action.
// It keeps pulling jobs from the queue and executing them until no more remain.
private void DoWork()
{
    while(true)
    {
        Action job = null;
        lock(this.jobsLock)
        {
            if(this.jobs.Count == 0)
            {
                return;
            }
            job = this.jobs[0];
            this.jobs.RemoveAt(0);
        }
        if(job != null)
        {
            job();
        }
    }
}
// Tester method
public void Run()
{
    // For all password lengths from 1 to 8, generate a job to test passwords.
    // You probably want to divide these differently (e.g. let i be the job that tests
    // all 1 - 8 character passwords starting with the character i, such that
    // all jobs are approximately of equal length).
    for(int i = 1; i <= 8; i++)
    {
        int length = i;
        this.jobs.Add(() => TestPasswords(length));
    }
    // Create a background thread for each of the cores except one, 
    // and let them execute the DoWork loop until the queue is empty.
    // You may build a ContinueWith or WaitAll mechanism to catch the results
    // and build some callback stuff to get the progress.
    int numberOfCores = 8;
    for(int i = 0; i < numberOfCores - 1; i++)
    {
        Task.Run(DoWork);
    }
}