编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

看我揭秘:利用系统时间戳破译勒索病毒加密:真实案例分析

wxchong 2024-07-29 08:03:06 开源技术 12 ℃ 0 评论

根据绿盟科技安全研究团队的研究结果得知,勒索病毒Z作者写了个加密密钥生成函数generate_key(),他利用随机数从预设的字符串序列中随机选出字符,组成一个长度为 60 字节的密钥。运行后会生成随机字符串,然后取前32字节作为密钥,并将byte_56F840 为预设的字符串序列,其值为:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789


根据这个思路,用C#如何实现呢?看我来模拟还原一下,学习一下如何生成密钥。

当然,制作者lucky的思路并不严谨,这也是他最终被国内牛人找的P解的原因之一。

好了,先不多说,看我的模拟代码:


namespace PerformanceComparisonExample
{
    using System;
    using System.Text;
    public class KeyGenerator
    {
        private const string Byte56F840 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        private static readonly Random random = new Random();
        public static string GenerateKey()
        {
            // 生成一个长度为60的随机字符串  
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 60; i++)
            {
                int index = random.Next(Byte56F840.Length);
                sb.Append(Byte56F840[index]);
            }
            // 从生成的字符串中取前32个字符作为密钥  
            string key = sb.ToString().Substring(0, 32);
            return key;
        }
        // 主函数,用于测试 GenerateKey 方法  
        public static void Main()
        {
            string key = GenerateKey();
            Console.WriteLine("Generated Key: " + key);
            // 注意:这里计算的是UTF-16字符数,不是字节数  
            Console.WriteLine("Key Length in Characters: " + key.Length);
            // 如果需要字节长度,使用 Encoding.UTF8.GetByteCount(key)  
            Console.WriteLine("Key Length in Bytes (UTF-8): " + Encoding.UTF8.GetByteCount(key));
        }
    }
}

这个就是当时的实现方法,通过这个代码,完成了生成密钥的过程。得到形如:

Generated Key: QnhetPjtLjjXgE53apC9wJqWIYCfxE2s
Key Length in Characters: 32
Key Length in Bytes (UTF-8): 32

这样的结果。

这个KeyGenerator类,生成一个基于预定义字符集的32个字符长度的密钥。存在的缺点很明显:

如果在一个短时间内频繁生成密钥,而没有为Random实例提供特定的种子,可能会因为默认种子基于当前时间戳而导致生成的密钥序列不是真正的随机。尤其是在多线程环境下或在短时间内多次调用时。

System.Random 类不是线程安全的,如果在多线程环境中并发地生成密钥,可能产生非预期结果或者异常。

那么更强壮一些应该怎么写呢?

// 方法是使用一个基于当前时间或其他不可预测源的独特种子初始化Random对象。
private static readonly Random random = new Random((int)DateTime.Now.Ticks);

其实,勒索病毒Z作者也是这么写的。

但有计算机基础的朋友都应该都知道计算机中不存在真随机数,所有的随机数都是伪随机数,而伪随机数的特征是:

对于一种算法,若使用的初值(种子)不变,那么伪随机数的数序也不变

所以,如果能够确定 generate_key() 函数运行时的时间戳,那么就能利用该时间戳作为随机种子,复现密钥的生成过程,从而获得密钥。

如何能够得到generate_key() 函数运行时的时间戳呢?这个很简单了,看这个勒索病毒加密后的文件信息就知道了。被加密的文件具有一个精确的修改时间,可以利用该时间以确定密钥的生成时间戳。

再通过模拟这个时间就可以实现爆破复现密钥了,当时国内很多解决该病毒加密文件复原就使用的这个方法,得到密钥再去解密就能还原被病毒加密的文件了。具体过程就不讲了,这里我只讲原理。防止别有用心者[呲牙]。

那么怎么写才更好呢?下次继续吧。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表