最近在研究编写.Net的壳(以.Net3.5 SP1环境做开发测试),思路如下:1.读取要加壳的.Net PE文件,对IL指令进行加密并移动位置(我放到了一个新PE节)
2.一个非托管的DLL,在这个DLL中HOOK JIT编译部分,当对IL指令做即时编译的时候读取并解密整个过程都是没问题的,现在遇到的问题是如何将非托管的DLL加入到目标的进程空间。最好是直接在PE文件上做改动,这样,只需要复制加壳后的文件,就可以直接在其它机器上运行。
而且JIT HOOK必须在Assembly执行前加载,如果被加密的方法被直接执行而缺少JIT HOOK DLL只会直接报错。1. 首先想到的办法是修改.Net PE的 Import Table,将自己的DLL导入。
试过之后发现这种方式不行,NT的PE Loader在检测到PE文件时.Net PE时,会在加载前先调用mscoree.dll中的_CorValidateImage检验文件,文件检验格式非法就返回0xC000002B。
而 CorValidateImage 把.Net PE文件的格式限制得非常死,很多东西不允许改。看下面。text:79005197                 push    ebp
.text:79005198                 mov     ebp, esp
.text:7900519A                 push    ecx
.text:7900519B                 push    ecx
.text:7900519C                 push    esi
.text:7900519D                 mov     esi, ecx
.text:7900519F                 test    byte ptr [esi+8], 40h
.text:790051A3                 jnz     loc_790223BC
.text:790051A3
.text:790051A9                 push    edi
.text:790051AA                 lea     eax, [ebp+var_4]
.text:790051AD                 push    eax
.text:790051AE                 call    PEDecoder::CheckCorHeader(void)
.text:790051AE
.text:790051B3                 xor     edi, edi
.text:790051B5                 cmp     [eax], edi
.text:790051B7                 jnz     loc_790223C7
.text:790051B7
.text:790051BD                 push    ebx
.text:790051BE                 mov     ecx, esi
.text:790051C0                 call    PEDecoder::GetNumberOfRvaAndSizes(void)
.text:790051C0
.text:790051C5                 xor     ebx, ebx
.text:790051C7                 inc     ebx
.text:790051C8                 test    eax, eax
.text:790051CA                 mov     [ebp+var_4], eax
.text:790051CD                 jbe     short loc_790051E1
.text:790051CD
.text:790051CF
.text:790051CF loc_790051CF:                           ; CODE XREF: PEDecoder::CheckILOnly(void)+48j
.text:790051CF                 push    edi
.text:790051D0                 mov     ecx, esi
.text:790051D2                 call    PEDecoder::HasDirectoryEntry(int)
.text:790051D2
.text:790051D7                 test    eax, eax
.text:790051D9                 jnz     short loc_79005160
.text:790051D9
.text:790051DB
.text:790051DB loc_790051DB:                           ; CODE XREF: PEDecoder::CheckILOnly(void)-26j
.text:790051DB                                         ; PEDecoder::CheckILOnly(void)-Ej
.text:790051DB                 inc     edi
.text:790051DC                 cmp     edi, [ebp+var_4]
.text:790051DF                 jb      short loc_790051CF
.text:790051DF
.text:790051E1
.text:790051E1 loc_790051E1:                           ; CODE XREF: PEDecoder::CheckILOnly(void)+36j
.text:790051E1                 push    ebx
.text:790051E2                 mov     ecx, esi
.text:790051E4                 call    PEDecoder::HasDirectoryEntry(int)
.text:790051E4
.text:790051E9                 test    eax, eax
.text:790051EB                 jz      loc_790223D5
.text:790051EB
.text:790051F1
.text:790051F1 loc_790051F1:                           ; CODE XREF: PEDecoder::CheckILOnly(void)+1D249j
.text:790051F1                                         ; PEDecoder::CheckILOnly(void)+1D259j
.text:790051F1                 lea     eax, [ebp+var_8]
.text:790051F4                 push    eax
.text:790051F5                 mov     ecx, esi
.text:790051F7                 call    PEDecoder::CheckILOnlyImportDlls(void)
.text:790051F7
.text:790051FC                 xor     edi, edi
.text:790051FE                 cmp     [eax], edi
.text:79005200                 jnz     short loc_7900518B
.text:79005200
.text:79005202                 lea     eax, [ebp+var_8]
.text:79005205                 push    eax
.text:79005206                 mov     ecx, esi
.text:79005208                 call    PEDecoder::CheckILOnlyBaseRelocations(void)
.text:79005208
.text:7900520D                 cmp     [eax], edi
.text:7900520F                 jnz     loc_7900518B
.text:7900520F
.text:79005215                 lea     eax, [ebp+var_8]
.text:79005218                 push    eax
.text:79005219                 mov     ecx, esi
.text:7900521B                 call    PEDecoder::CheckILOnlyEntryPoint(void)
.text:7900521B
.text:79005220                 cmp     [eax], edi
.text:79005222                 jnz     loc_7900518B
mscoree.dll把修改导入表这条路封死了。(我是不是可以试试其它方式?比如IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT??)2.第2个想到的办法是修改.Net入口 EntryPointToken 
首先修改.Net PE的MetaTable,加入一个自己的函数,然后修改导入点, 在程序启动的时候调用LoadLibrary一次。不过这样也存在一个问题,如果是ASP.Net Web Site,编译出来是DLL, EntryPointToken 为0, 我试过改成某函数也根本无效。看来mscoree.dll的_CorDllMain完全忽略EntryPointToken 。欢迎高手给点建议或者意见

解决方案 »

  1.   

    你想挂接JIT做什么?拦截让部分代码得不到编译执行?
      

  2.   

    进来废话几句,其实.Net的加壳软件有,但是实际上并不是“加壳”,拦截JIT是很麻烦的某牛逆向的结果是,某XX商业级.Net加壳软件是重写了方法体,在JIT的时候,将原来的代码的方法体偏移给了JIT.Net逆向学习过一点皮毛,后来荒废就没兴趣了。实在是不好啃
      

  3.   

    JIT Hook也不是不可以,有点麻烦罢了,你看看这里的例子
    某牛的DEMO
      

  4.   


    现在遇到的问题是如何将非托管的DLL加入到目标的进程空间 其它都已经解决了
      

  5.   

    不需要注入.那些成熟的.Net商业壳没有哪个是靠注入实现的,也不现实
      

  6.   

    import table 可实现慢慢研究吧。
      

  7.   

    这个我有研究过,一个老外的demo
    老外的实现是一个程序加密后,分成三部分
    loader.exe 用于启动的loader
    native.dll 用于hook compilemethod等关键函数实现运行是解密,这个dll基本是shellcode形式实现
    cryxed.dll 加密后的程序,il代码被加过密下面是我还原老外的loader代码,可以看到,以函数的形式执行native代码和启动assemble的方法
    ,native.dll还没有弄完,期待你的加密壳,可以与我讨论 mail:[email protected]
    using System;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Reflection;
    namespace Project1
    {
    class Program
    {
    private delegate int obfuscation8();
    public static void Main()
    {
        long num6;
        FileStream stream = new FileInfo("native.dll").OpenRead();
        long length = stream.Length;
        byte[] array = new byte[((int) length) + 1];
        stream.Read(array, 0, (int) length);
        stream.Close();
        long num7 = length;
        for (num6 = 0L; num6 <= num7; num6 += 1L)
        {
            array[(int) num6] = (byte) (array[(int) num6] ^ 0x37);
        }
        IntPtr destination = new IntPtr();
        destination = Marshal.AllocCoTaskMem((int) length);
        Marshal.Copy(array, 0, destination, (int) length);
        obfuscation8 delegateForFunctionPointer = (obfuscation8) Marshal.GetDelegateForFunctionPointer(destination, typeof(obfuscation8));
    File.WriteAllBytes("decrypted_fun.exe", array);
        long num = new long();
    //System.Reflection.Emit.Break;
        num = delegateForFunctionPointer();
    System.Console.WriteLine(" num = " + num);
        stream = new FileInfo("cryxed.dll").OpenRead();
        length = stream.Length;
        byte[] buffer2 = new byte[((int) length) + 1];
        stream.Read(buffer2, 0, (int) length);
        stream.Close();
        long num8 = length;
        for (num6 = 0L; num6 <= num8; num6 += 1L)
        {
            buffer2[(int) num6] = (byte) (buffer2[(int) num6] ^ 0x37);
        }
        File.WriteAllBytes("decrypted_assembly.exe", buffer2);
        Assembly assembly = Assembly.Load(buffer2);
        object[] parameters = new object[1];
        string[] strArray = new string[] { "" };
        parameters[0] = strArray;
        assembly.EntryPoint.Invoke(null, parameters);
    }
    }
    }
      

  8.   

    《Windows内核及高级调试》里面好像讲过