Jump to content
Tuts 4 You
  • 0
HellSpider

[DevirtualizeMe] VMProtect 3.0.9

Question

HellSpider

Difficulty : 8
Language : C++
Platform : Windows 32-bit and 64-bit
OS Version : All
Packer / Protector : VMProtect 3.0.9

Description :

The objective is to interpret virtualized functions in the attached binaries.
No additional options have been used - no memory protection, no import protection and no compression.
The virtualized function(s) will execute when the following key(s) is/are pressed:

VMP32 (V1) : P
VMP32 (V2) : 1 and 2
VMP64 (V1) : P
VMP64 (V2) : 1 and 2

The virtualized functions are not very large.

Detailed information of the interpreting procedure/internals or a complete solution paper is preferable.

I will post similar challenges for other protectors if someone supplies me with a recent version (CodeVirtualizer, Themida, Enigma ...).

Accepted solutions:

VMP32 (V1) : @Raham
VMP32 (V2) : @Raham
VMP64 (V1) : @SmilingWolf @fvrmatteo
VMP64 (V2) : @fvrmatteo @SmilingWolf @mrexodia @xSRTsect

Files:

devirtualizeme32_vmp_3.0.9_v1.rar
devirtualizeme32_vmp_3.0.9_v2.rar
devirtualizeme64_vmp_3.0.9_v1.rar
devirtualizeme64_vmp_3.0.9_v2.rar

Screenshot :

devirtualizeme32_vmp_3.0.9_v1_2017-12-15_00-12-45.png.c019ad1506c9478af99c749349f404f3.png

 

 

Edited by HellSpider
Awards (see edit history)
  • Like 2

Share this post


Link to post
Share on other sites

Recommended Posts

  • 5
SmilingWolf

Not much to say. Questions are welcome. Requests will be ignored. The software created to solve this challenge won't be released.

I am posting the final file, but it's actually correct to say that @fvrmatteo did the bulk of the work and I helped with the smaller bits. Oh, and by suggesting some music to listen to while working :D

Time taken: circa 7 days. We still don't handle the code flow, but I guess the file speaks for itself as far as "seeing some results" goes as of now.

devirtualizeme64_vmp_3.0.9.DeVed.7z

Edited by SmilingWolf (see edit history)
  • Like 13

Share this post


Link to post
Share on other sites
  • 2
fvrmatteo
1 minute ago, SmilingWolf said:

Not much to say. Questions are welcome. Requests will be ignored. The software created to solve this challenge won't be released.

I am posting the final file, but it's actually correct to say that @fvrmatteo did the bulk of the work and I helped with the smaller bits. Oh, by suggesting some music to listen to while working :D

Time taken: circa 7 days. We still don't handle the code flow, but I guess the file speaks for itself as far as "seeing some results" goes as of now.

devirtualizeme64_vmp_3.0.9.DeVed.7z

Don't even believe him, guys :D  I will list some of the things he really did:

1) He jumped into the project and boosted it 100x, ported the code from VMP64 to VMP32, fixed bugs, added new features!

2) The file was cleaned and repackaged entirely by him!

3) He boosted my research every single time I shared with him the work I was doing well before joining the project.

4) He also suggested some nice music to listen to :P that's true.

Useless to say we still have plenty of research to do.

  • Like 10

Share this post


Link to post
Share on other sites
  • 1
Techlord

@fvrmatteo and @SmilingWolf :

Firstly, congratulations for your excellent work ! :)

Just wanted to ask.. Is this something similar to the OoWoodOne based VMP reversing DLL plugin for OLLY that was released in 2015 ?

I did modify the sources of that plugin at that time and it did work for quite a few VMP targets successfully to devirtualize the instructions.

It was from PedIy I think.

A bit of code (of course its for old versions o fthe VMP) from the sources :
 

Quote

 

Code from the HANDLER souce file for example (just a tiny bit) :  

{
        VM_PopR16,
        {
            { "mov al,byte ptr ds:[esi$]", "movzx eax,byte ptr ds:[esi$]" },
            { "mov dx,word ptr ss:[ebp]" },
            { "add ebp,0x2" },
            { "mov word ptr ds:[eax+edi],dx", "mov word ptr ds:[edi+eax],dx" },
        }
    },
    {
        VM_PushI32,
        {
            { "mov eax,dword ptr ds:[esi$]" },
            { "sub ebp,0x4" },
            { "mov dword ptr ss:[ebp],eax" },
        }
    },
    {
        VM_PopEsp,
        {
            { "mov ebp,dword ptr ss:[ebp]" },
        }
    },
    {
        VM_Mul32,
        {
            { "mov edx,dword ptr ss:[ebp]" },
            { "mov eax,dword ptr ss:[ebp+0x4]" },
            { "mul edx" },
            { "mov dword ptr ss:[ebp+0x4],edx" },
            { "mov dword ptr ss:[ebp+0x8],eax" },
        }
    },

 

Code from the deobfuscator ( once again only bits of code) :

Quote

case ASM_SUB:
        case ASM_SBB:
        {
            if (__isMemOp(0))
            {
                __addRef(udr[0]);
                if (udr[0] == ud_esp)
                {
                    __addEspDef(_esp_pos + disasm->adrconst);
                }
                else if (udr[0] == ud_ebp)
                {
                    __addEbpDef(1);
                }
            }
            else
            {
                __addDef(udr[0]);
                if (udr[0] == ud_esp)
                {
                    __addSkDef(-(int)disasm->immconst) ;
                }
            }
            if (__isMemOp(1))
            {
                if (udr[1] == ud_esp)
                {
                    __addEspRef(_esp_pos + disasm->adrconst);
                }
                else if (udr[1] == ud_ebp)
                {
                    __addEbpDef(1);
                }
            }
            __addRef(udr[0]);
            __addRef(udr[1]);
            break;
        }
        case ASM_DEC:
        case ASM_INC:
        {
            __addRef(udr[0]);
            if (!__isMemOp(0))
            {
                __addDef(udr[0]);
            }
            break;
        }
        case ASM_CMP:
        case ASM_TEST:
        case ASM_BT:

 

My question here :

Are we able to modify that plugin's SOURCES to make it work for the PRESENT versions of the VMP as well ? :o

Frankly, I didnot have the time to work on it but after seeing your success, I have a nagging feeling that modifications of the sources of the plugin would make it work on the present versions of the VMP as well ;)

Comments anyone ?

Just so that we are all clear : This is not to discredit the work of SmilingWolf and fvrmatteo to bve sure ! I really appreciate their hard work.But this was an idea that was nagging me for the past 2 days after they published the devirtualized version. I dug up the source code of the plugin and did a quick compile.

I found that just a few modifications could make the plugin possible work on the newer and present versions of the VMP as well !

 

Edited by Techlord (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites
  • 1
fvrmatteo

Thank you too for the answer, I will answer you quickly here because I'm in the middle of a AoE2 HD LAN party :P 

1) I'm sorry to have specified more than once that we do not share, it's a new world for me sharing something on T4Y and I don't know well enough how it works, I was overly protective because I really believe in researching without hurting the software house. I heard good things about you and I never thought you were looking for a ready-made script :) 

2) You have private versions of the VMP devirtualizer, that's a really good thing and I think we can compare the approach and discuss so you can update your version to VMP64 and in case we can think about supporting properly the control-flow.

Given the 2 things I said up here, I'm going to contact you via PM @Techlord, not because I don't like to share in public, but because I know that some things can't be shared otherwise people without the interest in understanding and learning will use the knowledge just for cracking (and making money).

I do think that the available information on the web are enough to get started with VMP, for anything else just write me on PM. <-- this is targeting anyone interesting in the details and that already researched VMP.

I just need to get more comfortable about sharing knowledge here, I'm free to discuss something on the forum and more details via private message.

  • Like 1

Share this post


Link to post
Share on other sites
  • 1
xSRTsect
5 hours ago, HellSpider said:

Results from quick value tests compared to my published file:

Devirtualized = Key#1 = different | Key#2 = different
Inlined version = Key#1 = ok | Key#2 = different

Did these work on your systems?

 

Well I am very sorry about this. But let me tell you why we are having all these fails: It turns out that our tool produces correct code, however not pretty enough, so what we did was to 'reverse' this code a little and re-write its logic in a more compact/appealing asm program. Unfortunately we are only humans and so I happened to copy a few values incorrectly namely the second if is <0xa and not 0xd (I seriously have no clue on what this value was doing there). Hopefully this time for the win,

 

 

 

devirtualizeme64_vmp_3.0.9.inlined_fx_.exe

Share this post


Link to post
Share on other sites
  • 1
mrexodia
On 5/27/2018 at 9:18 AM, VirtualPuppet said:

Since VMProtect is one of the easier protectors to devirtualize (since the VM is very simple) I assume they targetted Vmp specifically.

They probably use basic compiler theory to collapse instruction-expansions and then categorize vm handlers based on patterns. Thereafter the rest is easy, trace a functions P-code to determine handler chain, then again use compiler theory to determine x86 equivalent of stack machine code.

For my own devirtualizer, I went with a much different approach; i wrote an Intel/AMD x86(_64) cpu simulator and use it to interpret my data for a full trace that allows branch prediction in realtime. This significantly narrows down things and after that I just have to "reduce" the instructionset. When this is done, I can categorize handlers based on a specific method I came up with, that I won't disclose here, as it seems to work for all VMP versions and i don't want to damage VMP in any way. And once they're categorized I run them through my converter for the restored code.

The smart thing about the cpu simulator is that I can also unpack using this method, and it will make sure malware does not impact me :)

 

Maybe you could solve VMP32 (2) to show how awesome your undisclosed method is?

One idea I toyed with was to do simple input/output tainting on the handler level and do some black box tests to determine what operation a handler does. This should work at least on VMP because handlers perform very simple operations. Regardless it would be a waste of time because the difficult part is not to disassemble the VM opcodes, but rather restoring as perfect x86 as you can.

Share this post


Link to post
Share on other sites
  • 0
tonyweb

Fantastic work guys! Both of you ... and on the x64 one :) Great!

You both say that you didn't nothing special and, yeah, in comparison to God who created the world in seven days (well, 6 exactly :P) you did indeed nothing ... but hey we are human (and I underline we, not you ;) ) ... and your work is brilliant. Well done :thumbsup:

I wish I could have at least an idea on how to start such a job ... :dunno:

Best Regards,
Tony

Edited by tonyweb (see edit history)
  • Like 5

Share this post


Link to post
Share on other sites
  • 0
SmilingWolf
23 hours ago, tonyweb said:

I wish I could have at least an idea on how to start such a job ... :dunno:

Which actually reminds me how I was so busy fending off beggars and showing off that I didn't write about the approach used. Sorry, my bad.

So far we have been working on a trace of the virtualized function. The first pass is some junk code removal, identify the instructions VMP inserts but that have no lasting effect. Removing those helps getting the noise lower. From there, it was possible to operate with dead code elimination. Again, this considerably lowers the noise. We decided we could divide the trace in smaller blocks (the single handlers) at this point.
After that, you can start to notice some patterns. So what do you do when there are patterns? Well, but of course, peephole optimization (a glorified way to call pattern matching I say :P). After this step the handlers appear in all of their 4-5-instructions-average-length glory.

If this echoes of something is because you have already read Rolf Rolles posts on OpenRCE. We did too. Aaaand the same theory applies :)

Edited by SmilingWolf (see edit history)
  • Like 7

Share this post


Link to post
Share on other sites
  • 0
root

Fantastic ;)

  • Like 2

Share this post


Link to post
Share on other sites
  • 0
alorent

Great work!

Any "preview" about how those "cleaned" handlers? At least a view of a couple of them ;)

Thanks!

Share this post


Link to post
Share on other sites
  • 0
fvrmatteo

The following is only a preview of some blocks which we called "sub-handlers".

POP VREG:

movabs rax, 0xc8
mov rcx, qword ptr [rbp]
add rbp, 8
mov qword ptr [rsp + rax], rcx

PUSH IMM:

movabs rax, -0x20
sub rbp, 8
mov qword ptr [rbp], rax

ADD:

mov rax, qword ptr [rbp]
mov rcx, qword ptr [rbp + 8]
add rax, rcx
mov qword ptr [rbp + 8], rax
pushfq
pop qword ptr [rbp]

Don't expect more details because otherwise anyone would be able to reproduce it, and we don't want to hurt VMPSoft in any way :) 

If the mods think too many information are shared about the protection please notify me or SmilingWolf so we can fix it.

Edited by fvrmatteo (see edit history)
  • Like 2

Share this post


Link to post
Share on other sites
  • 0
joker33337

If that's not giving out too much information, I'm interested in knowing which tools/frameworks were involved in deobfuscation, unless you wrote your own optimization engine of course ;)

Edited by joker33337 (see edit history)

Share this post


Link to post
Share on other sites
  • 0
fvrmatteo
18 minutes ago, joker33337 said:

If that's not giving out too much information, I'm interested in knowing which tools/frameworks were involved in deobfuscation, unless you wrote your own optimization engine of course ;)

We used Triton to have an easy to use and reliable enough x86_64 to IR conversion. The idea was to apply symbolic execution at first, but that didn't last long mostly because the deobfuscation was too slow and complex (note that it's a valid approach nonetheless, but I think it is over-engineering the problem); we then switched to implement our own simplified version of the dead-code elimination algorithm which worked pretty well. The handlers detection and final devirtualization involved custom algorithms adapted to the VMP logic (I'm not going to explain it deeply, it's a nice research to be done, a lot can be learned in the process and the RE level requested to do so is not incredibly high).

Rolf Rolles in his VMP exploration took a different path from the one we took to solve the devirtualization-optimization problem, I invite you to look into his approach and you'll find out how detailed it is. If you research VMP well enough you can actually identify the best approach to be taken to solve it; if you have some basic knowledge about compilers (Dragon Book cough cough) you'll surely notice how many different paths can be taken to devirtualize VMP.

So as a recap the "tools" we wrote are just 2 Python scripts, one of which uses Triton disassembly engine to extract all the implicit/explicit information related to an assembly instruction; the other is just the devirtualization core. I also shared my crappy "general" deobfuscator on Tuts4You past year, it implemented some well known algorithms: dead-code elimination, constant folding, constant propagation, registers propagation, peephole optimisation; I invite you to play a bit with those algorithms and generally to study more about compilers. This is not strictly related to VMP, but it's something that should be done while attacking protectors like VMP and Themida.

The best thing to do for anyone who wants to attack VMP is to do some initial research in a blackbox way, just to get some insight of how VMP works and the tricks it uses. A reading of Rolf Rolles documentation is highly suggested: http://www.msreverseengineering.com/blog/2014/6/23/vmprotect-part-0-basics

  • Like 8

Share this post


Link to post
Share on other sites
  • 0
fvrmatteo

@Techlord I think I heard about that plugin during some conversation but never tried it; we applied the blackbox approach because most of the times you find yourself finding a different solution from others (not necessarily better) and you'll learn a lot more because you don't have your mind "pre-set" to solve the challenge in a specific way. We were aware of the Rolf Rolles research and indeed his approach is what influenced all the plugins and scripts used to attack VMP, and what we checked to know if we were taking the correct path.

No discredit at all, it's incredibly interesting to know that other solutions are available! I took a quick look and I should say that the approach is for sure able to deal perfectly with VMP32 and with some adjustment with VMP64 too. Seems like the guys at VMPSoft didn't really change the whole idea since VMP1, and that's why the Rolf Rolles approach still applies with minor changes.

With the x64 version you should deal with a little more obfuscation tricks, but they used almost the same core logic for the VM. I don't know how the devirtualization is implemented on the OoWoodOne plugin, but I have the feeling it's the same idea applied by Rolf Rolles and so it's different by our approach (finger crossed our approach is going to do well on other challenges too). If you want to discuss about it in private feel free to reach us, maybe you can port and adapt the Olly plugin and make it work with x64dbg, but we are not going to do that :)

In any case we are not sharing our scripts but we'll surely continue the research and will focus on handling properly the control-flow (actually it would be nice to have a virtualized routine using branching instructions). We temporarily switched context to another protection :D and will spend some time on it.

Edited by fvrmatteo (see edit history)
  • Like 3

Share this post


Link to post
Share on other sites
  • 0
HellSpider
8 hours ago, fvrmatteo said:

... actually it would be nice to have a virtualized routine using branching instructions) ...

I could throw together an additional x64 challenge in this thread. :)

  • Like 2

Share this post


Link to post
Share on other sites
  • 0
HellSpider

I added a second x64 challenge to the main post.

It contains two virtualized functions. They will execute when '1' and '2' are pressed.

  • Like 4

Share this post


Link to post
Share on other sites
  • 0
Techlord

@fvrmatteo: Thank you for the response :) .

20 hours ago, fvrmatteo said:

we applied the blackbox approach because most of the times you find yourself finding a different solution from others (not necessarily better) and you'll learn a lot more because you don't have your mind "pre-set" to solve the challenge in a specific way.

I fully agree with you. Its better to start fresh sometimes, so that you may come up with something unique ! I do this many a time myself.

 

20 hours ago, fvrmatteo said:

We were aware of the Rolf Rolles research and i....

The link you gave to Rolf Rolles' Research Blog 4 posts above this post was really helpful. I am aware of Rolf Rolles and his research but I had a good read once again yesterday after following your link.

 

20 hours ago, fvrmatteo said:

I took a quick look and I should say that the approach is for sure able to deal perfectly with VMP32 and with some adjustment with VMP64 too.

What I posted is some of the representative code snippets of the PUBLIC version that was floating around in 2015. We had made many PRIVATE versions using that code as the base and it is able to devirtualize and unpack as well, for many version of VMP (tested upto the last v2.xx - no time to test on the v3.xx). I can CONFIRM that it works perfectly (the private versions especially, for the 32-bit versions) in all our tests.

 

20 hours ago, fvrmatteo said:

I don't know how the devirtualization is implemented on the OoWoodOne plugin, but I have the feeling it's the same idea applied by Rolf Rolles

Yes, its more or less the same approach.

 

20 hours ago, fvrmatteo said:

If you want to discuss about it in private feel free to reach us, maybe you can port and adapt the Olly plugin and make it work with x64dbg, but we are not going to do that

Thank you. Yes, I may port it to x64dbg in the near future...

 

20 hours ago, fvrmatteo said:

In any case we are not sharing our scripts

Just so that we are all clear here, and since this fact that you are not sharing scripts had been mentioned multiple times in this thread, both bu you and SmilingWolf, I want to clarify that I am not one of persons intersted in the scripts. I am an intellectual and if you see my posts in the various other RCE forums over the past several years, you can clearly see that I am interested in the implementations, underlying concepts and how one had arrived at the solution and therefore at the most, I just ask for snippets of source code of other programs (if the author is willing to share it of course), so as to enable me to understand the techniques and principles used better.

Having said that, I know that  you did not direct that statement that you're not sharing the scripts, specifically at me, and hence of course, I have not taken any offence or anything :)

The link you gave to the Rolf Rolles Papers was incredibly useful, and far more useful than any ready-made scripts. I suggest that everyone interested in this topic read up those papers. Reading them once again yesterday after many years definitely made me understand the papers much better.

 

21 hours ago, fvrmatteo said:

we'll surely continue the research and will focus on handling properly the control-flow

I hope you would share the results of your future research as well, with all of us. Of course, no ready-made scripts or anything, but knowledge and concepts :)

  • Like 1

Share this post


Link to post
Share on other sites
  • 0
Techlord

@fvrmatteo :

I fully and one hundred percent (100%) AGREE with all that you have said above !

4 hours ago, fvrmatteo said:

I was overly protective because I really believe in researching without hurting the software house.

Even I fully agree that while we can show that we have defeated VMP, we should not necessarily hurt the VMP Software guys and their sales :D

 

 

4 hours ago, fvrmatteo said:

some things can't be shared otherwise people without the interest in understanding and learning will use the knowledge just for cracking (and making money).

I have the same opinion regarding this matter and I have posted this thought on several RCE forums over the past few years. Especially, I am against the indiscriminate sharing of private stuff on public forums. So yes, please feel fere to communicate with me via PM (in fact I do already collaborate witth  quite a few respected individuals in PRIVATE for sensitive matters such as these) :)

 

4 hours ago, fvrmatteo said:

I just need to get more comfortable about sharing knowledge here, I'm free to discuss something on the forum and more details via private message

Once again, as I said above this will be best.

Share this post


Link to post
Share on other sites
  • 0
fvrmatteo
15 hours ago, recrc said:

Hi fvrmatteo,

Congratulations. Is your solution a script for olly or a tool? I mean does it work for ring0 vmp protected drivers too? Does it devirtualize functions in ring0 too?

Actually it's our solution :P and to be honest we only worked on the 2 proposed challenges, so I have no idea of what's going on at ring0 level. I assume that if you can save a trace the current solution may be working (I don't think they changed the way obfuscation/virtualization works). If we take a further step into control-flow handling, we are dealing with it now and updating our tools to handle properly the code-coverage problem. In the future we'll probably look into ring0 stuff, but the road is long and we have a lot of project going on (IRL too) :)

And to answer the first question: our "tool" is a bunch of Python scripts, no plans to support Olly or x64dbg for now.

Share this post


Link to post
Share on other sites
  • 0
ruikangzhu1990

Hi,

I am new at this vmprotect, virtualization thing, but it have peaked my interest, any guides on how to start? I'm not asking for a solution or anything like that but a guide for me to learn to get a start.

Thank you.

Share this post


Link to post
Share on other sites
  • 0
SmilingWolf

We're still on this!

Today, some notes.

First part is about a weird expression we met while simplifying the code. Mathematically proving our theoretical simplification was important to make sure it wasn't some weird error generated by other incorrect simplifications. Now we know this won't come and bite us in the ass. I took this upon myself, so first part's author is yours truly.

Second and perhaps most interesting part is about the logic used by VMP virtualize conditional jumps, by @fvrmatteo.

Weird.Expression+JCC.Notes.txt

  • Like 3

Share this post


Link to post
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

×