.NET Assembly를 Win32 Native 환경에 직접 노출하는 방법

인터넷 서핑을 하던 도중 눈에 띄는 아티클 하나가 보였습니다. Jim Teeuwen씨에 의해 작성된 “Exporting Managed Code as Unmanaged” (http://www.csharphelp.com/archives3/archive500.html) 라는 글이었습니다. 이 글의 내용은 IL Assembler와 IL Disassembler를 활용하여 Win32 Native 환경에서 직접 로드할 수 있는 DLL을 만드는 방법이었습니다.


 


이 글을 작성하였던 분의 경우, Blitz Basic이라는 개발 환경에서 COM Interop을 사용할 수 없었던 점을 고심한 끝에 찾게된 방법을 소개한 것으로, 이러한 방법은 Visual C++ CLR 혼합 모드 컴파일의 결과물로부터 아이디어를 고안해 내신 것으로 보입니다.


 


이 글에서 소개하는 방법의 요지는, 기본적으로 Managed 환경에서는 필요로 하지 않는 V-TABLE과 함수 노출에 대한 데이터를 MSIL이 제공하는 기본 사양 내에 포함된 명령어를 통해서 데이터를 작성하고, DLL의 유형을 Win32 일반 DLL로 변경한다는 것에 있습니다. 다음은 수정 전의 MSIL 코드와 수정 후의 MSIL 코드입니다. 수정 후의 MSIL 코드에는 강조 표시를 해두었습니다.


 



[#M_수정 전의 코드|접어두기..|

.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 1:0:3300:0
}
.assembly HelloWorld
{
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module HelloWorld.dll
.imagebase 0x00400000
.subsystem 0x00000003
.file alignment 512
.corflags 0x00000001

.namespace HelloWorldDll
{
.class public auto ansi beforefieldinit HelloWorldClass
extends [mscorlib]System.Object{}
}

.namespace HelloWorldDll
{
.class public auto ansi beforefieldinit HelloWorldClass
extends [mscorlib]System.Object
{
.method public hidebysig static string SayHello(string name)
cil managed
{
.maxstack 2
.locals init (string V_0)
IL_0000: ldstr “Hello ”
IL_0005: ldarg.0
IL_0006: call string [mscorlib]System.String::Concat
(string, string)
IL_000b: stloc.0
IL_000c: br.s IL_000e

  IL_000e:  ldloc.0
  IL_000f:  ret
}

.method public hidebysig specialname rtspecialname
   instance void  .ctor() cil managed
{
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  ret
}

}
}

_M#]


 



[#M_수정 후의 코드|접어두기..|

‘// ### CHANGE ####’

.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 1:0:3300:0
}
.assembly HelloWorld
{
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module HelloWorld.dll
.imagebase 0x00400000
.subsystem 0x00000003
.file alignment 512

// ### CHANGE #### -> Change Image CoreFlag to
// COMIMAGE_FLAGS_32BITSREQUIRED to fix the potential WinXP pitfall
.corflags 0x00000002

// ### CHANGE #### -> Create a VTable entry
// wich will contain the needed data to identify our function
.vtfixup [1] int32 fromunmanaged at VT_01

// ### CHANGE #### -> Create a data entry to hold the Virtual
// Address to our function
.data VT_01 = int32(0)

.namespace HelloWorldDll
{
.class public auto ansi beforefieldinit HelloWorldClass
extends [mscorlib]System.Object{}
}

.namespace HelloWorldDll
{
.class public auto ansi beforefieldinit HelloWorldClass
extends [mscorlib]System.Object
{
.method public hidebysig static string
SayHello(string name) cil managed
{
// ### CHANGE #### -> Specify wich VTable entry to use
// for this function
.vtentry 1 : 1

// ### CHANGE #### -> Export the method as unmanaged code with
// the alias “SayHello”
.export [1] as SayHello

.maxstack 2
.locals init (string V_0)
IL_0000: ldstr “Hello ”
IL_0005: ldarg.0
IL_0006: call string [mscorlib]System.String::Concat(string, string)
IL_000b: stloc.0
IL_000c: br.s IL_000e

  IL_000e:  ldloc.0
  IL_000f:  ret
}

.method public hidebysig specialname rtspecialname
   instance void  .ctor() cil managed
{
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  ret
}

}
}

_M#]


 


위의 코드를 ILASM으로 다시 묶어서 만들어진 DLL을 Dependency Walker로 살펴보면 아주 흥미로운 결과가 나타납니다.


 



 


SayHello라는 일반적인 DLL Export 문맥이 나타나는 것을 볼 수 있습니다. 그리고 MSCOREE.DLL과 연결되어있고, 클래스 라이브러리이므로 CorDllMain과 연관되어있다는 것이 보입니다. 그러면 Reflector에서의 결과는 어떨까요?


 



 


다를 것이 없습니다. 다만 도출된 IL 결과를 살펴보면 우리가 방금 추가했던 명령어들만은 누락된채 MSIL이 나오는 것을 볼 수 있습니다.


 


기술적으로, 이와 같이 COM Interop이 아닌 방법으로 양쪽을 연결하는 것은 가능하지만, 생각해봐야할 문제점들이 몇 가지가 존재합니다.



  • 작업 비용이 큰 편입니다. 컴파일러에 의하여 한번에 빌드될 수 없는 형태를 취하고 있으며 뿐만 아니라 수작업으로 진행해야 합니다.

  • 마샬링 문제가 있을 수 있으며, 사용할 수 있는 형식에도 제한이 많다는 점을 감안해야 합니다.

시간적인 여유가 된다면, Reflection 기술과 Mono Project의 일부인 Cecil 라이브러리를 활용하여 이 아티클에서 설명하고 있는 기능에 대한 빌드 자동화 툴을 만드는 것도 재미있을것 같다는 생각이 듭니다.


 


cfile2.uf.202FF2044BDDAABF582726.rar


 


소스 코드 및 실제 샘플을 보고 싶으신 분은 위의 파일을 다운로드하시면 되겠습니다.

댓글 남기기