Monday, January 4, 2016

Bypassing Protections: Reversing and Recreating a Protected DLL


Hello and welcome to this new series called Bypassing Protections. Together, we will learn some new methods to bypass protections which have certain flaws in their implementation. In this example, we will look at an dll which is protected with asprotect and use a simple method to recreate it. Since this protected dll only performs license check procedures, it is very easy for us to recreate the dll in Delphi, bypassing the protection all together. In some applications, the authors like to place all of the license management code into a single dll which all modules of the application reference to determine if the it is registered. Since this handles all license management, this becomes the Achilles heel in the application. Together, we will reverse engineer this small dll and recreate all of the functions and procedures in delphi so that they always return that correct values. Due to legal purposes, I will not mention the name of this application in the article, but will include pictures that will clearly help you determine which application this tutorial is based upon.


Let's download the application. When you run it, you are met with this screen. Probing through the directory with protectionID, you will soon discover that the dll named ba8pro is protected with ASProtect. Let's view the export table of ba8pro in PETools and see what functions and procedures it contains.


As we can see, this only contains 4 procedures. If we check the main executable, we see that there are no import references to this dll and that on startup, this dll is not in memory. That means that it likely loads this dll using the LoadLibrary function and obtains the procedure VA using GetProcAddress. Since this is the case, we can find where these procedures are called by simply searching for string references of the function names. When we load the main executable in ollydbg, we can already see the ba8pro dll referenced in the main procedure. Below that we can see references to CheckVersion and CheckDays.
After we step to the point which I labeled Call To CheckVersion, we notice nothing is pushed onto the stack before we call this function. Therefore, we can conclude that the CheckVersion function does not take parameters. After this procedure, we return the value of $FFFFFFFF to EAX and store it at 5D9B04. Since we move the full EAX register to this value, we can conclude that CheckVersion Return an Integer. After playing around, I discovered that if we return a 0 from CheckVersion, it will run as registered. Therefore, we can recreate this dll function in Delphi like this:

Function CheckVersion(): Integer; stdcall;
Begin
Result:=0; //pro
End;

The next function CheckDays works the same way. It does not take parameters and returns the number of days as an integer. We can declare it like this:

Function CheckDays():Integer;  stdcall;
Begin
 Result:=255; //Any value greater than 0 and <= $7FFFFFFF will work
End;

Next, we will look at the function GetModeVersion. After a quick string search for GetModeVersion, we should arrive here:






Let's toggle a breakpoint here, run the application, go to help, and click the about button. This will cause ollydbg to break here. Once we step down to the call, we realize that a value is pushed onto the stack prior to entering this call. Take note of the value. Let's step into this routine to get a better idea of what is going on.





After stepping to the end of the procedure, we discover that the value pushed onto the stack is a pointer to a Unicode string value which gets populated with the registration information string which will appear on the about form. This routine does not return a value to EAX, so we can conclude that this is a procedure. After playing around with this procedure, I found that it will return the following string if registered: Registered Version /n Single User License /n Lifetime Free Upgrades We can recreate this Procedure to return this string like this:

Procedure GetModeVersion(s:pWideString); stdcall;
Begin
s^:='Registered Version'+#13+'Single User License'+#13+'Lifetime Free Upgrades'; //Write to the String.
End;

Finally, we will look at the final function RegisterApplication. Since we are making this registered by default, this function we not be used, but we will add this anyway to complete the dll. Let's restart the application. After a quick string search, we can find the call to RegisterApplication.

Let's run the application and enter some random registration details.





As we can see, this is passing two strings to the function. When we return from this routine, we see that al is populated with a 0. Since the next function tests whether or not al is equal to 0, we can determine that al is a boolean where 0=false and 1=true. That means that the RegisterApplication function takes two constant(unchanging) strings as parameters and returns a boolean. We can recreate this function like this:

Function RegisterApplication(CONST s,s2:string):Boolean; stdcall;
Begin
Result:=true;
End;

Now that we have recreated these functions, our finished code will look like this:

The only thing left to do is to replace the dll in the directory with the one that we created, patch the integrity checks in the modules(not shown for legal purposes), and add a fake key in the registry(not shown for legal purposes).

Now that we have done this, we will discuss some ways for the author to improve this protection. Since this dll contains only licensing information, it makes it easy for us to duplicate. However, if the company were to add some core application functions along side of these license check routines, it would make recreating the dll much more difficult. They could also protect each individual module with asprotect to make it necessary for us to unpack each file in order to bypass/patch the integrity checks.

With that said, I hope you enjoyed the tutorial. Feel free to ask any questions you have below. Until next time, happy reversing.