修改PE中的函数为导出函数
作者:admin 日期:2009-10-04
1、前言:为什么要这么做
很多时候,我们发现一个PE(EXE或DLL)中非常有用且功能独立的函数(call xxxxxxxx),并且已经知道了这个函数的各个入口参数的类型和具体含义,我们想在其他的软件中使用这个函数。于是,我想到了将这个PE中的函数改成一个导出函数,这样,我们就可以在任何软件中通过“LoadLibrary("ThisPE.EXE")”等API来使用这个函数了。
2、技术基础:已经了解PE结构
3、分类:
(1)有导出表的DLL和EXE文件--非常简单
对于这类PE文件,要简单的多,因为只要修改一下PE中的Export,增加上一个导出函数,并把这个导出函数的入口指向我们要导出的call的调用地址(RVA格式)就可以了。甚至可以更简单的处理:找个不用的导出函数,改一下入口就可以了。
(2)没有导出表的EXE文件--稍微复杂
因为大部分EXE文件没有导出表,所以我们必须要给它增加一个导出表。其实也很简单,给EXE增加一个节,并在这个节中按照导出表的格式构造一个导出函数,并将这个函数入口指向我们要导出的call的调用地址的RVA,并在PE头中指出其位置和大小。
4、举例说明:
test.exe:ImageBase=0x00400000
发现test.exe 的 0x00408050 处为call 0x0040A012 的 0x0040A012是我们要导出的函数,我们将它导出为MyFunction函数。
(1)给test.exe增加一个节:RVA=0x28000,size=0x1000
(2)构造导出表:
My_Export_Table dd 0 ;Characteristics
My_TimeDateStamp dd 0 ;TimeDateStamp
dw 0 ;MajorVersion
dw 0 ;MinorVersion
My_nName dd My_DLL_nName-ImageBase ;nName
dd 1 ;nBase
dd 1 ;NumberOfFunctions
dd 1 ;NumberOfNames
My_AddressOfFunctions dd 0x0040A012-ImageBase ;AddressOfFunctions
My_AddressOfNames dd My_Fun_Name-ImageBase ;AddressOfNames
My_AddressOfNameOrdinals dd 0 ;AddressOfNameOrdinals
---------------------------------------------------------------------
My_Fun_Name db 'MyFunction',0
My_DLL_nName db 'test.exe',0
(3)LoadPe修改PE头,将导出表地址填入0x28000,大小填入0x1000,保存。
Spirng.W/2005.3.14
PS:
没有导出表的EXE文件 情况下,没必要添加新节,可以找一块剩余空间代替。
如果单独使用其中的某个call,有时候加载需要第3方DLL才可以加载。举个例子,人家写了一个程序A.exe,附加有个B.dll,我仅仅想用到A.exe里面的一个函数,不想把B.dll牵扯进来,但是如果没有B.dll,加载A.exe的时候无法加载,可能会提示缺少B.dll,这时候可以把A.exe的import表信息请除掉。就是不引入B.dll信息。如果A.exe也是一个DLL,那么有时候还需要把A.exe(这时候是A.dll)的入口处直接ret,防止入口处执行B.dll里面的函数。
很多时候,我们发现一个PE(EXE或DLL)中非常有用且功能独立的函数(call xxxxxxxx),并且已经知道了这个函数的各个入口参数的类型和具体含义,我们想在其他的软件中使用这个函数。于是,我想到了将这个PE中的函数改成一个导出函数,这样,我们就可以在任何软件中通过“LoadLibrary("ThisPE.EXE")”等API来使用这个函数了。
2、技术基础:已经了解PE结构
3、分类:
(1)有导出表的DLL和EXE文件--非常简单
对于这类PE文件,要简单的多,因为只要修改一下PE中的Export,增加上一个导出函数,并把这个导出函数的入口指向我们要导出的call的调用地址(RVA格式)就可以了。甚至可以更简单的处理:找个不用的导出函数,改一下入口就可以了。
(2)没有导出表的EXE文件--稍微复杂
因为大部分EXE文件没有导出表,所以我们必须要给它增加一个导出表。其实也很简单,给EXE增加一个节,并在这个节中按照导出表的格式构造一个导出函数,并将这个函数入口指向我们要导出的call的调用地址的RVA,并在PE头中指出其位置和大小。
4、举例说明:
test.exe:ImageBase=0x00400000
发现test.exe 的 0x00408050 处为call 0x0040A012 的 0x0040A012是我们要导出的函数,我们将它导出为MyFunction函数。
(1)给test.exe增加一个节:RVA=0x28000,size=0x1000
(2)构造导出表:
My_Export_Table dd 0 ;Characteristics
My_TimeDateStamp dd 0 ;TimeDateStamp
dw 0 ;MajorVersion
dw 0 ;MinorVersion
My_nName dd My_DLL_nName-ImageBase ;nName
dd 1 ;nBase
dd 1 ;NumberOfFunctions
dd 1 ;NumberOfNames
My_AddressOfFunctions dd 0x0040A012-ImageBase ;AddressOfFunctions
My_AddressOfNames dd My_Fun_Name-ImageBase ;AddressOfNames
My_AddressOfNameOrdinals dd 0 ;AddressOfNameOrdinals
---------------------------------------------------------------------
My_Fun_Name db 'MyFunction',0
My_DLL_nName db 'test.exe',0
(3)LoadPe修改PE头,将导出表地址填入0x28000,大小填入0x1000,保存。
Spirng.W/2005.3.14
PS:
没有导出表的EXE文件 情况下,没必要添加新节,可以找一块剩余空间代替。
如果单独使用其中的某个call,有时候加载需要第3方DLL才可以加载。举个例子,人家写了一个程序A.exe,附加有个B.dll,我仅仅想用到A.exe里面的一个函数,不想把B.dll牵扯进来,但是如果没有B.dll,加载A.exe的时候无法加载,可能会提示缺少B.dll,这时候可以把A.exe的import表信息请除掉。就是不引入B.dll信息。如果A.exe也是一个DLL,那么有时候还需要把A.exe(这时候是A.dll)的入口处直接ret,防止入口处执行B.dll里面的函数。
评论: 0 | 查看次数: 8261