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

  • 标 题: 答复
  • 作 者:dwing
  • 时 间:2005-04-11 18:52

给出个另类方法:
mod=LoadLibrary("xxx.dll"); //载入文件
func=(char*)mod+offset;     //找到函数入口地址
__asm push param2           //参数2
__asm push param1           //参数1
__asm call func;            //直接硬调用
__asm mov ret,eax           //保存返回值

  • 标 题: 答复
  • 作 者:riijj
  • 时 间:2005-04-12 08:32

引用:
最初由 dwing 发布
给出个另类方法:
mod=LoadLibrary("xxx.dll"); //载入文件
func=(char*)mod+offset;     //找到函数入口地址
__asm push param2           //参数2
__asm push param1           //参数1
........ 



在 C 中呼叫地址,我通常用 function pointer

HINSTANCE mod;
int offset;
int (*func)( int, int );

...

mod = LoadLibrary( "xxx.dll" );
func = (void *)( (char*)mod + offset );

...

myvalue = func( 50, 100 );  //一般呼叫


如果呼叫 API 地址,便使用WINAPI 方式的 calling convention 
  int (WINAPI *MessageBoxPointer)( HWND, LPCTSTR, LPCTSTR, UNIT );

  • 标 题: 答复
  • 作 者:peaceclub
  • 时 间:2005-04-12 10:26

VB中用CallWindowProc API调用即可。
重定位是个问题。要不然把父程序的基址改掉。

  • 标 题: 答复
  • 作 者:peaceclub
  • 时 间:2005-04-12 11:30

引用:
最初由 peaceclub 发布
VB中用CallWindowProc API调用即可。
重定位是个问题。要不然把父程序的基址改掉。 


改父程序的基址不行.我把父程序的基址改成了800000,加载目标exe(基址400000)后,Handle不是400000,晕.
怎么解决呢?

  • 标 题: 答复
  • 作 者:oep1
  • 时 间:2005-04-13 12:40

自程序之中再套嵌自程序的时候,一般调用都发生错误,因为基地址变了,而EXE中的基地址还是原来的。

只有子程序中没有其他套嵌子程序,或者被套嵌的子程序寻址方式是动态(比如取此时的IP数进行变换),才可以正常运行,还有个前提是EXE自程序中不再存在对EXE全局变量的存取.........

我觉得用CREATE_SUSPENDED 形式的CreateProcess来建立进程,再调用进程中的子程序,或许效果好一点。