a reference to the actual data, much like the conventional notion of pointers.
Values are typically allocated on the stack or inside some other object, while
with references the actual objects are typically allocated in a heap block, which
is freed automatically by the garbage collector (granted, this explanation is
somewhat simplistic, but it’ll do for now).
The typical use for value data types is for built-in data types such as inte-
gers, but developers can also define their own user-defined value types, which
are moved around by value. This is generally only recommended for smaller
data types, because the data is duplicated when passed to other methods, and
so on. Larger data types use reference types, because with reference types only
the reference to the object is duplicated—not the actual data.
Finally, unlike values, reference types are self-describing, which means that a
reference contains information on the exact object type being referenced. This
is different from value types, which don’t carry any identification information.
One interesting thing about the CTS is the concept of boxingand unboxing.
Boxing is the process of converting a value type data structure into a reference
type object. Internally, this is implemented by duplicating the object in question
and producing a reference to that duplicated object. The idea is that this boxed
object can be used with any method that expects a generic object reference as
input. Remember that reference types carry type identification information with
them, so by taking an object reference type as input, a method can actually check
the object’s type in runtime. This is not possible with a value type. Unboxing is
simply the reverse process, which converts the object back to a value type. This
is needed in case the object is modified while it is in object form—because box-
ing duplicates the object, any changes made to the boxed object would not
reflect on the original value type unless it was explicitly unboxed.
Intermediate Language (IL)
As described earlier, .NET executables are rarely shipped as native executa-
bles.^1 Instead, .NET executables are distributed in an intermediate form called
Common Intermediate Language (CIL) or Microsoft Intermediate Language
(MSIL), but we’ll just call it IL for short. .NET programs essentially have two
compilation stages: First a program is compiled from its original source code
to IL code, and during execution the IL code is recompiled into native code by
the just-in-time compiler. The following sections describe some basic low-level
.NET concepts such as the evaluation stack and the activation record, and
introduce the IL and its most important instructions. Finally, I will present a
few IL code samples and analyze them.
Reversing .NET 429
(^1) It is possible to ship a precompiled .NET binary that doesn’t contain any IL code, and the pri-
mary reason for doing so is security-it is much harder to reverse or decompile such an executable.
For more information please see the section later in this chapter on the Remotesoft Protector
product.