TurboFloat 4.0.9 crypto++ errorSolved

Hello,

I've encountered a problem using the current TurboFloat builds on Windows, both static and DLL options. I think the error may be caused by a bug in the crypto++ library.

The VS2013 static TF library is consistently failing when I request a lease via TF_RequestLease:

Exception:0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

Call Stack: rtd.dll!memcpy() Line 236 Unknown rtd.dll!CryptoPP::ArraySink::Put2(unsigned char const *,unsigned __int64,int,bool) C++ rtd.dll!CryptoPP::BufferedTransformation::ChannelPut2(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,unsigned char const *,unsigned __int64,int,bool) C++ rtd.dll!CryptoPP::StringStore::CopyRangeTo2(class CryptoPP::BufferedTransformation &,unsigned __int64 &,unsigned __int64,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,bool) C++ rtd.dll!CryptoPP::BufferedTransformation::Peek(unsigned char *,unsigned __int64) C++ rtd.dll!CryptoPP::BufferedTransformation::Peek(unsigned char &) C++ rtd.dll!CryptoPP::BufferedTransformation::AnyRetrievable(void) C++ rtd.dll!CryptoPP::BufferedTransformation::TransferMessagesTo2(class CryptoPP::BufferedTransformation &,unsigned int &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,bool) C++ rtd.dll!CryptoPP::BufferedTransformation::TransferAllTo2(class CryptoPP::BufferedTransformation &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,bool) C++ rtd.dll!CryptoPP::StringSource::StringSource(unsigned char const *,unsigned __int64,bool,class CryptoPP::BufferedTransformation *) C++ rtd.dll!LicenseLease::Request(bool) C++ rtd.dll!TF_RequestLease() C++

When using the DLL build, the function call does succeed and I'm able to obtain a floating lease. But upon closing, the application frequently hangs and the debugger reports first-chance exceptions in TurboFloat.dll, such as:

0xC0000096: Privileged instruction.

This type of exception is indicative of heap corruption within the library.

Poking around in the latest release of crypto++ I see a bugfix was introduced into their ArraySink::Put2 function. It was modified to call memmove instead of memcpy to avoid problems with overlapping buffers. I think the TF library may be hitting this bug. Can you look into this?

Thanks

Tim

Hey Tim,

We can't reproduce this in our tests. Any chance you can put together a simple example that can reproduce this bug?

>> "Poking around in the latest release of crypto++ I see a bugfix was introduced into their ArraySink::Put2 function."

We use a version of that library that already contains that fix.

Hi Wyatt,

Sure, I've included an example code below. When running this smaller code I have not duplicated the crash on calls to TF_RequestLease. But the program does hang on exit fairly consistently. In debug sessions I see this exception reported:

First-chance exception at 0x000000013F2CA21E in tftest.exe: 0xC0000096: Privileged instruction.

The call stack in my previous post is the main reason I suspected a problem in the crypto++ library. It died at a call to memcpy. The revised Put2 routine does not call memcpy:

// filters.cpp - written and placed in the public domain by Wei Daisize_t ArraySink::Put2(const byte *begin, size_t length, int messageEnd, bool blocking){ CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking);

// Avoid passing NULL pointer to memcpy. Using memmove due to // Valgrind finding on overlapping buffers. size_t copied = 0; if (m_buf && begin) { copied = STDMIN(length, SaturatingSubtract(m_size, m_total)); memmove(m_buf+m_total, begin, copied); } m_total += copied; return length - copied;}

For reference, my TF libraries have a build date of 1/31/2017. My windows dev environment is MSVS Professional 2013.

Here is my example code. It mimics the floating license function of my larger application, but replaces error logging with messages to stdout.

[code=c++]#include <string>#include <iostream>

#define TURBOFLOAT_STATIC#include "TurboFloat.h"

//Product detail header#include "pdets.h"//This header defines://#define TurboActivate_GUID "GUID string"//unsigned char TurboActivate_dat[] //unsigned int TurboActivate_dat_len

#ifdef _WIN32#include <tchar.h>#define MBSTRJOIN(x,y) x##y#define TA_GUID(x) MBSTRJOIN(L,x)#else#define TA_GUID(x) x#endif

void TF_CC FloatingLeaseCallback( uint32_t status ){

}

int main( int argc, char* argv[] ){ std::string server_hostname = "localhost"; unsigned short server_port = 20013;

//Used to store TurboFloat responses. HRESULT hr;

// Load the product details from pdets.h hr = TF_PDetsFromByteArray( TurboActivate_dat, TurboActivate_dat_len );

if ( hr == TF_E_PDETS ) { //This should not fail. The product data must be malformed std::cout << "Product details failed to load."; return -1; //no need to continue } //Get the handle that will be used for TurboFloat function calls. unsigned int license_handle = TF_GetHandle( TA_GUID( TurboActivate_GUID ) );

//Set the callback function for the license monitor hr = TF_SetLeaseCallback( license_handle, FloatingLeaseCallback );

hr = TF_HasLease( license_handle ); if ( hr != TF_OK ) hr = TF_RequestLease( license_handle );

if ( hr != TF_OK ) { //We don't have a lease. //Save the server address, then make the request again.#ifdef _WIN32 const size_t servlen = server_hostname.size( ) + 1; size_t csz = 0; STRTYPE server_name = new wchar_t[servlen]; mbstowcs_s( &csz, server_name, servlen, server_hostname.c_str( ), server_hostname.size( ) );#else STRTYPE server_name = new char[hostname.size( ) + 1]; memcpy( server_name, hostname.c_str( ), hostname.size( ) ); server_name[hostname.size( )] = 0;#endif

hr = TF_SaveServer( license_handle, server_name, server_port, TF_SYSTEM ); if ( hr == TF_E_PERMISSION ) hr = TF_SaveServer( license_handle, server_name, server_port, TF_USER );

if ( hr != TF_OK ) { std::cout << "Failed store the floating license server: " << server_hostname << " : " << server_port << std::endl; } else { //try to get a lease again hr = TF_RequestLease( license_handle ); } delete[] server_name; } if ( hr == TF_OK || hr == TF_E_LEASE_EXISTS ) std::cout << "Floating license acquired." << std::endl; else std::cout << "Failed to acquire a floating license: " << hr << std::endl; //cleanup if ( TF_HasLease( license_handle ) == TF_OK && TF_DropLease( license_handle ) != TF_OK ) std::cout << "Error dropping TF lease."; if ( TF_Cleanup( ) != TF_OK ) std::cout << "Error on TF cleanup";

return 0;}

#if defined(_WIN32)#ifdef TURBOFLOAT_STATIC#ifdef _DEBUG#ifdef _DLL#pragma comment(lib, "TurboFloat-MDd.lib")#else#pragma comment(lib, "TurboFloat-MTd.lib")#endif#else#ifdef _DLL#pragma comment(lib, "TurboFloat-MD.lib")#else#pragma comment(lib, "TurboFloat-MT.lib")#endif#endif#else#pragma comment (lib, "TurboFloat.lib")#endif#endif[/code]

Update: I've managed to replicate the crash at TF_RequestLease using the example code I posted Friday by linking both static libraries for TurboFloat and TurboActivate into the application.

The call trace of the debug build dies at the same function in the crypto library. Release builds are not crashing but hang in about 50% of my tests.

Shoot me an email at wyatt@wyday.com and we'll send you the latest build. We can't reproduce this with our latest builds.

We've just released TA/TF 4.0.9.6 which should fix these problems.

Let me know if you still have problems and we'll be happy to help.

Get the latest versions of TA, TF, TFS here: https://wyday.com/limelm/api/

I am statically linking both TurboActivate and TurboFloat; using 4.0.9.6 in VS2013 x64. I get that exact crash in TF_requestLease().

Anu

Only statically link one of the libraries (TurboActivate or TurboFloat). If you want to include both in your app then either use the dynamic versions or use one static version and one dynamic version.

Or wait until TA / TF 4.1 when we solve this particular problem of statically linking both libraries in the same app.

Thanks, yes that works.Can you tell us if linking dynamically makes it easier to "hack" the Limelm license? OR, static vs dynamic makes no difference. You are the expert, so best to ask you.

Honestly, you're better off using the dynamic versions of the library. They get *significantly* more testing (an order of magnitude more tests) and there's a less likelihood of your compiler or another library interfering with the functionality.

As far as cracking goes, there's absolutely no difference.