C++ Cryptopp.dll访问冲突读取位置0x74736554
我正在尝试使用cryptopp,下面的代码在stringsource函数中导致访问冲突。可能的原因是什么?我以前成功地运行过类似的代码,但差别不大 AESShelper.cppC++ 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
#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
getstd::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::string0x74736554是四个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