Showing posts with label securom. Show all posts
Showing posts with label securom. Show all posts

Saturday, September 12, 2020

I wanted to practice some Java and Python and what better way for me than writing some RE tools. I decided on my SecuROM protected executable. While I was at it I loaded up the executable in Olly and even x64dbg and to my surprise it no longer ran under a debugger. 

It took me a while to figure out that I had fiddled with Scyllahide's settings a few years back. I found out the reason it didn't work no more. A hook of NtUserFindWindowEx caused SecuROM to detect the debugger somehow, whether intentionally or it's a byproduct of something


So far, no clue but after I finish up my tooling I may find out what it is, could end up being a good anti-debug check.

Sunday, April 3, 2016

Great article on API hooking!

As I was browsing RE related blogs and articles I stumbled upon this gem.

Amazing article that gave me more insight on how to perform more stealthy hooking.

Monday, March 28, 2016

Analyzing the SecuROM 8.10.X VM Part 2

This will be a small post that I will update here-after once I discover more.

If you go back to the previous article, I mentioned the part where SecuROM walks all 100 possible VM contexts and finds the first free one. Well, the table starts at address 0x3BF7C2FC, since all the contexts are allocated from a single Heap(likely created by HeapCreate and later, memory is allocated using RtlAllocateHeap with said heap handle) they are contiguous, so I subtracted the address of one context with the previous in the table and came up with a size of 0x460(1120) bytes for each VM context, this includes the VM Context structure and the scratchpad, which is the area where the virtual registers are written, as well as code being written and executed.

Address 0x3BF7C2F8 is the spinlock value.

Now, when analyzing the first VM program, on the surface it felt like it wouldn't do much, but I actually saw that before it zeroes out the busy flag, it recursively(although I could be wrong) called the VM a dozen more times with different arguments, that much code will take very long to trace. In addition to this, it also writes and executes code off the scratchpad.

Now, let's analyze the first obfuscated VM handler from the previous post:
mov esi,dword ptr ds:[ebx+4]
add esi,dword ptr ds:[ebx+0C]
add esi,4
push dword ptr ds:[esi]
pop edi
mov dword ptr ds:[ebx+400],4
sub esi,dword ptr ds:[ebx+400]
push dword ptr ds:[esi]
pop esi
mov cl,byte ptr ds:[ebx+10]
push eax
xor eax,esi
xor eax,dword ptr ss:[esp]
add esp,4
shl eax,10
shr eax,18
xor al,2A
add byte ptr ds:[ebx+10],al
mov eax,3BF7C894
push edi
push eax
mov eax,esi
shl eax,18
shr eax,18
ror al,cl
xor al,78
shl eax,2
add eax,ebx
mov edi,eax
pop eax
push eax
pop dword ptr ds:[edi]
pop edi
push edi
pop eax
sub al,cl
xor eax,00B42D00
add dword ptr ds:[ebx+4],8 <-- Update VM EIP with 8 bytes.
jmp eax <-- Jump to computed handler.

mov esi,dword ptr ds:[ebx+4]
add esi,dword ptr ds:[ebx+0C]
add esi,4

This part fetches the current VM EIP(which is a delta from the VM entry point), adds the entry point to compute the pointer to the opcodes. "add esi, 4" increments the VM EIP by 4 bytes.

push dword ptr ds:[esi]
pop edi

Translates to exactly mov edi, dword ptr ds:[esi] which moves the new opcode into register EDI.

mov dword ptr ds:[ebx+400],4
sub esi,dword ptr ds:[ebx+400]

This here is both boring and interesting, it's boring because it decrements the VM EIP by 4 bytes, but it's interesting that instead of fetching the opcode first, then incrementing by 4 bytes to get the next one, it does it backwards. It's also interesting, because offset 0x400 in the VM context is referenced elsewhere lots of times. Anyway, to basically simplify this, it's the equivalent of "sub esi, 4".

push dword ptr ds:[esi]
pop esi

Translates to "mov esi, dword ptr ds:[esi]". Again, moving an opcode into register ESI.

mov cl,byte ptr ds:[ebx+10] moves the modifier from the VM context into 8-bit register CL.

push eax
xor eax, esi
xor eax,dword ptr ss:[esp]
add esp,4

While eax isn't referenced before, it contains the address of the start of the handler, in my case it was 0x38F78918.
The address of the handler is xor'ed with the opcode we extracted into ESI. 38F78918 ^ 687ADD02 = 508D541A. And because push eax, pushed 38F78918 to the stack, xor eax,dword ptr ss:[esp] translates to 508D541A ^ 38F78918 = 687ADD02.
To summarize this uses the xor method of swapping values, which can be translated as mov eax, esi.

shl eax,10
shr eax,18
xor al,2A
add byte ptr ds:[ebx+10],al

So one of the opcodes we previously moved into ESI, then into EAX is used as a modifier, by adding it to the previous one(which by default is always 0x95). The shifts there essentially chopping off bits to extract the 3rd byte of the opcode and adds it to the default value to equal 0x72(1 byte add).

mov eax,3BF7C894
push edi
push eax
mov eax,esi
shl eax,18
shr eax,18
ror al,cl
xor al,78
shl eax,2

The constant being moved to EAX will be discussed later on as it is saved on the stack for later use. We will focus on mov eax, esi which moves the value 687ADD02 which we figured out how it was produced earlier, into register EAX, the next two shifts essentially extract the 4th byte, which is 0x2 and right rotate it with the default modifier 0x95 stored into CL. Since 0x95 is larger than the 32 bits, the value should wrap around, in the end we get a value of 0x10, which I suppose can be translated as al << 3. The value is then xor'ed with 0x78 and produced 0x68 which is then left shifted by 0x2 to produce 0x1A0.

add eax,ebx
mov edi,eax
pop eax
push eax

So what happened before, all that junk above just to compute offset 0x1A0, then the value from EBX is added to 0x1A0, EBX contains the address of the VM context. Now remember the constant before, 0x3BF7C894, it's moved to EAX via the first pop eax, and then it's pushed again. So pop eax, push eax can be translated as mov eax, dword ptr ss:[esp].

pop dword ptr ds:[edi]

The constant is stored to where EDI points to via that pop. It points to offset 0x1A0 in the VM context.

pop edi
push edi
pop eax

So what happens here? Well, pop edi moves one of the opcodes into EDI, then pushes it onto the stack again and pops it right back into EAX. So we can translated this as either mov eax, dword ptr ss:[esp] or if we take into account the pop edi instruction, then mov eax, edi. The opcode was 3852A852.

sub al,cl
xor eax,00B42D00

So, the last byte of opcode 3852A852 is subtracted by CL(0x95) and produces value 3852A8BD. which is xor'ed by 00B42D00 and the final value in EAX is 38E685BD.

add dword ptr ds:[ebx+4],8 <-- Update VM EIP with 8 bytes.
jmp eax <-- Jump to computed handler.

Pretty self-explanatory. VM EIP is incremented by 8 bytes, and we jump to the address in EAX, which is the next handler.

So what this handler did in a nutshell, is not only store the constant 3BF7C894 into 0x1A0(this could be a virtual register), but also compute the address of the next handler. So we can probably simplify this handler to "mov reg, imm" or as "mov reg1A0, 3BF7C894".


UPDATE:

Let's look at the handler that we jump to, which is the second handler. First thing to notice is this is a 12 byte opcode, and not 8 as with the previous one.

mov esi, dword ptr [ebx + 4]
add esi, dword ptr [ebx + 0xc]

Standard VM EIP delta, with the VM address being added to it.

add esi, 4
mov edi, dword ptr [esi]

One opcode being loaded into EDI, note again how ESI was incremented by 4, so it's loading the second DWORD opcode. The value is 02C4EC00.

mov dword ptr [ebx + 0x400], 4
sub esi, dword ptr [ebx + 0x400]
push dword ptr [esi + 8]

As ESI is decremented by 4, then a value at offset 0x8  is pushed on the stack, which is the 3rd opcode. So it's stored for later use.

push esi
xor esi, dword ptr [esi]
xor esi, dword ptr [esp]
add esp, 4

Again, standard swap using the xor trick. So essentially, this is mov esi, dword ptr ds:[esi]. We just loaded the first opcode.

mov cl, byte ptr [ebx + 0x10]

The modifier in the VM context is loaded into CL.

push eax
xor eax, esi
xor eax, dword ptr [esp]
add esp, 4

This piece translates to exactly, mov eax, esi.

shl eax, 0x10
shr eax, 0x18
xor al, 0x40
add byte ptr [ebx + 0x10], al

The value in EAX is E518721C, (0xE518721C << 0x10) >> 0x18 = 0x72 ^ 0x40 = 0x32 - we are extracting the third byte, decrypting it with the xor and updating the modifier.

push eax
xor eax, edi
xor eax, dword ptr [esp]
add esp, 4

Don't even need to see this in action to know that it is doing mov eax, edi.

xor eax, 0x2c4ec60

So 02C4EC00 ^ 02C4EC60 = 0x60.

sub esp, 4
mov dword ptr [esp], eax

This can simply be interpreted as push eax.

push esi
pop eax

Seems like we are moving what was in ESI to EAX e.g mov eax, esi.

shl eax, 0
shr eax, 0x18
rol al, cl
xor al, 0x36
shl eax, 2

This piece is is decrypting the value using the modifier. The first left shift is redundant, the whole operation is as follows: E5 << CL(0x8C) | E5 >> 32 - CL(0x8C) = 0x5E ^ 0x36 = 0x68 << 2 = 0x1A0. Woohoo, so it's our virtual register where we stored our constant before.

push eax
add dword ptr [esp], ebx
pop eax

The value in EAX is now 0x1A0. It is pushed on the stack, EBX is added to it(it contains the VM context address) and is popped back into EAX.

push edi
xor edi, eax
xor edi, dword ptr [esp]
add esp, 4

Translates to mov edi, eax.

pop eax
push eax
neg eax
sub dword ptr [edi], eax

By this point, pop eax moves into eax the value 0x60 that was pushed earlier on. Pushes it on the stack again.. It negates it which is to say -0x60 or 0-0x60 = FFFFFFA0 and substracts it from the virtual register reg1A0 which holds the constant 3BF7C894 to equal 3BF7C8F4.

mov dword ptr [ebx + 0x400], 0x2152f
mov eax, dword ptr [ebx + 0x400]
pop eax

Completely redundant operation. You move the value from EBX+400 to eax, but then do pop eax, which moves the value 0x60 to EAX overwriting the previous value. Which is also irrelevant, because it's overwritten in the next sequence.

pop eax
rol al, cl
xor eax, 0x2c4ec60
add dword ptr [ebx + 4], 0xc
jmp eax

So the first instruction moves the value 3A2245FD which is also the third opcode, rotates the last byte 0xFD with CL(0x8C) to produce the value 3A2245DF and then it's xor'ed with 02C4EC60, so 3A2245DF  ^ 02C4EC60 = 38E6A9BF.
VM EIP is then incremented by 12!!! bytes and we jump to the next handler at address 38E6A9BF.

So this handler essentially does add reg1A0, 0x60, or "add vmreg, imm"?






Monday, February 15, 2016

Have I found the mysterious anti-debug?

In my previous post I mentioned that running the game under a debugger, would, after a while, force terminate the game.
I speculated either the debugger was being found by an API directly, or indirectly via a timing anti-debug.

I did some experiments. And the evidence points to a timing anti-debug. The time it takes to terminate the game is variable, and it turns out, it only happens if the performance of the game is rather bad. In this case, it was Olly 2's fault. There seems to be some kind of bug in Ollydbg 2.01 whereby all threads of a running application are suspended and resumed constantly, the game runs although with a 30-35% penalty. The timing anti-debug sees this, sees that more ticks are being expended than normal and with careful communication between two threads, it calls NtTerminateProcess by spawning several threads that point to a VM program(only of the thread has a different VM program than the rest)..
In most cases, what Olly is doing is normal behaviour, it's how it's usually done, but not in my case, I've observed olly idling and not doing this suspend/resume thing. The bug seems to disappear if I(at least in my case) I hit a memory breakpoint. Then olly is acting normal, and the game does not terminate, or at least not as fast as before, if the avg grows as time passes, because of small slowdowns, then it will terminate eventually.

I looked at my trace log of one of the obfuscated threads, lo and behold, RDTSC on address 3955DEA9(quick reminder there is no ASLR). The result of RDTSC is stored in EDX:EAX, these values are later used in a loop and are encrypted and stored in a table.
Now that I know what is what, I can better understand the underlying algorithm. One thing is certain, the mystery is solved.

Quick reminder that timing anti-debugs are in my opinion, the most difficult to handle, it isn't as easy returning 0 on GetTickCount.

Wednesday, February 10, 2016

Hunting for the mysterious anti-debug.

Well, it's probably not that mysterious. But let me point you to my last post, where I mentioned the problem briefly in the last paragraph.

I mentioned there were two threads, one is 3939EF70 and the other is 3939F9C0. Since the game utilizes no ASLR, and SecuROM expects most addresses to be the same on any system(hardcoded), there is no need to recompute them for each system.

The first thread to be started is 3939EF70, the thread is extremely obfuscated, here is but a sample of it

lea esp,[esp-4]
mov dword ptr ss:[esp],ebp
mov ebp,esp
sub esp,4
mov dword ptr ss:[esp],32E
xor dword ptr ss:[esp],00000326
sub esp,dword ptr ss:[esp]
lea esp,[esp-4]
mov dword ptr ss:[esp],esi
mov eax,-1D9
mov eax,dword ptr ds:[eax+3C04C67D]
xor eax,0000911A
mov dword ptr ds:[3C04C4A4],eax
mov eax,-0E7
mov eax,dword ptr ds:[eax+3C04C58F]
xor eax,00009A12
mov dword ptr ds:[3C04C4A8],eax
mov eax,-55
mov eax,dword ptr ds:[eax+3C04C4F9]
add eax,dword ptr ds:[3C04C4A8]
mov dword ptr ds:[3C04C4AC],eax
call 3939EFE5
add dword ptr ss:[esp],3E
push dword ptr ss:[esp]
sub dword ptr ss:[esp],3B
push ebx
mov ebx,dword ptr ss:[esp+4]
xchg dword ptr ss:[esp],ebx
xchg dword ptr ss:[esp],ebp
mov ebp,dword ptr ss:[ebp]
sub ebp,13
xchg dword ptr ss:[esp],ebp
mov dword ptr ss:[esp+4],A60004C2
jmp short 3939F00F
retn 4

This is from the tracer, in reality some of these instructions are overlapped. This thread seems to, initially, just loop over, checking for a value if it is bigger or smaller than another at particular hardcoded addresses, and jumps to different piece of code, but they all ultimately end at the same place initially, GetTickCount,+120 seconds to the value returned by GetTickCount, and then Sleep(120 seconds).

It repeats the aforementioned Sleep infinitely, until the other thread 3939F9C0 signals it, by writing different values to these hardcoded addresses, thereby making that thread 3939EF70 take different branches. At some point, 3939EF70 starts another thread with CreateRemoteThread that executes the VM. Interestingly, there is no synchronization between the threads, both threads rely on the fact that the either of them will Sleep when one is modifying the same addresses.

I mentioned an anti-debug, that's right. The game runs under a debugger for as long as thread 3939F9C0 allows it to, then randomly between 5-30 minutes(rarely longer) the thread calls NtTerminateProcess.
I've been speculating this is a timing anti-debug, that there is some 'avg' value that goes up as the debugger handles various events and generally slows down the game by 20-30%. As soon as this value crosses some threshold, it calls NtTerminateProcess. This seems to be further reinforced by the fact, that if I were to start the game under a debugger, detach, the game would never terminate. If that is not the case, then I am being detected by a different method.

Oh yes, I managed to manually patch the exe to disable code verification. Now I can tamper with some of the code(except the packed code which I can only modify at runtime).

Sunday, January 31, 2016

Analyzing the SecuROM 8.10.X VM.

I want to thank ARTeam for providing the docs on SecuROM 7.30 VM they really helped and are mostly still relevant today.

That said, I have not worked on SecuROM 7.30 ever, but I believe the VM has changed since then.

Here is an overview of the VM initialization.

When entering the VM, an argument is pushed to the stack. It's a pointer to a pointer to the VM opcodes. I call this argument a "program".
The dummy call after pushfd is used to get the address of the VM.



In the picture above several things happen. A spinlock is created by the thread which enters the VM and will initialize the context, all other threads, if any, will wait till the first thread has finished the initialization.

Then SecuROM uses the loop x86 construct to loop over all 100 possible VM thread contexts, and finds the first free one. The busy flag 0x66666666 indicates if a thread is busy or not. I should note that SecuROM 7.30 only supported up to 10 threads, SC 8.10 supports 100.

After the first free context is found, SecuROM jumps to the following code which sets the busy flag.

lea edx,[ebx+24]
mov dword ptr ds:[edx],66666666

then the VM context is zeroed out, but care is taken not to zero out the busy flag. Afterwards the lock is removed and the jump "je short 38D702FE" takes us to the last step of the initialization.


pop ebx loads the VM context for this thread in ebx.

sub dword ptr ss:[esp],7 subtracts 7 bytes from the VM function address which I mentioned above that it is pushed to the stack with a dummy call so it ends up as 38D70280 in this exe.

This part fills the VM context struct. I've taken the liberty of adding captions next to the instructions which are self-explanatory.


Next is this obfuscated code.


In a nutshell, it fetches the delta to the pointer to the opcodes, adds the VM entry point, and fetches 2 DWORDs(aka 8 bytes).

CPU Disasm
Address   Hex dump                 Command                                                      Comments
38D7035A    8B70 04              mov esi,dword ptr ds:[eax+4]
38D7035D    8B00                   mov eax,dword ptr ds:[eax]

The first 4 bytes of the opcode is the modifier, the next 4 bytes is the obfuscated address of the handler.
The modifier is used to calculate the next handler address. The one in the VM context is updated with this new one, after some xor and shifts are performed.

The "encrypted" address of the first handler is decrypted with a XOR.
xor esi,48371826
 It's then copied to eax.

Finally

CPU Disasm
Address   Hex dump                 Command                                                      Comments
38D70396    B9 19000000       mov ecx,19
38D7039B    83F1 1D              xor ecx,0000001D
38D7039E    01D9                   add ecx,ebx
38D703A0    8301 08              add dword ptr ds:[ecx],8 <-- Add 8 bytes to VM EIP
38D703A3    FFE0                  jmp eax

The VM EIP(program counter) is incremented by 8 bytes, and we jump to the address of the first handler.

Here comes the juicy part. The jump to first handler goes to this code

Step 1.

First, ebx+20 is updated with the address of the next pseudo handler, for a lack of a better word. And if we follow the jump we end up where the actual first instruction is executed in this particular handler.

Step 2.

and if we follow the jump we end up at what I call the "dispatcher". 

Step 3.

The dispatcher adds the VM entry point to the value added in ebx+20 to form the address of the next pseudo handler.

Basically, from what I understood, a single handler which is usually a sequence of instructions has been split into several small pseudo handlers each reached in three steps. In my opinion this is just obfuscation to slow down reverse engineering.

Sometimes in Step 1 there is an additional instruction that moves a value in ebx+400, which is usually used to substract 4 bytes from the stack pointer.

Now, if we follow the each jump and where it leads to, remove all jumps and dispatcher code, the first handler's code is basically this.

mov esi,dword ptr ds:[ebx+4]
add esi,dword ptr ds:[ebx+0C]
add esi,4
push dword ptr ds:[esi]
pop edi
mov dword ptr ds:[ebx+400],4
sub esi,dword ptr ds:[ebx+400]
push dword ptr ds:[esi]
pop esi
mov cl,byte ptr ds:[ebx+10]
push eax
xor eax,esi
xor eax,dword ptr ss:[esp]
add esp,4
shl eax,10
shr eax,18
xor al,2A
add byte ptr ds:[ebx+10],al
mov eax,3BF7C894
push edi
push eax
mov eax,esi
shl eax,18
shr eax,18
ror al,cl
xor al,78
shl eax,2
add eax,ebx
mov edi,eax
pop eax
push eax
pop dword ptr ds:[edi]
pop edi
push edi
pop eax
sub al,cl
xor eax,00B42D00
add dword ptr ds:[ebx+4],8 <-- Update VM EIP with 8 bytes.

In my case, this handler basically calculated the address of another handler.

This isn't an exhaustive analysis of the Securom 8 VM, it's but a scratch of the surface. Furthermore, I have not identified the VM exit procedure.

Denuvo and VMProtect are the same?

Recently I've been reading on Denuvo, and how certain code seems not similar but identical to that of VMProtect. Russian websites are also saying that Denuvo<=>VMProtect indicating that perhaps the two companies are sharing the same code base. That certain features in VMProtect appear in Denuvo and disappear in VMProtect, and vice-versa.

Here is the article in question (Russian).

Friday, November 7, 2014

FIFA15 and the new DRM Denuvo

So at first I speculated it had SecuROM, just like FIFA14, but then we(when I say "we" I do mean the internet) find out it has a new DRM called Denuvo and this is why there is no crack yet, it's new and it will take time for it to be studied and bypassed, and maybe the rather low chance of there being no crack at all.
It took me 30 days just to run SecuROM under a debugger, so it's not unlikely the same thing to happen with a new DRM.

I've no idea what Denuvo employs, frankly I do not care, but if it gains traction and remains uncracked, things will get "interesting".

To say this in simple words, there is no crack yet, any crack you do find googling will likely turn out to be a virus.

Addendum: The upcoming GTA V game will also use this DRM. Seems like GTA V will not use Denuvo afterall, http://www.incgamers.com/2014/11/grand-theft-auto-v-will-not-use-denuvo-drm-says-company-co-owner

Sunday, September 14, 2014

I have not posted in a few days. The reason is because I was preoccupied by SecuROM, for two days straight since my last post I had been working on my dumped exe, figuring out why it crashed beyond a certain point. It took me 2 days, almost sleepless and not eating at all to figure out the problem.

It was difficult as my trace was inconclusive, it showed the main thread simply continuing execution to some invalid address. After working on it for days, I found out that my trace was being b0rked by OllyExt, a plugin for Ollydbg 2.01, so I disabled that and found my problem.

The offending code was a huge jump table, I guess at some point execution jumped to that location, but the jump table itself had unfilled addresses to pointers to the FMOD Sound System.

From then on because of my poor pointer arithmetic skills and almost no knowledge of the PE format, it was a whole day before I wrote a small tool to identify the pointers in the original exe to those in the FMOD Sound system DLL(s). This was further delayed by some unknown bug where the index of an exported function did not match the index of the name array, if it was a C unmangled exported function. All C++ mangled/decorated functions's indexes into the name array were correct.

Then I generated my own table of GetProcAddress-es to include in my stub. After that execution of the exe continued, till I stumbled on another problematic area, of some address not being correct, one that is filled by the SecuROM VM before OEP is reached.

So thats going to take some more days.

Thursday, September 11, 2014

RtlUserThreadStart modification.

And back to SecuROM folks. Two days ago I stumbled on some stuff by accident. Turns out, SecuROM modifies the IAT of some modules(predetermined I believe) during runtime, and replaces pointers to various kernel routines such as CreateThread,LoadLibraryExA,LoadlibraryExW,LoadLibraryW to its own obfuscated routines, this in several modules.
I wrote my own tool to repatch back to the old routines. It worked fine after I patched back the old pointers, with the exception of RtlUserThreadStart, securom gets the address of this routine(via GetProcAddress, not in IAT of any module), and modifies this jump at RtlUserThreadStart+0x8, to point to a trampoline jump in a codecave in ntdll.dll, and then another jump back into securom code. If this code is not executed, securom cannot continue, it just waits.

Tuesday, September 2, 2014

SecuROM v8.10 might pack more than I thought.

Once you bypass the anti-debug APIs, you realise that bypassing those is the easy part, now I feel a bit ashamed that it took me 30 days just to bypass them. Oh well.

I've identified a few threads that are started before OEP which are essential, I've only just started to analyse them, they are obfuscated so reading the assembly will be difficult.

A small sidenote unrelated to all of this. There is a method on the internet for finding out the version of securom, searching for the string 'AddD' will show a version number next to it, for Securom v8, this method no longer works, there is a version displayed, but it's not correct.

Friday, August 15, 2014

Spotcheck/Triggers in SecuROM.

Spotcheck/Triggers are what the developer of SecuROM, Robert Yates, calls the piece of code which is responsible for altering the game if tampering of any kind is detected.

Altering like making the final boss in Crysis 3 invincible, or making the ball in Fifa 14 unusually large. These are not bugs/glitches, they are intentional. They are, however not always caused by tampering with the game, but sometimes because of an installation gone wrong with the game, and usually a reinstall should resolve this. Worst case scenario, it's because of some piece of malware running on the system.

Once I was able to run the game under a debugger, it would suddenly get terminated after a while. I identified two threads that were responsible for this and brutally killed them, this didn't affect the game and it was no longer being terminated.

Saturday, July 5, 2014

Some insight about Process Virtual Machines.

So, I understood more about Process VMs, simply last night, I was all of a sudden aware out of the blue of how it works, roughly.

I also found a sample VM implementation, the one which is supposedly used in packers/protectors, albeit probably not as advanced, but still worth the read. Here's the link http://syprog.blogspot.com/2011/12/simple-virtual-machine.html

Anyway, I guess it's sort of a misconception that a VM executes anything, it does not, the VM instructions are simply "interpreted" i.e if  the instruction is MOV REG_DEST, REG_SRC, you are the one that must handle this operation.

I might write my own VM implementation, just to learn more.

Wednesday, July 2, 2014

IDA is too glorified for x86/x64 RE.

I only mentioned x86 and x64, because while Ollydbg is a better debugger for those(and it's free), it cannot debug other platforms, such as ARM. It also lacks a decompiler.

But anyway, I see people mentioning IDA like it's the go-to tool for RE, it's not. I've had more success in RE-ing SecuROM than IDA ever has let me.

Simply, when it comes to x86/x64 it's only good for static analysis of binaries that are not protected. Once we go into packing,antidebugging and obfuscation, it's useless not as good as Olly.

P.S
Ollydbg x64 is in development.

Friday, June 20, 2014

This is what SecuROM v8.10.008 packs so far.

I've identified the following anti-debug techniques.

ZwQueryInformationProcess, the parent process PID is stored in the InheritedFromUniqueProcessId field of the _PROCESS_BASIC_INFORMATION structure, which is then used in an OpenProcess call, which opens the parent process. No idea what happens when the call is made.
CreateFileA on the parent process, afterwards call to ReadFile, SecuROM tries to read the PE header supposedly.
Then we have various calls to CreateFileA on various files like ntice,sice,jcdspy etc.
FindWindow searching for various applications's windows, some of which are at or over 10 years old.
A call to EnumWindows with a custom callback function.
NtQueryObject call to check for the DebugObject.
ZwQuerySystemInformation with the SystemKernelDebuggerInformation class(0x23) which doesn't seem to indicate a debugger under Windows 7 x64.
And obviously, calls to IsDebuggerPresent,CheckRemoteDebuggerPresent,GetTickCount,QueryPerformanceCounter,GetSystemTime.

This is by far an exhaustive list. I've barely scratched the surface.

On a sidenote, GetTickCount is proving to be much more difficult to beat. Because if GetTickCount is patched to return 0, I end up getting an error code value of 2001 meaning Win95 not supported, oddly, GetTickCount was introduced in Windows 2000.

Monday, June 9, 2014

Process Virtual Machines.

Understanding SecuROM takes time, but even with time I still cannot understand the VM implementation it utilizes, no idea when it enters the vm, when it exits, or how to follow what it does. At this point I am unsure how to analyze SecuROM further.

If anybody has any tips about Process Virtual Machines, something that will be useful in unpacking this, comments are welcome.

And after asking a person, he told me the SecuROM version used in Crysis 3 is 8.10.008.

Friday, June 6, 2014

SecuROM is a tough beast.

I've been battling the protection of Crysis 3 for 3 days straight, no progress whatsoever. I have olly loaded up with many different anti anti-debug plugins and none of them seem to work against SecuROM.

[8/6/2014] A small edit to clarify if it wasn't clear, I removed the EADRM protection, it was easy as pie, but at the OEP where I would've expected Crysis 3's code to start I ended up with the SecuROM code.

RELOADED/SKiDROW, if you are reading this(and it's very likely that you aren't). Am I to understand that you never managed to beat SecuROM in Crysis 3? Because SecuROM is still there in your cracks and you only exploit the license manager to make the game work.
Sorry, my ego got the best of me.

Regarding EADRM in general.

So while I was writing my Crysis 2 articles, I found out something, the OEP for what I can assume is every game released in the past few years via Origin, is stored in the actual .exe, near the end of the file, just after the four characters IREW(all capital), as in the 4 bytes after IREW is the OEP. So writing those down, adding to them the image base(and working out any relocation that might happen), you are at OEP, you put a HW breakpoint for instance on execution on the OEP, once you break you can just dump, all that's left is to fix imports.

That said, Crysis 2 was easy as pie to unpack, but Crysis 3 after unpacking has another layer of protection, this time much more advanced for the average joe(aka me) to unpack. Robert Yates, the guy who cracked SecuROM a while back told me that Crysis 3 uses an older version of SecuROM, obviously not that old, probably 8.X.
For now, SecuROM is beyond me.

Addendum: Fixed typo, it was IREW and not IWER.

Update 8d/2m/2016. The information above is no longer relevant, Origin have updated their DRM.

Wednesday, June 4, 2014

Reverse Engineering. Unpacking Crysis 2! The actual stuff.

Before I continue, I want to stress that I legally own both Crysis 2, and Crysis 3 on Origin.

Now, I want to first say that my experience with RE is very limited, I don't really know ASM as well I should, nor do I know anything about the PE(Portable Executable) format. Or anti-debugging techniques and how to bypass them.

The tools used by me:

  • Ollydbg 1.10 with the following plugins: HideOD,StrongOD,phant0m,HideDebugger. Can't tell you which combo of options(anti anti-debug options) work, just try them all, until the executable does not crash, gives exceptions, exits etc.
  • Ollydbg 2.01 with OllydumpEX for 2.x, no other plugins.
  • Hex Editor


Much of our work will be done using Ollydbg 2.01, since Ollydbg 1.10 doesn't seem to like some patches that will be required. And much of our work will be done on the file called awc.dll, located in the Core folder, it's part of EADRM. It's responsible for unpacking and launching Crysis 2.

A few important abbreviations to remember before we begin:

  • OEP - Original Entry Point.
  • IAT - Import Address Table.
  • EP - Entry Point.
  • EIP - Extended Instruction Pointer.
  • RVA - Relative Virtual Address.
  • VA - Virtual Address.
  • JMP - Jump Instruction.
When it comes to packing/unpacking, OEP refers to the entry point the way it was BEFORE the executable was packed. Most packers though, also destroy the Import Table and the executable does not know where to find say, the function Sleep, or say CreateProcess. So the unpacker stub basically does a few calls to LoadLibrary and GetProcAddress and rebuilds it, this doesn't mean it's as simple as using Import Reconstructor to fix things. In our case, it might require manual work to fix this.


[Deleted]

[18/9/2014]
The article was "useless", please read this instead, Regarding EADRM in general.

Reverse Engineering. Unpacking Crysis 2!

It has been a long time since I wrote anything in the blog, thought it might be time to share some experience.

So, what is so special about Crysis 2? Isn't it a really old 2011 game? It's special in my heart, it all started in February of 2011, Crytek had released the DEMO Multiplayer of Crysis 2 and after having tried it for the first time, I fell in love immediately with the multiplayer component. Here came March 21st and March 22nd, the game came out, but I couldn't buy it then, so I patiently waited for a cracked version to appear, astonishingly, it took 2-3 days for somebody to release a crack, meanwhile there was a non-cracked version available.

So, what did I do? Well, I tried to crack it myself, of course! Did I succeed? Absolutely not! I didn't know a thing about RE(Reverse Engineering) or ASM(Assembly), but I still tried for a while.

I played the Singleplayer, after a cracked version was released, I loved how spooky and eerie the story felt, because it was saying the suit was alive and could think for itself. The story was all about the suit. Graphics were as always, pretty good. But the AI was dumb, really dumb.

After I finished the singleplayer, I kept wondering, how do I play the multiplayer? I couldn't. After a while(a month or two?), something amazing was released, something I didn't believe was even possible. A multiplayer crack! However strange as it may seem, it only worked in limited hours, between 16-21PM UTC. I never figured out how it worked.

Did I play? Yes, oh my god yes, the multiplayer was really competitive, it took skill to aim. After a while, I found a website that was selling Crysis 2 serial keys for just $16 dollars, even as low as $11. Should have noticed the signs. The key was legit, it worked fine up to the moment GameSpy shutdown in 2014 May. Yes, from the $11 dollar price of a game not even 2 months old, the sign was obvious, it was dying and sure enough, after about 3 months, Crytek stopped patching it, abruptly, and there was ZERO communication from them TILL the Crysis 3 announcement in the summer of 2012. I must stress the word ZERO.
The game was left unpatched, with various GAMEBREAKING bugs, such as the infamous Scar+Laser bug, which made you strafe faster and was abused a lot. And cheaters, that could bypass the votekick system easily, very easily.
Hint: Same thing happened to Crysis 3.

So, there you have it. Much of 2011 and 2012 was Bitcoin and Crysis 2, mine and play and play and mine. Those were the days!

Actual unpacking bits in next article.