一种变换PE文件引入表结构的软件水印

时间:2022-08-20 03:35:06

一种变换PE文件引入表结构的软件水印

摘 要:通过分析PE文件引入表结构特点与模块函数调用方式,提出一种新的变换引入表结构的软件水印方法。新方法将数字水印信息隐藏于PE文件引入表模块与函数的排列顺序之中。分析表明,该方法比利用PE文件冗余空间和资源结构的水印算法有更好的隐蔽性和更强的鲁棒性,提供了更加安全的软件版权保护方式。

关键词:PE文件;引入函数;水印容量;版权保护

中图分类号: TP309

文献标志码:A

Software watermark based on structure transform of PE file import table

LONG Feiyu1, LIU Jiayong1, YUAN Xi2

1.Information Security Institute, Sichuan University, Chengdu Sichuan 610064, China;

2.School of Automation, University of Electronic Science and Technology of China, Chengdu Sichuan 611731, China

)

Abstract: By analyzing the structural characteristics of import table and the calling approach of function in the module, a new software watermark based on structure transform of PE file import table was proposed. The new method made digital watermark information hidden in the sequence of import modules and functions in the PE file. Analysis shows that the method is more covert and robust than that utilizing redundant PE file space or resources structure, and it provides a more secure way of software copyright protection.

Key words: PE file; inducting function; watermarking capacity; copyright protection

0 引言

PE文件是Win32环境自身所带的执行体文件格式,它的一些特性继承自Unix的COFF(Common Object File Format)文件格式。PE的意思是Portable Executable(可移植可执行),意味着此文件格式与平台体系结构无关。在Win32平台下,除VxD和16位的DLL外,所有Win32执行体都使用PE文件格式,包括NT的内核模式驱动程序[1-2]。因此,为了保护软件版权,研究适用于PE文件的软件水印尤其重要。

现阶段在PE文件中嵌入数字水印的方法有两类[3]。第一类是研究最多的将水印信息嵌入到PE文件的冗余空间[4-7]。这类方法使用了PE文件自身废弃的空间来存放水印信息,缺点是水印的隐蔽性和鲁棒性不够好。第二类是研究较少的利用PE文件自身结构特点来隐藏水印信息,如PE文件资源结构[8]。这类信息隐藏方法没有添加、修改PE文件的冗余空间,因此和第一类方法相比,具有更好的隐蔽性和鲁棒性。本文提出的软件水印属于第二类,与基于PE文件资源结构的水印相比,其水印容量更大,并进一步提高了水印的隐蔽性和鲁棒性。

1 引入表结构及其变换方法

引入表包含了多个引入函数,一个引入函数是被某模块调用的但又不在调用者模块中的函数,因而命名为“引入”。引入函数实际位于一个或者更多的DLL里。调用者模块里只保留一些函数信息,包括函数序号、函数名及其驻留的DLL名[1,9]。

可通过以下方法在PE文件中定位引入表:1)从DOS Header定位到PE Header;2)从PE Header的Optional Header里读取 Data Directory 的地址;3)用IMAGE_DATA_DIRECTORY结构尺寸乘上引入表的索引号“1”,再加上Data Directory的地址,得到指示引入表地址的IMAGE_DATA_DIRECTORY结构地址;4)第3)步得到的IMAGE_DATA_DIRECTORY结构中VirtualAddress即为引入表地址。引入表的结构如图1所示。

图片

图1 PE文件引入表结构

引入表是由IMAGE_IMPORT_DESCRIPTOR结构组成的数组,该数组以一个全0的IMAGE_IMPORT_DESCRIPTOR结构结束,每个非0的IMAGE_IMPORT_DESCRIPTOR结构表示一个被引入的模块。IMAGE_IMPORT_DESCRIPTOR结构的成员Name表示了模块的名称。从某个模块引入的所有函数由该模块IMAGE_IMPORT_DESCRIPTOR结构的成员OriginalFirstThunk和FirstThunk共同表示。

经过分析跨模块函数调用过程和进行实验验证,当变换引入表中模块和函数的排列顺序,并对原程序的机器码进行适当修正后,程序仍能够保持所有原功能正确运行。两种变换方法如下:

1)变换引入模块自身的排列顺序。

因为PE装载器在加载一个PE文件时,对引入表中各模块IMAGE_IMPORT_DESCRIPTOR结构的先后次序不敏感,且程序在执行过程中调用位于其他模块内的函数时,不再需要IMAGE_IMPORT_DESCRIPTOR结构的任何信息。所以直接改变引入表IMAGE_IMPORT_DESCRIPTOR结构数组中各元素的排列顺序即可,不需要对原程序的机器码进行修正。

2)变换模块引入函数的排列顺序。

模块内引入函数的排列顺序与IMAGE_IMPORT_DESCRIPTOR结构的成员OriginalFirstThunk和FirstThunk有关。OriginalFirstThunk和FirstThunk分别指向两个不同的IMAGE_THUNK_DATA结构数组,该数组以全0的IMAGE_THUNK_DATA结构结束。从一个模块引入了几个函数,IMAGE_THUNK_DATA结构数组就有几个元素,每一个IMAGE_THUNK_DATA结构表示了一个引入函数。通过IMAGE_THUNK_DATA结构可以直接或间接得到引入函数的序号和名称。当PE装载器成功加载一个PE文件后,会用引入函数的实际地址去替换由FirstThunk指向的IMAGE_THUNK_DATA结构数组相应元素的值。

另一方面,当编译器编译源代码时,跨模块调用的函数地址会从由FirstThunk指向的IMAGE_THUNK_DATA结构数组相应元素中去取。

因此,变换模块引入函数的顺序分为以下步骤:

1)判断OriginalFirstThunk是否为0。若是,直接根据需要变换FirstThunk指向的结构数组的元素顺序,并跳转到4)。

2)若OriginalFirstThunk不为0,直接根据需要变换OriginalFirstThunk指向的结构数组的元素顺序。

3)变换FirstThunk指向的结构数组的元素顺序,使其与OriginalFirstThunk指向的结构数组的元素顺序一致,即怎么变换OriginalFirstThunk指向的结构数组,就怎么变换FirstThunk指向的结构数组。

4)搜索PE文件代码节,对引用其他模块的函数地址作相应变换。

例如,Test.exe使用了模块Kernel32.dll,并从Kernel32.dll导入了函数GetProcessHeap和HeapFree。Test.exe的引入表状态如图2所示。

在Test.exe中调用函数GetProcessHeap的反汇编代码为:

程序前

CALL DWORD PTR DS:[Address1]

程序后

程序前

MOV Register, DWORD PTR DS:[Address1]

CALL Register

程序后

交换函数GetProcessHeap和HeapFree在IMAGE_THUNK_DATA结构数组中的顺序后,原来指向函数GetProcessHeap的地址Address1变为了指向函数HeapFree,而原来指向函数HeapFree的地址Address2变为了指向函数GetProcessHeap,所以应修正代码为:

程序前

CALL DWORD PTR DS:[Address2]

程序后

程序前

MOV Register, DWORD PTR DS:[Address2]

CALL Register

程序后

一个特殊情况是绑定引入技术[1,9]。判断源程序是否使用了绑定引入,可通过检测PE文件Optional Header里IMAGE_DATA_DIRECTORY结构数组中索引号为“11”的元素值是否为0,若是0,则没有使用绑定引入,否则在变换引入表结构后,需要利用“bind.exe”工具重新绑定引入表。命令格式为:“bindu 可执行文件全路径及文件名”。

图片

图2 Test.exe的引入表状态

┑1期 ┝飞宇等:一种变换PE文件引入表结构的软件水印

┆扑慊应用 ┑30卷

2 基于引入表结构的水印技术

2.1 引入表结构的水印表示方法

设PE文件共引入了N个不同模块,从第n(n∈[1,N],n∈Z)个模块共引入了Tn个不同函数。通过式(1)可以计算出引入表的排列方式总数C:

C=PNN×∏Nn=1PTnTn(1)

定义1 设有限数列a0,a1,…,an(n>0)中的元素互不相同,数列b0,b1,…,bn-k是数列a0,a1,…,an中去除k(k

V=∑n-1k=0[(n-k)!g(Bk)](2)

性质1 в墒列a0,a1,…,an不同排列方式计算而得的V值与[0,(n+1)!-1]中的整数一一对应。

证明 因为数列a0,a1,…,an共有(n+1)!种不同排列方式,所以其可表达的不同数值一共有(n+1)!个,设其可表达的整数数值所在区间为[0,(n+1)!-1]。

数列a0,a1,…,an中最大元素所在位置共有n+1种情况,其位置(下标)记为g(B0)(g(B0)∈[0,n])。将区间[0,(n+1)!-1]平均划分为n+1个互不交叉的子区间,分别为[0,n!-1]、[n!,2n!-1]、[2n!,3n!-1]、…、[n×n!,(n+1)n!-1],取其中第g(B0)个子区间[g(B0)×n!, (g(B0)+1)×n!-1]。

同理,当数组a0,a1,…,an中最大元素所在位置确定后,考虑将剩下元素按原顺序组成一个新的数列b0,b1,…,bn-1,其最大元素的位置记为g(B1),进一步将区间[g(B0)×n!, (g(B0)+1)×n!-1] 平均划分为n个互不交叉的子区间,取其中第g(B1)个子区间。该步骤一直进行到只剩一个元素。进行m(m>0)次区间平均划分后,数列a0,a1,…,an排列方式的表达数值所在的区间为:

[∑m-1k=0[(n-k)!g(Bk)],∑m-1k=0[(n-k)!g(Bk)]+[n-(m-1)]!-1]

特别的,当m=n时,数列b0,b1,…,bn-m只剩一个元素,不能再进行区间划分,此时区间上限和下限均为∑n-1k=0[(n-k)!g(Bk)],即V值。因为每次区间平均划分都是在原区间基础上进行的,且每次划分的区间连续无交叉,所以根据数列a0,a1,…,an不同排列方式划分的区间连续无交叉,即数列a0,a1,…,an不同排列方式所表达的V值均不相同。又因为初始区间范围为[0,(n+1)!-1],且数列a0,a1,…,an共有(n+1)!种不同排列方式,所以由数列a0,a1,…,an不同排列方式计算而得的V值与[0,(n+1)!-1]中的整数一一对应。

设M为引入模块的集合,Fn为第n个模块引入函数的集合,下面将建立引入表排列方式与水印的关系。

规则1 设PE文件引入了两个模块分别为mi、mj(i≠j,i, j∈[1,N],i, j∈Z,mi,mj∈M),逐一比较模块名各字符的ASCII码大小,若mi模块名的ASCII码比mj模块名的ASCII码小,则mimj。

规则2 设PE文件从第n个引入模块引入了两个函数分别为fni、 fnj(i≠j,i, j∈[1, Tn],i, j∈Z,fni, fnj∈Fn),若fni的函数序号小于fnj的函数序号,则fnifnj。

根据定义1、性质1、规则1和规则1,可将式(1)应用于PE文件引入表结构的排序,从而通过PE文件引入表结构来隐藏水印数值信息。

2.2 水印嵌入算法

设水印数值为W,PE文件共引入N个模块,从第n(n∈[1,N],n∈Z)个模块共引入Tn个函数。水印嵌入算法如下:

① 根据式(1)计算C;

② 确定整数R,使(W-R)∈[0,C-1],将R隐藏到密钥K中;

③ 计算m0=(W-R) mod N!,变换引入模块的顺序,使其V值为m0;

④ 初始化U(W-R)/N!(结果取整),n1;

⑤ 计算mn=U mod Tn!,变换第n个模块引入函数的顺序,使其V值为mn;

⑥ 若n=N,结束;否则UU/Tn!(结果取整),nn+1,跳转到⑤。

2.3 水印提取算法

设水印数值为W,密钥K中隐藏的整数为R,PE文件共引入了N个模块,从第n(n∈[1,N],n∈Z)个模块共引入了Tn个函数。水印提取算法如下:

①从密钥K中提取整数R,WR;

②根据式(2)计算引入模块的V值V0,WW+V0;

③初始化UN!,n1;

④根据式(2)计算第n个模块引入函数的V值Vn,WW+Vn×U;

⑤若n=N,结束;否则UU×Tn!,nn+1,跳转到④。オ

3 实验结果与分析

本文提出的水印算法对引入模块和引入函数顺序进行了全排列,其不同排列方式非常多,与基于资源结构的水印算法相比,容量(总排列数)如表1所示。

本文提出的基于引入表结构的水印容量远远大于基于资源结构的水印容量。另外,PE文件的缺省资源结构是有序的,利用改变资源结构嵌入水印会破坏其缺省的顺序,引起怀疑。而对于本文提出的变换PE文件引入表结构的水印,由于引入表结构原本就是无序的,因此其隐蔽性和鲁棒性更高。

实验采用“超大整数完全精度快速算法库(HugeCalc)”进行超大整数的运算,修正函数调用地址时使用了多模式匹配ACBM算法进行地址的搜索。对几种常见PE文件进行水印嵌入后,PE文件仍然能够被正常载入执行,实验数据如表2所示。

表格(有表名)

表1 引入表结构与资源结构的水印容量对比

PE文件基于引入表结构的に印容量(总排列数)基于资源结构的水び∪萘(总排列数) [8]

AcroRd32.exe>1012318B085B600B741

Explorer.exe>1093381B206B010

msPaint.exe>10187135B659B712

wordPad.exe>1020394B608B000

表格(有表名)

表2 常见PE文件的实验数据

PE文件水印容量(总排列数)水印嵌と牒氖/s修正地ぶ泛氖/s水印提と『氖/s

AcroRd32.exe>101230.0160.0010.002

Notepad.exe>102460.0220.0020.002

PhotoShop.exe>106490.0340.2000.006

Kernel32.dll>108460.0610.0200.006

从实验数据中可以看出,采用HugeCalc算法库和ACBM算法实现文章提出的水印方案,对于10的数百次方数量级的整数运算和代码段多地址搜索,耗时相当短。表明该水印方案除了具有水印容量大,隐蔽性和鲁棒性较强的优点,还有水印嵌入、提取效率高的优点,并完全实现了水印盲检测。

4 结语

软件水印是现代密码学、软件工程、算法设计、图论、程序设计等学科的交叉研究新领域。在Windows平台下,通常软件的载体为PE文件。文章对PE文件引入表结构特点与模块函数调用方式进行研究分析后,提出了在保证原程序所有功能正常运行的条件下,对引入表结构进行变换的方法,并利用排列组合原理,建立了引入表结构与水印信息的关系,实现了将软件水印嵌入到引入表结构的排列顺序中。由于该方法没有利用PE文件的冗余空间,而是将水印信息直接嵌入到PE文件引入表的结构上,具有较强的隐蔽性和鲁棒性。

参考文献:[1] 看雪学院. 软件加密技术内幕[M]. 北京: 电子工业出版社, 2004.

[2] PIETREK M. Peering inside the PE: A tour of the Win32 Portable executable file format[EB/OL].[2009-05-10]./enus/library/ms809762.aspx.

[3] 徐晓静. 基于PE文件的信息隐藏技术研究[D]. 长沙: 湖南大学, 2007.

[4] 陈刚, 李丽娟, 刘友继. 一种基于代码插入的PE文件水印方案[J]. 科学技术与工程, 2008, 8(14):3946-3949.

[5] 吴振强, 冯绍东, 马建峰. PE文件的信息隐藏方案与实现[J]. 计算机工程与应用,2005,41(27):148-150.

[6] 方旺盛, 邵利平, 张克俊. 基于PE文件格式的信息隐藏技术研究[J]. 微计算机信息,2006, 22(33):77-81.

[7] 徐晓静, 徐向阳, 梁海华,等. PE文件资源节的信息隐藏研究与方案实现[J]. 计算机应用,2007, 27(3):621-623.

[8] 徐晓静,徐向阳,梁海华. 基于PE文件资源结构的水印算法[J]. 计算机工程与设计,2007, 28(23):5802-5804.

[9] 看雪学院. 加密与解密――软件保护技术及完全解决方案[M]. 北京: 电子工业出版社, 2001.

上一篇:基于图像类推的遥感图像超分辨率技术 下一篇:基于相似关系粗糙集模型的数值属性约简算法