12

将 PE 二进制文件转换为 ELF 二进制文件的最佳工具是什么?

以下是这个问题的简要动机:

  1. 假设我有一个简单的 C 程序。
  2. 我使用 gcc for linux 编译它(这给出了 ELF),并使用 'i586-mingw32msvc-gcc' for Windows(这给出了一个 PE 二进制文件)。
  3. 我想分析这两个二进制文件的相似之处,使用 Bitblaze 的静态分析工具 - vine( http://bitblaze.cs.berkeley.edu/vine.html )
  4. 现在 vine 对 PE 二进制文件没有很好的支持,所以我想转换 PE->ELF,然后继续我的比较/分析。

由于所有分析都必须在 Linux 上运行,我更喜欢在 Linux 上运行的实用程序/工具。

谢谢

4

3 回答 3

13

可以将 EXE 重新构建为 ELF 二进制文件,但由于缺少操作系统,生成的二进制文件在加载后很快就会出现段错误。

这是一种方法。

概括

  1. 转储 EXE 文件的节标题。
  2. 从 EXE 中提取原始部分数据。
  3. 将原始节数据封装在 GNU 链接描述文件片段中。
  4. 编写链接描述文件以构建 ELF 二进制文件,包括上一步中的那些脚本。
  5. 使用链接描述文件运行ld以生成 ELF 文件。
  6. 运行新程序,并观察它的段错误,因为它没有在 Windows 上运行(它尝试调用导入地址表中的函数,该表不存在)。

详细示例

  1. 转储 EXE 文件的节标题。我正在使用objdump交叉mingw编译器包来执行此操作。

    $ i686-pc-mingw32-objdump -h trek.exe
    
    trek.exe:文件格式pei-i386
    
    部分:
    Idx 名称大小 VMA LMA 文件关闭 Algn
      0 自动 00172600 00401000 00401000 00000400 2**2
                      内容、分配、加载、只读、代码
      1.idata 00001400 00574000 00574000 00172a00 2**2
                      内容、分配、加载、数据
      2 D组 0002b600 00576000 00576000 00173e00 2**2
                      内容、分配、加载、数据
      3 .bss 000e7800 005a2000 005a2000 00000000 2**2
                      分配
      4.reloc 00013000 0068a000 0068a000 0019f400 2**2
                      内容、分配、加载、只读、数据
      5 .rsrc 00000a00 0069d000 0069d000 001b2400 2**2
                      内容、分配、加载、只读、数据
    
  2. 使用dd(或十六进制编辑器)从 EXE 中提取原始部分数据。在这里,我将复制代码和数据部分(在本例中名为 AUTO 和 DGROUP)。不过,您可能想要复制其他部分。

    $ dd bs=512 skip=2 count=2963 if=trek.exe of=code.bin
    $ dd bs=512 skip=2975 count=347 if=trek.exe of=data.bin
    

    请注意,我已将文件偏移量和节大小从十六进制转换为十进制以用作skip和字节)。countdd

  3. 将原始节数据封装在 GNU ld 链接器脚本片段中(使用 BYTE 指令)。这将用于填充这些部分。

    猫码.bin | hexdump -v -e '"BYTE(0x" 1/1 "%02X" ")\n"' >code.ld
    猫数据.bin | hexdump -v -e '"BYTE(0x" 1/1 "%02X" ")\n"' >data.ld
    
  4. 编写链接描述文件以构建 ELF 二进制文件,包括上一步中的那些脚本。注意我还为未初始化的数据 (.bss) 部分留出了空间。

    开始 = 0x516DE8;
    进入(开始)
    OUTPUT_FORMAT("elf32-i386")
    部分{
        .text 0x401000 :
        {
            包括“code.ld”;
        }
        .data 0x576000:
        {
            包括“data.ld”;
        }
        .bss 0x5A2000:
        {
            . = 。+ 0x0E7800;
        }
    }
    
  5. 使用 GNU 运行链接ld描述文件以生成 ELF 文件。注意我必须使用仿真模式elf_i386,因为我使用的是 64 位 Linux,否则会产生 64 位 ELF。

    $ ld -o elf_trek -m elf_i386 elf_trek.ld
    ld:警告:elf_trek.ld 包含输出部分;你忘了-T吗?
    $文件elf_trek
    elf_trek:ELF 32 位 LSB 可执行文件,Intel 80386,版本 1 (SYSV),
              静态链接,未剥离
    
  6. 运行新程序,并观察它的段错误,因为它没有在 Windows 上运行。

    $ gdb elf_trek
    (gdb) 运行
    启动程序:/home/quasar/src/games/botf/elf_trek
    
    程序收到信号 SIGSEGV,分段错误。
    0x0051d8e6 在?? ()
    (gdb) BT
    \#0 0x0051d8e6 在?? ()
    \#1 0x00000000 在 ?? ()
    (gdb) x/i $eip
    => 0x51d8e6: 子 (%edx),%eax
    (gdb) 退出
    

    该位置的 IDA Pro 输出:

    0051D8DB ; size_t 堆栈可用(无效)
    0051D8DB proc stackavail 附近
    0051D8DB 推送 edx
    0051D8DC 通话 [ds:off_5A0588]
    0051D8E2 mov edx, eax
    0051D8E4 mov eax, esp
    0051D8E6 子 eax,[edx]
    0051D8E8 流行 edx
    0051D8E9 重新
    0051D8E9 endp stackavail
    

考虑到 Wine 项目,将二进制文件移植到 Linux 是没有意义的。对于像 OP 这样的情况,它可能是合适的。

于 2014-11-12T00:58:05.017 回答
5

我找到了一种更简单的方法来做到这一点。使用剥离命令。

例子

strip -O elf32-i386 -o myprogram.elf myprogram.exe

让它以这种-O elf32-i386格式写出文件。

查看支持的格式运行

strip --info

我正在使用mxe中的 strip 命令,它在我的系统上实际上被命名为/opt/mxe/usr/bin/i686-w64-mingw32.static-strip.

于 2015-12-09T20:51:05.957 回答
2

我不知道这是否完全符合您的需求,但是您可以选择与您的 MinGW 版本的 gcc 进行交叉编译吗?

我的意思是说:将 i586-mingw32msvc-gcc 直接编译为 ELF 格式的二进制文件(而不是您当前获得的 PE)是否符合您的需要。可以在此处找到有关如何在另一个方向上做事的描述-我想这会有点笨拙,但完全有可能在另一个方向上为您工作(我必须承认我还没有尝试过)。

于 2011-03-13T10:29:15.473 回答