《二进制代码路径混淆技术研究》阅读笔记

《二进制代码路径混淆技术研究》阅读笔记

代码混淆技术的分类

布局混淆

删除或者混淆软件源代码或者中间代码中与执行无关的辅助文本信息,增加攻击者阅读和理解代码的难度。

  1. 删除注释之类的,改变字符(变量名,函数名等)名称。

数据混淆

指在不影响软件功能的前提下,变换软件代码中的数据或数据格式,增加软件代码的复杂度,可以分为存储和编码变换、聚集变换和次序变换等。

存储和编码变换

  1. 分割变量,使得一个变量p表达成两个变量a,b的某种函数映射;
  2. 将简单的标量变成复杂的对象结构,如JAVA中的int型使用Integer类表达;
  3. 改变变量的生命周期,如局部变量变成全局变量;
  4. 将静态数据用函数表示;(这里感觉是2方法的一种延伸?)
  5. 修改编码方式,如用等价的多项式替换数组变量原始的下标表达式(f(x)->a,还是2吧)等;

    聚集变换

    通过将多个数据聚集在一起形成新的数据结构,实现隐藏原始数据格式的目的。
  6. 合并标量变量,将多个变量V1,…,Vn合并成一个变量Vm;
  7. 重新构造数组来混淆数组运算;
  8. 修改类的继承关系也可以增加代码的复杂度,可以把两个无关的类进行聚集,生成一个新的无意义的父类,也可以把一个类拆分成两个类,其关键是要增加软件代码中类的继承深度;

    控制混淆

    增加软件中控制流的复杂度,分为聚集变换、次序变换和计算变换等类型。

    聚集变换

    通过破坏代码间的逻辑关系实现控制流混淆
  9. 内嵌函数的方法,用函数体内部的代码去替换程序中该函数的调用语句(这个方法可以躲过算法导论作业查重);
  10. 外提函数的方法,和1相反,把没有任何关系的代码合在一起创造一个新的函数,并多次调用该函数;
  11. 克隆函数的方法,将一个函数克隆成多个函数,新生成函数的功能是一致的,但是名称和实现的细节有些不同,可以调用其中的任何一个函数来替换原来的函数;
  12. 循环变换是指通过对循环退出条件的等价变换使循环的结构体变得复杂,例如循环的模块化、循环展开和循环分裂等;
  13. 交叉合并:把不同功能的函数合并成一个函数;

    次序变换

    语义相关的代码分散到不同的位置,尽量增加代码的上下文无关性,实现方法包括对文件中的函数重新排序,循环体或函数体内部的语句块重新排序,以及语句块内部的语句重新排序等。

    计算混淆

    引入混淆计算代码来隐藏真实的控制流,实现方法包括引入不透明谓词、插入垃圾代码、扩展循环条件、代码并行化和跳转表等。

    不透明谓词技术

    预防性混淆

    四大指标:强度、弹性、开销和隐蔽性

3X+1(克拉兹猜想)

对于任何的正整数n,如果n是偶数则除以2,如果n是奇数则乘以3再加1,重复这个计算,最终n都会收敛于1。

代码实现举例

源代码

1
2
3
if(x==a){
do_behaviour();
}

“3X+1”的代码
1
2
3
4
5
6
7
8
while(y>1){
if(y%2==1){
y=3*y+1;
}
else{
y=y/2;
}
}

混淆后的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//x:用户输入
//y:引入的混淆变量
y=x+1000;//这里的1000可以是其他一个较大的整数
while(y>1){
if(y%2==1){
y=3*y+1;
}
else{
y=y/2;
}
if((x-y)>a-2&&
(x+y)<a+2){//这里的条件判断与源代码中的"x==a"对应
do_behaviour();
}
}

上述代码的一些说明:

  1. 其实这里不仅可以用克拉兹猜想,其余的一个有最终收敛值的一个未解数学问题都可以引用作为混淆代码。
  2. 这里混淆后代码的if语句条件是生成动态路径分支条件的方法。