Jump to content
Tuts 4 You

ByTanimsizVM Obfuscator v2.0


Leopar36
Go to solution Solved by Washi,

Recommended Posts

  • 3 months later...
  • Solution

Went for a keygen instead of a full devirtualization. I don't fancy devirtualizing VMProtect stacked on top of KoiVM, so I went with a fully dynamic analysis approach. Code is clear enough though if you are able to set the right breakpoints at the right places. Personally am not a fan of including anti-VM in challenges, it only makes it annoying rather than interesting, but maybe that's just me.

Sample key:

Spoiler

m9shdsqdMUeDkVlB1hR5P/TGknZX433UemIoR9ryfk3qk1TOTa/R87ES0upPIqY4+SMP99G8z7hdTPtodOlskMN5Ionv8yG6d4zMwcvwxg3GMVLCfg0u0lao3C55iLSztKRiLdvPhjS+ydl3QTRbAhm9DxJHUN51pookjSIsjjo=

image.png.a80696d20eaeaadaed6dcd080225eb82.png

Approach:

Spoiler

Getting passed VMP anti-debug and anti-VM:

  • Notice app has anti debug enabled, but these are part of virtualized code so we cannot easily patch them out.
  • Important realization here is that the code might be hidden behind two layers of VMs, but external functions are still used, and they can still be observed. Both VMP and KoiVM use MethodBase.Invoke to call external functions. Therefore, setting a breakpoint on RuntimeMethodInfo.UnsafeInvokeInternal in mscorlib.dll reveals basically everything that it is doing behind the scenes.
  • For the anti-debug, you will notice from the methods that are called that the anti debug consists of calling:
    • Debugger.IsAttached (bypassed by dnSpy)
    • Debugger.IsLogging (bypassed by dnSpy)
    • NtQueryInformationProcess. (bypassed e.g. using ScyllaHide using command line "InjectorCLIx86.exe UnpackMe.exe HookLibraryx86.dll", with a config set to hook on NtQueryInformationProcess, this is the only thing you should enable, if enabling others dnSpy seems to have some trouble with debugging the app).
  • Notice app still doesn't run in a VM, because it has anti VM detection in place. It does so by:
    • Using the cpuid x86 instruction to check for the existence of a hypervisor, happens multiple times in method 0x060003D4. This returns an integer in the 3rd element of the array where the last bit is set to 1 if hypervisor was found, otherwise 0. We can patch this at runtime by setting a breakpoint there and unsetting that very last bit every time it hits.
    • Then it calls EnumSystemFirmwareTables and GetSystemFirmwareTable to get firmware data. If using a VM,  this returns a buffer containing strings with known names (e.g. VirtualBox). These strings are checked in method 0x060003F2. To bypass, set a breakpoint again and simply clear out the buffers returned by these functions.

This will get you passed the VMP anti-analysis. Now onto KoiVM:

  • Notice app still does not let you run it in a VM. The app closes itself and starts a cmd.exe with the message that a VM was detected.
  • A good guess here is that Process.Kill is used to kill itself. Process.Kill uses TerminateProcess to kill itself, which we can easily modify to not terminate the process at all. Set a breakpoint on Process.Kill, find the address to TerminateProcess (e.g. using Go To Disassembly and looking for the call), open the memory window and change the first bytes of TerminateProcess to
    B8 01 00 00 00 C3

    Which decodes to

    mov eax, 1
    ret

    making the function always just return 1 without actually terminating the app. This makes the app run fine now, (it  still spawns the cmd.exe, but you can ignore it)

Finding the key validation algorithm:

  • Now that we have all the anti-analysis techniques out of the way, we can use the same trick to figure out the key validation algorithm. Again, set a breakpoint on RuntimeMethodInfo.UnsafeInvokeInternal but add the following breakpoint condition to reduce some of the noise that you'll get from other threads:
  • System.Threading.Thread.CurrentThread.ManagedThreadId == 1 // or whatever the id of the main thread is.
  • Hitting F5 numerous times after typing in some garbage and pressing the validate button reveals pretty quickly that the key is a base64 string that consists of three parts:
  • [Rfc2898DeriveBytes salt (32 bytes)] [IV (32 bytes)] [Encrypted payload]
  • The first two parts are used together with the hardcoded password "PiskopatYazar" to decrypt the third part using AES-CBC 256bit with PKCS7 padding.
  • A key is considered valid if the decryption succeeds with those parameters.

Keygen is just doing the reverse.

 

 

Keygen.cs

Edited by Washi
  • Like 6
  • Thanks 4
Link to comment
Share on other sites

On 7/14/2021 at 9:21 PM, Washi said:

Went for a keygen instead of a full devirtualization. I don't fancy devirtualizing VMProtect stacked on top of KoiVM, so I went with a fully dynamic analysis approach. Code is clear enough though if you are able to set the right breakpoints at the right places. Personally am not a fan of including anti-VM in challenges, it only makes it annoying rather than interesting, but maybe that's just me.

Sample key:

  Reveal hidden contents

m9shdsqdMUeDkVlB1hR5P/TGknZX433UemIoR9ryfk3qk1TOTa/R87ES0upPIqY4+SMP99G8z7hdTPtodOlskMN5Ionv8yG6d4zMwcvwxg3GMVLCfg0u0lao3C55iLSztKRiLdvPhjS+ydl3QTRbAhm9DxJHUN51pookjSIsjjo=

image.png.a80696d20eaeaadaed6dcd080225eb82.png

Approach:

  Reveal hidden contents

Getting passed VMP anti-debug and anti-VM:

  • Notice app has anti debug enabled, but these are part of virtualized code so we cannot easily patch them out.
  • Important realization here is that the code might be hidden behind two layers of VMs, but external functions are still used, and they can still be observed. Both VMP and KoiVM use MethodBase.Invoke to call external functions. Therefore, setting a breakpoint on RuntimeMethodInfo.UnsafeInvokeInternal in mscorlib.dll reveals basically everything that it is doing behind the scenes.
  • For the anti-debug, you will notice from the methods that are called that the anti debug consists of calling:
    • Debugger.IsAttached (bypassed by dnSpy)
    • Debugger.IsLogging (bypassed by dnSpy)
    • NtQueryInformationProcess. (bypassed e.g. using ScyllaHide using command line "InjectorCLIx86.exe UnpackMe.exe HookLibraryx86.dll", with a config set to hook on NtQueryInformationProcess, this is the only thing you should enable, if enabling others dnSpy seems to have some trouble with debugging the app).
  • Notice app still doesn't run in a VM, because it has anti VM detection in place. It does so by:
    • Using the cpuid x86 instruction to check for the existence of a hypervisor, happens multiple times in method 0x060003D4. This returns an integer in the 3rd element of the array where the last bit is set to 1 if hypervisor was found, otherwise 0. We can patch this at runtime by setting a breakpoint there and unsetting that very last bit every time it hits.
    • Then it calls EnumSystemFirmwareTables and GetSystemFirmwareTable to get firmware data. If using a VM,  this returns a buffer containing strings with known names (e.g. VirtualBox). These strings are checked in method 0x060003F2. To bypass, set a breakpoint again and simply clear out the buffers returned by these functions.

This will get you passed the VMP anti-analysis. Now onto KoiVM:

  • Notice app still does not let you run it in a VM. The app closes itself and starts a cmd.exe with the message that a VM was detected.
  • A good guess here is that Process.Kill is used to kill itself. Process.Kill uses TerminateProcess to kill itself, which we can easily modify to not terminate the process at all. Set a breakpoint on Process.Kill, find the address to TerminateProcess (e.g. using Go To Disassembly and looking for the call), open the memory window and change the first bytes of TerminateProcess to
    B8 01 00 00 00 C3

    Which decodes to

    mov eax, 1
    ret

    making the function always just return 1 without actually terminating the app. This makes the app run fine now, (it  still spawns the cmd.exe, but you can ignore it)

Finding the key validation algorithm:

  • Now that we have all the anti-analysis techniques out of the way, we can use the same trick to figure out the key validation algorithm. Again, set a breakpoint on RuntimeMethodInfo.UnsafeInvokeInternal but add the following breakpoint condition to reduce some of the noise that you'll get from other threads:
  • System.Threading.Thread.CurrentThread.ManagedThreadId == 1 // or whatever the id of the main thread is.
  • Hitting F5 numerous times after typing in some garbage and pressing the validate button reveals pretty quickly that the key is a base64 string that consists of three parts:
  • [Rfc2898DeriveBytes salt (32 bytes)] [IV (32 bytes)] [Encrypted payload]
  • The first two parts are used together with the hardcoded password "PiskopatYazar" to decrypt the third part using AES-CBC 256bit with PKCS7 padding.
  • A key is considered valid if the decryption succeeds with those parameters.

Keygen is just doing the reverse.

 

 

Keygen.cs 2.13 kB · 8 downloads

can you try to open the package.

Link to comment
Share on other sites

1 hour ago, Leopar36 said:

can you try to open the package.

I am of the opinion that any solution posted here should be reproducible (hence the name tuts4you). Anyone reading my solution should be able to follow the steps and get to the same conclusion. For the case of a VM, since they are complicated beasts, it means it gives me only two options:

  • I would have to release the source code of any type of devirtualizer that I would've made, or
  • I would have to spend an entire blog post talking about how VMP's VM works and how to reverse it.

While I genuinely enjoy doing both, both options take a lot of time, something I have very little of these days. But even if I had the time, it's arguably not really worth it. If I were to make a devirtualizer for VMP and release it, it will not take long for the VMP developers to catch on and update their software. Unless the devirtualizer was made in such a way that it would be resistant towards the kinds of changes (which again, takes more time), it means it is probably only going to be useful for a short period. Just doing this for a single unpackme posted on a forum does not really make it worth it for me.

Also, while I generally don't have any problem with publishing articles or source code (unlike other people that post solutions here it seems), I do have a problem with potentially harming other people's businesses. I am not a fan of releasing devirtualizers or unpackers for protectors that are still in business and have customers. From a legal and ethical perspective, that's just not something I would do easily.

Generally speaking though, with reverse engineering it is often not required to fully unpack anyways. You extract what you need and leave out the unimportant business. In a lot of cases that does not require a full deobfuscation.  Especially not with keygenme's like these.

Maybe someone else thinks differently about that, and does pick this up as a challenge though :)

Edited by Washi
  • Like 11
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...