卿海军,黄寄洪,陈丽萍
(1.梧州学院 计算机科学系,广西 梧州 543002;2.梧州市第一中学,广西 梧州 543002)
代码迷惑技术属于一种重要的软件保护技术,其本质是利用程序等价变换的方法,将原始程序转变为语义等价、难以被理解或反编译的程序[1].它与其它技术相比简单、廉价.特别是伴随着Java和.Net语言的出现,代码迷惑技术已从一种可选的安全放技术,演变成为一种必需的安全技术,因为任何不想开放自己源代码的软件开发者,都得对源代码进行迷惑处理.因此,一些软件开发环境集成了代码迷惑功能.
代码迷惑技术主要分为词法变换、控制流变换、数据流变换和类结构变换.隐藏变量代码迷惑技术属于词法变换.目前词法变换的方法有:①引进非法标识符用作变量名[2],这些非法标识符包括对于变量命名规则非法的字符、关键字、布尔字符、空字符等,这些非法标识符在字节码里是合法的,但在源程序中是不允许的,从而反编译就会出错;②尽可能多地使用同一变量,比如变量既是类成员变量又是方法局部变量或方法名,使嵌套类内层类与外层类同名等.但是上面提到的这些方法并没有对方法的参数变量及方法的局部变量进行迷惑,这就使得迷惑不够彻底,同时它的迷惑弹性与力度不够,文献[3]基于此提出了相应的反迷惑方法;③将标识符作交换而非更改成毫无意义的名字的方法进行迷惑[4].标识符交换包括交换变量名、交换函数名和交换类名三个步骤,同样它的迷惑弹性也不够.针对现有的一些词法迷惑弹性不够、不能有效抵御反迷惑的攻击,本文提出了一种迷惑弹性较好的代码迷惑方法.
文献[5]提出了实体更名迷惑范围的概念,并指出了实体更名迷惑的范围,这其中不包括方法的参数变量和方法的局部变量,这些变量在有些方法里的所有使用的变量当中占据100%的份额.因此若把这些变量排除在迷惑范围之外,迷惑的程度是相当不够的.现有的迷惑方法之所以把方法的参数变量和方法的局部变量排除在迷惑范围之外是因为字节码文件结构导致的,源代码在编译成字节码时可以选择是否保留参数变量和局部变量的信息,可见编译时可忽略参数变量和局部变量名,只需保留它所占的相对位移信息.同样在反编译时也可忽略参数变量和局部变量名的存在.因此若不加处理,将参数变量及局部变量加以迷惑是无效的.
考虑到变量若以类成员变量的形式存在,在字节码储存的是类成员变量名,而不是相对位移,自然而然地可以把参数变量和局部变量分别提取出来组成一个个的类,这样便可以保证编译与反编译时不会忽略变量名的存在,然后这些类成员变量名采用无意义的易混淆的名字,从而可达到迷惑的效果.但是该方法的迷惑弹性仍然不够,可以采用自动的变量名替换技术将这些迷惑的变量转变成有意义易区分的变量名,经过分析可知,自动的变量名替换技术必然会改变变量名字,那么这种改变变量名字后,程序是否可以察觉到呢?恰好Java提供了一种反射技术,完全可以用来检测变量名是否更改,这样可以在进入每个方法前都检测变量名是否可更改,若已更改,则可以立即采取保护措施.从而使得采用自动变量名替换技术的反迷惑方法处理后的程序不可运行,这样增加了反迷惑的难度,提高了迷惑技术的弹性.因为Java与.Net编译技术相似,同时它们都具有反射功能,所以这种方法适用这两种跨平台语言,对于其他语言也有一定的借鉴意义.
抽取变量组成类的迷惑方法对具有继承关系的父子类也同样是适用的,抽取变量主要是指抽取方法局部变量及方法参数变量,当采用这种方法时,父类与子类互不影响,可以各自分别运用,特别是对于Java,一般情况下一个文件只包含一个类,此时对各个类的处理都是独立的,无论是对于父子类之间,还是不相关的类之间.
对于任意一个方法m,设LocalVars(m)表示方法m的局部变量集合,ParamVars(m)表示方法m的参数变量集合,Cl表示某方法局部变量组成的类,Cp表示某方法的参数变量组成的类.设源程序有有n个方法(不包括构造方法),则迷惑后将会新生成2n个类.Fields(c)表示类C的成员变量集合,则采用抽取变量组成类方法迷惑之前的代码与迷惑之后的代码变量之间可描述为两个映射f1,f2.
对于本文提出的隐藏变量的代码迷惑方法,本文在Java平台上进行了编程实现,并进行了实验验证,实验是针对源代码进行的,实验划分为预处理,变量信息收集和迷惑三个阶段.
将要抽取变量的源代码如下:
图1展示了分别采用文献[5]和抽取变量组成类的方法迷惑后源代码的变化情况,图中右边的代码对于gcd方法生成了两个新类它们分别为gcd方法的参数变量和局部变量所组成的类,对于构造函数test1并没有生成其参数变量类,因为如果生成其参数变量类,则在生成正在迷惑的类的实例时,必须把调用构造函数的形式做一定的变化,还得更改类名,涉及到类以外的范围,情况较为复杂,因此未加处理.从迷惑后的代码对比来看,采用抽取变量组成类的方法进行迷惑的程序更难以分析、理解,且代码的规模有大幅度增加.
图2对图1生成的2段迷惑代码用反编译器Jad分别进行了反编译.从图中可以看出采用文献[5]的方法对方法参数及方法局部变量进行迷惑,经过反编译后是无效的,因为反编译器用自己生成的变量取代了原来的变量.与此形成对比的是将参数变量和局部变量组成类后再反编译,变量仍然保持原来的名字,仍然具有迷惑性,从图2右边可以看出反编译的效果不是很好,前面的代码有点混乱.当然抽取变量组成类的迷惑方法也扩展了迷惑的范围,将变量的迷惑范围扩展到了参数变量和局部变量.
图1 迷惑后的代码Fig.1 The code after obfuscated
附图3采用文献[3]中的ADAM工具对图1中两段迷惑代码分别进行反迷惑,在图中左边的代码中变量已完全用新产生的变量名替换了,变量已很容易识别,可以说反迷惑已成功,但对于附图3右边的代码已经变成一个不能正常运行的程序,首先在加载参数变量组成的类和局部变量组成的类时便会抛出找不到类的错误,其次在检查相应的类成员变量时也会检测到变量名已更改,当然不会到这一步程序早已非正常结束.这时,抽取变量组成类的抗攻击效果便体现出来了.
图2 反编译图1的迷惑代码Fig.2 Decompilation of the obfuscated code of figure 1
本文在考虑现有的实体更名迷惑的弹性不够的情况下,提出了一种具有一定抵抗反迷惑攻击能力的方法.抽取变量组成类的方法很好地保持了参数变量和局部变量迷惑的有效性,同时还利用新一代语言的反射功能检测变量名是否更改,提高了迷惑的弹性.
[1]王建民,余志伟,王朝坤,等.Java程序混淆技术综述[J].计算机学报,2011,34(9):1578-1588.
[2]Chan J T,Yang W.Advanced obfuscation techniques for java byte-code[J].The Journal of Systems and Software,2004,71(1/2):1-10.
[3]Cimato S,Santis A D,Petrillo U F.Overcoming the obfuscation of java programs by identifier renaming[J].The Journal of Systems and Software,2005,78(1/2)60-72.
[4]De Roo A,v.den Oord L.Stealthy obfuscation techniques:misleading the pirates[EB/OL].[2007-02-12].http://www.home.cs.utwente.nl/~oord/paper.pdf.
[5]Chan J T,Yang W.Advanced obfuscation techniques for Java bytecode[J].The Journal of Systems and Software,2004,71(1/2):1-10.
附图3 采用ADAM工具对图1的迷惑代码分别进行反迷惑后的结果BriefFig.3 The result after decompiling obfuscation code of figure 1 by ADAM tool