Obsidium fatality. Bypass the trial protection of the popular protector

Kisame

Kisame

Kisame Hoshigaki
 
93
Reputation
1
49
18
Drachma
1,533
Rating - 0%
0   0   0
Today we will continue talking about popular program protections and how to bypass them. Next in line is Obsidium , which is considered one of the most serious tools along with VMProtect and Themida. Among the declared functions - a complete gentleman's set: virtualization, anti-debugging, VM detection, memory protection, integrity checking, import protection, its own API for integration into a user program, and other goodies that complicate the life of a simple hacker.

Using the example of a program using one of the latest versions of Obsidium, let's try to analyze the weak and strong points of this protection. In an article devoted to another popular protector - Enigma, I talked about a popular method of protecting an application among developers: the user is given a trial period of working with the program - you can use it for a certain time or perform a certain number of launches. Obsidium also has such an opportunity. After downloading a demo version of protection from the official website (the latest current version is 1.7.3.3), we launch it.




To begin with, as we are advised, we will create a new project and in its settings we will indicate the protection of the application in the form of a trial period. To do this, click the Settings button with gears in the left vertical panel and open the Time trial tab, second from the right.



Setting up a trial period for the program

As you can see, there is the same gentlemanly set of functions as in Enigma:

  • trial until a certain date;
  • trial for a certain number of days;
  • trial for a certain number of launches.
The purpose of the four input fields in the lower left part of the window under the general heading User-defined trial counters seems a bit unclear. In fact, as I said, for those fastidious users who don't have enough standard protection in terms of time or number of launches, Obsidium offers a set of its functions for integration into the program. As one of the options, the developer can set his own trial counters, controlled directly from the code during program execution. These are four 16-bit integer variables that are stored in the system until the next program start, the values of which can be read with the int obsGetTrialCounter (DWORD dwCtrIdx) function and decremented with the bool obsDecTrialCounter function (DWORD dwCtrIdx, short wValue). This function can be used, for example, if we want so that the program, after ten saves, blocks the Save function and continues to work as if nothing had happened, without further opportunity to save the file to disk. This toolkit provides users with more flexible trial management options.



Protection is installed!

After setting the necessary protection parameters, click the second button from the bottom in the left panel with the inscription PROTECT, then in the Executables tab, select the file of the protected program and, finally, click the Protect All button. Now our application is protected by the Obsidium demo, which we will be reminded of by an annoying window every time it is launched.

Having trained on cats, let's move on to hacking the application. So, we have a trial version of the program, which DIE identifies as follows:
Code:
Obsidium v1.5.4.x - [ v1.6.x.x - 1.x.x ] - Obsidium Software - www.obsidium.de *ACM , Overlay : FE4711... Nothing detected
At first glance, it is obvious that loading this into a disassembler is completely useless: the code is highly compressed or encrypted (in fact, both). The sections are empty, only four functions are available from the import. Let's try to load it into the debugger right away.

We'll use x64dbg, because it has wonderful plugins Scylla and Scylla Hide, which will be very useful to us. For example, in order not to fire the debugger, there is a special profile in Scylla Hide, sharpened exclusively for Obsidium. Turn it on and start tracing.

Walking along the insane protector code is a rather tedious task and, in addition, unsafe, because Obsidium, like other "adult" protections such as VMProtect, is able to control the time it takes to pass certain sections of the code inside itself. No Scylla Hide will help us to hide our presence. In addition, we, as usual, want to do everything as quickly and at a minimum cost, so we just let the program run before the main window appears on the screen.

The program runs perfectly and even interrupts - Scylla Hide perfectly fulfills its purpose. At this moment, we see the decrypted and unpacked module, which we will try to dump using the same Scylla. To do this, we stop somewhere inside the code of the main module and make an IAT autosearch relative to this OEP. After that Get Imports produces a very long list of errors, but it still builds the import table.

We painstakingly delete the erroneous nodes marked with red crosses and dump the module. Everything seems to be fine, we seem to have received a clean module with the protector removed, but, unfortunately, this does not always work from half a kick. In particular, after this procedure, our module refuses to start - it does not give any error, it simply exits silently.

On closer inspection, it becomes clear why: the entry point was found incorrectly, it points to a completely left empty procedure. Finding the right entry point, in theory, is possible (as will be shown below), but that's not even the point. In principle, in some cases the problem can already be considered solved and you can start drinking champagne - for example, if the module is written in dolphi, BASIC, hang out and the like. In this case, it is already quite suitable for loading into the reverse engineering tool. But what can I say, even an ordinary compiled module is suitable for reverse - for example, you can find a place for an inline patch and write a loader or disassemble an algorithm to create a keygen.

Let's try to develop the last idea technically. As I said, the module has only four imported functions: GetModuleHandleA, MessageBoxA, RegOpenKeyExA, and ImageList_Add. First, let's set a breakpoint on GetModuleHandleA. The program starts, and even breaks the breakpoint a couple of times, but after that the debugger loops with endless attempts to exclude by ACCESS_VIOLATION. The protection has clearly burned the debugger, and ScyllaHide is no longer helping.

A negative result does not discourage us from working in this direction, and from old memory we are trying to repeat this trick with ReadFile. Surprisingly, the breakpoint works quite effectively several times and does not get stuck. We look closely at the call stack - the first few times it contains a complete mess, but at some point a meaningful sequence of nested calls appears, starting from the bottom with a call to the thread of our program from BaseThreadInitThunk and ending at the top in the depths of the user32 and gdi32full modules. It was our program that first called LpkDrawTextEx, and he got to the disk for the font.

We carefully study the code of the procedure running in this thread located at the very bottom of the list, and find the beginning of this procedure itself - 0xB634EC. So, we have found a potential entry point and now we have something to hook on during the debugging process.

Restart the program, display the memory state at this address in the dump window. As you might expect, the memory is pristine and filled with zeros. We start the program, again stopping at ReadFile. Literally after a couple of breaks, we see the ready unpacked code at the address 0xB634EC. We happily put a breakpoint on it, removing it from ReadFile for clarity. Click on the continuation, and here we stop at the very entrance to the unpacked and decrypted program.

In case we decide to write a bootloader, we've found a good injection site. Now it would be nice to find the code for the inline patch. Logically, to control the license, the program must call Obsidium functions directly from within itself, and not far from the start of the download. We begin to trace the program step by step and literally after a few commands we stumble upon a suspicious procedure 0xB62030, which causes an ignored exception attempt inside itself in approximately the following context:


Code:
02DC091A | 0F0B | ud2 |
02DC091C | 0F0B | ud2 |
02DC091E | EB 01 | jmp 2DC0921 |
02DC0920 | 70 EB | jo 2DC090D |
02DC0922 | 0115 F7F0EB05 | add dword ptr ds:[5EBF0F7],edx |
02DC0928 | D2A4A7 872CEB1E | shl byte ptr ds:[edi+1EEB2C87],cl |
02DC092F | EB 04 | jmp 2DC0935 |
02DC0931 | BD A4FCBFEB | mov ebp,EBBFFCA4 |
02DC0936 | 05 D21DA654 | add eax,54A61DD2 |
02DC093B | 5D | pop ebp |
02DC093C | 8B5424 30 | mov edx,dword ptr ss:[esp+30] |
02DC0940 | EB 03 | jmp 2DC0945 |
02DC0942 | A9 CBF2EBBA | test eax,BAEBF2CB |
02DC0947 | EB 04 | jmp 2DC094D |
02DC0949 | A2 29F963EB | mov byte ptr ds:[EB63F929],al |
02DC094E | 03D8 | add ebx,eax |
02DC0950 | A2 55EBE1EB | mov byte ptr ds:[EBE1EB55],al



It looks a hell of a lot like code where the debugger stumbled periodically as we slowly but surely approached unpacking the program. Immediately after calling this procedure, we see the following code:
Code:
00B63567 | 8B15 ACAEC000 | mov edx,dword ptr ds:[C0AEAC] |
00B6356D | 8B12 | mov edx,dword ptr ds:[edx] |
00B6356F | 8B92 1C030000 | mov edx,dword ptr ds:[edx+31C] |
00B63575 | 8B92 94010000 | mov edx,dword ptr ds:[edx+194] | [edx+194]:L"Unregistered trial version\r\nYou have 30 day(s) left"
In fact, we have no doubts - it is this particular procedure 0xB62030 that calls the Obsidium license check and fills in the information about it in the structure at the address pointed to by ds: [C0AEAC].

So, our initial task - with little blood to completely remove the protector from this module - was doomed from the very beginning: the protection was integrated into the image. The module contains links and calls outside of it; moreover, these links are initialized before the start of the main thread.

If you thoughtfully dig a dumped program into IDA, you can find a lot of such links to Obsidium in the code in the places where the license is checked. Each such call is unique (personally, I did not find repetitive ones right off the bat, even if they perform the same functions), its code is virtualized and equipped with its own anti-debugger. Of course, you can tinker and free the code from all these calls (although this is also not always achievable, because theoretically Obsidium is able to virtualize user-marked blocks of the main program code), but it is still easier to make a loader and inline patch as you like.

However, I promised to reveal a method of bypassing protection for the laziest, without any debugger, reverse and tinkering with the code. Anyone who has read my articles on Enigma has probably already guessed what this is about. And we are talking about resetting the Obsidium trial by external means - using only ProcMon, RegEdit and skilled hands.

Let's say we have a protected Obsibium program that works for a limited period, which we really want to extend. Desirable forever. However, we are too lazy to go into the debugger for this and remove the protection completely. We routinely run ProcMon and study the log of program calls to the registry at startup. Naturally, instantly our gaze will be presented with a huge sheet, the size of which plunges into despondency. However, fortunately, the authors of Obsidium (as well as the authors of Enigma) do not differ much in their imagination, and when searching for Obsidium, there is also an appeal to the key \ HKEY_CURRENT_USER \ SOFTWARE \ Obsidium \ {XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXX for each program).

Without much hope, we delete the key from the registry and restart the program - of course, the trial does not reset. But, as I already said, the creators of these protections do not differ much in their imagination, so we assume that they support the registry check with some cleverly hidden file on the disk. We begin to study the log of access to the file system, and then a surprise awaits us!

The authors of Enigma turned out to be even more original: they, as you remember, stored registration information in a file with an unpronounceable name in a temporary system folder. For this, Obsidium authors have created a special subfolder of their name in the RoamingAppData subdirectory of the current user (the path to the file looks something like this: C: / Users / <Username> / AppData / Roaming / Obsidium / {XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXIDXXX}, GU as in the registry). We delete this file along with the registry branch - bingo, trial has been reset!

IN THE TOTAL

As you can see, not all types of protection of executable files are bypassed with a dashing cavalry swoop: sometimes developers try to make life as difficult as possible for researchers and come up with ingenious anti-debugging methods. However, for any cunning bolt, as you know, you will find a nut with a left-hand thread - the complexity of the tread is sometimes more than compensated by a stereotyped approach to working with the registry and file system. Than understanding people, if necessary, may well use.
 
Last edited:
  • Watchers 0
  • Top