本帖最后由 Martin 于 2014-11-1 22:06 编辑
一、开篇 本篇主要讲的是.NET PE关于我们想要的东西,其实这篇文章我犹豫了很久不知道取什么名字,其实这篇文章也是一篇原理性的文章,大家破解过.NET程序的人都知道Reflector这个反编译软件还有一个插件是专门用来改IL的插件叫Reflexil,这里我们也要用到前面那个工具Reflector,后面的插件我们这里我们不用,其实我想着叫另类破解.NET来着,后来想想还是这个比较好。这里我们要破解的软件是Blue 发的(【Blue原创教程】NET破解之第二课(数字和字符串修改))blue里面用的是Reflexil插件修改的变量的值将变量的值设置很大。Blue的方法我这里不说了,转到Blue的地址可以详情看一下:http://www.52pojie.cn/thread-249034-1-1.html,嘿嘿,这里我要说一下我的方法,以及让大家能够更深入.NET的PE,深入内幕来看看,好,闲话少说….直接上分析。(软件下载可以看一下Blue的连接) 二、详细分析过程
1
我们现在要用Reflector工具将我们要破解的程序反编译一下看一下哪里没有跳转到MessagBox弹出对话框了!反编译成C#代码后我们可以看到这个程序就一个主界面,看到了Form名字就说明这个是一个Windows的窗体:
2
点开之后,就发现ProgressChanged方法里面有内容,里面包含了弹出消息框的全部代码,好的我们这里就确定了是这个方法让这个消息框弹出来的!的确他就是罪魁祸首,先记录备案。
3
现在已经知道是哪个方法弹出消息框来了,那么我们就可以再元数据表中进行查找该方法所在的RVA,这里我要讲一个元数据表中的表这个表就是MethodDef表,这个表很重要也很好玩,这个表里不但指出了该方法的IL代码的位置,还限定了方法的属性。下面来看一下表结构: 偏移 | | | | | | | 该方法体的RVA(方法体包括:方法头、IL代码、异常处理定义) | | | | 限定了方法的执行方法(如abstract、P/Invoke) | | | | | | | | | | | | 指向#Blob的偏移,Signature定义了方法的调用方式(如返回值类型等) | | | | |
看到上面这个表不禁让我开心,因为我能找到这个方法存放的位置,也就是我需要的是这个RVA的地址,那么这个方法的RVA是多少呢?带着疑问思考,我们会想到用到一个工具来帮助我们查找这个方法到底在Method的第几个,这里不讲直接打开CFF也可以看到这个方法。我要曲折的找一下。打开ILDASM,既然.NET里面有元数据这个一号人物,我们就来小窥一下元数据表,该方法的元数据肯定在里面。
4
果然不出我们所料,确实在元数据里面有描述,因为元数据是描述数据的数据,那么我们就拿到了这个Token标示:0600001F,可以翻回到上一篇文章找一下这个对应的表是MethodDef正还是我们想要的,在这个表下的第31的位置就是我们要找的内容,怀着疑问打开CFF软件,来证实一下我们找的没有错!!!
5
经过证实是我要找的ProgressChanged方法在元数据表中的描述,现在就可以取出关键信息ProgressChanged方法的RVA:0x3184
通过CFF查看一下区块的内容:
6
可以正确的观察到该方法的RVA存放在.text区块中,因为该区块的范围是:2000~14A00,而3184正好落在了这段地址当中,好,接下来就可以算出该代码在物理地址了:3184-2000+200=1384,好的,0x1384就是我们要在文件中查找的的物理地址。这时候打开16进制编辑器,将程序载入到16进制编辑器中。CTRL+G搜索0x1384这个地址,下面是我们搜到的地址:
7
你们会疑问我怎么知道这么一段就是这个方法的代码呢?让我来揭晓这个谜底。OK,RVA我们算的肯定没错,也就是开始位置1384这个肯定是没错的,但是代码的长度不是很确定对吧?好,打开ILDASM找到这个方法就知道这个方法的长度,或者是在这个方法的头部我们就可以确定这个方法的长度。
8
验证结果的时候到了通过ILDASM来验证下:
9
通过上述结论我们可以证实确实是存放的IL的代码,我们可以看到上面有一个开始指令,是我标记的这个开始指令的IL代码是ldarg.2加载方法参数2到堆栈上。这里不看他的个什么东东!我们只要知道他的Opcode是多少就好了这个指令的Opcode是04,那么我们就在上面的16进制编辑器中进行搜索:
10
意思就是04这个指令的前面都是在做初始化堆栈和初始化参数的操作,而从04开始才是真正执行代码。好的开始的指令已经找好了,我们就要看一下我们要修改那段代码了,先观察这段比较num--==0这里,注意这里修改代码的时候不能破坏代码的长度和代码的堆栈平衡原理。我们想如何能让这个条件永远不成立,OK,我想到了一个方法就是不让这个参数进行减法操作,让他一直进行加法操作!首先先小窥一下的他的IL代码我们开讲一下整体IL的实现,这里只讲num--==0处的代码:
11
代码详细讲解如下: IL_002f: ldloc.3 //加载3到堆栈上。 IL_0030: dup //复制栈顶数据 IL_0031: ldc.i4.1 //加载1到堆栈上 IL_0032: sub //3-1的操作。 IL_0033: stloc.3 //保存到局部变量3中这是由原来的3变成了2 IL_0034: ldc.i4.0 //加载变量0到堆栈 IL_0035: ceq //于O比较后的结果放在堆栈上(返回0或1) IL_0037: ldc.i4.0 //因为我们比较后的结果为0或1所以在压入一个0后面进行比较false(ceq从堆栈弹出两个参数) IL_0038: ceq IL_003a: brfalse IL_0113//条件成立跳到消息框 OK分析到这里,这段指令的sub指令是我们的关键,我们要将这个指令改为Add就可以实现了,对应的Sub的Opcode是59,而对应AddOpcode是58这样我们把59变成58再把16进制另存一份就可以实现所有功能了。
12
改好后我们来看一下效果如何吧!!!
13
其实我们看似Reflexil简简单单的修改了一个指令的值,其实背后做了大内容,比如要对区块的RVA进行修正,就当前的方法的RVA的修改以及所有方法的修改等操作。这块就不多说了有兴趣的自己研究下! 三、结束语
这东西虽然看着没有Reflexil来得快但是能让你更深入的了解.NET的PE结构,还是比较叼的!各位看官多多加热心值,分析真心不易!破文皆为原创作品,转载请注明出处!!
|