C++ Cryptopp.dll访问冲突读取位置0x74736554

C++ Cryptopp.dll访问冲突读取位置0x74736554,c++,visual-c++,cryptography,crypto++,C++,Visual C++,Cryptography,Crypto++,我正在尝试使用cryptopp,下面的代码在stringsource函数中导致访问冲突。可能的原因是什么?我以前成功地运行过类似的代码,但差别不大 AESShelper.cpp #include "dll.h" #include "AesHelper.h" #include "aes.h" using CryptoPP::AES; #include "ccm.h" using CryptoPP::CBC_Mode; #include "filters.h" using CryptoPP::S

我正在尝试使用cryptopp,下面的代码在stringsource函数中导致访问冲突。可能的原因是什么?我以前成功地运行过类似的代码,但差别不大

AESShelper.cpp

#include "dll.h"
#include "AesHelper.h"

#include "aes.h"
using CryptoPP::AES;
#include "ccm.h"
using CryptoPP::CBC_Mode;

#include "filters.h"
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::StreamTransformationFilter;

#include "hex.h"
using CryptoPP::HexEncoder;
using CryptoPP::HexDecoder;

#include <string>
using namespace std;

#include "osrng.h"
using CryptoPP::AutoSeededRandomPool;

byte AesHelper::_key[AES::DEFAULT_KEYLENGTH];
byte AesHelper::_iv[AES::BLOCKSIZE];

void AesHelper::encrypt(const char* str, char ** outIv, char ** encrypted )
{
    try
    {
        AutoSeededRandomPool prng;

        byte key[AES::DEFAULT_KEYLENGTH];
        prng.GenerateBlock(key, sizeof(key));

        byte iv[AES::BLOCKSIZE];
        prng.GenerateBlock(iv, sizeof(iv));

        string cipher, encoded;
        string plain = "CBC Test Mode";

        CBC_Mode<AES>::Encryption e;
        e.SetKeyWithIV(key, sizeof(key), iv);

        // The StreamTransformationFilter removes
        //  padding as required.
        StreamTransformationFilter *stf = new StreamTransformationFilter(e,
                new StringSink(cipher),
                CryptoPP::BlockPaddingSchemeDef::ZEROS_PADDING
            );

        StringSource s(plain, true, stf); // This line cause Access Violation

        StreamTransformationFilter filter(e);
        filter.Put((const byte*)plain.data(), plain.size());
        filter.MessageEnd();

        const size_t ret = filter.MaxRetrievable();
        cipher.resize(ret);
        filter.Get((byte*)cipher.data(), cipher.size());

        //encode the cipher to hexadecimal
        StringSource(cipher, true,
        new HexEncoder(
                new StringSink(encoded)
            ) // HexEncoder
        ); // StringSource


        //set the output parameter
        outIv = (char**)_iv;
        encrypted = (char**)cipher.c_str();
    }
    catch(const CryptoPP::Exception& e)
    {
        cerr << "exception : " << e.what() << endl;
        exit(1);
    }

}
错误

PaymentManager.exe已触发断点

节目在

void __cdecl _free_base (void * pBlock) {

        int retval = 0;


        if (pBlock == NULL)
            return;

        RTCCALLBACK(_RTC_Free_hook, (pBlock, 0));

        retval = HeapFree(_crtheap, 0, pBlock); // program stop at this line
        if (retval == 0)
        {
            errno = _get_errno_from_oserr(GetLastError());
        } }

我不知道这个库,但正如我看到的
StringSource
get
std::string
作为第一个参数。在这种情况下,您应该绝对确定,DLL和您的程序都使用完全相同的STL编译和链接,使用完全相同的编译器及其选项,我不知道这个库,但正如我看到的,StringSource将std::string作为第一个参数。在这种情况下,您应该绝对确信,DLL和您的程序都是用完全相同的STL编译和链接的,使用完全相同的编译器及其选项,对于四个ASCII字符,0x74736554是十六进制的
“tseT”
(big-endian)或
“Test”
(little-endian)-后者正好是
纯字符串
索引4-7处的字节。
StringSource
构造函数试图读取该地址的事实表明,您的可执行文件和DLL在
std::string
的外观上存在分歧。特别是,库正在从传递给它的对象取消对偏移量4处的内存地址的引用,但传递给它的对象在那里没有有效的指针值

换句话说,您正在传递的
字符串(或者可能是它的某个子对象)在内存中看起来如下所示:

Offset    0      1      2      3      4      5      6      7
       +------+------+------+------+------+------+------+------+--
Value  | 0x43 | 0x42 | 0x43 | 0x20 | 0x54 | 0x65 | 0x73 | 0x74 | ...
       | 'C'  | 'B'  | 'C'  | ' '  | 'T'  | 'e'  | 's'  | 't'  | ...
       +------+------+------+------+------+------+------+------+--
但是,图书馆是这样对待它的:

Offset    0      1      2      3      4      5      6      7
       +------+------+------+------+------+------+------+------+--
Value  |           ?????           | Pointer to character data | ...
       +------+------+------+------+------+------+------+------+--
我通过意识到导致故障的地址完全由与源代码中的值相匹配的ASCII值组成,从而解决了这一问题

原因几乎可以肯定是您的代码和库使用了不同的
std::string
实现,它们具有不同的对象布局。这和我的问题完全一样。为了传递模块之间的C++对象(即它所加载的主可执行文件和任何DLL),两个模块都需要对对象如何布局进行约定。如果模块是在不同的时间编译的,那么您需要更加努力地确保它们是根据相同的头文件编译的

<>如果您正在编译源代码中的DLL,那么最简单的方法就是确保DLL和可执行文件都使用相同的C++标准库实现。如果您使用的是已经由其他人编译的DLL,那么您需要询问或检查文档以找到编译的C++标准库,然后在同一库上编译可执行文件。

如果不能这样做,那么下一个最好的解决办法是避免在C++中跨模块边界传递C++对象。所有< /强>用例只使用预定义数据类型(如整数和原始指针)或在DLL头文件中定义的数据类型的API。这将完全避免问题,但也会使代码更难编写,因为您无法再传递或接收

std::string

0x74736554是四个ASCII字符的十六进制-后者正好是
纯字符串
索引4-7处的字节。
StringSource
构造函数试图读取该地址的事实表明,您的可执行文件和DLL在
std::string
的外观上存在分歧。特别是,库正在从传递给它的对象取消对偏移量4处的内存地址的引用,但传递给它的对象在那里没有有效的指针值

换句话说,您正在传递的
字符串(或者可能是它的某个子对象)在内存中看起来如下所示:

Offset    0      1      2      3      4      5      6      7
       +------+------+------+------+------+------+------+------+--
Value  | 0x43 | 0x42 | 0x43 | 0x20 | 0x54 | 0x65 | 0x73 | 0x74 | ...
       | 'C'  | 'B'  | 'C'  | ' '  | 'T'  | 'e'  | 's'  | 't'  | ...
       +------+------+------+------+------+------+------+------+--
但是,图书馆是这样对待它的:

Offset    0      1      2      3      4      5      6      7
       +------+------+------+------+------+------+------+------+--
Value  |           ?????           | Pointer to character data | ...
       +------+------+------+------+------+------+------+------+--
我通过意识到导致故障的地址完全由与源代码中的值相匹配的ASCII值组成,从而解决了这一问题

原因几乎可以肯定是您的代码和库使用了不同的
std::string
实现,它们具有不同的对象布局。这和我的问题完全一样。为了传递模块之间的C++对象(即它所加载的主可执行文件和任何DLL),两个模块都需要对对象如何布局进行约定。如果模块是在不同的时间编译的,那么您需要更加努力地确保它们是根据相同的头文件编译的

<>如果您正在编译源代码中的DLL,那么最简单的方法就是确保DLL和可执行文件都使用相同的C++标准库实现。如果您使用的是已经由其他人编译的DLL,那么您需要询问或检查文档以找到编译的C++标准库,然后在同一库上编译可执行文件。

如果不能这样做,那么下一个最好的解决办法是避免在C++中跨模块边界传递C++对象。所有< /强>用例只使用预定义数据类型(如整数和原始指针)或在DLL头文件中定义的数据类型的API。这将完全避免这个问题,但它也会使您的代码更难编写,因为您无法再传递或接收

std::string

除了Boris和Adam的答案之外,我发现这会在Linux上导致问题(我知道您在Windows上):

匿名声明是合法的C/C++。但是GCC的特定版本(大约4.3或4.4或4.5)会在生成的代码中过早地开始运行析构函数。2011年,我曾和乔纳森·韦克利谈论过这件事,但我始终无法找出原因。这是导致m开始查看它的线程:
    StringSource ss(cipher, true,
    new HexEncoder(
            new StringSink(encoded)
        ) // HexEncoder
    ); // StringSource