吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 52072|回复: 81
上一主题 下一主题
收起左侧

[原创] superdog 加密狗.NET 方法体加密去狗研究

  [复制链接]
跳转到指定楼层
楼主
whshizy 发表于 2016-1-19 17:25 回帖奖励
superdog safenet推出的功能较为强大的加密狗,其中的基于.NET方法体加密的功能比较有特点,使用了代码混淆,将原方法体代码加密后保存到程序数据,程序运行是动态解密数据,并使用.NET的DynamicMethod,动态创建代码执行。本文不是从加密狗模拟破解程序,旨在研究一下这种加密机制的原理,探寻一种代码还原方法,目前只能手动,而且只能带狗操作,因为加密狗将方法体数据通过狗加密后保存为.protect资源,运行时需要加密狗将数据解密,主要是对.NET文件结构不熟悉,哪位大大可以指点一下,想写一个通用的工具。文章有点长,看完要有点耐心。
写一个测试程序:
[C#] 纯文本查看 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using myFirstDll;

namespace rundll
{
    class Program
    {
        static void Main(string[] args)
        {
            int i=123;
            myFirstDll.Show a = new myFirstDll.Show();
            Console.WriteLine(a.Messages()+i.ToString());
            Console.WriteLine(a.myadd(2,3).ToString());
        }
    }
}

myFirstDll代码这里就不贴出了,只是一些测试代码,主要研究对MAIN方法加密还原。
使用SUPERDOG的外壳加密工具加密刚才生成的EXE文件。



发现生成文件目录下多了几个文件

我们使用DNSPY打开加密后的程序,看看MAIN方法变成什么了
[C#] 纯文本查看 复制代码
private static void Main(string[] args)
{
	try
	{
		DynamicMethod dynamicMethod = 7120480.80071137(null, MethodBase.GetCurrentMethod(), true);
		if (dynamicMethod != null)
		{
			dynamicMethod.Invoke(null, new object[]
			{
				args
			});
		}
		7120480.80071137(null, MethodBase.GetCurrentMethod(), false);
	}
	catch (Exception arg_50_0)
	{
		Exception expr_55 = arg_50_0.InnerException;
		if (expr_55 == null)
		{
			throw;
		}
		throw expr_55;
	}
}

原来的代码不见了,看代码,明显经过混淆了,使用De4dot去混淆得到rundll-cleaned.exe,这下代码好看多了
[C#] 纯文本查看 复制代码
private static void Main(string[] args)
{
	try
	{
		DynamicMethod dynamicMethod = Class0.smethod_7(null, MethodBase.GetCurrentMethod(), true);
		if (dynamicMethod != null)
		{
			dynamicMethod.Invoke(null, new object[]
			{
				args
			});
		}
		Class0.smethod_7(null, MethodBase.GetCurrentMethod(), false);
	}
	catch (Exception arg_49_0)
	{
		Exception expr_4E = arg_49_0.InnerException;
		if (expr_4E == null)
		{
			throw;
		}
		throw expr_4E;
	}
}

可以看到,关键方法于 Class0.smethod_7,通过跟踪(这里不演示如何跟踪程序了,篇幅较多,时间较长,只贴出关键代码),发现这个方法主要完成几个功能:
1、读取.protect资源数据
2、校验dogdnert.dll,dogdnert_x64.dll是否被修改。
3、读取加密数据,传入加密狗解密。
4、根据一定的规则生成dynamicMethod方法,并对参数和本地变量进行还原,并返回给主程序,主程序运行该dynamicMethod方法。
经过分析可以看出,生成dynamicMethod方法过程很关键,取得这个方法体就可以还原原代码了。使用DNSPY调试加密反混淆的程序,定位到关键代码是 Class0.smethod_8,在如下地方下断点

程序运行到这里后,array数据里就是原main方法代码,打开调试器local 窗口,选择Show in Memory Window -memory1


复制选中数据,001F7B0A733B0100060B076F39010006120028AB00000A281F00000A282C01000A000718196F3A0100060C120228AB00000A282C01000A002A,这个即是原来main方法进制代码。
我们复制一下原main方法进制码,对比分析一下

选择Hex Copy Method Body,得到如下数据:
133003003900000053000011001F7B0A733B0100060B076F39010006120028B900000A283F00000A282A01000A000718196F3A0100060C120028B900000A282A01000A002A
                                                001F7B0A733B0100060B076F39010006120028AB00000A281F00000A282C01000A000718196F3A0100060C120228AB00000A282C01000A002A
和原数据对比,少了头部:133003003900000053000011,这个头部数据所有字段含义没有全部弄明白,只知道部分,比如39是长度,还有一些是token,哪位大神可以指点一下,将133003003900000053000011附加到解密数据头部,使用Hex Write mothod Body写回rundll-cleaned.exe,再反编译,发现代码不正确,应该是头部token不正确造成,我们可以使用加密后的文件头部,使用Hex Copy Method Body复制加密后main方法体二进制代码:
1B3004005900000054000011001F7B0A733B0100060B076F39010006120028AB00000A281F00000A282C01000A000718196F3A0100060C120228AB00000A282C01000A002A14282E01000A1628080000062626DE0F6F9100000A2514FE012C0326FE1A7A2A00000001100000000000004949000F06000001
取文件头部,1B3004005900000054000011修改为1B3004003900000054000011,主要是修改了方法体代码长度,将数据
1B3004003900000054000011001F7B0A733B0100060B076F39010006120028AB00000A281F00000A282C01000A000718196F3A0100060C120228AB00000A282C01000A002A
使用Hex Write mothod Body写回rundll-cleaned.exe,再反编译,发现IL码与原来main方法一样了,只是有一点不同,以下是对比图
写回二进制数据后IL码
[Asm] 纯文本查看 复制代码
// Token: 0x0600013C RID: 316 RVA: 0x000093D4 File Offset: 0x000075D4
.method private hidebysig static 
	void Main (
		string[] args
	) cil managed 
{
	// Header Size: 12 bytes
	// Code Size: 57 (0x39) bytes
	// LocalVarSig Token: 0x11000054 RID: 84
	.maxstack 4
	.entrypoint
	.locals init (
		[0] object[],
		[1] class [mscorlib]System.Reflection.Emit.DynamicMethod
	)

	/* 0x000075E0 00           */ IL_0000: nop
	/* 0x000075E1 1F7B         */ IL_0001: ldc.i4.s  123
	/* 0x000075E3 0A           */ IL_0003: stloc.0
	/* 0x000075E4 733B010006   */ IL_0004: newobj    instance void myFirstDll.Show::.ctor()
	/* 0x000075E9 0B           */ IL_0009: stloc.1
	/* 0x000075EA 07           */ IL_000A: ldloc.1
	/* 0x000075EB 6F39010006   */ IL_000B: callvirt  instance string myFirstDll.Show::Messages()
	/* 0x000075F0 1200         */ IL_0010: ldloca.s  0
	/* 0x000075F2 28AB00000A   */ IL_0012: call      instance string [mscorlib]System.Int32::ToString()
	/* 0x000075F7 281F00000A   */ IL_0017: call      string [mscorlib]System.String::Concat(string, string)
	/* 0x000075FC 282C01000A   */ IL_001C: call      void [mscorlib]System.Console::WriteLine(string)
	/* 0x00007601 00           */ IL_0021: nop
	/* 0x00007602 07           */ IL_0022: ldloc.1
	/* 0x00007603 18           */ IL_0023: ldc.i4.2
	/* 0x00007604 19           */ IL_0024: ldc.i4.3
	/* 0x00007605 6F3A010006   */ IL_0025: callvirt  instance int32 myFirstDll.Show::myadd(int32, int32)
	/* 0x0000760A 0C           */ IL_002A: stloc.2
	/* 0x0000760B 1202         */ IL_002B: ldloca.s
	/* 0x0000760D 28AB00000A   */ IL_002D: call      instance string [mscorlib]System.Int32::ToString()
	/* 0x00007612 282C01000A   */ IL_0032: call      void [mscorlib]System.Console::WriteLine(string)
	/* 0x00007617 00           */ IL_0037: nop
	/* 0x00007618 2A           */ IL_0038: ret
} // end of method Program::Main

原方法IL码:
[Asm] 纯文本查看 复制代码
// Token: 0x06000005 RID: 5 RVA: 0x000020A8 File Offset: 0x000002A8
.method private hidebysig static 
	void Main (
		string[] args
	) cil managed 
{
	// Header Size: 12 bytes
	// Code Size: 57 (0x39) bytes
	// LocalVarSig Token: 0x11000003 RID: 3
	.maxstack 3
	.entrypoint
	.locals init (
		[0] int32 i,
		[1] class myFirstDll.Show a,
		[2] int32 CS$0$0000
	)

	/* 0x000002B4 00           */ IL_0000: nop
	/* 0x000002B5 1F7B         */ IL_0001: ldc.i4.s  123
	/* 0x000002B7 0A           */ IL_0003: stloc.0
	/* 0x000002B8 7304000006   */ IL_0004: newobj    instance void myFirstDll.Show::.ctor()
	/* 0x000002BD 0B           */ IL_0009: stloc.1
	/* 0x000002BE 07           */ IL_000A: ldloc.1
	/* 0x000002BF 6F02000006   */ IL_000B: callvirt  instance string myFirstDll.Show::Messages()
	/* 0x000002C4 1200         */ IL_0010: ldloca.s  i
	/* 0x000002C6 281300000A   */ IL_0012: call      instance string [mscorlib]System.Int32::ToString()
	/* 0x000002CB 281100000A   */ IL_0017: call      string [mscorlib]System.String::Concat(string, string)
	/* 0x000002D0 281400000A   */ IL_001C: call      void [mscorlib]System.Console::WriteLine(string)
	/* 0x000002D5 00           */ IL_0021: nop
	/* 0x000002D6 07           */ IL_0022: ldloc.1
	/* 0x000002D7 18           */ IL_0023: ldc.i4.2
	/* 0x000002D8 19           */ IL_0024: ldc.i4.3
	/* 0x000002D9 6F03000006   */ IL_0025: callvirt  instance int32 myFirstDll.Show::myadd(int32, int32)
	/* 0x000002DE 0C           */ IL_002A: stloc.2
	/* 0x000002DF 1202         */ IL_002B: ldloca.s  CS$0$0000
	/* 0x000002E1 281300000A   */ IL_002D: call      instance string [mscorlib]System.Int32::ToString()
	/* 0x000002E6 281400000A   */ IL_0032: call      void [mscorlib]System.Console::WriteLine(string)
	/* 0x000002EB 00           */ IL_0037: nop
	/* 0x000002EC 2A           */ IL_0038: ret
} // end of method Program::Main

通过对比发现,这里面主要有两个差异:1、.maxstack ;2、.locals init,主要是堆的大小和本地变量,堆的大小是根据本地变量一次使用变量数据来决定的,这里取大的,这个参数代码里面也有还原,一时记不清在哪了,等找到了再补充,本地变量需要还原成原来的,这里也许有人会问,你有原来的代码,当然知道如何恢复了,我们这里假设没有原代码,看看如何还原,继续在下面下断

这个函数即是还原参数的关键,我们按F11跟踪进去,
[C#] 纯文本查看 复制代码
	private static bool smethod_6(DynamicILInfo dynamicILInfo_0, byte[] byte_0, ref SignatureHelper signatureHelper_0, Type[] type_0, Type[] type_1)
	{
		int num = 0;
		Class0.Enum5 @enum = (Class0.Enum5)Class0.smethod_3(byte_0, ref num);
		bool result;
		if (@enum == Class0.Enum5.const_3)
		{
			int num2 = Class0.smethod_3(byte_0, ref num);
			for (int i = 0; i < num2; i++)
			{
				Type type = Class0.smethod_5(dynamicILInfo_0, byte_0, ref num, type_0, type_1);
				if (type == null)
				{
					result = false;
					return result;
				}
				signatureHelper_0.AddArgument(type);
			}
		}
		result = true;
		return result;
	}

在这条语句上下断,循环三次后得到三个参数类型:{System.Int32}{myFirstDll.Show}{System.Int32}
这时我们就可以还原参数了。在main方法上按鼠标右键,选择Edit Method body,在打开的窗口中选择locals 页面

将原来两个变量修改,至于如何操作,使用鼠标右键,自己摸索
再增加一个变量,最后结果如下图

OK,退出,点FILE菜单 save module
再反编译修改后的代码,rundll-cleaned2.exe,看看main方法体
[C#] 纯文本查看 复制代码
using System;
using myFirstDll;

namespace rundll
{
	// Token: 0x0200005C RID: 92
	internal class Program
	{
		// Token: 0x0600013C RID: 316 RVA: 0x000093D4 File Offset: 0x000075D4
		private static void Main(string[] args)
		{
			int num = 123;
			Show show = new Show();
			Console.WriteLine(show.Messages() + num.ToString());
			int num2 = show.myadd(2, 3);
			Console.WriteLine(num.ToString());
		}
	}
}

除了变量名称不一样,其他完全一样,运行也与原来功能相同,至此,代码成功。
第一次写这么长的破文,肯定有很多不周到的地方,希望大家见谅。
想做一个通用工具,把这些手工过程程序化,但对.NET文件结构不了解,不知道如何下手,哪位大神可以指点下,谢谢


免费评分

参与人数 19吾爱币 +2 热心值 +19 收起 理由
nationdo + 1 + 1 我很赞同!
LoadAsia + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
feng1990 + 1 谢谢@Thanks!
smartway + 1 谢谢@Thanks!
8048875062 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
Falcon_2015 + 1 52大牛层出不穷,努力学习大牛高招。
sxhytds + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
rigo0 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
ghostfish + 1 52大牛层出不穷,努力学习大牛高招。
courageous + 1 热心回复!
EvillenG + 1 热心回复!
speedboy + 1 这样的文章不多,加分
罒_罒 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
Tortoise + 1 谢谢@Thanks!
Dicker + 1 不明觉厉
山顶的一棵草 + 1 我很赞同!
逍遥枷锁 + 1 域天加密狗有解决方法吗,老师。
Sound + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
yAYa + 1 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

来自 #
 楼主| whshizy 发表于 2016-1-31 10:36 |楼主

superdog 加密狗.NET 方法体加密去狗研究(续)

本帖最后由 whshizy 于 2016-1-31 10:56 编辑

在我上一篇文章http://www.52pojie.cn/thread-459242-1-1.html中,我们使用DNSPY自身的一些功能来恢复被狗加密过的方法体,经过这几天的再研究,发现上次那种方法有两个缺陷:
1、加密后的方法体基本上都是如下面的的结构
[C#] 纯文本查看 复制代码
private static void Main(string[] args)
{
    try
    {
        DynamicMethod dynamicMethod = Class0.smethod_7(null, MethodBase.GetCurrentMethod(), true);
        if (dynamicMethod != null)
        {
            dynamicMethod.Invoke(null, new object[]
            {
                args
            });
        }
        Class0.smethod_7(null, MethodBase.GetCurrentMethod(), false);
    }
    catch (Exception arg_49_0)
    {
        Exception expr_4E = arg_49_0.InnerException;
        if (expr_4E == null)
        {
            throw;
        }
        throw expr_4E;
    }
}
方法体长度一般在85-100 bytes之间,如果原方法体长度小于这个加密后的方法体长度,采用复制的方法没有问题,如果长度大于这个范围,则会产生不可预料的问题,以前看过一篇文章,采用CFF工具在原EXE文件中增加一个区段,将取得的方法体附加进这个段,再修改元数据的RAV重新指向这个区段来解决,这样虽然能解决长度问题,但需要修改的地方太多,如果加密的方法体太多,工作量较大。本文采用另一种方法,可以较快、准确、较快的还原方法体,后面会有详述。
1、如果原有方法体中有异常处理模块(TRY CATCH等)处理模块,采用上一次我发的方法是无法还原的,这也是我们今天要解决的问题。
老办法,我们写一个测试程序,里面有异常处理程序。
[C#] 纯文本查看 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using myFirstDll;

namespace rundll
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 123;
            try
            {

                myFirstDll.Show a = new myFirstDll.Show();
                string test = "这是SUPERDOG加密狗的测试程序";
                test = test + "主要用于测试字符串加密";
                Console.WriteLine(test);
                Console.WriteLine(a.Messages() + i.ToString());
                Console.WriteLine(a.myadd(2, 3).ToString());
                string testasc = "this is a test programe";
                Console.WriteLine(testasc);

            }
            catch
            {
                i = 1000;
                Console.WriteLine("出错了");
            }
            finally
            {
                Console.WriteLine("最后执行测试");
            }
        }
    }
}
我们使用DNSPY打开编译好的EXE程序,选中MAIN方法,选择Edit Method Body,查看方法体异常结构,这个数据我们记录下来,后面要用到。
这里简单普及一下.NET异常处理数据结构。(有兴趣的朋友可以参考一下:http://www.ecma-international.org/publications/standards/Ecma-335.htm   ECMA spec partiton II 25.4.6),上图表示的异常结构在PE文件里面是按如下格式存储的:标志/Try结构偏移/Try结构长度/Handler偏移/Handler长度/Handler类型meta data token/filter-base exception hander,这个结构分为smallfat两种类型,这两种类型结构一样的,只是存储长度不同而已,small异常结构适用于tryhandle代码块长度都小于256字节并且偏移量小于65536的方法,反之则使用fat异常处理结构。我们来看一下上图第一行异常处理是如何存储的:00/0400/5f/6300/16/01000001,这是一个small异常处理模块。
编译,加密,使用de4dot去混淆,这些步骤在上一篇文章已经说过了,这里就不再啰嗦。以下开始我们的代码还原之旅。
1、打开DNSPY调试去混淆后的加密程序rundll-cleaned.exe,在glass0.smethod_8的这223行下断点
2在内存中取得原方法体代码为:(如何取得,请参照我的上一篇文章,这里也不再啰嗦) 001F7B0A00733B0100060B725307007028730000060C0872850700702873000006281F00000A0C08282C01000A00076F39010006120028AB00000A281F00000A282C01000A000718196F3A0100061304120428AB00000A282C01000A0072A707007028730000060D09282C01000A0000DE16260020E80300000A72D9070070282C01000A0000DE0000DE0E0072E1070070282C01000A0000DC002A
3使用“IL字节码解码工具”将取得的二进制码翻译成IL码:
大家可能看到这解码后的IL码有一些乱码,这是由于SUPERDOG加密狗加密常量字符串造成,我们后面将研究如何处理这些加密字符串。
4、打开ILDASM,将rundll-cleaned反编译成IL码,文件名我们暂定为crack.il
5、使用ULTRAEDIT打开crack.il,找到main方法体如下:
[C#] 纯文本查看 复制代码
.method private hidebysig static void  Main(string[] args) cil managed
  {
    .entrypoint
    // 代码大小       89 (0x59)
    .maxstack  4
    .locals init (class [mscorlib]System.Object[] V_0,
             class [mscorlib]System.Reflection.Emit.DynamicMethod V_1)
    .try
    {
      IL_0000:  ldnull
      IL_0001:  call       class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetCurrentMethod()
      IL_0006:  ldc.i4.1
      IL_0007:  call       class [mscorlib]System.Reflection.Emit.DynamicMethod Class0::smethod_7(object,
                                                                                                  class [mscorlib]System.Reflection.MethodBase,
                                                                                                  bool)
      IL_000c:  stloc.1
      IL_000d:  ldloc.1
      IL_000e:  ldnull
      IL_000f:  ceq
      IL_0011:  brfalse.s  IL_0016

      IL_0013:  ldnull
      IL_0014:  br.s       IL_0039

      IL_0016:  ldc.i4     0x1
      IL_001b:  newarr     [mscorlib]System.Object
      IL_0020:  stloc.0
      IL_0021:  ldloc.0
      IL_0022:  ldc.i4     0x0
      IL_0027:  ldarg      args
      IL_002b:  box        string[]
      IL_0030:  stelem.ref
      IL_0031:  ldloc.1
      IL_0032:  ldnull
      IL_0033:  ldloc.0
      IL_0034:  callvirt   instance object [mscorlib]System.Reflection.MethodBase::Invoke(object,
                                                                                          object[])
      IL_0039:  ldnull
      IL_003a:  call       class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetCurrentMethod()
      IL_003f:  ldc.i4.0
      IL_0040:  call       class [mscorlib]System.Reflection.Emit.DynamicMethod Class0::smethod_7(object,
                                                                                                  class [mscorlib]System.Reflection.MethodBase,
                                                                                                  bool)
      IL_0045:  pop
      IL_0046:  pop
      IL_0047:  leave.s    IL_0058

    }  // end .try
    catch [mscorlib]System.Exception 
    {
      IL_0049:  callvirt   instance class [mscorlib]System.Exception [mscorlib]System.Exception::get_InnerException()
      IL_004e:  dup
      IL_004f:  ldnull
      IL_0050:  ceq
      IL_0052:  brfalse.s  IL_0057

      IL_0054:  pop
      IL_0055:  rethrow
      IL_0057:  throw

    }  // end handler
    IL_0058:  ret
  } // end of method Program::Main
将方法体替换成上面我们使用工具解码出来的IL码,现在MAIN方法体如下:
[C#] 纯文本查看 复制代码
 .method private hidebysig static void  Main(string[] args) cil managed
  {
    .entrypoint
    // 代码大小       89 (0x59)
    .maxstack  4
    .locals init (class [mscorlib]System.Object[] V_0,
             class [mscorlib]System.Reflection.Emit.DynamicMethod V_1)
IL_0000: nop 
IL_0001: ldc.i4.s 0x7B
IL_0003: stloc.0 
IL_0004: nop 
IL_0005: newobj instance void myFirstDll.Show::.ctor()
IL_000A: stloc.1 
IL_000B: ldstr "&#16554;哖&#15118;垸&#47780;婛&#7218;復间π&#1410;&#41849;阝&#62427;&#7091;&#47073;&#61416;&#46487;&#19460;隝逩&#62833;"
IL_0010: call string GClass3/GClass6::smethod_4(string )
IL_0015: stloc.2 
IL_0016: ldloc.2 
IL_0017: ldstr "&#44427;&#654;&#9851;&#50629;&#3565;洇饑&#49012;偠黸&#41966;&#64675;&#17853;瞒&#6633;&#7869;"
IL_001C: call string GClass3/GClass6::smethod_4(string )
IL_0021: call string [mscorlib]System.String::Concat(string , string )
IL_0026: stloc.2 
IL_0027: ldloc.2 
IL_0028: call void [mscorlib]System.Console::WriteLine(string )
IL_002D: nop 
IL_002E: ldloc.1 
IL_002F: callvirt instance string myFirstDll.Show::Messages()
IL_0034: ldloca.s 0x0
IL_0036: call instance string [mscorlib]System.Int32::ToString()
IL_003B: call string [mscorlib]System.String::Concat(string , string )
IL_0040: call void [mscorlib]System.Console::WriteLine(string )
IL_0045: nop 
IL_0046: ldloc.1 
IL_0047: ldc.i4.2 
IL_0048: ldc.i4.3 
IL_0049: callvirt instance int32 myFirstDll.Show::myadd(int32 , int32 )
IL_004E: stloc.s 0x4
IL_0050: ldloca.s 0x4
IL_0052: call instance string [mscorlib]System.Int32::ToString()
IL_0057: call void [mscorlib]System.Console::WriteLine(string )
IL_005C: nop 
IL_005D: ldstr "&#673;麅覌&#47433;&#2976;&#61462;&#6934;&#11591;&#14136;&#60614;k&#8267;老&#41333;摣ρ憾嚳滺&#53226;&#7636;諚鋙&#6955;"
IL_0062: call string GClass3/GClass6::smethod_4(string )
IL_0067: stloc.3 
IL_0068: ldloc.3 
IL_0069: call void [mscorlib]System.Console::WriteLine(string )
IL_006E: nop 
IL_006F: nop 
IL_0070: leave.s IL_0088
IL_0072: pop 
IL_0073: nop 
IL_0074: ldc.i4 0x3E8
IL_0079: stloc.0 
IL_007A: ldstr "出错了"
IL_007F: call void [mscorlib]System.Console::WriteLine(string )
IL_0084: nop 
IL_0085: nop 
IL_0086: leave.s IL_0088
IL_0088: nop 
IL_0089: leave.s IL_0099
IL_008B: nop 
IL_008C: ldstr "最后执行测试"
IL_0091: call void [mscorlib]System.Console::WriteLine(string )
IL_0096: nop 
IL_0097: nop 
IL_0098: endfinally 
IL_0099: nop 
IL_009A: ret 
  } // end of method Program::Main
再在在glass0.smethod_6的这里下断开,找到局部变量定义
看NUM2值为5,说明局部变量有5个,执行5次,得到局部变量类型如下:[0] int 32,[1] {myFirstDll.Show},[2] string ,[3]string,[4] int32
修改main方法体如下代码
修改main方法体如下代码
    .locals init (class [mscorlib]System.Object[] V_0,
             class [mscorlib]System.Reflection.Emit.DynamicMethod V_1)
为  .locals init ([0] int32 V_0,
           [1] class myFirstDll.Show V_1,
           [2] string V_2,
           [3] string V_3,
           [4] int32 V_4)
6、进入命令行,使用ILASM重新编译CRACK.IL文件C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm crack.il 这时会生成CRACK.EXE文件
7、现在还没有完,我们还得处理异常模块,在glass0.smethod_8里下断点
这时ARRAY5数组内的数据就是异常处理数据,这里解释一下这个数组的含义,[0]0x01表示这是一个small异常处理结构,[1]0x1c,表示数组长度,后面[4]-[15]为异常结构处理体00/0400/6e/7200/16/01000001,前面我们分析过,前两位为00表示这是一个有异常处理类型的结构,类型TOKEN为后40x01000001,我们打开METADATA看看这是什么类型,原来是System.Object,后面[16]-[27]是另一个异常处理结构finally,和前面分析相同,这里不多说,大家可以自行分析下。
8、下面我们来为方法体添加异常处理模块,用DNSPY打开CRACK.EXE选中MAIN方法,选择Edit Method Body-Exception Handlers,我们添加两个异常处理,如下图
第一条是根据前身得到的异常处理模块数据00/0400/6e/7200/16/01000001得来的,为什么是这样,前面已经解释过,第二条根据后面的数据得来,点OK,我们看看这时MAIN方法是什么样子。
[C#] 纯文本查看 复制代码
// rundll.Program
// Token: 0x0600013C RID: 316 RVA: 0x000093D4 File Offset: 0x000075D4
private static void Main(string[] args)
{
    int num = 123;
    try
    {
        Show show = new Show();
        string text = GClass3.GClass6.smethod_4("&#16554;哖&#15118;垸&#47780;婛&#7218;復间π&#1410;&#41849;阝&#62427;&#7091;&#47073;&#61416;&#46487;&#19460;隝逩&#62833;");
        text += GClass3.GClass6.smethod_4("&#44427;&#654;&#9851;&#50629;&#3565;洇饑&#49012;偠黸&#41966;&#64675;&#17853;瞒&#6633;&#7869;");
        Console.WriteLine(text);
        Console.WriteLine(show.Messages() + num.ToString());
        Console.WriteLine(show.myadd(2, 3).ToString());
        string value = GClass3.GClass6.smethod_4("&#673;麅覌&#47433;&#2976;&#61462;&#6934;&#11591;&#14136;&#60614;k&#8267;老&#41333;摣ρ憾嚳滺&#53226;&#7636;諚鋙&#6955;");
        Console.WriteLine(value);
    }
    catch
    {
        Console.WriteLine("出错了");
    }
    finally
    {
        Console.WriteLine("最后执行测试");
    }
}
和前面对比,发现程序除了字符串常量不正确外,全部已经正确了,这时找到被加密的字符串常量就可以收工了,这个很简单,程序提示已经非常明显了,在Gclass3.Gclass6.method_4方法,最后一条语句下断,循环执行,就能看到所有解密字符串了,当然有兴趣的朋友可以研究一下狗的字符串加密原理,自己写一个解密程序,也行,看兴趣,我这里就不啰嗦了,找到解密后的字符串,替换一下,原来的代码,至此,去狗操作全部完成,这种方法可以完美去除狗。
解密完成后,可以进一步优化程序,将狗壳附加的代码全部删除,这样就和原来的代码一模一样了,大家可以去尝试下。

点评

膜拜 刚读完第一集  发表于 2016-1-31 10:41

免费评分

参与人数 3威望 +1 吾爱币 +1 热心值 +3 收起 理由
allcam + 1 + 1 用心讨论,共获提升!
Sound + 1 + 1 已经处理,感谢您对吾爱破解论坛的支持!
5org + 1 太难了,不会

查看全部评分

推荐
howardjin098 发表于 2016-12-9 11:02 来自手机
另外以前的軟件狗X宝上有很多,可以复制克隆,现在的超级狗就没有,如果按照使用自己的工具(如VB、VC等)重新编写构造一个和加密狗API一样的DLL动态库文件,里面也包含Read、Write等全部API中包含的函数,使用的参量及返回值和原来的函数一样,所有函数返回零。然后对Query、Read函数进行处理,返回应用软件需要的数值即可。 这个新的DLL文件编写成功后,直接替换掉原来的DLL文件,这时候再运行应用软件,软件访问加密狗的操作就全部会被拦截,拦截程序永远会返回正确的数据给软件,从而实现了模拟加密狗的运行,这种方式可行吗?
推荐
howardjin098 发表于 2016-12-8 01:38 来自手机
to:whshizy 老版本的safe net软件狗有研究吗?如果手上有原始狗,有配套的开发商工具,有密码能读取,能脱壳100%还原软件源代码吗?如果新加壳超级狗的软件源代码和老版本软件狗的相同,是否就能测试脱壳会引起哪些bug吗?小白问题多请楼主多包涵
沙发
凉游浅笔深画眉 发表于 2016-1-19 17:31
前排围观 有意思。分析不易
3#
caxzan 发表于 2016-1-19 17:51
楼主也是强悍啊,佩服你了。
4#
Sound 发表于 2016-1-19 19:50
看完了 不错。第一篇技术贴 加精鼓励。
5#
xiawan 发表于 2016-1-19 20:06
技术文章必须支持
6#
学会珍惜321 发表于 2016-1-19 22:02
楼主也是强悍啊,佩服你了
7#
segasonyn64 发表于 2016-1-20 00:05
技术贴,感谢分享,学习@@@
8#
张静池 发表于 2016-1-20 00:35 来自手机
小白路过、为大神加油
9#
speedboy 发表于 2016-1-20 08:56
这样的文章不多,加分。
10#
haoer6238 发表于 2016-1-20 09:03
谢谢楼主分析自己的思路
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-17 00:42

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表