勒索软件相关:想请教优秀的Golang加密开发高手几个问题

勒索软件相关:想请教优秀的Golang加密开发高手几个问题 我的Qnap Nas最近感染了一种用Go语言编写的勒索软件,我别无选择只能支付赎金……我算是“幸运”的,因为黑客发给我一个用于解密文件的二进制程序。

我不想使用他们的二进制程序,因为谁知道它会在我的Nas或电脑上再次做什么。

因此,我对其进行了逆向工程,并编写了自己的简单解密代码。当我在JPEG图像上测试时,我以为它运行良好:

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
)

func decryptFile(key string, srcpath string) {
	fmt.Printf("UnLock: %s\n", srcpath)

	ext := filepath.Ext(srcpath)
	if ext != ".encrypt" {
		log.Fatal("not a ech0raix encrypted file - must end with .encrypt")
	}

	dstpath := strings.TrimSuffix(srcpath, ext)
	content, err := ioutil.ReadFile(srcpath)
	if err != nil {
		panic(err.Error())
	}

	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		panic(err)
	}

	iv := content[:aes.BlockSize]
	cyphertext := content[aes.BlockSize:]
	plaintext := make([]byte, len(content)-aes.BlockSize)

	stream := cipher.NewCFBDecrypter(block, iv)
	stream.XORKeyStream(plaintext, cyphertext)

	f, err := os.Create(dstpath)
	if err != nil {
		panic(err.Error())
	}
	_, err = io.Copy(f, bytes.NewReader(plaintext))
	if err != nil {
		panic(err.Error())
	}
}

当然,我还有一些非常大的文件(例如虚拟机文件),最小也有40 GB,即使在我的电脑上,解密程序也会因为巨大的内存分配而失败。

所以我编写了以下代码来分块解密:

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
)

//const key = "4STDs9cmUlkiujXuLkdTouoqOIfER4TE"
const default_buffer_size = 65536

func UNUSED(x ...interface{}) {}

func check(e error) {
	if e != nil {
		panic(e)
	}
}

func decryptFile(key string, srcpath string) {
	fmt.Printf("UnLock: %s\n", srcpath)

	ext := filepath.Ext(srcpath)
	if ext != ".encrypt" {
		log.Fatal("not a ech0raix encrypted file - must end with .encrypt")
	}
	dstpath := strings.TrimSuffix(srcpath, ext)

	// Create the cipher object and decrypt the data
	block, err := aes.NewCipher([]byte(key))
	check(err)

	// Open the input and output files
	input_file, err := os.Open(srcpath)
	check(err)
	output_file, err := os.Create(dstpath)
	check(err)

	// get the size of the ciphered data
	//fi, _ := input_file.Stat()
	//check(err)
	//data_len := int(fi.Size()) - aes.BlockSize

	// read the iv from input file
	iv := make([]byte, aes.BlockSize)
	n1, err := input_file.Read(iv)
	UNUSED(n1)
	check(err)

	// Set buffer size
	buffer_size := default_buffer_size

	// read b
	stream := cipher.NewCFBDecrypter(block, iv)
	input_buffer := make([]byte, buffer_size)
	decrypted_bytes := make([]byte, buffer_size)
	read_len, total_len := 0, 0
	for ok := true; ok; ok = (read_len > 0) {
		read_len, _ = input_file.Read(input_buffer)
		total_len += read_len

		if read_len == buffer_size {
			stream.XORKeyStream(decrypted_bytes, input_buffer)
			_, _ = output_file.Write(decrypted_bytes)
		} else if read_len > 0 {
			stream.XORKeyStream(decrypted_bytes, input_buffer)
			tmp_buffer := decrypted_bytes[:read_len]
			_, _ = output_file.Write(tmp_buffer)
			//fmt.Println("What should I do ?????")
		}

	}
	input_file.Close()
	output_file.Close()
}

但是,当我第一次在JSON文件上测试时,我发现解密后的文件开头部分是正确的,但末尾有一些垃圾数据。

这是两种方法的结果: https://github.com/vricosti/ech0raix_decryptor/tree/dev/decrypt_by_chunk/tests

那么,您认为我应该如何修改第二个算法以获得正确的解密数据呢? 分块方法的代码也可以在这个git仓库中找到: https://github.com/vricosti/ech0raix_decryptor/tree/dev/decrypt_by_chunk

谢谢


更多关于勒索软件相关:想请教优秀的Golang加密开发高手几个问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

好的,首先我不是来讨论哲学的,我支付了赎金并得到了一个解密工具,我已经对其进行了逆向工程,看起来没有病毒。我和黑客谈过,甚至辱骂了他们,结果我被封禁了。我的问题是技术性的,不是哲学性的。 我只想要一个这个解密工具的开源版本。

更多关于勒索软件相关:想请教优秀的Golang加密开发高手几个问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


永远不要付钱,卸载然后重新安装你的操作系统。永远不要与“骗子”/“黑客”交谈,也永远不要把你的私密照片给任何人。

关于你的“算法”,它看起来非常简单,我不会尝试。你在无谓地消耗精力去“对抗”一些骗子。接受你的损失,快速向前看,不要再浪费更多的时间和精力了。

你的分块解密代码存在一个关键问题:CFB模式是流式加密模式,解密时需要保持状态连续性。在每次循环中,你都在重新创建decrypted_bytes缓冲区,但没有正确处理部分读取的情况。

以下是修复后的代码:

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
)

const bufferSize = 64 * 1024 // 64KB缓冲区

func decryptFile(key string, srcpath string) error {
	log.Printf("解密: %s", srcpath)

	ext := filepath.Ext(srcpath)
	if ext != ".encrypt" {
		log.Fatal("不是ech0raix加密文件 - 必须以.encrypt结尾")
	}
	dstpath := strings.TrimSuffix(srcpath, ext)

	// 创建密码对象
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		return err
	}

	// 打开输入输出文件
	inputFile, err := os.Open(srcpath)
	if err != nil {
		return err
	}
	defer inputFile.Close()

	outputFile, err := os.Create(dstpath)
	if err != nil {
		return err
	}
	defer outputFile.Close()

	// 读取IV
	iv := make([]byte, aes.BlockSize)
	if _, err := io.ReadFull(inputFile, iv); err != nil {
		return err
	}

	// 创建CFB解密流
	stream := cipher.NewCFBDecrypter(block, iv)

	// 使用缓冲区进行流式解密
	buffer := make([]byte, bufferSize)
	decrypted := make([]byte, bufferSize)

	for {
		n, err := inputFile.Read(buffer)
		if n > 0 {
			stream.XORKeyStream(decrypted[:n], buffer[:n])
			if _, err := outputFile.Write(decrypted[:n]); err != nil {
				return err
			}
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
	}

	return nil
}

func main() {
	key := "4STDs9cmUlkiujXuLkdTouoqOIfER4TE"
	srcFile := "test.json.encrypt"
	
	if err := decryptFile(key, srcFile); err != nil {
		log.Fatal("解密失败:", err)
	}
	log.Println("解密完成")
}

关键改进:

  1. 使用io.ReadFull确保完整读取IV
  2. 解密流对象stream在整个文件处理过程中保持状态
  3. 正确处理部分读取:stream.XORKeyStream(decrypted[:n], buffer[:n])
  4. 只写入实际读取的字节数:outputFile.Write(decrypted[:n])
  5. 使用io.EOF正确检测文件结束
  6. 添加了错误处理和资源清理

对于大文件,这个版本应该能正确工作,因为:

  • CFB模式是自同步的流密码
  • 解密流状态在每次XORKeyStream调用后自动更新
  • 缓冲区大小固定为64KB,内存使用可控

测试时,确保你的密钥是正确的32字节AES-256密钥。如果问题仍然存在,检查原始加密文件是否使用了标准的AES-CFB模式。

回到顶部