20 May 2016

Beautiful code

After making quite a few unpackers and other RE-related tools, publishing sources for them and having to maintain and bugfix them, all I can say is: "Read this. Remember this. Worship this."

All code is born ugly.

It starts disorganized and inconsistent, with overlaps and redundancies and gaps.

We begin working it into an imperfect solution for an often poorly defined problem.

As we start building up like clay, a solution starts taking form. The feedback guides us in moving, removing and adding material. It allows us to add and remove details. We learn from our mistakes.

Thank you, Dennis, you made my day so much better.

11 Mar 2016

About .NET, googling and lazy programmers.

Delphi fail. .NET win.

Recently, several people sent me bug reports where my EnigmaVB unpacker failed to extract files. In all cases, the problem was caused by really large files, like 3.5GB in size. So, what's causing the problem?

EnigmaVB unpacker is a 32bit application written in Delphi. And Delphi streams are retarded. They look like they've been written in 1990s and were never updated. TMemoryStream uses a continuous memory range, so it can never support anything larger than 2GB. TFileStream internally uses longint, so it doesn't properly support files larger than 2GB. WTF?

So, I have two choices. I can either make a custom stream class in Delphi, or I can pick another framework and rewrite my tool to use that.

I'm not a programmer, I'm a reverser. I don't want to spend my time developing custom stream classes. I'd very much rather use this time breaking some code. So, say hello to .NET framework - my next version of EnigmaVB unpacker will be made in C#.. smile

Am I a programmer or a googler?

While researching all the Delphi limitations and possible workarounds, I ran into this great article by Scott Hanselman. Reading both the post and the comments made me think a lot.

Does using Google to solve your programming tasks makes you less of a programmer? I don't think so.

In fact, I'm just lazy. Most people are. Why should I spend 30 minutes remembering basic algorithms for converting string to hex, if Google query can solve it in 10 seconds? Why reinvent the wheel and write CRC calculation from scratch? I'll just open StackOverflow and have a solution that's already tried and tested. It doesn't mean I can't do those boring tasks - I just don't want to.

How about you? Would you be able to write some tools without using Google and StackOverflow?

16 Feb 2016

Updated Meltdown and EnigmaVB Unpacker

About Error Messages

Users can't read.

Or maybe they don't want to read. I don't know.

But one thing I know for sure - you must make your tools foolproof. If your tool is showing an error message, make sure even your grandma could understand it. Otherwise you'll be getting lots and lots of invalid bug reports.

For example, this is the error message my EnigmaVB unpacker used to show (as reported by ho3ein at Tuts4You):
enigmavb_error_message

It seemed to be very clear to me. First, tool tells user all the versions of Enigma Virtual Box it supports. Then tool explains that it expects to see a PE section with a name ".enigma2" but it found section with a name ".rsrc" instead. To me it's absolutely clear what happened: this file is not protected with Enigma Virtual Box (or it's hacked).

But you won't believe how many times this gets reported as a bug.

There was a similar problem with Meltdown. It clearly stated which versions of DeepFreeze it supports. Then it printed the detected DeepFreeze version. However, the error message didn't explicitly say "This version of DeepFreeze is not supported", it said "DeviceIoControl failed." It makes perfect sense from developer's point of view, but apparently is very confusing for users.

So, here are improved versions of my tools, fixing the error messages and some other stuff..

Improved EnigmaVB Unpacker

First of all, I fixed the error message. I also added detection and tested compatibility with the latest EnigmaVB v7.40. Hopefully, this will make users happier and less confused. smile
EnigmaVBUnpacker_v034

Improved Meltdown

Meltdown 1.7 fixes confusing error message with DeepFreeze Standard v8.x. Thanks to Alexander for reporting it.

I also took a closer look at DeepFreeze Enterprise versions and found a way to make Meltdown more user friendly. If DeepFreeze Enterprise v7.20+ is detected, Meltdown will get OTP Token automatically and immediately generate correct password.

meltdown17

Download links

Enigma Virtual Box Unpacker: Please get latest version from this post
Meltdown v1.7: https://www.mediafire.com/?b0bamd3t2d6bbkq

05 Nov 2015

Keygen templates in Visual Studio

I'm lazy and I hate doing the same tasks over and over again. Making UI for my crackme solutions is one of such tasks. It always goes like this: open Visual Studio, create new Windows Forms project in C#, drop 2 labels, 2 edit boxes and one button on the form. Set label texts to "Name" and "Serial", set button title to "Generate..", set the project icon, etc., etc..

There must be a better way!

..and it's certainly not the way Blue Indian did his keygen template:

To build this template on your own, open the solution in Visual studio, comment out the calls for uFMOD and implement your own logic, after successful build of keygen, close the Visual studio, open the Form_Main.cs file in any text editor and uncomment those two calls to uFMod, save it. Now double click on the build.bat file to built it finally.
...
-To change the ICON and XM tune, edit the mini.res (resource file) with any resource editor like Restorator or any of your choice.

Open this, delete those, compile that, and what? I'm already confused, sorry.

Introducing Visual Studio project templates

I'm sure you know that when you click "New project" in Visual Studio, you're presented with number of choices, like "Windows Forms Application", "Console Application", "Class Library" and so on. All these are project templates that are installed by default.

They provide all the files that are required for a particular project type, include standard assembly references, and set default project properties and compiler options. Hmm, that's exactly what I needed! smile

This article at MSDN nicely explains that project template is simply a ZIP file that contains all the necessary files and a special .vstemplate file. This .vstemplate file is an XML file containing metadata Visual Studio needs to display the template in the "New Project" dialog.

Let's try to put it all together.

Making simple keygen template

Making a new template is actually very easy. You take an existing Visual Studio project, replace project-specific strings with template parameters and press File->Export Template.

Here is my keygen for Mr. eXoDia's simple crackme:
keygen_template1
Obviously, template should not contain code for specific crackme. Let's change that to something trivial and mark as FIXME:
keygen_template2
Now I need to remove all references to crackme name. I will replace them with template parameter $safeprojectname$ in all files. After this change, project won't compile anymore, so you need to be extra careful when changing stuff!
keygen_template3
Hardcoding year in the (c) string is not a good idea because I want to use this template in year 2016 as well:
keygen_template4
Now I just need to update AssemblyInfo.cs to make sure each project has correct name, (c) and GUIDs:
keygen_template5
Did it work? Let's see... File->Export Template, follow the wizard and...

It works. Kinda. The created template still has quite a few references to Mr eXodia's crackme, I'll need to modify project and solution files manually. Unzip the template, fix the files in text editor and ZIP them back. And now it works!

Few more cosmetic fixes (like using $projectname$ where possible), using $if$ and $targetframeworkversion$ to target all .NET framework versions, better namespace names and we have a template that's actually useful.

Download here: https://www.mediafire.com/?sx1i5ba1uijjkii

It's not particularly pretty but that's pretty much what I've been using for 2+ years now - and hopefully it can inspire you to do something similar with your own code. wink

Further reading

Reason→Code→Example : Creating Visual Studio project templates
Rebuilding template cache
How to: Manually Create Project Templates
How to: Create Multi-Project Templates

29 Jun 2015

Linking OMF files with Delphi

Continuing the discussion about Delphi compiler and the object files.

Here is the OMF file template I made for 010 Editor: https://www.mediafire.com/?bkpbkjvgen7ubz1
omf_parser

Please note, it is not a full-featured implementation of OMF specification. I only implemented all OMF file records that are processed by Delphi 2007 compiler. So, next time you have a cryptic compiler error while trying to link OMF file in Delphi, you can take a look into your OBJ file and make an educated guess what's causing the problem.

TL;DR version

In 95+% of cases you will encounter OBJ file that has unsupported segment name in SEGDEF record. And it's a simple fix, too - you just need to use objconv.exe by Agner Fog and use -nr option to rename the offending segment. Something like this:

Next possible issue is exceeding the number of EXTDEF or LNAMES records - this can happen if you're trying to convert a really large DLL file into OBJ file.

Finally, your OBJ file might contain some record type which is not supported by Delphi compiler at all. I'm not aware of a simple way to fix it, I would try using 010Editor and OMF template to remove the entire record.

If your problem is not caused from any of the above issues, please feel free to drop me a note - I'll be happy to look into it.

Known limitations of Delphi compiler

This is a list of limitations I was able to compile and/or confirm. Some of them come from Embarcadero official notes and the rest I obtained by analyzing dcc32.exe.

SEGDEF (98H, 99H)

  • Not more than 10 segments - if number of segments exceeds 10, buffer overrun will probably happen.
  • Segments must be 32bits. Will cause "E2215 16-Bit segment encountered in object file '%s'"
  • Segment name must be one of (case insensitive):
    • Code segments: "CODE", "CSEG", "_TEXT"
    • Constant data segments: "CONST", "_DATA"
    • Read-write data segments: "DATA", "DSEG", "_BSS"

    Segment with any other name will be ignored.

LNAMES (96H)

Not more than 50 local names in LNAMES records - will cause "E2045 Bad object file format: '%s'" error.

EXTDEF (8CH)

Not more than 255 external symbols - will cause "E2045 Bad object file format: '%s'"
Certain EXTDEF records can also cause "E2068 Illegal reference to symbol '%s' in object file '%s'" and "E2045 Bad object file format: '%s'"

PUBDEF (90H, 91H)

Can cause "E2045 Bad object file format: '%s'" and "F2084 Internal Error: %s%d"

LEDATA (A0H, A1H)

Embarcadero says that "LEDATA and LIDATA records must be in offset order" - I am not really sure what that means. Can cause "E2045 Bad object file format: '%s'"

LIDATA (A2H, A3H)

Embarcadero says that "LEDATA and LIDATA records must be in offset order" - I am not really sure what that means. Can cause "E2045 Bad object file format: '%s'"

FIXUPP (9CH)

This type of record is unsupported, will cause immediate error "E2103 16-Bit fixup encountered in object file '%s'"

FIXUPP (9DH)

Embarcadero documentation says:

  • No THREAD subrecords are supported in FIXU32 records
  • Only segment and self relative fixups
  • Target of a fixup must be a segment, a group or an EXTDEF

Again I'm not sure what they mean. But there are lots of checks that can cause "E2045 Bad object file format: '%s'"

THEADR (80H)

Accepted by compiler, but no real checks are performed.

LINNUM (94H, 95H)

Accepted by compiler, but no real checks are performed.

MODEND (8AH, 8BH)

Accepted by compiler, but no real checks are performed.

COMMENT (88H) and GRPDEF (9AH)

Ignored by compiler.

That's the end of the list. Any other entry type will cause immediate error "E2045 Bad object file format: '%s'" smile

Useful links

My OMF file template for 010Editor: https://www.mediafire.com/?bkpbkjvgen7ubz1
OMF file format specification.
The Borland Developer's Technical Guide
Objconv.exe by Agner Fog
Manual for objconv.exe

19 Jun 2015

Weirdness of C# compiler

I've been quite busy lately. I made OMF file template I promised few weeks ago, found a remote code execution vulnerability in One Big Company's product and spent some time breaking keygenme by li0nsar3c00l. I'll make a blog post about most of these findings sooner or later.

But today I want to show you something that made me go WTF..

I needed to see how the loop "while true do nothing" looks like in IL. Since C# compiler and .NET JIT compiler are quite smart and optimize code that's certainly an eternal loop, I needed to get creative:

Nothing fancy, but C# & JIT compiler don't track param values, so they both generate proper code..

Well, I thought it's a proper code, until I looked at generated MSIL:

WTF WTF WTF? Can anyone explain to me why there are 2 ceq instructions?

I could understand extra nop and stloc/ldloc instructions, but that ceq completely blows my mind.. And it's the same for .NET 2.0 and 4.5 compilers.

02 Jun 2015

Since you asked.. How to inject byte array using dnlib

Quite often I receive random questions about dnlib from my friends. To be honest, I have no idea why they think I know the answers to life the universe and everything else. smile So, in this series of posts I'll attempt to solve their problems - and hope that the solution helps someone else too.

So, today's question is:

We're trying to add a byte array to an assembly using dnlib. We wrote some code* but dnlib throws exception when saving modified assembly:
An unhandled exception of type 'dnlib.DotNet.Writer.ModuleWriterException' occurred in dnlib.dll
Additional information: Field System.Byte[] ::2026170854 (04000000) initial value size != size of field type

I gave the friend the standard answer - make a sample app, see how it looks and then implement it with dnlib. Seriously, how hard can it be? smile

Well, array initialization in .NET is anything but simple.

How arrays are initialized in C#

Note - the following explanation is shamelessly copied from "Maximizing .NET Performance" by Nick Wienholt. It's a very nice book but getting little outdated. You can Google for "Apress.Maximizing.Dot.NET.Performance.eBook-LiB", if interested.

Value type array initialization in C# can be achieved in two distinct ways—inline with the array variable declaration, and through set operations on each individual array element, as shown in the following snippet:

For a value type array that is initialized inline and has more than three elements, the C# compiler in both .NET 1.0 and .NET 1.1 generates a type named <PrivateImplementationDetails> that is added to the assembly at the root namespace level. This type contains nested value types that reference the binary data needed to initialize the array, which is stored in a .data section of the PE file. At runtime, the System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray method is called to perform a memory copy of the data referenced by the <PrivateImplementationDetails> nested structure into the array's memory location. The direct memory copy is roughly twice as fast for the initialization of a 20-by-20 element array of 64-bit integers, and array initialization syntax is generally cleaner for the inline initialization case.

Say what? You can read the text 3 times and still be no wiser. So, let's make a small sample application and disassemble it.

How array initialization looks in MSIL

Let's start with sample app that does nothing.

Compile without optimizations, and disassemble using ildasm. And even after removing all extra stuff, there's still a lot of code & metadata for such a simple thing. smile

For one byte array that we declared, compiler created .data directive, 2 static fields, one class and one nested class. And it added a global static constructor. Yikes!

Implementing it in dnlib

Now that we know all the stuff that's required for an array, we can make a tool that will add byte array to an assembly of our choice. To make things simpler, I decided not to create a holder class (named <PrivateImplementationDetails>{E21EC13E-4669-42C8-B7A5-2EE7FBD85904} in the example) and put everything in global module instead.

Note - Since I'm not a .NET/dnlib wizard, I always do it one step at a time, make sure it works and then continue. So, my workflow looks like this: write a code that does X → compile and run it → disassemble the result → verify that result X matches the expected → fix the bugs and repeat. Only after I've tested one thing, I move to the next one.

It also helps to make small test program first. Once you know that your code works as intended, you can use it in a larger project. Debugging the entire ConfuserEx project just to find a small bug in modifications made by someone - it's not fun! So, step-by-step...

First, we need to add the class with layout. It's called '__StaticArrayInitTypeSize=5' in the example above. That's quite simple to do in dnlib:

Now we need to add the static field with data, called '$$method0x6000003-1'.

Once that is done, we can add our byte array field, called bla in the example.

That's it, we have all the fields. Now we need to add code to global .cctor to initialize the array properly.

And that's it! Simples!

Further reading

Commented demo code at Pastebin
Longer explanation how array initialization works in C#


Updates

Just to clarify - this is a sample code. It works for me but if it blows up in your project, it's your problem. And there always are some things that can be improved.

• Sometimes I'm overcomplicating things.. You don't need to explicitly import System.Byte, you can use mod.CorLibTypes.Byte for that.

SZArraySig is a cleaner but less obvious way to refer to any array. If you need to reference complex arrays, this is better:

11 May 2015

Improving Meltdown

More than 2 years ago I released Meltdown. It's a proof-of-concept tool that showed several security issues in Faronics DeepFreeze products. Faronics are infamous for their attempts to hide the issues, so I was really curious how it will work out.

Bugs in my code

First, a few bugs in my code surfaced. None of them were in the core components dealing with DeepFreeze, I had that part tested thoroughly. But I overlooked issues with UAC, possibility that Windows are not installed on drive C:\, empty passwords and other edge cases.

All in all, it was a good learning experience.

Requests for source code

The very first version of Meltdown came with a full source code and explanation of the vulnerabilities in Faronics products. Once I started fixing bugs, I released only the updated binary. Yet quite a few people kept asking for the updated source.

To be honest, I have no idea why. So far, I haven't seen a single tool that would be based on my source code, not even a straightforward rip with a changed name and copyrights. Weird..

Bug reports

People reported bugs. Big bugs, small bugs, non-bugs and everything in between.

Most bug reports came from arabic-speaking guys. Some of them even didn't bother to use Google Translate and wrote in their native language. No, I really don't speak Arabic, German, French or Indonesian.

Also, most bug reports came without any actionable information whatsoever. Just "It doesn't work". Well, that's not helpful at all! I really want to help you, but you must tell me more than that. In later versions, I added information to main window about detected OS, 32/64bits, detected DF version, etc, etc. And then I can just ask for a screenshot, it contains most of the info I need to replicate the issue.

It was a good learning experience again. I learned how to make my tools more user-proof.

Faronics response

For a year, there was none.

Then in June 2014 they released DeepFreeze Enterprise 8.11 where the issue was fixed. At least the changelog says so:

7936 Resolved a security issue that could result in the user accessing Deep Freeze without authorization.

Yeah, right.. In reality they just added yet-another-layer of xor-encryption and removed useful data from frzstate2k.exe. But the same data are still present in dfserv.exe.

Wow, that's what I call "resolving a security issue"! smile

In September 2014 they released DeepFreeze Standard 8.10 where the other vulnerability was fixed. However, there was no mention of anything like that in the changelog. From a quick glance, it looks like they finally got their code right and aren't sending xor-encrypted password from driver to usermode anymore.

What now?

I'm presenting you an updated version of Meltdown.

Meltdown v1.5
It shows that vulnerabilities in Enterprise version are still present, just slightly more obfuscated. But security through obscurity does not work!

The glaring vulnerability in Standard version is fixed, and 8.x Standard versions seem to be safe. Funny, isn't it - you'd expect a corporate product to provide better security than home-edition, yet this is not the case.. smile

Download link for Meltdown v1.5: http://www.mediafire.com/?0wc0vv1kauhwxbb

24 Apr 2015

Sniffing correct serial in .NET crackmes

Introduction

In this tutorial I'll show you a generic way how to break most of the crackmes written in VB.NET. It uses the fact that most crackmes made by beginners will calculate correct serial and do a simple comparison "if enteredSerial = correctSerial then"...

To break such a crackme, you only need to find this comparison and sniff the correct serial. This is a very common approach in x86 world but in .NET world it's not that popular yet.

As for my target, I'm using "RDG Simple Crackme .NET v4 2015"

GetProcAddress in .NET

In x86 world you can use GetProcAddress function to get address of any API function from any DLL. Can we do something similar in managed environment like .NET? It turns out that we can, but it's a little bit harder.

So, for example, to get address of Assembly.Load(byte[]) you need to do:

This works well with static classes and static methods. How about non-static methods like RijndaelManaged.CreateDecryptor(byte[], byte[])?

That's doable as well, like this:

To make this reference almost complete - here's how to get address of .ctor:

There are a few gotchas, however..

  • In case your target type is located in assembly that's not NGEN'ed yet, I suggest that you use ngen and install the assembly in cache. That can prevent certain problems later.
  • Addresses of functions are obviously different in .NET 2.0 and 4.0. You must compile for correct framework version and target the correct .NET assembly.
  • Addresses of functions are different for x86 and x64 framework versions, too. Make sure your assembly is compiled correctly.

Sniffing string compare

Suprisingly, string comparison in VisualBasic.NET and other .NET languages is different. It's caused by Option Compare statement present in Visual Basic language. So, if the crackme is made in VB.NET, you need to examine Operators.CompareString(string,string,bool) function. For crackmes made in other languages, you'll need to examine string.Equals(string) or some other variation of this method.

So, using the code I mentioned above, I learned that address of Operators.CompareString(string,string,bool) on my PC is 599F1D30. Now I need to sniff data passed to this function.

There are several possible approaches. You can try using VisualStudio & Reflector plugin as SpoonStudio tried, you can try using ILSpy and it's debugger plugin, or you can inject DLL into crackme process, as suggested by noth!ng - but I prefer to use OllyDbg.

Load crackme in OllyDbg, make sure that all the anti-anti-debug plugins are working, all the exceptions ignored, put a breakpoint on 599F1D30 and hope for the best.

Nope. Operators.CompareString is called literally thousands of times. So, we need to do something smarter.

For example, we can use conditional logging breakpoints in Olly. Those breakpoints are quite slow, but it's still faster than to write some sort of hooking DLL and inject it into crackme. So, we need to set 2 logging breakpoints - one for each string compared. Here is first one:
crackme_conditional_breakpoint
Place second breakpoint at the next instruction (59CD1D31) and log string at edx+8.

Run the crackme, enter some fake but easily recognizable serial and few minutes later we have the answer:
crackme_logged_results
My entered serial was "1234567890123456789012345678901234567890" and it's being compared to "C49476D583364356253377056314435396D456F44796C7A55746431564433544". Hmm, could that be the correct serial for my nickname? wink Yes, it is!

Final notes

This was quite nice crackme and I only showed the simplest way to beat it. When you start looking into it, you'll find some nice anti-debug tricks, some nice anti-patching tricks and pretty nicely obfuscated code.

But that's a matter for another story. Have fun!