What’s wrong with this file – ASLR is tricky!

kao

I love magic tricks. My absolute favorites are "there's nothing up my sleeve" kind of tricks. You can look at the equipment, you can examine magicians outfit, everything seems fine - yet the rabbit magically appears and disappears.

Here's a similar reversing challenge for you: https://www.mediafire.com/?38evlc6gmyieskn

This EXE file contains relocations. It has all the necessary necessary flags in PE header. And it gets ASLR support in Windows 10, as you can see in picture:
win10_has_aslr
But on Windows 7/8.1 this poor executable will be always loaded at it's preferred imagebase 0x400000, and doesn't get ASLR support:
win7_no_aslr
Can you figure out what's so special about it? ๐Ÿ™‚

I will provide the correct answer in one week. Or you can provide your opinions in comments. Extra respect awarded for detailed answers and explaining how you figured that out. Extra extra respect if you knew the answer even before looking at the executable. ๐Ÿ™‚

Beautiful code

kao

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.

About .NET, googling and lazy programmers.

kao

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#.. ๐Ÿ™‚

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?

Updated Meltdown and EnigmaVB Unpacker

kao

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. ๐Ÿ™‚
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

Keygen templates in Visual Studio

kao

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! ๐Ÿ™‚

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. ๐Ÿ˜‰

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

Linking OMF files with Delphi

kao

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:

objconv.exe input.obj -nr:BadSegmentName:DATA output.obj

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'" ๐Ÿ™‚

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

Weirdness of C# compiler

kao

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:

using System;

static class Test
{
  static void bla(Int32 param)
  {
     while (param != 0) {};  // loop loop loop!
     Console.WriteLine("1");
  }

  static void Main()
  {
     bla(123);
  }
}

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:

.method private hidebysig static void  bla(int32 param) cil managed
  {
    // Code size       28 (0x1c)
    .maxstack  2
    .locals init (bool V_0)
    IL_0000:  nop
    IL_0001:  br.s       IL_0005

    IL_0003:  nop
    IL_0004:  nop
    IL_0005:  ldarg.0
    IL_0006:  ldc.i4.0
    IL_0007:  ceq
    IL_0009:  ldc.i4.0
    IL_000a:  ceq
    IL_000c:  stloc.0
    IL_000d:  ldloc.0
    IL_000e:  brtrue.s   IL_0003

    IL_0010:  ldstr      "1"
    IL_0015:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_001a:  nop
    IL_001b:  ret
  } // end of method Test::bla

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.

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

kao

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. ๐Ÿ™‚ 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? ๐Ÿ™‚

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:

//inline
int[] arrInline = new int[]{0,1,2};

//set operation per element
int[] arrPerElement = new int[3];
arrPerElement[0] = 0;
arrPerElement[1] = 1;
arrPerElement[2] = 2;

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.

using System;
class Program
{
    static byte[] bla = new byte[] {1,2,3,4,5};
    static void Main()
    {
    }
}

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. ๐Ÿ™‚

.assembly hello {}

.class private auto ansi beforefieldinit Program extends [mscorlib]System.Object
{
  .field public static uint8[] bla

  .method private hidebysig specialname rtspecialname static void  .cctor() cil managed
  {
    ldc.i4.5
    newarr     [mscorlib]System.Byte
    dup
    ldtoken    field valuetype '<PrivateImplementationDetails>{E21EC13E-4669-42C8-B7A5-2EE7FBD85904}'/'__StaticArrayInitTypeSize=5' '<PrivateImplementationDetails>{E21EC13E-4669-42C8-B7A5-2EE7FBD85904}'::'$$method0x6000003-1'
    call       void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
    stsfld     uint8[] Program::bla
    ret
  }
}

.data cil I_00002098 = bytearray (01 02 03 04 05) 

.class private auto ansi '<PrivateImplementationDetails>{E21EC13E-4669-42C8-B7A5-2EE7FBD85904}' extends [mscorlib]System.Object
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  .class explicit ansi sealed nested private '__StaticArrayInitTypeSize=5' extends [mscorlib]System.ValueType
  {
    .pack 1
    .size 5
  }

  .field static assembly valuetype '<PrivateImplementationDetails>{E21EC13E-4669-42C8-B7A5-2EE7FBD85904}'/'__StaticArrayInitTypeSize=5' '$$method0x6000003-1' at I_00002098
}

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:

ModuleDefMD mod = ModuleDefMD.Load(args[0]);
Importer importer = new Importer(mod);
ITypeDefOrRef valueTypeRef = importer.Import(typeof(System.ValueType));
TypeDef classWithLayout = new TypeDefUser("'__StaticArrayInitTypeSize=5'", valueTypeRef);
classWithLayout.Attributes |= TypeAttributes.Sealed | TypeAttributes.ExplicitLayout;
classWithLayout.ClassLayout = new ClassLayoutUser(1, 5);
mod.Types.Add(classWithLayout);

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

FieldDef fieldWithRVA = new FieldDefUser("'$$method0x6000003-1'", new FieldSig(classWithLayout.ToTypeSig()), FieldAttributes.Static | FieldAttributes.Assembly | FieldAttributes.HasFieldRVA);
fieldWithRVA.InitialValue = new byte[] {1,2,3,4,5};
mod.GlobalType.Fields.Add(fieldWithRVA);

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

ITypeDefOrRef byteArrayRef = importer.Import(typeof(System.Byte[]));
FieldDef fieldInjectedArray = new FieldDefUser("bla", new FieldSig(byteArrayRef.ToTypeSig()), FieldAttributes.Static | FieldAttributes.Public);
mod.GlobalType.Fields.Add(fieldInjectedArray);

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

ITypeDefOrRef systemByte = importer.Import(typeof(System.Byte));
ITypeDefOrRef runtimeHelpers = importer.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers));
IMethod initArray = importer.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray", new Type[] { typeof(System.Array), typeof(System.RuntimeFieldHandle) }));

MethodDef cctor = mod.GlobalType.FindOrCreateStaticConstructor();
IList instrs = cctor.Body.Instructions;
instrs.Insert(0, new Instruction(OpCodes.Ldc_I4, 5));
instrs.Insert(1, new Instruction(OpCodes.Newarr, systemByte));
instrs.Insert(2, new Instruction(OpCodes.Dup));
instrs.Insert(3, new Instruction(OpCodes.Ldtoken, fieldWithRVA));
instrs.Insert(4, new Instruction(OpCodes.Call, initArray));
instrs.Insert(5, new Instruction(OpCodes.Stsfld, fieldInjectedArray));

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.

instrs.Insert(1, new Instruction(OpCodes.Newarr, mod.CorLibTypes.Byte.ToTypeDefOrRef()));

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

FieldDef fieldInjectedArray = new FieldDefUser("bla", new FieldSig(new SZArraySig(mod.CorLibTypes.Byte)), FieldAttributes.Static | FieldAttributes.Public);
mod.GlobalType.Fields.Add(fieldInjectedArray);

Improving Meltdown

kao

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"! ๐Ÿ™‚

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.. ๐Ÿ™‚

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