SmartRM.com is an venture capital-backed service (founded by italian people in the USA) that allows to protect user documents and videos, letting the user to store locally a copy of the encrypted document for easy and secure distribution via email, USB keys etc.

In order to view the original document, the user needs to login into SmartRM and then use a proprietary viewer to open the encrypted PDF, in our test case.

The problem is that the viewer can be easily hacked in order to obtain a copy of the original document, starting from an encrypted version of the document itself.
This is pretty obvious and easy to accomplish, in any case.

The promises of the service are listed in their homepage, and sum up the nature of the application:
  • Alice cannot read the document before tomorrow morning
  • Bob can watch the video only once
  • Everyone can listen to my song for a week
  • Everyone can ask me the permission to open my file
Although the first and the last statements remain allegedly true, a simple viewer hack makes the second and third statements misleading and exposes the user’s sensitive data to an high risk of leakage.

There are 2 “solutions” to this problem:
  • “Security through obscurity”, ie by using “tricks” to complicate the work of an hacker, as Windows Media Player does, for example. But “security through obscurity” is not security, as someone has said, and is a “solution” doomed to failure in the short-term.
  • Completely redesign the security and application model, considering, for example, the idea of storing the user data on a central server, and then serving the content as images or in a streaming way (as SmartRM's competitors do). But in this case there are a lot of other security problems and considerations that need to be taken into consideration… Out of the scope of this demonstration.
This video demonstrates the simple hack:



Technically speaking, the hack proposed in this post is pretty simple: it required only 3 hours to be discovered and developed.

The SmartRM viewer is implemented as a FireFox extension: any time you need to open a document (currently only PDF files are supported by SmartRM), the extension decrypts locally the document, calls a third party PDF library (Quick PDF Library - www.quickpdflibrary.com) passing the original unencrypted version of the document and then the file is showed to the user as a series of images, that the user can only view or, eventually, print, if given the appropriate permission. The PDF rendering job is done by the Quick PDF Library (QuickPDFDLL0717.dll).

The hack, and then the “concept flaw” of the whole idea is simple: it is enough to “intercept” the call from the SmartRM extension to the Quick PDF Library dll to obtain an original, unencrypted version of the PDF.

As said before and considering that having the user's encrypted files stored locally is the main competitive advantage of the service against its competitors, the only remedy to this problem is employing some form of “security through obscurity”, that, as you probably know, is a very short-term solution to the problem and, for a company involved in protecting sensitive data for its clients, is simply a credibility suicide.

As a computer user, some years ago, I remember the case of the live streaming of RealMedia video files (rtsp protocol). The premise of that technology was to allow an internet user to gain access to a video file only through live streaming, without the ability to download and then potentially share the content with other (non-paying) internet users. The response of the internet community was a very smart tool (Streambox VCR) which allowed to “record” a rtsp live stream into a file saved into the user’s hard drive. The response of Real.com was a lawsuit to discontinue the support and distribution of Streambox, making it one of the most famous “underground” tools of that time: people started to reverse engineer Streambox in order to make it up-to-date with the changes in the rtsp protocol… A lawsuit was the only option in this case for RealMedia and this is the point of the whole discussion.

Another (in)famous case was that of the “Sony Rootkit”, intended for copy protection, discovered by Mark Russinovich (search Google for more info).

Windows Media Player, for example, in a typical spirit of “security through obscurity”, doesn’t allow to play DRM-protected files if a debugger is attached to the player’s Windows process… This should stop only the very inexperienced hacker !

As it should be clear, it is impossible to guarantee protection of sensitive data from technological premises like these.

How the hack works (and the Proxy Dll hooking trick)

As said before, the SmartRM extension calls into the QuickPDFDLL0717.dll through its exported functions in order to render a PDF page into a GDI Device Context. The relevant flow of calls into QuickPDFDLL0717.dll is as follow:

QuickPDFCreateLibrary : initializes the library.
QuickPDFUnlockKey : unlocks the library.
QuickPDFCreateBuffer : creates a “buffer”.
QuickPDFAddToBuffer : copies the unencrypted PDF bytes into the buffer.
QuickPDFRenderPageToDC : renders the PDF to a Device Context.


So, simply by intercepting the call to QuickPDFAddToBuffer is enough to get an unencrypted version of the PDF.

As you may already know, there are a lot of systems and tricks to intercept an API call (take a look at my site). The case in question is the most simple: a DLL calling into an other DLL through an exported reference… The most simple interception system is to build a “proxy dll”, ie a module with the same name of the one we want to monitor and, above all, with the exact same exports of the original image (in this case QuickPDFDLL0717.dll), respecting the same calling convention, function names, number and order of parameters, type of each parameter and return value of the original module.

So I downloaded the Quick PDF Library (which includes a C++ SDK) and found 2 files (a source and an header file) that allow to late bind to QuickPDFDLL0717.dll: the most important information is the declaration of each exported symbol; for example in the .h file we find a list of type definitions, as this one:

typedef char* (__stdcall *QuickPDFFuncType7)(int, double, double, double, double, char*);

and then, in the .cpp file, we discover the association between the type name (QuickPDFFuncType7 in this case) and the exported symbol name:

QuickPDFDrawHTMLTextBox = (QuickPDFFuncType7)AttachFunction("QuickPDFDrawHTMLTextBox");

By the way, the type name doesn’t directly reflect the function name only for space saving reasons (many exports share the same prototype).

So, after an hour of “Replace All” and “Quick Macros” I come out with something like this:

#define FuncDecl1(fnname) extern "C" char* __stdcall fnname(int paramEND)

#define FuncParams1 (paramEND)

typedef char* (__stdcall *QuickPDFFuncType1)(int);

HMODULE DllRef = NULL;

#define FuncInit(ord, fnname) \
    if ( DllRef == NULL ) DllRef = LoadLibraryA("original_QuickPDFDLL0717.dll"); \
    QuickPDFFuncType##ord FnPtr = (QuickPDFFuncType##ord) GetProcAddress( DllRef, #fnname );

FuncDecl1(QuickPDFFontFamily)
{
    FuncInit( 1, QuickPDFFontFamily )
    AddToLog( "QuickPDFFontFamily" );
    return FnPtr FuncParams1 ;
}


These entry points in the proxy DLL simply are dinamically bound to the calling module, log or do something and then call the original function.

This is only an example of one function: it may seem an huge work, but, a bit of knowledge of Visual Studio Macros and a bit of “creative editing” (and a good keyboard) is enough to create a proxy like the one used in this demonstration in about 1 hour.

So, how the SmartRM hack works ? This is the proxy QuickPDFAddToBuffer:

FuncDecl28(QuickPDFAddToBuffer)
{
    FuncInit( 28, QuickPDFAddToBuffer )
    AddToLog( "QuickPDFAddToBuffer" );
    AddToLog( paramEND );

    // save.
    FILE* fp = ::fopen( "c:\\unencrypted.pdf", "wb" );
    if ( fp )
    {
        ::fwrite( param2, 1, paramEND, fp );
        ::fclose( fp );
    }

    return FnPtr FuncParams28 ;
}


That's it.

To apply the patch, follow these steps:
  1. Go to this folder (under Windows 7): C:\Users\<your_name>\AppData\Roaming\Mozilla\Firefox\Profiles\<your_firefox_profile_name>\extensions\smart-rm@smartrm.com\libraries
  2. Create a folder with name: “test”.
  3. Copy (copy, don’t move!) all the files in the libraries folder (log4cxx.dll, msvcp71.dll, msvcr71.dll, QuickPDFDLL0717.dll, smartrm_comp.dll, xerces-c_3_0.dll) to the newly created “test” folder.
  4. In the libraries folder, replace QuickPDFDLL0717.dll with QuickPdfProxy.dll (ie delete the first file and rename the second file with the name of the first file).
That’s it. From now on SmartRM will save a “plain-text” version of each opened PDF in c:\unencrypted.pdf.

P.S. Note that the SmartRMInterceptor.exe in the video does just this (replacing
QuickPDFDLL0717.dll with QuickPdfProxy.dll ).

Source codes and DLL available here.