2013-03-19 159 views
0

我想使用cryptopp,下面的代碼會導致字符串源函數的訪問衝突。這可能是什麼原因?我以前曾經成功運行過類似的代碼,幾乎沒有區別。Cryptopp.dll訪問衝突讀取位置0x74736554

AesHelper.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); 
    } 

} 

錯誤

在0x550714CA(cryptopp.dll)未處理異常 PaymentManager.exe:0000005:訪問衝突讀取位置 0x74736554。 !

cryptopp.dll的memcpy(無符號字符* DST,無符號字符* SRC,無符號長計數)線188未知

UPDATE: 問題使得無論DLL和EXE後問題程序到「發佈」。但現在有新的問題。 在這條線,這個問題也stringsource功能

StringSource(cipher, true, 
      new HexEncoder(
        new StringSink(encoded) 
       ) // HexEncoder 
      ); // StringSource 

錯誤

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()); 
     } } 
+1

這看起來像一個調試器,而不是一個問答網站的工作。 – Johnsyweb 2013-03-19 03:59:35

回答

2

我不知道這個庫,但我看到StringSource得到std::string作爲第一個參數。在這種情況下,你應該是絕對肯定的是,該DLL和你的程序都編譯和完全相同的STL鏈接,具有完全相同的編譯器及其選項

+0

嗨,我認爲這可能是可能的問題,我正在使用visual studio 2012 express。我對這個鏈接過程很陌生,可否具體瞭解哪些編譯器選項?謝謝 – William 2013-03-19 04:12:48

+1

編譯DLL和可執行文件時編譯器選項應該是一樣的。也許你將DLL編譯爲'Release'並將exe編譯爲'Debug'?如果是的話 - 這是一個答案 – borisbn 2013-03-19 05:34:49

+0

嗨,謝謝,是的,這是答案,我的DLL在調試,在發佈的應用程序,所以我同時釋放。謝謝,但現在我正面臨新的問題。我已經在上面更新了我的問題。可以幫助遮擋一些光線? – William 2013-03-19 06:33:18

2

0x74736554是爲四個ASCII字符"tseT"(大端)十六進制或​​(little-endian) - 後者恰好是string plain索引4-7中的字節。 StringSource構造函數試圖讀取該地址的事實表明您的可執行文件和DLL不同意std::string的外觀。特別是,庫將從傳遞它的對象的偏移量4中取消引用內存地址,但傳遞它的對象在那裏沒有有效的指針值。

換句話說,在string你傳遞(也可能是它的一些子對象)看起來像這樣的記憶:

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實現,它們有不同的對象佈局。這與Allocating and freeing memory across module boundaries的問題完全相同。爲了在模塊之間傳遞C++對象(即主要可執行文件和它加載的任何DLL),兩個模塊需要就如何佈置對象達成一致。如果模塊是在不同的時間編譯的,那麼你需要更加努力工作,以確保它們是針對相同的頭文件進行編譯的。

如果您從源代碼編譯DLL,那麼最簡單的方法就是確保DLL和可執行文件都使用相同的C++標準庫實現。如果您使用的是已經由其他人編譯的DLL,那麼您需要詢問它們或查看文檔以找到它所編譯的C++標準庫,然後針對同一個庫編譯您的可執行文件。

如果你不能做到這一點,那麼下一個最好的解決辦法是避免將C++對象跨模塊邊界所有需要預定義的數據類型(如整數和原始指針)或數據類型案件使用的唯一的API在DLL的頭文件中定義。這將完全避免這個問題,但它也會使你的代碼更難寫,因爲你不能再傳遞或接收std::string

+0

嗨我有該庫的源代碼,我可以知道,如果你能指出我在哪裏可以在Visual Studio 2012中設置STL?我也要對此進行研究。感謝您的真棒回答,我現在更瞭解現在有什麼問題。 – William 2013-03-19 04:47:16

0

除了鮑里斯和亞當的答案,我已經看到了這個導致Linux上的問題(我知道你是在Windows上):++

StringSource(cipher, true, 
    new HexEncoder(
      new StringSink(encoded) 
     ) // HexEncoder 
    ); // StringSource 

匿名聲明是合法的C/C。但是特定版本的GCC(大約4.3或4.4或4.5)會在生成的代碼中很快開始運行析構函數。我在2011年與Jonathan Wakely談論這件事,但我從未能夠找出原因。這是導致m開始查看它的線程:Running the RSA samples and some installation issues

周圍的工作只是到:

StringSource ss(cipher, true, 
    new HexEncoder(
      new StringSink(encoded) 
     ) // HexEncoder 
    ); // StringSource