• 采用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 部分
    void InvokeAssemblyResource()
    {
     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");
      return false;
     }
     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");
       break;
      }

      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 false;
     }

     return bSuccess;
    }

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

    不过单纯的整体加密保护安装性是很低的,可以配合一些其它的方式来提高保护强度,如 .Net Reactor的 NecroBit.
    因为在Load时很容易被dump出程序集.这种方式就是让Load时载入的程序集不是完整的(除去了IL代码部分,NecroBit).
    然后在Load完成后,程序集执行之前,还原IL代码.

  • 相关阅读:
    SQLite的使用
    Messenger类的使用
    Binder的使用(跨进程——AIDL,非跨进程)
    Android Studio中如何创建AIDL
    第二章——Parcelable接口的使用(跨进程,Intent传输)
    InetAddress的作用
    第二章——Serializable的使用(跨进程使用和Intent的传递对象)
    SurfaceView绘图机制
    双缓冲机制简介
    内部类代码
  • 原文地址:https://www.cnblogs.com/rick/p/1060865.html
Copyright © 2020-2023  润新知