本类共有 70 篇文章,今日更新 0

“PE文件格式”1.9版 完整译文(附注释)(二)

[ 来源:http://www.91now.com/down/ | 作者: | 时间:2007-5-18 18:30:21 | 浏览: 人次 ]


原著:Bernd. Luevelsmeyer                               
翻译:ah007 

[注意:本译文的所有大小标题序号都是译者添加,以方便大家阅读。圆圈内的数字是注释的编号,其中注释②译自微软的《PECOFF规范》,其它译自网络。----译者] 

十一、Bug报告(Bug reports)  
----------------------------  
Bug报告(或其他建议)请发送至:bernd.luevelsmeyer@iplan.heitec.net  



十二、版本(Versions)  
----------------------  
你可在文件的顶部找到当前的版本号。  

1998-04-06  
  第一次公开发表  

1998-07-29  
  将映象文件版本和子系统版本中错误的“byte”改为“word”  
  更正“栈只限于1 MB”的错误(实际上没有上限)  
  更正一些输入错误  

1999-03-15  
  更正输出目录的描述,原来非常不全  
  调整输入目录的描述,原来讲的不清  
  更正输入错误并为其它节改了一些词句  
    


十三、参考文献(Literature)  
----------------------------  
[1]  
"Peering Inside the PE: A Tour of the Win32 Portable Executable File  
Format" (M. Pietrek), in: Microsoft Systems Journal 3/1994  

[2]  
"Why to Use _declspec(dllimport) & _declspec(dllexport) In Code", MS  
Knowledge Base Q132044  

[3]《Windows 问与答》  
"Windows Q&A" (M. Pietrek), in: Microsoft Systems Journal 8/1995  

[4]《编写多语言资源》  
"Writing Multiple-Language Resources", MS Knowledge Base Q89866  

[5]  
"The Portable Executable File Format from Top to Bottom" (Randy Kath),  
in: Microsoft Developer Network  

[6]《Windows下TIS格式规范1.0版》  
Tool Interface Standard (TIS) Formats Specification for Windows Version  
1.0 (Intel Order Number 241597, Intel Corporation 1993)  




附录(Appendix: hello world):  
-------------------------------  
在这个附录中我将给大家展示一下怎样手工建立一个程序。因为我不会DEC Alpha的,本例将使用Intel汇编语言。  

本程序相当于  

    #include   
    int main(void)  
    {  
        puts(hello,world);  
        return 0;  
    }  

首先,我使用Win32函数来翻译它以取代C运行时库:   

    #define STD_OUTPUT_HANDLE -11UL  
    #define hello "hello, world\n"  

    __declspec(dllimport) unsigned long __stdcall  
    GetStdHandle(unsigned long hdl);  

    __declspec(dllimport) unsigned long __stdcall  
    WriteConsoleA(unsigned long hConsoleOutput,  
                    const void *buffer,  
                    unsigned long chrs,  
                    unsigned long *written,  
                    unsigned long unused  
                    );  

    static unsigned long written;  

    void startup(void)  
    {  
        WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE),hello,sizeof(hello)-1,&written,0);  
        return;  
    }  

现在我将笨拙的将它汇编出来:  
    startup:  
                ; WriteConsole()的参数, 反向的  
    6A 00                     push      0x00000000  
    68 ?? ?? ?? ??            push      offset _written  
    6A 0D                     push      0x0000000d  
    68 ?? ?? ?? ??            push      offset hello  
                ; GetStdHandle()的参数  
    6A F5                     push      0xfffffff5  
    2E FF 15 ?? ?? ?? ??      call      dword ptr cs:__imp__GetStdHandle@4  
                ; 结果是WriteConsole()的参数  
    50                        push      eax  
    2E FF 15 ?? ?? ?? ??      call      dword ptr cs:__imp__WriteConsoleA@20  
    C3                        ret         

    hello:  
    68 65 6C 6C 6F 2C 20 77 6F 72 6C 64 0A   "hello, world\n"  
    _written:  
    00 00 00 00  

以上就是编译的部分。任何人都能做到这点。从现在起让我们扮演起链接器的角色,这会非常有趣 :-)  

我需要先找出函数WriteConsoleA()和GetStdHandle()。碰巧它们都在“kernel32.dll”中。(这是“输入库”部分。)  

现在我开始做可执行文件。问号代表待定的值;它们将在以后被修正。  

首先是DOS-根,开始于0x0,有0x40字节长:  
    00 | 4d 5a 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
    10 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
    20 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
    30 | 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00  
正如你所见到的,这不是真正的MS-DOS程序。它只是一个开始部分有“MZ”签名的头和紧跟在头后面的e_lfanew指针,没有任何代码。这是因为它并非打算运行于MS-DOS之上;它之所以在这里只是因为规范的需要。  

然后是PE签名,开始于0x40,有0x4字节长:  
        50 45 00 00  

现在到了文件头,开始于0x44,有0x14字节长:  
    Machine                     4c 01       ; i386  
    NumberOfSections            02 00       ; 代码段和数据段  
    TimeDateStamp               00 00 00 00 ; 谁管它?  
    PointerToSymbolTable        00 00 00 00 ; 未用  
    NumberOfSymbols             00 00 00 00 ; 未用  
    Si

[1] [2] [3] [4] [5] [6] [7] [8] [9] 下一页

广告位