<em id="pzl9c"></em>
      <dl id="pzl9c"><ins id="pzl9c"></ins></dl>
      <dfn id="pzl9c"></dfn>

        <progress id="pzl9c"></progress>
        <div id="pzl9c"><ol id="pzl9c"></ol></div>
          <div id="pzl9c"><tr id="pzl9c"></tr></div>

          <em id="pzl9c"></em>

            <em id="pzl9c"><ins id="pzl9c"><mark id="pzl9c"></mark></ins></em>
            <dl id="pzl9c"></dl>

            <dl id="pzl9c"></dl>

              <div id="pzl9c"></div>
              <dl id="pzl9c"><ins id="pzl9c"></ins></dl>

              <dfn id="pzl9c"></dfn>
              <sup id="pzl9c"><ins id="pzl9c"></ins></sup>

                <dl id="pzl9c"></dl>

                飄云閣(PYG官方論壇)

                 找回密碼
                 加入論壇

                QQ登錄

                只需一步,快速開始

                掃一掃,訪問微社區

                查看: 1003|回復: 19
                打印 上一主題 下一主題

                [原創] [.NET]詳解ConfuserEx的Anti Tamper與Anti Dump by Wwh / NCK

                [復制鏈接]
              1. TA的每日心情
                開心
                2018-9-21 22:58
              2. 簽到天數: 2 天

                [LV.1]初來乍到

                跳轉到指定樓層
                樓主
                發表于 2018-8-15 10:29:22 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
                # [.NET]詳解ConfuserEx的Anti Tamper與Anti Dump by Wwh

                許多人都知道利用dnSpy單步調試+Dump+CodeCracker的一系列工具可以脫去ConfuserEx殼,這些在網上都有教程,但是并沒有文章說明過背后的原理。本文講盡可能詳細解說ConfuserEx的Anti Tamper與Anti Dump**(有耐心并且了解一點點的PE結構完全可以看懂)**

                ## ConfuserEx整個項目結構

                在開始講解之前,我們大概了解一下ConfuserEx項目的結構。
                我們用Visual Studio打開ConfuserEx,項目大概是這樣的:

                Confuser.CLI的是命令行版本,類似de4dot的操作方式
                Confuser.Core是核心,把所有部分Protection組合到一起
                Confuser.DynCipher可以動態生成加密算法
                Confuser.Protections里面包含了所有Protection,這是需要研究的部分
                Confuser.Renamer可以對類名、方法名等重命名,包括多種重命名方式,比如可逆的重命名,這些沒有在ConfuserEx的GUI里面顯示就是了
                Confuser.Runtime是運行時,比如Anti Dump的實現,其實就在這個項目里面。上面提到的Confuser.Protections會把Confuser.Runtime中的Anti Dump的實現注入到目標程序集。
                ConfuserEx是GUI,沒必要多說。
                **整個項目幾乎沒什么注釋,下面的中文注釋均為我添加的。**

                ## Anti Dump

                Anti Dump比起Anti Tamper簡單不少,所以我們先來了解一下Anti Dump。
                Anti Dump的實現只有一個方法,非常簡潔。
                我們找到Confuser.Protections項目的AntiDumpProtection.cs。

                [C#] 純文本查看 復制代碼
                protected override void Execute(ConfuserContext context, ProtectionParameters parameters) {
                    TypeDef rtType = context.Registry.GetService<IRuntimeService>().GetRuntimeType("Confuser.Runtime.AntiDump");
                    // 獲取Confuser.Runtime項目中的AntiDump類
                
                    var marker = context.Registry.GetService<IMarkerService>();
                    var name = context.Registry.GetService<INameService>();
                
                    foreach (ModuleDef module in parameters.Targets.OfType<ModuleDef>()) {
                        IEnumerable<IDnlibDef> members = InjectHelper.Inject(rtType, module.GlobalType, module);
                        // 將Confuser.Runtime.AntiDump類注入到目標程序集,返回目標程序集中的所有IDnlibDef
                
                        MethodDef cctor = module.GlobalType.FindStaticConstructor();
                        // 找到<Module>::.cctor
                        var init = (MethodDef)members.Single(method => method.Name == "Initialize");
                        cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, init));
                        // 插入call void Confuser.Runtime.AntiDump::Initialize()這條IL指令
                
                        foreach (IDnlibDef member in members)
                            name.MarkHelper(member, marker, (Protection)Parent);
                        // 將這些IDnlibDef標記為需要重命名的
                    }
                }
                

                AntiDumpProtection做的只是注入,所以我們轉到Confuser.Runtime中的AntiDump.cs

                [C#] 純文本查看 復制代碼
                static unsafe void Initialize() {
                    uint old;
                    Module module = typeof(AntiDump).Module;
                    var bas = (byte*)Marshal.GetHINSTANCE(module);
                    byte* ptr = bas + 0x3c;
                    // 存放NT頭偏移的地址
                    byte* ptr2;
                    ptr = ptr2 = bas + *(uint*)ptr;
                    // ptr指向NT頭
                    ptr += 0x6;
                    // ptr指向文件頭的NumberOfSections
                    ushort sectNum = *(ushort*)ptr;
                    // 獲取節的數量
                    ptr += 14;
                    // ptr指向文件頭的SizeOfOptionalHeader
                    ushort optSize = *(ushort*)ptr;
                    // 獲取可選頭的大小
                    ptr = ptr2 = ptr + 0x4 + optSize;
                    // ptr指向第一個節頭
                
                    byte* @new = stackalloc byte[11];
                    if (module.FullyQualifiedName[0] != '<') //Mapped
                    {
                        // 這里判斷是否為內存加載的模塊(dnSpy里面顯示InMemory的),比如Assembly.Load(byte[] rawAssembly)
                        // 如果是內存加載的模塊,module.FullyQualifiedName[0]會返回"<未知>"
                        //VirtualProtect(ptr - 16, 8, 0x40, out old);
                        //*(uint*)(ptr - 12) = 0;
                        byte* mdDir = bas + *(uint*)(ptr - 16);
                        // ptr指向IMAGE_COR20_HEADER
                        //*(uint*)(ptr - 16) = 0;
                
                        if (*(uint*)(ptr - 0x78) != 0) {
                            // 如果導入表RVA不為0
                            byte* importDir = bas + *(uint*)(ptr - 0x78);
                            byte* oftMod = bas + *(uint*)importDir;
                            // OriginalFirstThunk
                            byte* modName = bas + *(uint*)(importDir + 12);
                            // 導入DLL的名稱
                            byte* funcName = bas + *(uint*)oftMod + 2;
                            // 導入函數的名稱
                            VirtualProtect(modName, 11, 0x40, out old);
                
                            *(uint*)@new = 0x6c64746e;
                            *((uint*)@new + 1) = 0x6c642e6c;
                            *((ushort*)@new + 4) = 0x006c;
                            *(@new + 10) = 0;
                            // ntdll.dll
                
                            for (int i = 0; i < 11; i++)
                                *(modName + i) = *(@new + i);
                            // 把mscoree.dll改成ntdll.dll
                
                            VirtualProtect(funcName, 11, 0x40, out old);
                
                            *(uint*)@new = 0x6f43744e;
                            *((uint*)@new + 1) = 0x6e69746e;
                            *((ushort*)@new + 4) = 0x6575;
                            *(@new + 10) = 0;
                            // NtContinue
                
                            for (int i = 0; i < 11; i++)
                                *(funcName + i) = *(@new + i);
                            // 把_CorExeMain改成NtContinue
                        }
                
                        for (int i = 0; i < sectNum; i++) {
                            VirtualProtect(ptr, 8, 0x40, out old);
                            Marshal.Copy(new byte[8], 0, (IntPtr)ptr, 8);
                            ptr += 0x28;
                        }
                        // 清零所有節的名稱
                        VirtualProtect(mdDir, 0x48, 0x40, out old);
                        byte* mdHdr = bas + *(uint*)(mdDir + 8);
                        // mdHdr指向STORAGESIGNATURE(開頭是BSJ**B的那個)
                        *(uint*)mdDir = 0;
                        *((uint*)mdDir + 1) = 0;
                        *((uint*)mdDir + 2) = 0;
                        *((uint*)mdDir + 3) = 0;
                        // 將IMAGE_COR20_HEADER的cb MajorRuntimeVersion MinorRuntimeVersion MetaData清零
                
                        VirtualProtect(mdHdr, 4, 0x40, out old);
                        *(uint*)mdHdr = 0;
                        // 刪除BSJ**B標志,這樣就無法搜索到STORAGESIGNATURE了
                        mdHdr += 12;
                        // mdHdr指向iVersionString
                        mdHdr += *(uint*)mdHdr;
                        mdHdr = (byte*)(((ulong)mdHdr + 7) & ~3UL);
                        mdHdr += 2;
                        // mdHdr指向STORAGEHEADER的iStreams
                        ushort numOfStream = *mdHdr;
                        // 獲取元數據流的數量
                        mdHdr += 2;
                        // mdHdr指向第一個元數據流頭
                        for (int i = 0; i < numOfStream; i++) {
                            VirtualProtect(mdHdr, 8, 0x40, out old);
                            //*(uint*)mdHdr = 0;
                            mdHdr += 4;
                            // mdHdr指向STORAGESTREAM.iSize
                            //*(uint*)mdHdr = 0;
                            mdHdr += 4;
                            // mdHdr指向STORAGESTREAM.rcName
                            for (int ii = 0; ii < 8; ii++) {
                                VirtualProtect(mdHdr, 4, 0x40, out old);
                                *mdHdr = 0;
                                mdHdr++;
                                if (*mdHdr == 0) {
                                    mdHdr += 3;
                                    break;
                                }
                                *mdHdr = 0;
                                mdHdr++;
                                if (*mdHdr == 0) {
                                    mdHdr += 2;
                                    break;
                                }
                                *mdHdr = 0;
                                mdHdr++;
                                if (*mdHdr == 0) {
                                    mdHdr += 1;
                                    break;
                                }
                                *mdHdr = 0;
                                mdHdr++;
                            }
                            // 清零STORAGESTREAM.rcName,因為這個是4字節對齊的,所以代碼長一些
                        }
                    }
                    else //Flat
                    {
                        // 這里就是內存加載程序集的情況了,和上面是差不多的,我就不再具體分析了
                        //VirtualProtect(ptr - 16, 8, 0x40, out old);
                        //*(uint*)(ptr - 12) = 0;
                        uint mdDir = *(uint*)(ptr - 16);
                        //*(uint*)(ptr - 16) = 0;
                        uint importDir = *(uint*)(ptr - 0x78);
                
                        var vAdrs = new uint[sectNum];
                        var vSizes = new uint[sectNum];
                        var rAdrs = new uint[sectNum];
                        for (int i = 0; i < sectNum; i++) {
                            VirtualProtect(ptr, 8, 0x40, out old);
                            Marshal.Copy(new byte[8], 0, (IntPtr)ptr, 8);
                            vAdrs[i] = *(uint*)(ptr + 12);
                            vSizes[i] = *(uint*)(ptr + 8);
                            rAdrs[i] = *(uint*)(ptr + 20);
                            ptr += 0x28;
                        }
                
                
                        if (importDir != 0) {
                            for (int i = 0; i < sectNum; i++)
                                if (vAdrs[i] <= importDir && importDir < vAdrs[i] + vSizes[i]) {
                                    importDir = importDir - vAdrs[i] + rAdrs[i];
                                    break;
                                }
                            byte* importDirPtr = bas + importDir;
                            uint oftMod = *(uint*)importDirPtr;
                            for (int i = 0; i < sectNum; i++)
                                if (vAdrs[i] <= oftMod && oftMod < vAdrs[i] + vSizes[i]) {
                                    oftMod = oftMod - vAdrs[i] + rAdrs[i];
                                    break;
                                }
                            byte* oftModPtr = bas + oftMod;
                            uint modName = *(uint*)(importDirPtr + 12);
                            for (int i = 0; i < sectNum; i++)
                                if (vAdrs[i] <= modName && modName < vAdrs[i] + vSizes[i]) {
                                    modName = modName - vAdrs[i] + rAdrs[i];
                                    break;
                                }
                            uint funcName = *(uint*)oftModPtr + 2;
                            for (int i = 0; i < sectNum; i++)
                                if (vAdrs[i] <= funcName && funcName < vAdrs[i] + vSizes[i]) {
                                    funcName = funcName - vAdrs[i] + rAdrs[i];
                                    break;
                                }
                            VirtualProtect(bas + modName, 11, 0x40, out old);
                
                            *(uint*)@new = 0x6c64746e;
                            *((uint*)@new + 1) = 0x6c642e6c;
                            *((ushort*)@new + 4) = 0x006c;
                            *(@new + 10) = 0;
                
                            for (int i = 0; i < 11; i++)
                                *(bas + modName + i) = *(@new + i);
                
                            VirtualProtect(bas + funcName, 11, 0x40, out old);
                
                            *(uint*)@new = 0x6f43744e;
                            *((uint*)@new + 1) = 0x6e69746e;
                            *((ushort*)@new + 4) = 0x6575;
                            *(@new + 10) = 0;
                
                            for (int i = 0; i < 11; i++)
                                *(bas + funcName + i) = *(@new + i);
                        }
                
                
                        for (int i = 0; i < sectNum; i++)
                            if (vAdrs[i] <= mdDir && mdDir < vAdrs[i] + vSizes[i]) {
                                mdDir = mdDir - vAdrs[i] + rAdrs[i];
                                break;
                            }
                        byte* mdDirPtr = bas + mdDir;
                        VirtualProtect(mdDirPtr, 0x48, 0x40, out old);
                        uint mdHdr = *(uint*)(mdDirPtr + 8);
                        for (int i = 0; i < sectNum; i++)
                            if (vAdrs[i] <= mdHdr && mdHdr < vAdrs[i] + vSizes[i]) {
                                mdHdr = mdHdr - vAdrs[i] + rAdrs[i];
                                break;
                            }
                        *(uint*)mdDirPtr = 0;
                        *((uint*)mdDirPtr + 1) = 0;
                        *((uint*)mdDirPtr + 2) = 0;
                        *((uint*)mdDirPtr + 3) = 0;
                
                
                        byte* mdHdrPtr = bas + mdHdr;
                        VirtualProtect(mdHdrPtr, 4, 0x40, out old);
                        *(uint*)mdHdrPtr = 0;
                        mdHdrPtr += 12;
                        mdHdrPtr += *(uint*)mdHdrPtr;
                        mdHdrPtr = (byte*)(((ulong)mdHdrPtr + 7) & ~3UL);
                        mdHdrPtr += 2;
                        ushort numOfStream = *mdHdrPtr;
                        mdHdrPtr += 2;
                        for (int i = 0; i < numOfStream; i++) {
                            VirtualProtect(mdHdrPtr, 8, 0x40, out old);
                            //*(uint*)mdHdrPtr = 0;
                            mdHdrPtr += 4;
                            //*(uint*)mdHdrPtr = 0;
                            mdHdrPtr += 4;
                            for (int ii = 0; ii < 8; ii++) {
                                VirtualProtect(mdHdrPtr, 4, 0x40, out old);
                                *mdHdrPtr = 0;
                                mdHdrPtr++;
                                if (*mdHdrPtr == 0) {
                                    mdHdrPtr += 3;
                                    break;
                                }
                                *mdHdrPtr = 0;
                                mdHdrPtr++;
                                if (*mdHdrPtr == 0) {
                                    mdHdrPtr += 2;
                                    break;
                                }
                                *mdHdrPtr = 0;
                                mdHdrPtr++;
                                if (*mdHdrPtr == 0) {
                                    mdHdrPtr += 1;
                                    break;
                                }
                                *mdHdrPtr = 0;
                                mdHdrPtr++;
                            }
                        }
                    }
                }
                

                這里面修改導入表的部分其實是可有可無的,這個是可逆的
                清空節名稱也是是可選的
                其中非常重點的是將IMAGE_COR20_HEADER.MetaData清零,CLR已經完成了元數據的定位,并且保存了有關數據(可以使用CE搜索內存驗證,搜索ImageBase+MetaData.VirtualAddress),不再需要這個字段,是可以清零的,但是我們讀取元數據,是需要這個字段的。
                接下來Anti Dump會刪除BSJ**B標志,這樣就無法搜索到STORAGESIGNATURE了。還有元數據流頭的rcName字段,一并清零,這樣也會讓我們無法定位到元數據結構體,但是CLR不再需要這些了。

                解決這個的辦法很簡單,把&lt;Module&gt;::.cctor()的call void Confuser.Runtime.AntiDump::Initialize()這條指令nop掉。我們要如何定位到這條指令呢?
                這里有個投機取巧的辦法,解決Anti Tamper之后,在dnSpy里面找出現了
                [C#] 純文本查看 復制代碼
                Module module = typeof(AntiDump).Module;
                byte* bas = (byte*)Marshal.GetHINSTANCE(module);
                ......
                if (module.FullyQualifiedName[0] != '<'){
                }
                

                這樣的方法,并且這個方法還多次調用了VirtualProtect,原版ConfuserEx是調用了14次。把call 這個方法的地方nop掉,注意顯示模式切換到IL,然后點一下IL所在的FileOffset,用十六進制編輯器改成0,不然容易出問題。

                ## Anti Tamper

                **Anti Tamper稍微麻煩一些,看不懂的地方實際操作一下,到ConfuserEx項目里面調試一下!!!!!!**

                ### 分析

                ConfuserEx里面有2種AntiTamper模式,一種的Hook JIT,另一種是原地解密。Hook JIT算是半成品,還沒法正常使用,所以我們實際上看到的是原地解密模式,強度不是特別高。
                我們轉到Confuser.Protections項目的AntiTamper\NormalMode.cs

                這里我就不注釋了,因為這里也是一個注入器,和AntiDumpProtection.cs是差不多的,看不懂也沒關系,看我后面分析實際實現就能明白了。
                找到AntiTamper的實現AntiTamper.Normal.cs

                [C#] 純文本查看 復制代碼
                static unsafe void Initialize() {
                	Module m = typeof(AntiTamperNormal).Module;
                	string n = m.FullyQualifiedName;
                	bool f = n.Length > 0 && n[0] == '<';
                          // f為true代表這是內存加載的程序集
                	var b = (byte*)Marshal.GetHINSTANCE(m);
                	byte* p = b + *(uint*)(b + 0x3c);
                          // pNtHeader
                	ushort s = *(ushort*)(p + 0x6);
                          // Machine
                	ushort o = *(ushort*)(p + 0x14);
                          // SizeOfOptHdr
                
                	uint* e = null;
                	uint l = 0;
                	var r = (uint*)(p + 0x18 + o);
                          // pFirstSectHdr
                	uint z = (uint)Mutation.KeyI1, x = (uint)Mutation.KeyI2, c = (uint)Mutation.KeyI3, v = (uint)Mutation.KeyI4;
                	for (int i = 0; i < s; i++) {
                		uint g = (*r++) * (*r++);
                              // SectionHeader.Name => nameHash
                              // 此時r指向SectionHeader.VirtualSize
                		if (g == (uint)Mutation.KeyI0) {
                                  // 查看Confuser.Protections.AntiTamper.NormalMode
                                  // 這里的Mutation.KeyI0是nameHash
                                  // 這個if的意思是判斷是否為ConfuserEx用來存放加密后方法體的節
                                  e = (uint*)(b + (f ? *(r + 3) : *(r + 1)));
                                  // f為true,e指向RawAddres指向的內容,反之指向VirtualAddress指向的內容
                			l = (f ? *(r + 2) : *(r + 0)) >> 2;
                                  // f為true,l等于RawSize >> 2,反之等于VirtualSize >> 2
                                  // 不用關心為什么>> 2了,這個到了后面還會<< 2回去
                              }
                              else if (g != 0) {
                			var q = (uint*)(b + (f ? *(r + 3) : *(r + 1)));
                                  // f為true,q指向RawAddres指向的內容,反之指向VirtualAddress指向的內容
                                  uint j = *(r + 2) >> 2;
                                  // l等于VirtualSize >> 2
                                  for (uint k = 0; k < j; k++) {
                                      // 比如VirtualSize=0x200,那這里就循環0x20次
                                      uint t = (z ^ (*q++)) + x + c * v;
                				z = x;
                				x = c;
                				x = v;
                				v = t;
                                      // 加密運算本身,不需要做分析
                			}
                		}
                		r += 8;
                              // 讓下一次循環時r依然指向SectionHeader的開頭
                	}
                
                	uint[] y = new uint[0x10], d = new uint[0x10];
                	for (int i = 0; i < 0x10; i++) {
                		y[i] = v;
                		d[i] = x;
                		z = (x >> 5) | (x << 27);
                		x = (c >> 3) | (c << 29);
                		c = (v >> 7) | (v << 25);
                		v = (z >> 11) | (z << 21);
                	}
                          // 加密運算本身,不需要做分析
                          Mutation.Crypt(y, d);
                          // 這里會ConfuserEx替換成真正的加密算法,大概是這樣:
                          // data[0] = data[0] ^ key[0];
                          // data[1] = data[1] * key[1];
                          // data[2] = data[2] + key[2];
                          // data[3] = data[3] ^ key[3];
                          // data[4] = data[4] * key[4];
                          // data[5] = data[5] + key[5];
                          // 然后這樣循環下去
                
                          uint w = 0x40;
                	VirtualProtect((IntPtr)e, l << 2, w, out w);
                
                	if (w == 0x40)
                              // 防止被重復調用,出現重復解密導致破壞數據
                		return;
                
                	uint h = 0;
                	for (uint i = 0; i < l; i++) {
                		*e ^= y[h & 0xf];
                		y[h & 0xf] = (y[h & 0xf] ^ (*e++)) + 0x3dbb2819;
                		h++;
                	}
                }
                

                上面是我注釋的,實際上的解密寫在了最末尾"*e ^= y[h & 0xf];",前面一大坨代碼都是計算出key和要解密數據的位置。
                為什么可以解密?因為xor 2次相同的值,等于xor 0,比如123 ^ 456 ^ 456 == 123。
                那么這段代碼究竟解密了什么呢?
                我們先了解一下元數據表的Method表

                我用紅框標記的RVA指向了方法體的數據,方法體里面存放了ILHeader ILCode LocalVar EH。
                ConfuserEx會修改RVA,讓RVA指向另一個紅框"章節 #0: 亂碼",這個Section專門存放了方法體(模塊靜態構造器和Anti Tamper本身的方法體不在這個節里面,否則都沒法運行了)。
                ConfuserEx會加密這一個節的內容。因為模塊靜態構造器是比程序集入口點更優先執行的,所以模塊靜態構造器的第一條IL指令就是call void AntiTamper::Initialize()。
                在程序集運行時會首先執行這一條IL指令,其它方法都會被解密,程序就可以正常的運行下去了。這種方法比Hook JIT的兼容性好非常多,幾乎不可能出現無法運行的問題。但是這種方法的強度也是遠不如Hook JIT的,尤其是那種用一個非托管DLL來Hook JIT,還給非托管DLL加個vmp殼的(說的哪幾個殼應該都清楚)。

                ### AntiTamperKiller成品

                剛才我們已經分析完了Anti Tamper,如果你看懂了,你也能寫出一個Anti Tamper的靜態脫殼機(dnSpy Dump法是有可能損壞數據的,靜態脫殼僅僅解密了一個節的數據)

                Anti Tamper脫殼機下載:
                鏈接: [https://pan.baidu.com/s/1IMWk7BywjVX1O2AsJ2qIrA](https://pan.baidu.com/s/1IMWk7BywjVX1O2AsJ2qIrA)密碼: 9ywx

                de4dot怎么用的這個就怎么用,支持ConfuserEx最大保護。

                評分

                參與人數 5威望 +28 飄云幣 +22 收起 理由
                HiPP + 2 + 2 感謝發布原創作品,PYG有你更精彩!
                凉游淺筆深畫眉 + 2 PYG有你更精彩!
                九層樓 + 2 原創精品 感謝分享!
                Rooking + 20 + 20 熱心分享 共同提升!
                零下八度 + 2 厲害了,果然是詳解,支持一下~

                查看全部評分

                分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友 微信微信
                收藏收藏5 轉播轉播 分享分享 分享淘帖 頂 踩 友情贊助 微信分享
              3. TA的每日心情
                郁悶
                2017-8-4 11:10
              4. 簽到天數: 2 天

                [LV.1]初來乍到

                沙發
                發表于 2018-8-15 10:38:45 | 只看該作者
                支持一個~~

                事實上呢,【dnSpy單步調試+Dump+CodeCracker的一系列工具可以脫去ConfuserEx殼】,很多菜鳥也是很難做到,

                比如CC的一套工具,很多人搞不清什么時候用哪個,什么順序使用有什么區別之類的。

                又比如用 dnSpy 來dump,別的不算,就在 .cctor 那里 NOP 保存那步,,保存出來的就千奇百怪的。。。。。
                回復 支持 反對

                使用道具 舉報

              5. TA的每日心情
                開心
                2018-9-21 22:58
              6. 簽到天數: 2 天

                [LV.1]初來乍到

                藤椅
                 樓主| 發表于 2018-8-15 10:42:45 | 只看該作者
                零下八度 發表于 2018-8-15 10:38
                支持一個~~

                事實上呢,【dnSpy單步調試+Dump+CodeCracker的一系列工具可以脫去ConfuserEx殼】,很多菜鳥 ...

                https://mindlocksite.wordpress.com/2017/02/11/easy-way-to-unpack-confuserex-1-0-max-settings/
                這個教程是說得非常好的,完全可以看懂的。文章后面貼了個自己寫的工具,可以靜態解密Anti Tamper,不需要dnSpy。文章還沒編輯好,有些內容pyg提示是不良信息,發不上
                回復 支持 反對

                使用道具 舉報

              7. TA的每日心情
                郁悶
                2017-8-4 11:10
              8. 簽到天數: 2 天

                [LV.1]初來乍到

                板凳
                發表于 2018-8-15 10:49:20 | 只看該作者
                wwh1004 發表于 2018-8-15 10:42
                https://mindlocksite.wordpress.com/2017/02/11/easy-way-to-unpack-confuserex-1-0-max-settings/
                這 ...

                發不上可以先草稿?我還以為你發完了呢,正奇怪這"詳解"好像不太對勁兒?

                這博客我也看過,上面幾乎每一篇文章幾乎都都是精品,很多值得研究和參考的東西。值得點個贊~

                但是,個人覺得需要一定的基礎,寫博客當然難以面面俱到,但是我個人還是認為對新手不太容易理解?maybe是我太菜了的原因。。。
                回復 支持 反對

                使用道具 舉報

              9. TA的每日心情
                開心
                2018-9-21 22:58
              10. 簽到天數: 2 天

                [LV.1]初來乍到

                報紙
                 樓主| 發表于 2018-8-15 10:58:02 | 只看該作者
                零下八度 發表于 2018-8-15 10:49
                發不上可以先草稿?我還以為你發完了呢,正奇怪這"詳解"好像不太對勁兒?

                這博客我也看過,上 ...

                回復 支持 反對

                使用道具 舉報

              11. TA的每日心情
                開心
                2018-7-9 22:48
              12. 簽到天數: 16 天

                [LV.4]偶爾看看III

                地板
                發表于 2018-8-15 11:26:01 | 只看該作者
                我是直接修改IL,還不會dump
                回復 支持 反對

                使用道具 舉報

              13. TA的每日心情
                郁悶
                2017-8-4 11:10
              14. 簽到天數: 2 天

                [LV.1]初來乍到

                7#
                發表于 2018-8-15 11:39:21 | 只看該作者
                話說這斜體用的,真心不忍直視啊。。。。。
                回復 支持 反對

                使用道具 舉報

              15. TA的每日心情
                郁悶
                2017-8-4 11:10
              16. 簽到天數: 2 天

                [LV.1]初來乍到

                8#
                發表于 2018-8-15 11:41:37 | 只看該作者
                dryzh 發表于 2018-8-15 11:26
                我是直接修改IL,還不會dump

                dump 跟 修改IL,不沖突,加殼混淆的程序很難直接改IL,dump 一般是作為解密去混淆之類的其中一環,脫了殼就才好編輯IL。

                點評

                嗯嗯,受教了。向表哥學習。  詳情 回復 發表于 2018-8-15 14:02
                回復 支持 反對

                使用道具 舉報

              17. TA的每日心情
                開心
                2018-7-9 22:48
              18. 簽到天數: 16 天

                [LV.4]偶爾看看III

                9#
                發表于 2018-8-15 14:02:36 | 只看該作者
                零下八度 發表于 2018-8-15 11:41
                dump 跟 修改IL,不沖突,加殼混淆的程序很難直接改IL,dump 一般是作為解密去混淆之類的其中一環,脫了 ...

                嗯嗯,受教了。向表哥學習。
                回復 支持 反對

                使用道具 舉報

              19. TA的每日心情
                開心
                9 小時前
              20. 簽到天數: 42 天

                [LV.5]常住居民I

                10#
                發表于 2018-8-18 09:10:36 | 只看該作者
                嗯嗯,學習學習學習學習學習
                回復 支持 反對

                使用道具 舉報

                您需要登錄后才可以回帖 登錄 | 加入論壇

                本版積分規則

                關閉

                站長推薦上一條 /1 下一條

                快速回復 返回頂部 返回列表
                11选5中奖报道