Jump to content
Tuts 4 You

[DevirtualizeMe] VMProtect 3.0.9


HellSpider
Go to solution Solved by SmilingWolf,

Recommended Posts

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
  • Like 2
Link to comment
Share on other sites

  • 4 weeks later...
  • Solution
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
  • Like 15
Link to comment
Share on other sites

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
Link to comment
Share on other sites

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
  • Like 5
  • Haha 1
Link to comment
Share on other sites

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
  • Like 7
Link to comment
Share on other sites

Great work!

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

Thanks!

Link to comment
Share on other sites

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
  • Like 2
Link to comment
Share on other sites

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
Link to comment
Share on other sites

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
Link to comment
Share on other sites

@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
  • Like 1
Link to comment
Share on other sites

@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
  • Like 2
Link to comment
Share on other sites

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
Link to comment
Share on other sites

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
Link to comment
Share on other sites

@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
Link to comment
Share on other sites

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
Link to comment
Share on other sites

@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.

Link to comment
Share on other sites

HostageOfCode

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?

Edited by recrc
error
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

  • 2 weeks later...
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
Link to comment
Share on other sites

  • 5 weeks later...
  • 5 weeks later...

Currently working on the VM32 version. My deobfuscator/demutizer (idk how to call that) is done and works for both x64 and x32 targets. Currently investing time into the 32-bit VM (works a bit different than 64 bit?). I've compared it to a target you've posted before and saw that they've stepped up their game with the instruction pointer and such? Instead of using a table hardwritten into the memory they have connected each handler with the following handler like some sort of linked list and unique, which means that there isn't just one handler for "push" as example but like for every push in the code there is a single handler. Therefore you have to analyze every single handler by it's own (can be automated I think but tricky) and see how it reads from the instruction chunk. That's just what I've figured out, maybe it's wrong and there is indeed a table with each handler. Because of using for each VM_OPCODE an unique implementation it would expand the output a lot which is really ineffecient.

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...