⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄

📁 兼容内核漫谈 适合想将Windows上的程序移植到其它平台上的朋友研究查看
💻
📖 第 1 页 / 共 2 页
字号:
    还要说明,IMAGE_OS2_HEADER并不如其名称所示那样仅仅是用于OS/2软件映像的,实际上也用于一些16位Windows软件的映像和DOS软件的映像。
    IMAGE_DOS_HEADER结构中的最后一个字段e_lfanew说明了扩充头部在文件中的位移,所以这一次把读/写指针移到这个位置上。
    读入扩充头部以后,首先就检查是否有“PE”格式的签名。如果是,并且头部是完整的,就根据头部中FileHeader.Characteristics字段的IMAGE_FILE_DLL标志位判定其为.exe映像还是DLL映像。此外,可能还要根据所读入头部提供的信息修正两个全局量res_start和res_end的数值,不过那与映像类型的识别是无关的。

    如果头部签名不是“PE”,那就可能是OS/2或其它Windows/DOS的可执行映像了,此类映像在扩充头部中的签名是“NE”。我们再往下看。

[code]        if (!memcmp( &ext_header.os2.ne_magic, "NE", 2 ))
        {
            /* This is a Windows executable (NE) header.  This can
             * mean either a 16-bit OS/2 or a 16-bit Windows or even a
             * DOS program (running under a DOS extender).  To decide
             * which, we'll have to read the NE header.
             */
            if (len >= sizeof(ext_header.os2))
            {
              switch ( ext_header.os2.ne_exetyp )
              {
              case 1:  return BINARY_OS216;  /* OS/2 */
              case 2:  return BINARY_WIN16;  /* Windows */
              case 3:  return BINARY_DOS;  /* European MS-DOS 4.x */
              case 4:  return BINARY_WIN16; /* Windows 386; FIXME: is this 32bit??? */
              case 5:  return BINARY_DOS;
                                            /* BOSS, Borland Operating System Services */
              /* other types, e.g. 0 is: "unknown" */
              default:
              return MODULE_Decide_OS2_OldWin(hfile, &header.mz, &ext_header.os2);
              }
            }
            /* Couldn't read header, so abort. */
            return BINARY_DOS;
        }

        /* Unknown extended header, but this file is nonetheless DOS-executable. */
        return BINARY_DOS;
    }

    return BINARY_UNKNOWN;
}[/code]

    显然,IMAGE_OS2_HEADER头部中的字段ne_exetyp进一步说明了具体的映像类型。从这里也可以看出,DOS/Windows与OS/2真的是你中有我、我中有你。除1-5以外,还有些类型码和头部特征是用于某些特别老的OS/2和Windows(版本3.0以前)目标映像的,那要进一步通过MODULE_Decide_OS2_OldWin()加以识别,这里就不赘述了,有兴趣的读者可以自己阅读和研究。
    最后,MODULE_GetBinaryType()的返回值就是目标映像的类型代码。
    有了这个函数,加上有关数据结构的定义,读者完全可以自己写个程序,打印出给定二进制映像文件的映像类型,并进一步打印出该映像的许多特性和参数。在Wine代码的tools/winedump目录下那些文件中有一些函数,包括dump_pe_header()、dump_le_header()、dump_ne_header()等等,就是用来打印出各种格式的映像头部。下面不加说明地列出其中dump_pe_header()的代码,供读者自己阅读,好处是可以从这些代码中看出各个头部(例如IMAGE_FILE_HEADER和IMAGE_OPTIONAL_HEADER)中许多字段的作用和意义:

[code]static void dump_pe_header(void)
{
    const char   *str;
    IMAGE_FILE_HEADER  *fileHeader;
    IMAGE_OPTIONAL_HEADER *optionalHeader;
    unsigned   i;

    printf("File Header\n");
    fileHeader = &PE_nt_headers->FileHeader;

    printf("  Machine:                      %04X (%s)\n",
    fileHeader->Machine, get_machine_str(fileHeader->Machine));
    printf("  Number of Sections:           %d\n", fileHeader->NumberOfSections);
    printf("  TimeDateStamp:                %08lX (%s) offset %lu\n",
    fileHeader->TimeDateStamp, get_time_str(fileHeader->TimeDateStamp),
    Offset(&(fileHeader->TimeDateStamp)));
    printf("  PointerToSymbolTable:         %08lX\n", fileHeader->PointerToSymbolTable);
    printf("  NumberOfSymbols:              %08lX\n", fileHeader->NumberOfSymbols);
    printf("  SizeOfOptionalHeader:         %04X\n", fileHeader->SizeOfOptionalHeader);
    printf("  Characteristics:              %04X\n", fileHeader->Characteristics);
#define X(f,s) if (fileHeader->Characteristics & f) printf("    %s\n", s)
    X(IMAGE_FILE_RELOCS_STRIPPED,  "RELOCS_STRIPPED");
    X(IMAGE_FILE_EXECUTABLE_IMAGE,  "EXECUTABLE_IMAGE");
    X(IMAGE_FILE_LINE_NUMS_STRIPPED,  "LINE_NUMS_STRIPPED");
    X(IMAGE_FILE_LOCAL_SYMS_STRIPPED,  "LOCAL_SYMS_STRIPPED");
    X(IMAGE_FILE_16BIT_MACHINE,  "16BIT_MACHINE");
    X(IMAGE_FILE_BYTES_REVERSED_LO,  "BYTES_REVERSED_LO");
    X(IMAGE_FILE_32BIT_MACHINE,  "32BIT_MACHINE");
    X(IMAGE_FILE_DEBUG_STRIPPED,  "DEBUG_STRIPPED");
    X(IMAGE_FILE_SYSTEM,   "SYSTEM");
    X(IMAGE_FILE_DLL,    "DLL");
    X(IMAGE_FILE_BYTES_REVERSED_HI,  "BYTES_REVERSED_HI");
#undef X
    printf("\n");

    /* hope we have the right size */
    printf("Optional Header\n");
    optionalHeader = &PE_nt_headers->OptionalHeader;
    printf("  Magic                              0x%-4X         %u\n",
    optionalHeader->Magic, optionalHeader->Magic);
    printf("  linker version                     %u.%02u\n",
    optionalHeader->MajorLinkerVersion, optionalHeader->MinorLinkerVersion);
    printf("  size of code                       0x%-8lx     %lu\n",
    optionalHeader->SizeOfCode, optionalHeader->SizeOfCode);
    printf("  size of initialized data           0x%-8lx     %lu\n",
    optionalHeader->SizeOfInitializedData, optionalHeader->SizeOfInitializedData);
    printf("  size of uninitialized data         0x%-8lx     %lu\n",
    optionalHeader->SizeOfUninitializedData, optionalHeader->SizeOfUninitializedData);
    printf("  entrypoint RVA                     0x%-8lx     %lu\n",
    optionalHeader->AddressOfEntryPoint, optionalHeader->AddressOfEntryPoint);
    printf("  base of code                       0x%-8lx     %lu\n",
    optionalHeader->BaseOfCode, optionalHeader->BaseOfCode);
    printf("  base of data                       0x%-8lX     %lu\n",
    optionalHeader->BaseOfData, optionalHeader->BaseOfData);
    printf("  image base                         0x%-8lX     %lu\n",
    optionalHeader->ImageBase, optionalHeader->ImageBase);
    printf("  section align                      0x%-8lx     %lu\n",
    optionalHeader->SectionAlignment, optionalHeader->SectionAlignment);
    printf("  file align                         0x%-8lx     %lu\n",
    optionalHeader->FileAlignment, optionalHeader->FileAlignment);
    printf("  required OS version                %u.%02u\n",
    optionalHeader->MajorOperatingSystemVersion,
           optionalHeader->MinorOperatingSystemVersion);
    printf("  image version                      %u.%02u\n",
    optionalHeader->MajorImageVersion, optionalHeader->MinorImageVersion);
    printf("  subsystem version                  %u.%02u\n",
    optionalHeader->MajorSubsystemVersion, optionalHeader->MinorSubsystemVersion);
    printf("  Win32 Version       0x%lX\n", optionalHeader->Win32VersionValue);
    printf("  size of image        0x%-8lx     %lu\n",
    optionalHeader->SizeOfImage, optionalHeader->SizeOfImage);
    printf("  size of headers       0x%-8lx     %lu\n",
    optionalHeader->SizeOfHeaders, optionalHeader->SizeOfHeaders);
    printf("  checksum           0x%lX\n", optionalHeader->CheckSum);
    switch (optionalHeader->Subsystem)
    {
    default:
    case IMAGE_SUBSYSTEM_UNKNOWN:   str = "Unknown";  break;
    case IMAGE_SUBSYSTEM_NATIVE:    str = "Native";  break;
    case IMAGE_SUBSYSTEM_WINDOWS_GUI:  str = "Windows GUI";  break;
    case IMAGE_SUBSYSTEM_WINDOWS_CUI:  str = "Windows CUI";  break;
    case IMAGE_SUBSYSTEM_OS2_CUI:    str = "OS/2 CUI";  break;
    case IMAGE_SUBSYSTEM_POSIX_CUI:   str = "Posix CUI";  break;
    }
    printf("  Subsystem      0x%X (%s)\n", optionalHeader->Subsystem, str);
    printf("  DLL flags       0x%X\n", optionalHeader->DllCharacteristics);
    printf("  stack reserve size    0x%-8lx     %lu\n",
    optionalHeader->SizeOfStackReserve, optionalHeader->SizeOfStackReserve);
    printf("  stack commit size    0x%-8lx     %lu\n",
    optionalHeader->SizeOfStackCommit, optionalHeader->SizeOfStackCommit);
    printf("  heap reserve size     0x%-8lx     %lu\n",
    optionalHeader->SizeOfHeapReserve, optionalHeader->SizeOfHeapReserve);
    printf("  heap commit size     0x%-8lx     %lu\n",
    optionalHeader->SizeOfHeapCommit, optionalHeader->SizeOfHeapCommit);
    printf("  loader flags         0x%lX\n", optionalHeader->LoaderFlags);
    printf("  RVAs & sizes       0x%lX\n", optionalHeader->NumberOfRvaAndSizes);
    printf("\n");

    printf("Data Directory\n");
    printf("%ld\n",
          optionalHeader->NumberOfRvaAndSizes* sizeof(IMAGE_DATA_DIRECTORY));

    for (i = 0;  i < optionalHeader->NumberOfRvaAndSizes && i < 16;  i++)
    {
printf("  %-12s  rva: 0x%-8lX  size: %8lu\n",
         DirectoryNames[i],
         optionalHeader->DataDirectory[i].VirtualAddress,
         optionalHeader->DataDirectory[i].Size);
    }
    printf("\n");
}[/code]

    代码中的PE_nt_headers是个PE格式头部数据结构指针,头部的内容在此以前已经读入。Rva是“Relative Virtual Address”的缩写,表示一个符号相对于其所在浮动代码块起点的虚拟地址。
    现在,读者应该已经大体上明白了如何识别目标映像,以及如何解释映像头部许多字段和标志位的作用和意义,为进一步考察目标映像的装入和启动打下了基础。在以后的漫谈中,我将讲述Wine怎样装入和启动目标映像,到那时这些字段的作用和意义就更清楚了。
    Wine的上述代码都是在用户空间执行的,但是若要将这些代码移到内核中也很容易。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -