An Introduction To .NET Reversing

May 23rd, 2008 Greg

The first time I saw a .NET application, I was scared. I was scared of the unknown and this fear was only heightened after looking closer with OllyDbg, IDA and LordPE. I imagine that every seasoned reverser out there felt the same way. Well if that’s you, and you’re anything like me, then you’ll have avoided the .NET paradigm-shift for as long as possible. But after seeing new .NET articles and tools popping up left, right and centre, I decided it was time to face my demons and get comfortable with the inevitable future. This post is aimed at those familiar with native RCE but not with .NET, and forms a distillation of the essential facts you’ll need to get started.

You probably already know that .NET is a semi-compiled language - that is, a .NET binary (called an ‘assembly’) exists as bytecode that is compiled into native code just before execution. The bytecode is called Common Intermediate Language, or CIL, (formerly known as Microsoft Intermediate Language - MSIL) and it is the product of any C#, VB.NET or J# compilation. These exe and DLL assemblies are wrapped up inside regular PE files having only one import - mscoree.dll - which acts as the assembly’s just-in-time (JIT) compiler and its gateway to the .NET Framework and its platform API, the Common Language Runtime (CLR). The PE header’s data directory contains a .NET directory entry, which points to a new header in the file containing everything the operating system needs to run it.

There are a lot of changes from the familiar native situation, some of which work for us and some against. From a hacker’s perspective, there are some pros:

  • CIL is reflective, meaning that the structure of the code can be deterministically inferred from its assembly.
  • For JIT compilation, linking and introspection to work, a considerable amount of type information must remain in the assembly.
  • .NET assemblies are a few levels of abstraction away from the user-mode platform, so there is far less scope for obfuscation, and anti-debug tricks.
  • The CLR provides standardised interfaces for a tremendous amount of functionality for standard operations, and this is typically embraced by .NET programmers. The result is short, concise code that can reveal even very complex algorithms at a glance.

and, of course, some cons:

  • The assembly effectively runs in a virtual machine, meaning the operations-to-clock-cycles ratio is a few orders of magnitude higher. This is of immediate consequence if you are tracing through the program natively (i.e. debugging the JIT compiler).
  • The abstracted nature of the program’s entities means that old friends like Olly’s ‘registers’ and ’stack’ windows are of very little use. In fact, the applicability of a low-level debugger is altogether questionable.
  • While the relatively small community is making tremendous efforts, the science of .NET RCE is still quite young and so the tools available are correspondingly immature and thin on the ground.

So put OllyDbg, LordPE and your hex-editor aside (you may want to keep IDA within reach) and meet your new arsenal:

  • Lutz Roeder’s .NET Reflector is perhaps the best-known and most advanced .NET reversing tool. It’s also an invaluable asset for every .NET job, giving you in-depth at-a-glance information about any assembly.
  • ILDAsm - This is Microsoft’s CIL disassembler and is far more useful than any native equivalent. You can download it from MSDN if necessary, but it comes as a part of Visual Studio (all versions) and can be found either at ($ProgramFiles)\Microsoft SDKs\Windows\[Version]\bin or ($VisualStudioDir)\SDK\2.0\… depending on your version. Be sure to check your non-x86 Program Files directory if you’re running Windows x64.
  • ILAsm - As you guessed, this is the CIL assembler. The great thing about this is that in many circumstances, you can pipe ILDAsm’s output into ILAsm and end up with a fully working assembly.
  • Explorer Suite - A Swiss Army Knife of .NET-aware tools. This will be your new PE editor for all things .NET.

    (I recommend you take a look around Dan Pistelli’s site once you’re comfortable with the terrain as he’s produced a lot of marvellous tools that can cut your workload down considerably.)

If you were wondering where the debugger is, then my answer is that you’re probably better off without one, at least for the moment. It would of course be a very handy addition, but I haven’t found any .NET debuggers that work too well. DILE is promising, but it’s very unstable on my 64-bit Windows, and WinDbg puts in a good effort with the SoS extension running, but you won’t find anything that’s a joy to use.

So with all the framework in place it’s remarkably easy to get going. The first step is to take a look at your target assembly in Reflector and get a feel for the program. If it isn’t obfuscated then you’ll probably be surprised how easy this is (in the many cases it’s just like having the source code). If it is obfuscated then you may need to work a little harder, or perhaps skip straight ahead to the next step:

ildasm Target.exe /out=Target.il

The resulting file contains a complete CIL listing of the assembly, which you can edit at your leisure. You may want to Google ‘MSIL’ to get an idea of what all those alien-looking opcodes do, but it’s really quite straightforward to do the basics:

  • ‘Push’ instructions start with ld (load), ‘Pop’s with st (store).
  • There is no MOV instruction. In order to copy from one place to another, push then pop.
  • Most manipulation involves arguments and locals, which are referenced by index using a dot, e.g.
    ldarg.1 // Push the second argument
    stloc.0 // Pop it into the first local
  • Constants are pushed using ldc. The size and type of constant must also be specified e.g.
    ldc.i4 12 // Push a 4-byte integer (of value 12)
    ldc.r4 33.33 // Push a 32-bit float
  • The values are returned by pushing them onto the stack prior to a return (ret)

Far more complete references exist on the web if you’re willing to search, but this is enough to short-circuit a function or two. Once you’re done playing with the CIL, compile it back up, being sure to specify any resource files that were created by the disassembler:

ilasm [/dll] Target.il [/res=Target.res] /out=TargetNew.dll

And you’re all ready to go. This is sufficient for the most basic cases, but it will only be a matter of time before you encounter an obfuscated assembly (which will cause you problems in Reflector) or one that’s signed using strong-names (which will refuse to run after compilation). I’ll discuss both of these situations and any relevant workarounds another day.

D3DLookingGlass v0.1

May 5th, 2008 Greg

The topic of debugging full-screen Direct3D applications came up a little while ago. If you’ve ever tried it on a single-monitor setup (or even multi-monitor if the app wasn’t designed to handle it) then you’ll know how much of a pain it is. Windows just can’t handle focus being stolen from a suspended exclusive-mode program. The solution’s exactly what you’d expect - to intercept the relevant window- and device-creation calls and coax the debuggee into running in a window. This works, but fiddling with the calls manually each time you restart the process quickly gets boring. So here’s my first attempt at a generic solution.

D3DLookingGlass is a DLL which, if injected into a Direct3D process early enough, will make sure that all video devices are created in windowed mode, allowing the hosting process to coexist with a debugger without any bother. If you can inject this DLL into the target process before the first call to CreateWindow, then everything should go smoothly. I think. Any later than this and your mileage may vary.

I’ve also written a ‘loader’ program that installs the DLL as a system-wide CBT hook, so that you don’t need to inject it manually. This kind of worked for my limited set of test-cases, but there seems to be no Windows-hooks method of injecting a DLL globally and beating the call to CreateWindow. Windows installs the DLL containing the hook at the latest possible moment for its function, and I can find no type of hook that needs to be around before a window is created. I’d love for somebody to prove me wrong (or suggest another way to install the DLL system-wide), but by the looks of things, my loader is of limited use.

In particular, I recall a situation where the game (Call Of Duty 4 Demo, I think) creates a non-overlapped window, which works fine for full-screen mode, but causes problems when you try force the device to bind as windowed. This will still be a problem unless the call to CreateWindow can be intercepted (and a well-formed window induced), which means that D3DLookingGlassLoader will struggle. Confirmation would be nice.

Here’s the source: D3DLookingGlass_Source.zip

Here’s the binary: D3DLookingGlass_Binary.zip

Here’s the small-print:

  • The DLL hooks CreateWindowExW and ShowWindow in its DLLMain. I think this is kosher in terms of loader-lock, but it’s obviously not too cool with regard to system stability. Especially if it’s being installed in every running process. If d3d9.dll isn’t found in the address-space then the hooks fall straight through, so that shouldn’t be too much of a problem. But if it is found then all attempts to create or show (or hide) a window will be overridden - possibly to the demise of the process if it’s doing anything but the basic behaviour. So in all cases, watch out, and make sure you aren’t running anything important in the background (in particular, I’ve noticed that it doesn’t play nice with Firefox).
  • The loader uses a system-wide hook, and you hate system-wide hooks. I trust that anybody who needs this tool has some degree of technical expertise and is aware of the stability concerns inherent in installing somebody else’s barely-tested system-wide hook.
  • This was harder to put together than I anticipated, and that’s probably evident from the slightly shabby code. Again, I intend for this only to be used for debugging purposes, so you’ll have to forgive me for the sub-production-quality code.
  • Despite the focus on Direct3D of this blog, I’m not really a gamer and I don’t actually have any commercial games installed on this machine. So I only got a chance to test this against my own programs. Obviously, there are several ways to skin the metaphorical Direct3D-initialisation cat, so please leave a comment when you find a game that this chokes on.