一、开篇

  首先写在前面,这篇文章源于个人的研究和探索,由于.NET有自己的反射机制,可以清楚的将源码反射出来,这样你的软件就很容易被破解,当然这篇文章不会说怎么样保护你的软件不被破解,相反是借用一个软件来讲述是怎么被攻破的,也会有人说这是一篇破文,我其实这篇文章已经写了很长时间了,不知道以什么形式发出来,因为毕竟是有些破解类的东西。但是我觉得从这篇文章相反的是能够带来一些启发。大家应该都知道Reflector这个反编译软件还有一个插件是专门用来改IL的插件叫Reflexil,这里我们也要用到前面那个工具Reflector,后面的插件我们这里我们不用,接下来分析的东西可以让大家能够更深入.NET的PE,深入内幕来看看,好,闲话少说….直接上分析。

二、详细分析过程

  如果不懂.NET的PE文件结构的帅哥美女,可以看一下上一篇文章http://www.cnblogs.com/dwlsxj/p/4052871.html,这里要用到PE的知识,首先我们来看一下这个程序的限制,这个程序有显示限制也就是显示的列表只能显示三行。如下图所示:

  我们现在要用Reflector工具将我们要破解的程序反编译一下看一下哪里没有跳转到MessagBox弹出对话框了!反编译成C#代码后我们可以看到这个程序就一个主界面,看到了Form名字就说明这个是一个Windows的窗体:

  点开之后,就发现ProgressChanged方法里面有内容,里面包含了弹出消息框的全部代码,好的我们这里就确定了是这个方法让这个消息框弹出来的!的确他就是罪魁祸首,先记录备案。

  现在已经知道是哪个方法弹出消息框来了,那么我们就可以再元数据表中进行查找该方法所在的RVA,这里我要讲一个元数据表中的表这个表就是MethodDef表,这个表很重要也很好玩,这个表里不但指出了该方法的IL代码的位置,还限定了方法的属性。下面来看一下表结构:

偏移

大小

名称

说明

0

4

RVA

该方法体的RVA(方法体包括:方法头、IL代码、异常处理定义)

4

2

ImplFlags

限定了方法的执行方法(如abstract、P/Invoke)

6

2

Flags

先顶了方法的调用属性和其他的一些性质

8

2(4)

Name

指向#String的偏移,表示该方法的名称

2(4)

Signature

指向#Blob的偏移,Signature定义了方法的调用方式(如返回值类型等)

2

ParamList

指向Param表的索引,指出了方法的参数

  看到上面这个表不禁让我开心,因为我能找到这个方法存放的位置,也就是我需要的是这个RVA的地址,那么这个方法的RVA是多少呢?带着疑问思考,我们会想到用到一个工具来帮助我们查找这个方法到底在Method的第几个,这里不讲直接打开CFF也可以看到这个方法。我要曲折的找一下。打开ILDASM,既然.NET里面有元数据这个一号人物,我们就来小窥一下元数据表,该方法的元数据肯定在里面。

  果然不出我们所料,确实在元数据里面有描述,因为元数据是描述数据的数据,那么我们就拿到了这个Token标示:0600001F,可以翻回到上一篇文章找一下这个对应的表是MethodDef正还是我们想要的,在这个表下的第31的位置就是我们要找的内容,怀着疑问打开CFF软件,来证实一下我们找的没有错!!!

  经过证实是我要找的ProgressChanged方法在元数据表中的描述,现在就可以取出关键信息ProgressChanged方法的RVA:0x3184

  通过CFF查看一下区块的内容:

  可以正确的观察到该方法的RVA存放在.text区块中,因为该区块的范围是:2000~14A00,而3184正好落在了这段地址当中,好,接下来就可以算出该代码在物理地址了:3184-2000+200=1384,好的,0x1384就是我们要在文件中查找的的物理地址。这时候打开16进制编辑器,将程序载入到16进制编辑器中。CTRL+G搜索0x1384这个地址,下面是我们搜到的地址:

  你们会疑问我怎么知道这么一段就是这个方法的代码呢?让我来揭晓这个谜底。OK,RVA我们算的肯定没错,也就是开始位置1384这个肯定是没错的,但是代码的长度不是很确定对吧?好,打开ILDASM找到这个方法就知道这个方法的长度,或者是在这个方法的头部我们就可以确定这个方法的长度。

  验证结果的时候到了通过ILDASM来验证下:

  通过上述结论我们可以证实确实是存放的IL的代码,我们可以看到上面有一个开始指令,是我标记的这个开始指令的IL代码是ldarg.2加载方法参数2到堆栈上。这里不看他的个什么东东!我们只要知道他的Opcode是多少就好了这个指令的Opcode是04,那么我们就在上面的16进制编辑器中进行搜索:

  意思就是04这个指令的前面都是在做初始化堆栈和初始化参数的操作,而从04开始才是真正执行代码。好的开始的指令已经找好了,我们就要看一下我们要修改那段代码了,先观察这段比较num--==0这里,注意这里修改代码的时候不能破坏代码的长度和代码的堆栈平衡原理。我们想如何能让这个条件永远不成立,OK,我想到了一个方法就是不让这个参数进行减法操作,让他一直进行加法操作!首先先小窥一下的他的IL代码我们开讲一下整体IL的实现,这里只讲num--==0处的代码:

代码详细讲解如下:

  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进制另存一份就可以实现所有功能了。

  改好后我们来看一下效果如何吧!!!

  其实我们看似Reflexil简简单单的修改了一个指令的值,其实背后做了大内容,比如要对区块的RVA进行修正,就当前的方法的RVA的修改以及所有方法的修改等操作。这块就不多说了有兴趣的自己研究下!

三、结束语

  这东西虽然看着没有Reflexil来得快但是能让你更深入的了解.NET的PE结构,小弟再次声明本文章只是为了研究技术,没有用做商业用途,为了支持正版我已经将标题遮挡住了,通过上述的文章,我有点小小的想法,就是我们可以讲我们需要加密的方法体抽出来,当jit调用时再进行还原这样就会对程序的安全性有一个提升。这里只是我自己的个人看法,还请各位大牛指点小弟,小弟在此谢过了。

再探.NET的PE文件结构(安全篇)的更多相关文章

  1. [老老实实学WCF] 第五篇 再探通信--ClientBase

    老老实实学WCF 第五篇 再探通信--ClientBase 在上一篇中,我们抛开了服务引用和元数据交换,在客户端中手动添加了元数据代码,并利用通道工厂ChannelFactory<>类创 ...

  2. COFF/PE文件结构

    COFF/PE文件结构 原创 C++应用程序在Windows下的编译.链接(二)COFF/PE文件结构 2.1概述 在windows操作系统下,可执行文件的存储格式是PE格式:在Linux操作系统下, ...

  3. PE文件结构及其加载机制

    一.PE文件结构 PE即Portable Executable,是win32环境自身所带的执行体文件格式,其部分特性继承自Unix的COFF(Common Object File Format)文件格 ...

  4. 【再探backbone 02】集合-Collection

    前言 昨天我们一起学习了backbone的model,我个人对backbone的熟悉程度提高了,但是也发现一个严重的问题!!! 我平时压根没有用到model这块的东西,事实上我只用到了view,所以昨 ...

  5. ViewPager+Fragment再探:和TAB滑动条一起三者结合

    Fragment前篇: <Android Fragment初探:静态Fragment组成Activity> ViewPager前篇: <Android ViewPager初探:让页面 ...

  6. PE文件结构详解(六)重定位

    前面两篇 PE文件结构详解(四)PE导入表 和 PE文件结构详解(五)延迟导入表 介绍了PE文件中比较常用的两种导入方式,不知道大家有没有注意到,在调用导入函数时系统生成的代码是像下面这样的: 在这里 ...

  7. PE文件结构详解(五)延迟导入表

    PE文件结构详解(四)PE导入表讲 了一般的PE导入表,这次我们来看一下另外一种导入表:延迟导入(Delay Import).看名字就知道,这种导入机制导入其他DLL的时机比较“迟”,为什么要迟呢?因 ...

  8. PE文件结构详解(四)PE导入表

    PE文件结构详解(二)可执行文件头的最后展示了一个数组,PE文件结构详解(三)PE导出表中解释了其中第一项的格式,本篇文章来揭示这个数组中的第二项:IMAGE_DIRECTORY_ENTRY_IMPO ...

  9. PE文件结构详解(二)可执行文件头

    在PE文件结构详解(一)基本概念里,解释了一些PE文件的一些基本概念,从这篇开始,将详细讲解PE文件中的重要结构. 了解一个文件的格式,最应该首先了解的就是这个文件的文件头的含义,因为几乎所有的文件格 ...

随机推荐

  1. CozyRSS开发记录12-MVVM,绑定RSS源和数据

    CozyRSS开发记录12-MVVM,绑定RSS源和数据 1.引入MvvmLight MVVM最近貌似在前端那块也挺火的.据说,WPF的程序如果不用MVVM,那跟MFC和winform的,也没啥区别. ...

  2. 2016 ACM/ICPC Asia Regional Dalian Online 1008 Function 二分+RMQ

    Time Limit: 7000/3500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submissio ...

  3. C#获取当前程序运行路径的方法集合

    //获取当前进程的完整路径,包含文件名(进程名).string str = this.GetType().Assembly.Location;result: X:\xxx\xxx\xxx.exe (. ...

  4. 【原】iOS学习之应用之间的操作

    关于应用之间的相互操作,小编一直觉得非常高大上,在一次面试中被面试官一顿暴虐,今天小编就决定学习一下!经过一顿度娘,找到一些博客,不过都比较凌乱,我就打算自己整理一下! 首先要说的是每一个APP都可以 ...

  5. fragment 重叠问题

    项目中用到了Android Fragment 在程序异常的时候 fragment 点击会造成fragment 重叠 在fragmentActivity中加入一下方法 @Override public ...

  6. $(function(){}) 与(function(){})()在执行时的优先级

    $(function(){}) 是在页面DOM元素加载完成后执行,这时页面中的DOM对象都可以找到; (function(){})()是匿名函数,按页面从上到下顺序,执行到它时才执行,这时可能有的在此 ...

  7. 【签名之坑】Decmail.GetBits()

    decimal类型有GetBits()方法 可以获取到值的int[4]值,进而获取到byte[16]值 在c#里,0m和0.00m获取到的byte[]是不一样的(具体为何不一样,自己百度) 在sql里 ...

  8. 【SRM】649 t2

    题意 一个数列\(A\),数的范围均在\([0, 2^N-1]\)内,求一个\(B\),使得新生成的数列\(C\)中逆序对最多(\(C_i = A_i xor B\)),输出最多的逆序对.(\(|A| ...

  9. bug: 在缓存行高时,总是记录错误.

    一,现象: 1.在 cell 中添加了一个 label, 并对 label 设置了 attributeText, 结果滑动的过程中,cell 的高度总是不对,多次出现下一个 cell 覆盖上一个 ce ...

  10. 获取img的真实宽高

    之前项目后台上传图片时需要对图片的宽高做限制,一开始百度了之后使用js进行判断,可是这种方式存在一定问题,后来就改在后台判断了.现在吧这两种方式都贴出来. 一.用js获取: 先说第一个方法:obj.s ...