You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++可用的RC4 Windows API解密函数移植Go语言后失效求助

使用SystemFunction033实现RC4加解密:C++转Go的问题

我通过advapi32.dll中的Windows API SystemFunction033实现RC4加解密,C++代码能正常解密加密后的单词"Hello",但移植到Go语言后无法得到正确结果,怀疑是unsafe.Pointer的使用方式有误。

可正常运行的C++代码

#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <iomanip>

using namespace std;

typedef NTSTATUS(WINAPI* _SystemFunction033)(
    struct ustring* memoryRegion,
    struct ustring* keyPointer);

struct ustring {
    DWORD Length;
    DWORD MaximumLength;
    PVOID Buffer;
} _data, key;

void printResult(const unsigned char* input, size_t size) {
    for (size_t i = 0; i < size; i++) {
        std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(input[i]) << std::endl;
    }
}

int main() {
    HMODULE hAdvapi32 = LoadLibraryA("advapi32.dll");
    if (hAdvapi32 == NULL) {
        std::cerr << "Failed to load advapi32.dll" << std::endl;
        return 1;
    }

    _SystemFunction033 SystemFunction033 = (_SystemFunction033)GetProcAddress(hAdvapi32, "SystemFunction033");
    if (SystemFunction033 == NULL) {
        std::cerr << "Failed to get the address of SystemFunction033" << std::endl;
        FreeLibrary(hAdvapi32);
        return 1;
    }

    std::cout << "Address of SystemFunction033: " << std::hex << (void*)SystemFunction033 << std::endl;

    char _key[] = "supersecretkey";
    unsigned char input[] = { 0xc6,0x22,0xb5,0x00,0x3a };

    unsigned int input_size = sizeof(input);

    std::string str;
    for (int i = 0; i < input_size; i++) {
        str += input[i];
    }
    std::cout << "Encrypted: " << str << std::endl;

    key.Buffer = (&_key);
    key.Length = sizeof(_key);

    _data.Buffer = input;
    _data.Length = input_size;

    SystemFunction033(&_data, &key);

    std::cout << "Result:" << std::endl;
    printResult(reinterpret_cast<unsigned char*>(_data.Buffer), _data.Length);

    unsigned char* ptr = reinterpret_cast<unsigned char*>(_data.Buffer);
    std::string strx;
    for (int i = 0; i < input_size; i++) {
        strx += ptr[i];
    }
    std::cout << "Decrypted: " << strx << std::endl;
}

无法得到正确结果的Go代码

package main

import (
    "fmt"
    "syscall"
    "unsafe"
)

type ustring struct {
    Length        uint32
    MaximumLength uint32
    Buffer        unsafe.Pointer
}

var (
    _data ustring
    key   ustring
)

func printResult(input []byte) {
    for _, b := range input {
        fmt.Printf("0x%02x\n", b)
    }
}

func main() {
    systemfunction033 := syscall.NewLazyDLL("advapi32.dll").NewProc("SystemFunction033")
    fmt.Printf("Address of SystemFunction033: %x\n", systemfunction033.Addr());

    _key := []byte("supersecretkey")
    input := []byte{0xc6,0x22,0xb5,0x00,0x3a}

    input_size := len(input)

    var str string
    for _, b := range input {
        str += string(b)
    }
    fmt.Println("Encrypted:", str)

    key.Buffer = unsafe.Pointer(&_key[0])
    key.Length = uint32(len(_key))

    _data.Buffer = unsafe.Pointer(&input[0])
    _data.Length = uint32(input_size)

    _, _, _ = systemfunction033.Call(
        uintptr(unsafe.Pointer(&_data)),
        uintptr(unsafe.Pointer(&key)),
    )

    dataBytes := unsafe.Slice((*byte)(_data.Buffer), input_size)
    printResult(dataBytes)

    var strx string
    for _, b := range dataBytes {
        strx += string(b)
    }
    fmt.Println("Decrypted:", strx)
}

问题原因及解决方案

核心问题

  1. ustring结构体的MaximumLength未初始化:SystemFunction033要求该字段必须等于Length,否则无法正确处理数据。C++中栈结构体默认值可能恰好满足,但Go中未赋值的字段会被初始化为0,导致API处理异常。
  2. Key长度不匹配:C++中char _key[] = "supersecretkey"会自动在末尾添加空字符\0,sizeof(_key)返回的长度包含这个空字符;而Go中len([]byte("supersecretkey"))只返回字符串本身的字节数,不含空字符,导致RC4密钥长度不一致,加解密结果错误。

修正后的Go代码

package main

import (
    "fmt"
    "syscall"
    "unsafe"
)

type ustring struct {
    Length        uint32
    MaximumLength uint32
    Buffer        unsafe.Pointer
}

func printResult(input []byte) {
    for _, b := range input {
        fmt.Printf("0x%02x\n", b)
    }
}

func main() {
    systemfunction033 := syscall.NewLazyDLL("advapi32.dll").NewProc("SystemFunction033")
    fmt.Printf("Address of SystemFunction033: %x\n", systemfunction033.Addr())

    // 末尾添加空字符,匹配C++中char数组的长度
    _key := []byte("supersecretkey\x00")
    input := []byte{0xc6, 0x22, 0xb5, 0x00, 0x3a}
    inputSize := len(input)

    var encryptedStr string
    for _, b := range input {
        encryptedStr += string(b)
    }
    fmt.Println("Encrypted:", encryptedStr)

    // 正确初始化key结构体:Length和MaximumLength必须相等
    key := ustring{
        Length:        uint32(len(_key)),
        MaximumLength: uint32(len(_key)),
        Buffer:        unsafe.Pointer(&_key[0]),
    }

    // 正确初始化_data结构体
    data := ustring{
        Length:        uint32(inputSize),
        MaximumLength: uint32(inputSize),
        Buffer:        unsafe.Pointer(&input[0]),
    }

    // 调用API并检查返回值,NTSTATUS为0表示成功
    ret, _, err := systemfunction033.Call(
        uintptr(unsafe.Pointer(&data)),
        uintptr(unsafe.Pointer(&key)),
    )
    if ret != 0 {
        fmt.Printf("调用SystemFunction033失败: %v\n", err)
        return
    }

    fmt.Println("Result:")
    resultBytes := unsafe.Slice((*byte)(data.Buffer), inputSize)
    printResult(resultBytes)

    var decryptedStr string
    for _, b := range resultBytes {
        decryptedStr += string(b)
    }
    fmt.Println("Decrypted:", decryptedStr)
}

关键修正点

  • 给ustring的MaximumLength字段赋值,确保和Length相等;
  • 在Go的key字节数组末尾添加\x00,让密钥长度和C++保持一致;
  • 添加API返回值检查,方便排查调用失败的情况;
  • 避免使用全局的_data和key变量,改用局部变量更安全。

内容的提问来源于stack exchange,提问作者Peterslav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 16:28:11