好友
阅读权限10
听众
最后登录1970-1-1
|
其实分析不难,改IL指令搞的我心力憔悴,清明出去玩都惦记着.
(求助:dnspy有没有编辑方法时显示IL指令的功能啊....)
等下要麻将,先发结果和几个参数,过会儿再写分析过程.
虚拟化代码存在在一个乱码的资源文件里,像这样.
进入虚拟化那个乱码的字符串".Ounr+YPC1" ,指向这个资源的某个位置,从而读出一些字节.
[C++] 纯文本查看 复制代码 \u000F\u2004\u200B\u2008.\u0005\u2005\u200B\u2008().\u0003(\u000F\u2004\u200B\u2008.\u0008\u2005\u200B\u2008(), ".Ounr+YPC1", u);
读出来的bytearr 经过解密 得到解密的bytearr,每4字节组合,得到一个操作指令.这些指令(应该,95%)是源程序的IL指令.暂时称它为指令数组.
指令数组在执行过程中看的到.像这样.解密过程我没看,这个过程也虚拟化了.
这些操作指令的意义是写死在程序里的.是个字典,对应相应的操作.执行过程中也可以看得到
指令数组中的指令在字典中查询并执行的代码在这里
[C#] 纯文本查看 复制代码 private void \u0005\u2000()
{
this.\u000E\u2002 = this.\u000E\u2001;
int key = this.\u0008\u2004.\u0003\u2000();
this.\u000E\u2001 += 4U;
\u0002\u2007.\u0002\u2000 u0002_u;
global::\u0002\u2007.\u0005.TryGetValue(key, out u0002_u);
u0002_u.\u0003(this, this.\u0002(this.\u0008\u2004, u0002_u.\u0002));
}
每次运行后的结果,保存在这里
比如比较注册的时间的过程,你会在结果集中看到
取出存取注册信息的那个类.
取出注册码过期时间.
执行call得到datetime.now
执行call比较时间大小
返回结果(0或1)
判断是否跳转
...
在这个程序块最后下断,可以很清晰的看到这个过程.按一次F5做一行事情.
当前运行到了IL指令数组的哪个位置,保存在这里
当要跳转的时候 \u000F\u2003的值变成新位置 并在这个程序块返回的程序块中进行判断.这个值不跳转的时候为null
[Asm] 纯文本查看 复制代码 private void \u0006(bool \u0002)
{
uint u000F_u = this.\u000F\u2002;
for (;;)
{
try
{
while (!this.\u0005\u2002)
{
if (this.\u000F\u2003 != null)
{
this.\u000E\u2001 = this.\u000F\u2003.Value;
this.\u0002((long)((ulong)this.\u000E\u2001));
this.\u000F\u2003 = null;
}
else if (this.\u000E\u2001 >= u000F_u)
{
break;
}
this.\u0005\u2000();
}
}
catch (object u)
{
this.\u0002(u, 0U);
if (\u0002)
{
continue;
}
this.\u0006(true);
}
break;
}
}
好了.现在总结下
1.根据指令数组的长度的不同,你基本可以判断出它在执行哪个虚拟化的程序块.
2.指令数组长度/4就是源程序IL指令的数量,大致可以判断出被虚拟方法的代码长度.如果长度相差太大,直接跳出虚拟化的循环就可以了.不用老点F5
3.我们可以修改\u000F\u2003的值跳转到虚拟方法的任何位置.
根据上2篇文章的经验,判断是否注册的代码很简单,大概长这样
[C#] 纯文本查看 复制代码 if (\u000F\u2008\u2004\u2001.\u000F != null && \u000F\u2008\u2004\u2001.\u000F.\u000E != (\u0002\u2009\u2004\u2001)0 && !(\u000F\u2008\u2004\u2001.\u000F.\u0006 < DateTime.Now) && \u0008\u2002\u2005.\u0003() != 4096)
{
return (\u0002\u2009\u2004\u2001)1;
}
return (\u0002\u2009\u2004\u2001)0;
最终调试结果是,这段判断注册与否的代码被虚拟化后的长度是0x0000013E(它加了很多干扰代码,把指令搞长了)
return 1 那里对应的数组位置是0x88,在虚拟化的跳转处下断,长度是0x13e时第一次跳转发生在数组位置0x6c.
我在这里注入了断代码,当\u000F\u2003==0x6c时,修改成0x88.
然后就成功了.
|
免费评分
-
查看全部评分
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|