Golang中如何加密嵌入文件及实现二进制保护

Golang中如何加密嵌入文件及实现二进制保护 我们计划将应用程序部署给客户,但除了法律保护外,还希望为二进制文件提供保护,以降低反编译的吸引力。我们已经通过使用 //go:embed 将所有必需的外部文件嵌入到二进制文件中,实现了单一二进制文件交付,但我们希望对这些文件进行加密,使其在二进制文件中无法直接以文本形式读取。有人在这方面有经验吗?

此外,我们打算使用 GitHub - burrowers/garble: Obfuscate Go builds 来混淆源代码,这将使反编译变得相当困难。另外,我考虑检查 /etc/machine-id 和当前日期是否早于某个特定时间点 X,这可以阻碍普通用户,但对于黑客来说很容易绕过。

我们也可以设置一个许可证主服务器并检查许可证是否有效,但同样,拦截流量或禁用检查许可证的 if 语句是相当容易的。有什么想法吗?


更多关于Golang中如何加密嵌入文件及实现二进制保护的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

你所要求做的事情从根本上来说就很困难。即使你加密了嵌入的文件,你的二进制文件很可能也需要知道如何解密它们,因此这部分代码可以被逆向工程。虽然我在这方面经验不算特别丰富,但我知道大语言模型(LLM)正在使逆向工程变得比以往任何时候都更容易。

我认为 Garble 是你最好的选择。它不会完美,但至少能实现你的目标,即让逆向工程变得更加困难。不过,将密钥发送到你控制范围之外的不受信任环境中,永远不可能做到绝对安全。

更多关于Golang中如何加密嵌入文件及实现二进制保护的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中加密嵌入文件并实现二进制保护,可以通过以下方式实现:

1. 加密嵌入文件

使用AES加密嵌入文件,运行时解密:

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "embed"
    "encoding/hex"
    "fmt"
    "io"
)

//go:embed config/*.json
var embeddedFiles embed.FS

// 加密密钥(实际应用中应从安全位置获取)
var encryptionKey = []byte("32-byte-long-key-here-123456789012")

// 加密文件数据
func encryptData(data []byte) ([]byte, error) {
    block, err := aes.NewCipher(encryptionKey)
    if err != nil {
        return nil, err
    }

    gcm, err := cipher.NewGCM(block)
    if err != nil {
        return nil, err
    }

    nonce := make([]byte, gcm.NonceSize())
    if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
        return nil, err
    }

    ciphertext := gcm.Seal(nonce, nonce, data, nil)
    return ciphertext, nil
}

// 解密文件数据
func decryptData(ciphertext []byte) ([]byte, error) {
    block, err := aes.NewCipher(encryptionKey)
    if err != nil {
        return nil, err
    }

    gcm, err := cipher.NewGCM(block)
    if err != nil {
        return nil, err
    }

    nonceSize := gcm.NonceSize()
    if len(ciphertext) < nonceSize {
        return nil, fmt.Errorf("ciphertext too short")
    }

    nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
    return gcm.Open(nil, nonce, ciphertext, nil)
}

// 嵌入加密文件
func main() {
    // 读取嵌入文件
    data, err := embeddedFiles.ReadFile("config/settings.json")
    if err != nil {
        panic(err)
    }

    // 加密数据
    encrypted, err := encryptData(data)
    if err != nil {
        panic(err)
    }

    // 将加密数据存储为十六进制字符串嵌入
    encryptedHex := hex.EncodeToString(encrypted)
    _ = encryptedHex // 可在编译时嵌入此值
}

2. 运行时解密嵌入的加密文件

package main

import (
    "embed"
    "encoding/hex"
    "fmt"
)

// 嵌入加密后的十六进制数据
//go:embed encrypted_data.txt
var encryptedHex string

func loadEncryptedConfig() ([]byte, error) {
    // 解码十六进制数据
    encryptedData, err := hex.DecodeString(encryptedHex)
    if err != nil {
        return nil, err
    }

    // 解密数据
    decrypted, err := decryptData(encryptedData)
    if err != nil {
        return nil, err
    }

    return decrypted, nil
}

3. 二进制保护增强方案

结合多种保护措施:

package main

import (
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "io/ioutil"
    "os"
    "runtime"
    "strings"
    "time"
)

// 二进制完整性检查
func checkBinaryIntegrity() bool {
    // 计算当前二进制文件的哈希值
    exePath, err := os.Executable()
    if err != nil {
        return false
    }

    data, err := ioutil.ReadFile(exePath)
    if err != nil {
        return false
    }

    hash := sha256.Sum256(data)
    expectedHash := "预计算的二进制哈希值"

    return hex.EncodeToString(hash[:]) == expectedHash
}

// 反调试检测
func antiDebugCheck() bool {
    // 检查是否在调试器中运行
    if runtime.GOOS == "linux" {
        // 检查/proc/self/status中的TracerPid
        data, err := ioutil.ReadFile("/proc/self/status")
        if err == nil {
            lines := strings.Split(string(data), "\n")
            for _, line := range lines {
                if strings.HasPrefix(line, "TracerPid:") {
                    pid := strings.TrimSpace(strings.TrimPrefix(line, "TracerPid:"))
                    return pid == "0"
                }
            }
        }
    }
    return true
}

// 时间限制检查(结合机器ID)
func checkLicenseExpiry() bool {
    // 读取机器ID
    machineID, _ := ioutil.ReadFile("/etc/machine-id")
    idHash := sha256.Sum256(machineID)

    // 基于机器ID生成过期时间
    expiryTime := generateExpiryTime(idHash[:])

    return time.Now().Before(expiryTime)
}

func generateExpiryTime(machineHash []byte) time.Time {
    // 基于机器哈希生成特定过期时间
    // 这里使用简化示例
    baseTime := time.Date(2024, 12, 31, 0, 0, 0, 0, time.UTC)
    return baseTime
}

// 代码混淆后的关键检查点
func performSecurityChecks() bool {
    if !antiDebugCheck() {
        return false
    }

    if !checkBinaryIntegrity() {
        return false
    }

    if !checkLicenseExpiry() {
        return false
    }

    return true
}

func main() {
    // 执行安全检查
    if !performSecurityChecks() {
        fmt.Println("安全检查失败")
        os.Exit(1)
    }

    // 正常程序逻辑
    fmt.Println("程序正常运行")
}

4. 构建时加密和混淆

创建构建脚本:

#!/bin/bash
# build.sh

# 使用garble混淆
go install mvdan.cc/garble@latest

# 加密配置文件
go run encrypt_files.go

# 使用garble构建
garble -literals -tiny build -o myapp main.go

# 添加二进制保护
go install github.com/burrowers/garble@latest

5. 高级保护技术

// 使用CGO调用原生保护库
/*
#include <stdbool.h>
#include <time.h>

bool check_protection() {
    // 原生保护逻辑
    return true;
}
*/
import "C"

// 运行时代码解密执行
func executeProtectedCode(encryptedCode []byte) {
    // 动态解密并执行关键代码
    decryptedCode, _ := decryptData(encryptedCode)
    
    // 这里可以使用plugin或其他机制执行解密后的代码
    // 注意:这增加了复杂性但提供了额外保护层
}

// 内存保护
func protectMemory() {
    // 使用mlock保护敏感数据在内存中
    // 使用mprotect设置内存页为只读
}

这些方法结合了文件加密、二进制混淆、反调试检测和完整性验证,显著增加了逆向工程的难度。实际部署时,密钥管理应使用安全方案,如硬件安全模块或密钥管理服务。

回到顶部