我在世界的巅峰吧 关注:34贴子:13,308

【考古】PE文件前考古和考古日记

取消只看楼主收藏回复



IP属地:广东1楼2022-05-05 06:31回复
    我要把这个写到有个人在,但他又看不懂的地方


    IP属地:广东2楼2022-05-05 06:31
    回复
      这样就好像有人陪我读书一样


      IP属地:广东3楼2022-05-05 06:31
      回复
        では
        DOS stub。
        翻译为dos 存根。
        在dos时代,windows是运行在dos上的,很有可能在dos系统上不小心运行了需要windows的程序(都是MZ开头)。为了避免这一情况发生的兼容,windows程序会在文件开头加一段名为DOS-stub的小程序。
        这一习俗沿用到现在windows上的所有可执行文件上。
        这个程序是合法的,可以把它单独切出来用


        IP属地:广东4楼2022-05-05 06:43
        回复

          以这个DOS游戏中的随便找的一个文件为例,用PEView查看:
          第二项,即0125十进制的293,最后一页里用了多少字节(Byte)
          第三项0082 ,十进制的130,一共有多少页
          第五项,01E0,十进制的480,是头部大小。
          那么,我们就可以计算出这个文件的大小:
          (130-1)*512+293=66341字节。那么我们开打开看看对不对!(其实写到这里我还没打开看过)
          答案是64.7 KB (66,341 字节)
          bingo!


          IP属地:广东5楼2022-05-05 06:52
          收起回复
            为了兼容PE格式,我们可以发现
            1.PE格式最开始的DOS头是合法的DOS头。但也不能说完全合法。
            用peview打开大部分文件,看他们的头,会观察到这页数都是3,最后一页用了144字节,也就是都是1168字节,但显然DOS stub并没有这么大。
            谷歌1168 dos stub,发现有人发现了,大部分连接器都在默认的DOS头里用了这个大小。
            并且如果你编写一个小于1168的win32程序,在dos里运行,它会拒绝,因为根本没有这么大的文件,证明你这个头是假的。对dos来说,大文件,读小部分进内存,无所谓,反正后面的用不上程序就执行到退出了,但小文件,却要读够1168.读不够就说明你不合法。自然无法执行。
            所以这是个矛盾点:
            为了兼容,后来的编译器都加了一段dos存根,以便在dos下能友好地提示:这个程序不能在dos下运行
            但它又不是完全合法!
            再查了一下,还是不知道为什么这个1168.
            作罢


            IP属地:广东6楼2022-05-05 07:48
            回复
              那么下一个议题是relocation table。
              dos头里的这玩意到底是咋用的呢?
              经过我艰苦卓越的搜索,目前我总结出来如下:
              这是链接器生成,给dos loader去重定位用的。作用是,如果我英文没错的话,首先载入程序后,找到这个表,给表里的每一个条目的第一项(段)加上程序开头在内存中的基指。再加上第二段(偏移),这是修改后的条目,然后根据在这些条目,作为地址,去找已经载入了内存中的程序中的WORD(也就是2字节……唔,大概是内存地址?),修改他们的地址(加上内存中的基址)。
              参考资料:
              一大大大大大堆。
              但比较有帮助的线索来自
              MS-DOS Version 4.0 Programmer's Reference

              《Linker and Loader》(《链接器和加载器》)
              查找的线索是先知道了这是linker生成给loader用的,然后再去找linker的原理的书和dos loader的资料。因为是读书笔记所以这不是教程而是随手写的.
              要找远古dos的资料真艰难啊。


              IP属地:广东7楼2022-05-05 07:58
              回复
                刚才我又一时兴起,搜了一下,关键词
                MS-DOS segment relocation table
                发现这篇文章 似乎!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!就是我找了很久的答案 就是relocation table到底是在什么场合用得上!
                https://stackoverflow.com/questions/61862626/dos-inserting-segment-addresses-at-runtime
                如果我没错的话就是这个!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!所以,这就是某山的力量


                IP属地:广东8楼2022-05-05 08:08
                回复
                  为了验证这个说法 写了如下汇编代码
                  assume cs:code
                  extra segment
                  db 97H
                  extra ends
                  extra1 segment
                  db 83H
                  extra1 ends
                  extra2 segment
                  db 98H
                  extra2 ends
                  code segment
                  mov cx, extra
                  mov cx, extra1
                  mov cx, extra2
                  mov ax, 4c00h
                  int 21h
                  code ends
                  end
                  定义了3个段 并且还特意用了这3个段地址的指令
                  然后生成exe 打开————
                  果不其然 relocation table有3项!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!于是到这里终于彻底搞清楚这个表是怎么用的了!!!!!!!!!!!


                  IP属地:广东9楼2022-05-05 08:59
                  回复
                    为了搞清楚硬编码 怎么来的 搞清楚1168 我不死心
                    于是我想到了这是编译器加的存根 我又知道了微软的链接器有stub参数 那么GCC呢 别的编译器呢 这个存根也是编译器加的!
                    于是搜索
                    "This program cannot be run in DOS mode" "mingw32-gcc"
                    找到了文章
                    ==============================
                    如何使用MinGW创建微小的PE(Win32)可执行文件
                    pts 7 c winapi mingw portable-executable
                    我有以下C程序:
                    #include <windows.h>
                    void __cdecl mainCRTStartup() {
                    DWORD bw;
                    HANDLE hfile = GetStdHandle(STD_OUTPUT_HANDLE);
                    WriteFile(hfile, "Hello, World!\r\n", 15, &bw, 0);
                    ExitProcess(0); /* Needed for successful (0) exit. */
                    }
                    我使用以下命令行使用GCC 4.8.2编译它:
                    i686-w64-mingw32-gcc -s -Os -fno-ident -fno-stack-protector -fomit-frame-pointer \
                    -fno-unwind-tables -fno-asynchronous-unwind-tables -falign-functions=1 \
                    -mpreferred-stack-boundary=2 -falign-jumps=1 -falign-loops=1 -mconsole \
                    -nostdlib -nodefaultlibs -nostartfiles -o h.exe h.c -lkernel32
                    生成的.exe文件长度为2048字节.如何使用MinGW将其缩小,最好是1024字节,或者(甚至更好)最多512字节?
                    我更喜欢没有编写汇编代码的解决方案,但我也对组装解决方案感兴趣.
                    我试图-Wl,-N减少部分(段)的数量,但是在Wine中运行.exe时会导致段错误.
                    该文章认为,480个字节是可能的.它使用以下设置:
                    #pragma comment(linker, "/FILEALIGN:16")
                    #pragma comment(linker, "/ALIGN:16")// Merge sections
                    #pragma comment(linker, "/MERGE:.rdata=.data")
                    #pragma comment(linker, "/MERGE:.text=.data")
                    #pragma comment(linker, "/MERGE:.reloc=.data")
                    #pragma optimize("gsy", on)
                    不幸的是,这些#pragma不适用于MinGW GCC.有等价物吗?
                    在这里,我能够找到GCC标志 -Wl,--section-alignment,16,--file-alignment,16,将.exe大小降低到752字节..exe似乎适用于Wine.
                    通过修改链接脚本我能够合并.data和.rdata,并深入到736个字节.除了以上那些之外,我正在使用这些GCC标志:-Wl,--section-alignment,16,--file-alignment,16,-T,tinygccpe.scr.
                    我还在寻找相当于MinGW的/MERGE.
                    这个问题类似,但它不会尝试低于9000字节.
                    我也在寻找一个strip工具(stripMinGW中的命令不会进一步减小.exe大小),它可以删除DOS存根(在偏移量0x40和0x80之间,它包含This program cannot be run in DOS mode.,我们可以节省64个字节).此代码可以删除它,但它也会破坏.exe中的所有绝对偏移量.不幸的是ld,MinGW中的链接器无法删除DOS存根,它在文件中硬编码bfd/peXXigen.c,就在上面NT_SIGNATURE.
                    是否可以从.exe中删除更多标题,即加载程序不使用的标题?
                    =============================
                    gcc依赖bfd库---(参考自 bfd库使用-nm源码分析)
                    至于为什么他们要用这个作为硬编码
                    由于这个数字在WINNT里毫无用
                    那就只能追溯DOS时代的编译器开发者 问他们为什么了
                    这个话题暂时结案


                    IP属地:广东10楼2022-05-05 10:32
                    回复
                      Introduction
                      This page is intended to document the format of DOS executable fileswhich have a filename extension of .EXE. Note that otherformats (e.g. .COM) are not covered.
                      This information is necessary for anyone who might wish to write programswhich process such files, including those who are writing bootstraps andprogram loaders.
                      Note that this only covers the 16 bit executable files used by DOS,and not those used by other systems such as Windows and OS/2, even thoughthey also have a filename extension of .EXE.


                      IP属地:广东12楼2022-05-06 01:51
                      回复
                        楼上的网页
                        [Eternal://3i9J3pG5MaaTZuNA10HHm7ifS/6Af3RgTUfiyrP5BvArevmENsYs4ZKfoWgzek4ffpOd39mFA3aRTmVmok4guk6TaEmVjiSB0jfftiNslld7wv2qSK+t84/ohRdbTFg0BAN7H2ecByPO+wMCVnnihfptVCWXL8tgFqnq8JWCC1AD0ricRLa/RzEZLlMZBJTt8No5kEEu5+569liNqITOKGFFOwOUC+MfNWWRsJn0vQwf1/KKbeE68muer9xM1HBwLW9Niup5C8Zs1gEMZQu0SU01/xRPxPrPJSWxr9qc+cA=|078462e21907704741e50f096b3f2740|16517742747,16517728835,26862]


                        IP属地:广东13楼2022-05-06 02:11
                        回复
                          重定位举例
                          例如操作数B8 0000 位置是在第二行(01H) 操作码位置是01H
                          第一行是代码段 段地址0000(刚好)
                          那么这个操作数00 00是一个段地址
                          那么linker就会给出一个重定位条目 01H:01H
                          分配给这个程序的内存SA(起始地址)是049E,DS也是指向这里
                          那么loader首先根据SA+10H(PSP)=04AE算出程序开头
                          然后根据这个重定位表找到这个指令B8 0000(MOV AX, SEGMENT),把操作码(段地址)加04AE。
                          然后内存中的指令就变成了B8 AE04(小端)


                          IP属地:广东14楼2022-05-06 09:00
                          回复
                            考古:
                            追溯了各WINDOWS远古版本,例如win1,winnt3.1,发现大部分exe的dos stub是不合法的(dos header的大小值为虚设)。就是跟前面说的统一。
                            那么我很好奇:在真正的MS-DOS(而不是DOSBOX)中,如果真的大小不合法的话,会怎么处理?
                            实际比较大,会只读小部分?比声称的小,会拒绝载入(如so上某人所言)么?
                            此实验需要真的装一个MS-DOS,我目前敬谢不敏,但我一定要把他挂在苹果树上


                            IP属地:广东15楼2022-05-06 09:03
                            回复
                              实验data segment
                              dw 2h
                              data ends
                              code segment
                              dw 123h
                              ;start:
                              mov ax, 4c00h
                              int 21h
                              code ends
                              ;end start
                              end
                              结论:
                              没有assume cs 没有start 不报错
                              有start 报错 no or unreachable cs


                              IP属地:广东16楼2022-05-06 19:39
                              回复