WIN32汇编语言教程:第17章 PE文件 · 17.3 导出表(2)

4. 从函数名称查找入口地址

如果已知函数的名称,如何得到函数的入口地址呢?与使用序号来获取入口地址相比,这个过程要相对复杂一点:

(1)最初的步骤是一样的,那就是首先得到导出表的地址。

(2)从导出表的NumberOfNames字段得到已命名函数的总数,并以这个数字作为循环的次数来构造一个循环。

(3)从AddressOfNames字段指向的函数名称地址表的第一项开始,在循环中将每一项定义的函数名与要查找的函数名相比较,如果没有任何一个函数名是符合的,表示文件中没有指定名称的函数。

(4)如果某一项定义的函数名与要查找的函数名符合,那么记下这个函数名在字符串地址表中的索引值,然后在AddressOfNameOrdinals 指向的数组中以同样的索引值取出数组项的值,暂且假定这个值为x。

(5)最后,以x值作为索引值,在AddressOfFunctions 字段指向的函数入口地址表中获取的RVA就是函数的入口地址。

17.3.2 查看PE文件导出表举例

有一个查看PE文件导出表的例子,例子的界面处理源代码同样沿用前面使用的Main.asm和Main.rc文件,只是用来处理PE文件内容的_ProcessPeFile.asm文件有所不同,下面列出的就是这个文件的内容,如果读者需要完整的源代码,可以查看本书所附光盘的Chapter17\Export目录。

                 .const
 
szMsg          db     '文件名: %s',0dh,0ah
                 db    '--------------------------------------',0dh,0ah
                   db     '导出表所处的节:%s',0dh,0ah
                  db    '--------------------------------------',0dh,0ah
                   db     '原始文件名         %s',0dh,0ah
                  db    'nBase              %08X',0dh,0ah
                  db    'NumberOfFunctions  %08X',0dh,0ah
                  db    'NumberOfNames      %08X',0dh,0ah
                  db    'AddressOfFunctions %08X',0dh,0ah
                  db    'AddressOfNames     %08X',0dh,0ah
                  db    'AddressOfNameOrd   %08X',0dh,0ah
                 db    '--------------------------------------',0dh,0ah
                   db     '导出序号 虚拟地址 导出函数名称',0dh,0ah
                  db    '------------------------------------',0dh,0ah,0
szMsgName db      '%08X %08X %s',0dh,0ah,0
szExportByOrd  db     '(按照序号导出)',0
szErrNoExport  db     '这个文件中没有导出函数!',0
 
                  .code
include       _RvaToFileOffset.asm
;####################################################################
_ProcessPeFile proc      _lpFile,_lpPeHead,_dwSize
                  local  @szBuffer[1024]:byte,@szSectionName[16]:byte
                  local  @dwIndex,@lpAddressOfNames,@lpAddressOfNameOrdinals
 
                  pushad
                  mov    esi,_lpPeHead
                 assume esi:ptr IMAGE_NT_HEADERS
;********************************************************************
; 从数据目录中获取导出表的位置
;********************************************************************
                  mov    eax,[esi].OptionalHeader.DataDirectory.VirtualAddress
                  .if    ! eax
                         invoke MessageBox,hWinMain,\
                                addr szErrNoExport,NULL,MB_OK
                        jmp    _Ret
                  .endif
                  invoke _RVAToOffset,_lpFile,eax
                  add    eax,_lpFile
                  mov    edi,eax
;********************************************************************
; 显示一些常用的信息
;********************************************************************
                  assume edi:ptr IMAGE_EXPORT_DIRECTORY
                  invoke _RVAToOffset,_lpFile,[edi].nName
                 add    eax,_lpFile
                  mov    ecx,eax
                  invoke _GetRVASection,_lpFile,[edi].nName
                  invoke wsprintf,addr @szBuffer,addr szMsg,\
                          addr szFileName,eax,ecx,[edi].nBase,\
                         [edi].NumberOfFunctions,[edi].NumberOfNames,\
                        [edi].AddressOfFunctions,[edi].AddressOfNames,\
                         [edi].AddressOfNameOrdinals
                  invoke SetWindowText,hWinEdit,addr @szBuffer
;********************************************************************
                  invoke _RVAToOffset,_lpFile,[edi].AddressOfNames
                  add    eax,_lpFile
                  mov    @lpAddressOfNames,eax
                  invoke _RVAToOffset,_lpFile,[edi].AddressOfNameOrdinals
                  add    eax,_lpFile
                  mov    @lpAddressOfNameOrdinals,eax
                  invoke _RVAToOffset,_lpFile,[edi].AddressOfFunctions
                  add    eax,_lpFile
                   mov    esi,eax    ;esi --> 函数地址表
;********************************************************************
; 循环显示导出函数的信息
;********************************************************************
                  mov    ecx,[edi].NumberOfFunctions
                  mov    @dwIndex,0
                  @@:
                          pushad
;********************************************************************
; 在按名称导出的索引表中
;********************************************************************
                          mov    eax,@dwIndex
                          push      edi
                          mov    ecx,[edi].NumberOfNames
                          cld
                          mov    edi,@lpAddressOfNameOrdinals
                          repnz  scasw
                           .if    ZERO?  ;找到函数名称
                                 sub    edi,@lpAddressOfNameOrdinals
                                  sub    edi,2
                                  shl    edi,1
                                  add    edi,@lpAddressOfNames
                                 invoke _RVAToOffset,_lpFile,dword ptr [edi]
                                add    eax,_lpFile
                          .else
                                 mov    eax,offset szExportByOrd
                          .endif
                          pop    edi
;********************************************************************
; 序号 --> ecx
;********************************************************************
                         mov    ecx,@dwIndex
                          add    ecx,[edi].nBase
                         invoke wsprintf,addr @szBuffer,addr szMsgName,\
                                 ecx,dword ptr [esi],eax
                          invoke _AppendInfo,addr @szBuffer
                         popad
                         add    esi,4
                         inc    @dwIndex
                  loop      @B
_Ret:
                 assume esi:nothing
                  assume edi:nothing
                  popad
                  ret
 
_ProcessPeFile endp
;####################################################################

上页:第17章 PE文件 · 17.3 导出表(1) 下页:第17章 PE文件 · 17.3 导出表(3)

第17章 PE文件

版权所有 © 云南伯恩科技 证书:粤ICP备09170368号