닷넷 프로그램을 컴파일 하면 중간언어로 된 실행파일을 만든다. 중간언어는 특정한 프로세스에 맞춘 어셈블리가 아니라 그 전단계로 어떤 기계어로던 번역에 편리한 언어로 만들어진 어셈블리로 생각하면 된다. 백마디 말보다 직접 만들어서 살펴보자. 우선 비주얼스튜디오닷넷을 실행한다.(VS.NET 2003 기준) VS.NET을 실행하고 파일->새로만들기->프로젝트 메뉴을 선택한다. 그러면 다양한 프로젝트의 종류가 나오는데 가장 간단히 만들어 보기 위하여 좌측의 프로젝트 형식은 Visual C# Project, 템플릿은 콘솔응용프로그램을 선택하고 프로젝트 디렉토리를 적절한 곳으로 입력한 후에(기본은 내문서\Visual Studio Projects 아래에 만들어진다.) 확인을 누른다.
그러면 기본 Class1.cs파일의 내용이 아래와 같이 나온다.
using
System;
namespace
ConsoleApplication2
{
///
///
Class1
에 대한 요약 설명입니다.
///
class
Class1
{
///
///
해당 응용 프로그램의 주 진입점입니다.
///
[STAThread]
static
void
Main(
string
[] args)
{
//
// TODO:
여기에 응용 프로그램을 시작하는 코드를 추가합니다.
//
}
}
}
여기에 아래와 같이 코드를 입력 한다. using System;
namespace ConsoleApplication2
{
///
/// Class1에 대한 요약 설명입니다.
///
class Class1
{
///
///해당 응용 프로그램의 주 진입점입니다.
///
[STAThread]
staticvoidMain(string[] args)
{
//
// TODO: 여기에 응용 프로그램을 시작하는 코드를 추가합니다.
//
int num = int.Parse(args[0]);
int sum = 0;
for(int i=1; i<=num; i++)
sum += i;
Console.WriteLine("합계 = {0}", sum);
Console.Read();
}
}
}
이 프로그램은 커맨드라인(명령줄) 파라메터로 입력된 숫자까지 1부터 합을 구하는 프로그램이다. 메뉴에서 빌드->솔루션빌드를 선택하여 프로그램을 컴파일 한다. 그러면 프로젝트 디렉토리에 .exe파일이 생성된다. 디컴파일러는 VS.NET으로 할수가 없고 인터넷에서 적당한 툴을 다운 받는다. 여기서는 "Reflector for .NET "을 사용한다. 이 프로그램은 http://www.aisto.com/roeder/dotnet/에서 받을 수 있다. 이 프로그램을 사용하면 아래와 같은 중간언어 결과를 얻을 수 있다.(이 프로그램의 상세한 사용법은 차후에 다시한번 설명하기로 한다)
.namespace ConsoleApplication2
{
.class private auto ansi beforefieldinit Class1
extends object
{
.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
// Code Size: 7 byte(s)
.maxstack 1
L_0000: ldarg.0
L_0001: call instance void object::.ctor()
L_0006: ret
}
.method private hidebysig static void Main(string[] args) cil managed
{
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
.entrypoint
// Code Size: 50 byte(s)
.maxstack 2
.locals init (
int32 num1,
int32 num2,
int32 num3)
L_0000: ldarg.0
L_0001: ldc.i4.0
L_0002: ldelem.ref
L_0003: call int32 int32::Parse(string)
L_0008: stloc.0
L_0009: ldc.i4.0
L_000a: stloc.1
L_000b: ldc.i4.1
L_000c: stloc.2
L_000d: br.s L_0017
L_000f: ldloc.1
L_0010: ldloc.2
L_0011: add
L_0012: stloc.1
L_0013: ldloc.2
L_0014: ldc.i4.1
L_0015: add
L_0016: stloc.2
L_0017: ldloc.2
L_0018: ldloc.0
L_0019: ble.s L_000f
L_001b: ldstr "\ud569\uacc4 = {0}"
L_0020: ldloc.1
L_0021: box int32
L_0026: call void [mscorlib]System.Console::WriteLine(string, object)
L_002b: call int32 [mscorlib]System.Console::Read()
L_0030: pop
L_0031: ret
}
}
}
이 코드는 이해할려고 할 필요가 없다. 단지 이런식으로 생긴 어셈블리로 만들어진다는 정도만 알아 두면 된다. Reflector for NET은 다양한 언어로 디컴파일 하는 기능도 가지고 있다. 아래는 비주얼베이직.NET으로 디컴파일 한 결과다.
Imports System
Namespace ConsoleApplication2
FriendClass Class1
' Methods
PublicSubNew()
EndSub
_
PrivateSharedSub Main(ByVal args AsString())
Dim num1 AsInteger = Integer.Parse(args(0))
Dim num2 AsInteger = 0
Dim num3 AsInteger = 1
DoWhile (num3 <= num1)
num2 = (num2 + num3)
num3 += 1
Loop
Console.WriteLine(ChrW(54633) & ChrW(44228) & " = {0}", num2)
Console.Read
EndSub
EndClass
EndNamespace
변수의 이름만 나오지 않을 뿐 프로그램은 원래의 모양대로 그대로 다시 만들 수 있음을 알수 있다. 또한 비주얼베이직과 C#완전하게 서로 호환가능한 언어구조를 가지고 있다는 사실 또한 알수 있다. 닷넷은 중간 언어를 매개로 실제 개발에 사용되는 언어와는 완전히 무관하게 설계가 되어 있는 것이다. 이래한 툴들 때문에 닷넷으로 만든 프로그램은 소스보호차원에서 보면 바이너리로 만드는 것보다는 훨씬 약하다는 것을 알 수 있다. 소스 보호를 위해서 특별한 조치가 필요한 중요한 소프트웨어라면 소스를 읽기 힘들게 하는 암호화 프로그램을 사용하는 것이 바람직하다 하겠다.