superdog 加密狗.NET 方法体加密去狗研究
superdog safenet推出的功能较为强大的加密狗,其中的基于.NET方法体加密的功能比较有特点,使用了代码混淆,将原方法体代码加密后保存到程序数据,程序运行是动态解密数据,并使用.NET的DynamicMethod,动态创建代码执行。本文不是从加密狗模拟破解程序,旨在研究一下这种加密机制的原理,探寻一种代码还原方法,目前只能手动,而且只能带狗操作,因为加密狗将方法体数据通过狗加密后保存为.protect资源,运行时需要加密狗将数据解密,主要是对.NET文件结构不熟悉,哪位大大可以指点一下,想写一个通用的工具。文章有点长,看完要有点耐心。写一个测试程序:
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方法变成什么了
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,这下代码好看多了
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码
// 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 (
object[],
class System.Reflection.Emit.DynamicMethod
)
/* 0x000075E0 00 */ IL_0000: nop
/* 0x000075E1 1F7B */ IL_0001: ldc.i4.s123
/* 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: callvirtinstance string myFirstDll.Show::Messages()
/* 0x000075F0 1200 */ IL_0010: ldloca.s0
/* 0x000075F2 28AB00000A */ IL_0012: call instance string System.Int32::ToString()
/* 0x000075F7 281F00000A */ IL_0017: call string System.String::Concat(string, string)
/* 0x000075FC 282C01000A */ IL_001C: call void 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: callvirtinstance 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 System.Int32::ToString()
/* 0x00007612 282C01000A */ IL_0032: call void System.Console::WriteLine(string)
/* 0x00007617 00 */ IL_0037: nop
/* 0x00007618 2A */ IL_0038: ret
} // end of method Program::Main
原方法IL码:
// 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 (
int32 i,
class myFirstDll.Show a,
int32 CS$0$0000
)
/* 0x000002B4 00 */ IL_0000: nop
/* 0x000002B5 1F7B */ IL_0001: ldc.i4.s123
/* 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: callvirtinstance string myFirstDll.Show::Messages()
/* 0x000002C4 1200 */ IL_0010: ldloca.si
/* 0x000002C6 281300000A */ IL_0012: call instance string System.Int32::ToString()
/* 0x000002CB 281100000A */ IL_0017: call string System.String::Concat(string, string)
/* 0x000002D0 281400000A */ IL_001C: call void 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: callvirtinstance int32 myFirstDll.Show::myadd(int32, int32)
/* 0x000002DE 0C */ IL_002A: stloc.2
/* 0x000002DF 1202 */ IL_002B: ldloca.sCS$0$0000
/* 0x000002E1 281300000A */ IL_002D: call instance string System.Int32::ToString()
/* 0x000002E6 281400000A */ IL_0032: call void 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跟踪进去,
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方法体
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文件结构不了解,不知道如何下手,哪位大神可以指点下,谢谢
superdog 加密狗.NET 方法体加密去狗研究(续)
本帖最后由 whshizy 于 2016-1-31 10:56 编辑在我上一篇文章http://www.52pojie.cn/thread-459242-1-1.html中,我们使用DNSPY自身的一些功能来恢复被狗加密过的方法体,经过这几天的再研究,发现上次那种方法有两个缺陷:1、加密后的方法体基本上都是如下面的的结构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等)处理模块,采用上一次我发的方法是无法还原的,这也是我们今天要解决的问题。老办法,我们写一个测试程序,里面有异常处理程序。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,这个结构分为small和fat两种类型,这两种类型结构一样的,只是存储长度不同而已,small异常结构适用于try与handle代码块长度都小于256字节并且偏移量小于65536的方法,反之则使用fat异常处理结构。我们来看一下上图第一行异常处理是如何存储的:00/0400/5f/6300/16/01000001,这是一个small异常处理模块。编译,加密,使用de4dot去混淆,这些步骤在上一篇文章已经说过了,这里就不再啰嗦。以下开始我们的代码还原之旅。1、打开DNSPY调试去混淆后的加密程序rundll-cleaned.exe,在glass0.smethod_8的这223行下断点2、在内存中取得原方法体代码为:(如何取得,请参照我的上一篇文章,这里也不再啰嗦) 001F7B0A00733B0100060B725307007028730000060C0872850700702873000006281F00000A0C08282C01000A00076F39010006120028AB00000A281F00000A282C01000A000718196F3A0100061304120428AB00000A282C01000A0072A707007028730000060D09282C01000A0000DE16260020E80300000A72D9070070282C01000A0000DE0000DE0E0072E1070070282C01000A0000DC002A3、使用“IL字节码解码工具”将取得的二进制码翻译成IL码:大家可能看到这解码后的IL码有一些乱码,这是由于SUPERDOG加密狗加密常量字符串造成,我们后面将研究如何处理这些加密字符串。4、打开ILDASM,将rundll-cleaned反编译成IL码,文件名我们暂定为crack.il。5、使用ULTRAEDIT打开crack.il,找到main方法体如下:.method private hidebysig static voidMain(string[] args) cil managed
{
.entrypoint
// 代码大小 89 (0x59)
.maxstack4
.locals init (class System.Object[] V_0,
class System.Reflection.Emit.DynamicMethod V_1)
.try
{
IL_0000:ldnull
IL_0001:call class System.Reflection.MethodBase System.Reflection.MethodBase::GetCurrentMethod()
IL_0006:ldc.i4.1
IL_0007:call class System.Reflection.Emit.DynamicMethod Class0::smethod_7(object,
class System.Reflection.MethodBase,
bool)
IL_000c:stloc.1
IL_000d:ldloc.1
IL_000e:ldnull
IL_000f:ceq
IL_0011:brfalse.sIL_0016
IL_0013:ldnull
IL_0014:br.s IL_0039
IL_0016:ldc.i4 0x1
IL_001b:newarr 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 System.Reflection.MethodBase::Invoke(object,
object[])
IL_0039:ldnull
IL_003a:call class System.Reflection.MethodBase System.Reflection.MethodBase::GetCurrentMethod()
IL_003f:ldc.i4.0
IL_0040:call class System.Reflection.Emit.DynamicMethod Class0::smethod_7(object,
class System.Reflection.MethodBase,
bool)
IL_0045:pop
IL_0046:pop
IL_0047:leave.s IL_0058
}// end .try
catch System.Exception
{
IL_0049:callvirt instance class System.Exception System.Exception::get_InnerException()
IL_004e:dup
IL_004f:ldnull
IL_0050:ceq
IL_0052:brfalse.sIL_0057
IL_0054:pop
IL_0055:rethrow
IL_0057:throw
}// end handler
IL_0058:ret
} // end of method Program::Main将方法体替换成上面我们使用工具解码出来的IL码,现在MAIN方法体如下: .method private hidebysig static voidMain(string[] args) cil managed
{
.entrypoint
// 代码大小 89 (0x59)
.maxstack4
.locals init (class System.Object[] V_0,
class 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 "䂪哖㬎垸몤婛ᰲ復间πւꍹ阝᮳럡떗䰄隝逩"
IL_0010: call string GClass3/GClass6::smethod_4(string )
IL_0015: stloc.2
IL_0016: ldloc.2
IL_0017: ldstr "궋ʎ♻업෭洇饑뽴偠黸ꏮﲣ䖽瞒᧩ẽ"
IL_001C: call string GClass3/GClass6::smethod_4(string )
IL_0021: call string System.String::Concat(string , string )
IL_0026: stloc.2
IL_0027: ldloc.2
IL_0028: call void 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 System.Int32::ToString()
IL_003B: call string System.String::Concat(string , string )
IL_0040: call void 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 System.Int32::ToString()
IL_0057: call void System.Console::WriteLine(string )
IL_005C: nop
IL_005D: ldstr "ʡ麅覌륉ᬖⵇ㜸k⁋老ꅵ摣ρ憾嚳滺쿪ᷔ諚鋙ᬫ"
IL_0062: call string GClass3/GClass6::smethod_4(string )
IL_0067: stloc.3
IL_0068: ldloc.3
IL_0069: call void 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 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 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次,得到局部变量类型如下: int 32, {myFirstDll.Show}, string ,string, int32修改main方法体如下代码修改main方法体如下代码 .locals init (class System.Object[] V_0, class System.Reflection.Emit.DynamicMethod V_1)为.locals init ( int32 V_0, class myFirstDll.Show V_1, string V_2, string V_3, 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数组内的数据就是异常处理数据,这里解释一下这个数组的含义,0x01表示这是一个small异常处理结构,0x1c,表示数组长度,后面-为异常结构处理体00/0400/6e/7200/16/01000001,前面我们分析过,前两位为00表示这是一个有异常处理类型的结构,类型TOKEN为后4位0x01000001,我们打开METADATA看看这是什么类型,原来是System.Object,后面-是另一个异常处理结构finally,和前面分析相同,这里不多说,大家可以自行分析下。8、下面我们来为方法体添加异常处理模块,用DNSPY打开CRACK.EXE选中MAIN方法,选择Edit Method Body-Exception Handlers,我们添加两个异常处理,如下图第一条是根据前身得到的异常处理模块数据00/0400/6e/7200/16/01000001得来的,为什么是这样,前面已经解释过,第二条根据后面的数据得来,点OK,我们看看这时MAIN方法是什么样子。// 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("䂪哖㬎垸몤婛ᰲ復间πւꍹ阝᮳럡떗䰄隝逩");
text += GClass3.GClass6.smethod_4("궋ʎ♻업෭洇饑뽴偠黸ꏮﲣ䖽瞒᧩ẽ");
Console.WriteLine(text);
Console.WriteLine(show.Messages() + num.ToString());
Console.WriteLine(show.myadd(2, 3).ToString());
string value = GClass3.GClass6.smethod_4("ʡ麅覌륉ᬖⵇ㜸k⁋老ꅵ摣ρ憾嚳滺쿪ᷔ諚鋙ᬫ");
Console.WriteLine(value);
}
catch
{
Console.WriteLine("出错了");
}
finally
{
Console.WriteLine("最后执行测试");
}
}和前面对比,发现程序除了字符串常量不正确外,全部已经正确了,这时找到被加密的字符串常量就可以收工了,这个很简单,程序提示已经非常明显了,在Gclass3.Gclass6.method_4方法,最后一条语句下断,循环执行,就能看到所有解密字符串了,当然有兴趣的朋友可以研究一下狗的字符串加密原理,自己写一个解密程序,也行,看兴趣,我这里就不啰嗦了,找到解密后的字符串,替换一下,原来的代码,至此,去狗操作全部完成,这种方法可以完美去除狗。解密完成后,可以进一步优化程序,将狗壳附加的代码全部删除,这样就和原来的代码一模一样了,大家可以去尝试下。 另外以前的軟件狗X宝上有很多,可以复制克隆,现在的超级狗就没有,如果按照使用自己的工具(如VB、VC等)重新编写构造一个和加密狗API一样的DLL动态库文件,里面也包含Read、Write等全部API中包含的函数,使用的参量及返回值和原来的函数一样,所有函数返回零。然后对Query、Read函数进行处理,返回应用软件需要的数值即可。 这个新的DLL文件编写成功后,直接替换掉原来的DLL文件,这时候再运行应用软件,软件访问加密狗的操作就全部会被拦截,拦截程序永远会返回正确的数据给软件,从而实现了模拟加密狗的运行,这种方式可行吗? to:whshizy 老版本的safe net软件狗有研究吗?如果手上有原始狗,有配套的开发商工具,有密码能读取,能脱壳100%还原软件源代码吗?如果新加壳超级狗的软件源代码和老版本软件狗的相同,是否就能测试脱壳会引起哪些bug吗?小白问题多请楼主多包涵 前排围观 有意思。分析不易 楼主也是强悍啊,佩服你了。 看完了 不错。第一篇技术贴 加精鼓励。 技术文章必须支持 楼主也是强悍啊,佩服你了 技术贴,感谢分享,学习@@@ 小白路过、为大神加油 这样的文章不多,加分。 谢谢楼主分析自己的思路