天天看点

采用Native 引导方式的.Net加密保护

这类加密保护方式属于整体程序集的加密保护.

这个方法首要解决的问题就是 native code 和 .Net Code如何交互.

这里介绍三种实现方式.

1. C++/CLI 实现.

这个比较简单了,会C++/CLI一下子就能完成了.

Loader是由C++/CLI实现的.运行时通过解码程序集通过反射载入然后运行.

void InvokeAssemblyResource()

{

 try

 {

  byte[] pBuf = GetDecryptedResource();  

  Assembly^ asm = Assembly::Load(pBuf);

  asm->EntryPoint->Invoke(nullptr,nullptr);

 }

 catch(Exception^ ex)

  MessageBox::Show(ex->Message);

}

2. 利用C#导出Com接口和native code交互.

Loader由C#和native code两部分组成.

C#部分代码

public interface IInvokeAssembly

 void LoadAndExecute(byte[] pBuf);

};

public class CInvokeAssembly : IInvokeAssembly

 public CInvokeAssembly()

 public void LoadAndExecute(byte[] pBuf)

  try

  {

   Assembly asm = Assembly.Load(pBuf);

   asm.EntryPoint.Invoke(null,null);

  }

  catch(Exception ex)

   MessageBox.Show(ex.Message);

这里导出的 IInvokeAssembly 接口,将在native code中使用.

native code 部分

 IInvokeAssemblyPtr pInvoker; //COM Pointer to the .Net Interface

 if(FAILED(pInvoker.CreateInstance(CLSID_CInvokeAssembly)))

  MessageBox(NULL,_T("Unable to Create Invoke Assembly Object !!"),_T("Error"),MB_OK|MB_ICONERROR);

  return;

 HRSRC hRC = FindResource(NULL,MAKEINTRESOURCE(IDR_EMBEDDED_ASSEMBLY),"RT_EMBEDDED_ASSEMBLY");

 HGLOBAL hRes = LoadResource(NULL,hRC);

 DWORD dwSize = SizeofResource(NULL,hRC);

 SAFEARRAY* pSA = NULL;

 if(NULL !=(pSA = SafeArrayCreateVector(VT_UI1, 0, dwSize)))

  LPVOID pBuf = NULL;

  if(FAILED(SafeArrayAccessData(pSA,&pBuf)))

   MessageBox(NULL,_T("Unable to Access SafeArray Data"), _T("Error"),MB_OK|MB_ICONERROR);

  else

   LPVOID hAsm = LockResource(hRes);

   memcpy(pBuf, hAsm, dwSize);

   UnlockResource(hRes);

   SafeArrayUnaccessData(pSA);

  pInvoker->LoadAndExecute(pSA); //Invoke the Reflection to load and Execute our Byte[]

 else

  MessageBox(NULL,_T("Unable to Allocate Memory"),_T("Memory Allocate Error"),MB_OK|MB_ICONERROR);

 if(pSA) SafeArrayDestroy(pSA);

这里还有一个问题,loader是两部分.加密的程序集可以作为资源签入到native code loader中.但是C#部分怎么处理?

一个比较隐蔽的方式是,在安装程序时将它安装到gac中.

3 是利用 CLR-Hosting 接口. 可以参考msdn中 本地接口部分的文档.

bool InvokeAssemblyResource()

{  

 CComPtr<ICorRuntimeHost> spRuntimeHost;

 CComPtr<_AppDomain> spAppDomain;

 CComPtr<IUnknown> spUnk;

 bool bSuccess = false;

 if(FAILED(CorBindToRuntimeEx( NULL, // Latest Version by Default

    L"wks",  // Workstation build

    STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN,

    CLSID_CorRuntimeHost ,

    IID_ICorRuntimeHost ,

    (void**)&spRuntimeHost)))

  gErrMsg = _T("Unable to Bind CLR");

  return false;

 if(FAILED(spRuntimeHost->Start()))

  gErrMsg = _T("Unable to Start CLR");

 do

  if(FAILED(spRuntimeHost->GetDefaultDomain(&spUnk)))

   gErrMsg = _T("Unable to GetDefaultDomain");

   break;

  if(FAILED(spUnk->QueryInterface(&spAppDomain.p)))

   gErrMsg = _T("Unable to Query AppDomain Interface");

  SAFEARRAY* pSA = GetDecryptedResource();

  if(pSA)

   try

   {    // Invoke the Entry Point with No Arguments

    spAppDomain->Load_3(pSA)->EntryPoint->Invoke_3(_variant_t(), NULL); 

    bSuccess = true; // Everything Went Fine !!

   }

   catch(_com_error ex)

   {

    gErrMsg = ex.ErrorMessage();

   SafeArrayDestroy(pSA);

   pSA = NULL; 

 }while(false);

 if(FAILED(spRuntimeHost->Stop()))

  gErrMsg = _T("Unable to Stop CLR");

 return bSuccess;

一般这类加密工具都会选择第三种实现方式.如 .Net Reactor.

不过单纯的整体加密保护安装性是很低的,可以配合一些其它的方式来提高保护强度,如 .Net Reactor的 NecroBit.

因为在Load时很容易被dump出程序集.这种方式就是让Load时载入的程序集不是完整的(除去了IL代码部分,NecroBit).

然后在Load完成后,程序集执行之前,还原IL代码.