第十一章 软件保护技术(二)(软件混淆技术)

软件混淆技术

  • 软件
    • 代码
    • 数据
  • 软件混淆(从宏观角度看)
    • 代码混淆
    • 数据混淆
  • 软件混淆(从软件的编译与链接生成过程看)
    • 事前的代码混淆
    • 事中的编译期混淆
    • 事后的二进制混淆

  • 代码混淆
    • Code Obfuscation
    • 指混淆过程发生在代码级别,包括对源码进行静态修改的源码混淆,和基于源码(针对 C++ 语言)模板展开的模板混淆
  • 编译期混淆
    • 发生于代码编译期间
    • 使用 LLVM 编译套件的情况下,可对代码进行混淆处理
    • 分为:
      • 编译器前端在进行原生代码分析时采取的前端混淆
      • 编译原生代码并生成中间代码 IR 时采取的 IR 混淆
    • 使用 ProGuard 对 DEX 进行优化保护时,采取的是 DEX 混淆
  • 二进制混淆
    • 指在生成目标软件后对软件的二进制代码进行的混淆
    • 典型
      • 生成 DEX 后对其进行反编译
      • 对 DEX 进行二次混淆

源码混淆

  • 即对源码进行混淆,让人从代码级别就无法理解程序的执行行为
  • 方法
    • 手工或使用工具替换源码中变量和符号信息
  • 优点
    • 经过这种处理的代码分析难度提高
  • 缺点
    • 若手工替换,则缺少自动化操作,开发和维护成本提高
    • 若用工具替换,虽能防止被逆向分析,但自身的调试和维护会很麻烦,当出现 bug,定位问题发生的位置会更难

模板混淆

  • 编译源码时自动进行代码混淆

  • 《关于 C++ 模板元编程实现 C++ 代码的加密混淆》(Binary code obfuscation through C++ metaprogramming):首次基于编译期代码混淆技术的成果性的讨论和实践

  • C++ 的宏模板具有在编译时展开的特性,可将其运用到代码的混淆加密中

  • 如使用 C 语言计算一个数的阶乘(factorial):

    long Factorial(int n)
    {
         
        if (n == 0)
        {
         
            return 1;
        }
        return n * Factorial(n - 1);
    }
    

  • 将上述代码编译成二进制程序,程序会在运行时计算某个数的阶乘。若用 C++ 的宏模板实现上述计算:
template<int N> struct Factorial
{
    static const int value = N * Factorial<N-1>::value;
};
 
template<> struct Factorial<0>
{
    static const int value = 1;
};
// std::cout << Factorial<6>::value << std::endl;

  • 使用宏模板后,编译生成的二进制程序不再包含阶乘的代码调用,取而代之的是计算后的数值 720

  • 使用宏模板也能高效实现线性同余生成器(Linear Congruential Generator),以便为加密算法生成伪随机数:

    typedef unsigned int u32;
    typedef unsigned long long u64;
    template<u32 S, u32 A = 16807UL, u32 C = 0UL, u32 M = (1UL<<31)-1> struct LinearGegerator
    {
        static const u32 state = ((u64)S * A + C) % M;
        static const u32 value = state;
        typedef LinearGenerator<state> next;
        struct Split    // Leapfrog
        {
            typedef LinearGenerator<state, A*A, 0, M> Gen1;
            typedef LinearGenerator<next::state, A*A, 0, M> Gen2;
        };
    };
    

  • 有了随机数生成器,只要扩展思路,配合代数恒等式 x+y==(x^y)+2(x&y) 的特点,即可实现加法运算的混淆加密。部分代码:
template<typename T, typename RandGen> struct ObfuscatedAdder
{
    enum Adder_Method
    {
        Adder_Method_0,
        // ...
        Adder_Method_Count
    };
    template<typename Gen, u32 MutationIndex> struct Mutation;
 
    template<typename Gen> struct Mutation<Gen, Adder_Method_0>
    {
        template<u32 N, typename D> struct Remaining
        {
            static inline T eval(const T a, const T b)
            {
                typedef Mutation<typename Gen::next, Gen::value%Adder_Method_Count> NextMutation;
                return NextMutation::template Remaining<N-1, D>::eval(a^b, 2*(a&b));
            }
        };
 
        template<typename D> struct Remaining<0, D>
        {
            static inline T eval(const T a, const T b)
            {
                return a^b;    // no more carries to propagate, just xor
            }
        };
    };    // ...
 
    static inline T eval(const T a, const T b)
    {
        typedef typename Mutation<RandGen::next, RandGen::value%Adder_Method_Count> M;
        return M::template Remaining<Bits<T>::value, NullType>::eval(a, b);
    }
};
  • 使用宏模板,不仅能对代码进行混淆,还能对数据进行混淆

AST 混淆

  • 模板混淆技术只能应用于 C++,无法应用于其他语言

  • LLVM 采用模块化和分层的思想完成程序的构建,基于 LLVM 的编译器前端 Clang,同样采用这种思想

  • Clang 在编译程序时会对目标代码进行分析,生成结构化的树状语法表述。此表述方式通称抽象语法树(Abstract Syntax Tree,AST)

  • 将程序的代码表示为 AST 给编译时的分析和优化带来极大便利。如,对高级语言而言,不同的类或名字空间中可能有相同的变量名,因此在重命名一个变量时不能简单地搜索变量名并将其替换(可能会对原程序的执行产生影响);若用 AST 将程序表示,替换变量名的操作将变得简单:因每个变量的定义都对应独一无二的抽象语法树节点,故只要改变对应变量用于声明 AST 节点的名称字段,把抽象语法树转换为原始代码即可

  • 基于此种操作 AST 的思想,可实现和模板混淆相同的代码混淆,即 AST 混淆

  • Clang 以高度模块化的方式驱动,所有编译时功能都有供外部使用的接口,同时提供了操作 AST 的 API 接口。LLVM 在其文档的 Using Clang as a Library 部分指出将 Clang 作为库使用的三种方法:LibClang、ClangPlugins、LibTooling,它们的差异主要体现在代码编译期间能操作的对象上。LIbTooling 能执行的操作最多,故以其为例学习如何替换源码中的所有字符串

  • 将 Clang 作为库使用时,要在程序中定义一个 ClangTool 对象,它将作为一个“内部”编译器操作源文件。构建该对象时,要传入一个命令行参数选项和两个操作目标文件的参数(可用 CommonOptionsParser 生成):

    CommonOptionsParser op(argc, (const char**)argv, StatSampleCategory);
    ClangTool Tool(op.getCompilations(), op.g
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值