混淆的概念与实践

 最近在看《微软.Net加密与解密》, 收获有些,倒也是值得欣慰了. 写下来做一个总结性的东西,记录下

混淆的几种方式 

  • 名称混淆
  • 流程混淆

 

名称混淆

概念

将类中原本友好的方法名称混淆成不易识别的名称 

例如 VisistHomePage(); -> adfsaluwabnjkdsf();

一两个方法,倒也作罢,可以猜猜. 一个项目里几千个方法全都这种变态的名字。这样像我这种三脚猫的破解新手,看着都烦了,自然没有心思看下去了.

实践

偶很懒,提供个思路好了 :)

我们知道Windows程序都会生成PE(Protable Execution)文件, 简单的说,就是保存程序的一些信息,其中包含方法名称,类名称等等。

这里我用CFF Explorer来看看一个简单程序的PE文件image

图1. 查看一个方法在PE文件中的格式

我们得到了这个方法的名称,哈哈,这意味着什么? 可以修改吗?

在PE文件中,#strings中保存着方法的名称, 如下图所示

image

图2:查看swap在#strings段中的位置

于是乎,我们看到了swap所对应的ASCII码为 73, 77, 61, 70 他们是16进制,对应的二进制值为115, 119, 97, 112

我们要把它改成AAAA, A 的 AscII代码为65, 16进制为41

image

图3: 修改的位置

保存,再用ILDASM查看下

image

图5: 查看修改后的结果

 

流程混淆

流程混淆是指在执行的过程中对IL的执行过程进行一些特殊处理,大概分为几种方式

  • 逻辑跳转
    1. 分块跳转
    2. If跳转
    3. switch跳转
  • 语法混淆
    1. 堆栈溢出
    2. 语法支持
    3. 无效指令
    4. 高级语言互相不支持
    5. 反编译器BUG

看到这些东西也许你会感觉到有点麻烦,什么东西嘛都是,我们一个一个来解释,首先,这里有一个很方便的测试原型.

using System;
using System.Collections.Generic;

namespace XWang
{
    public class Test
    {    
        public static void Main()
        {
            // TODO:: TEST THE LOGIC HERE
            //
            string userName = "XWang";
            string password = "http://www.xwang.org";
            
            Console.WriteLine("Please Input Your Name:");
            string name = Console.ReadLine();
            while(string.IsNullOrEmpty(name)) {
                Console.WriteLine("Your User Name Is Invalid");
                name = Console.ReadLine();
            }
            
            Console.WriteLine("Please Input Your Password");
            string pwd = Console.ReadLine();
            while(string.IsNullOrEmpty(pwd)){
                Console.WriteLine("Your Password Is Invalid");
                pwd = Console.ReadLine();
            }
            
            if(userName.Equals(name) && password.Equals(pwd))
                Console.WriteLine("Welcome: {0}", name);
            else
                Console.WriteLine("Oops..., your username or password doesn't match! Good Bye");
            
            Console.WriteLine("Press Any Key To Exit...");
            Console.Read();
        }
    }
}

首先DUMP出IL代码,而后进行实现

  • 分块跳转

      概念:讲原本正常的执行过程,拆分为几个部分,而后利用跳转指令执行

实践:  在程序执行过程中加上两个跳转指令

image

图6: 跳转指令

而后,跳转回来

image

图7: 跳转回指令

这样就完成一个跳转的过程, 现在我们用Reflector反编译下现在我们修改过的程序

image

图8: 修改跳转指令后的结果

可以看到,已经起到了加密的效果.

而所谓分块,就是把原来程序执行的几个部分按照这样的跳转指令把原先的执行顺序打乱

  • If跳转

           和前面的分块跳转不同的是加入了变量的支持,我们知道br为跳转指令,而brtrue, brfalse 为条件判断跳转指令

           image

         加上一个判断指令,因为进行了栈上的操作,所以需要增加.maxstack的大小

  • switch跳转

         和前面类似, 不同的是, 现在的指令换成了switch.

         swtich指令,您可以查看ECMA,也可以看透过IL看C# (1) switch语句

  • 堆栈溢出

       代码放在所有代码执行之前,即栈空的时候,  利用检查的漏洞, 欺骗反编译工具., 在栈空的时候还执行pop. 实际上,这段代码在运行时根本不会执行

br IL_0000
pop
ldc.i4.1
使用Reflector, 报错
image
  • 语法支持

所谓语法支持,是指一些IL上有,而一些高级语言例如C#不支持的特性,例如,接口上的静态变量, try, catch中的filter, fault块

.try
{
    throw
    leave end
}
filter
{
    pop
    // TODO:: Add your logic code here
    endfilter
}
catch [mscorlib]System.Object
{
    pop
    // TODO:: do something for the end of logic
    leave end
}
end:
    ret
  • 无效指令

插入一些无用,或者明显不存在的指令,导致错误

  • 高级语言互相不支持

例如 C++里不支持ref参数

  • 反编译器BUG

这个。。。 经验。。。 经验。。。

Summary

本文相当于一个介绍性的东西,大部分知识来源于《微软.Net加密与解密》, 相比于作者两年细心钻研的精神,偶等逊色了许多,学习之,反思之,奋进之.

关于IL的详细解释,您应该去查看ECMA335. 或者Expert IL 2.0 Assembler,似乎老包在翻译这本书,感兴趣的可以问问他 :)

posted on 2008-12-21 00:31  xwang  阅读(3362)  评论(11编辑  收藏  举报

导航