WIN32汇编语言教程:第17章 PE文件 · 17.3 导出表(2)
4. 从函数名称查找入口地址
如果已知函数的名称,如何得到函数的入口地址呢?与使用序号来获取入口地址相比,这个过程要相对复杂一点:
(1)最初的步骤是一样的,那就是首先得到导出表的地址。
(2)从导出表的NumberOfNames字段得到已命名函数的总数,并以这个数字作为循环的次数来构造一个循环。
(3)从AddressOfNames字段指向的函数名称地址表的第一项开始,在循环中将每一项定义的函数名与要查找的函数名相比较,如果没有任何一个函数名是符合的,表示文件中没有指定名称的函数。
(4)如果某一项定义的函数名与要查找的函数名符合,那么记下这个函数名在字符串地址表中的索引值,然后在AddressOfNameOrdinals 指向的数组中以同样的索引值取出数组项的值,暂且假定这个值为x。
(5)最后,以x值作为索引值,在AddressOfFunctions 字段指向的函数入口地址表中获取的RVA就是函数的入口地址。
有一个查看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文件
版权所有 © 云南伯恩科技 证书:粤ICP备09170368号