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) }
问题原因及解决方案
核心问题
ustring结构体的MaximumLength未初始化:SystemFunction033要求该字段必须等于Length,否则无法正确处理数据。C++中栈结构体默认值可能恰好满足,但Go中未赋值的字段会被初始化为0,导致API处理异常。- 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
相关产品推荐
相关产品推荐

