linux下如何将PE(Portable Executable)格式转换为ELF

发布于 2024-08-27 08:22:09 字数 486 浏览 15 评论 0原文

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

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

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

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

谢谢

What's the best tool for converting PE binaries to ELF binaries?

Following is a brief motivation for this question:

  1. Suppose I have a simple C program.
  2. I compiled it using gcc for linux(this gives ELF), and using 'i586-mingw32msvc-gcc' for Windows(this gives a PE binary).
  3. I want to analyze these two binaries for similarities, using Bitblaze's static analysis tool - vine(http://bitblaze.cs.berkeley.edu/vine.html)
  4. Now vine doesn't have a good support for PE binaries, so I wanted to convert PE->ELF, and then carry on with my comparison/analysis.

Since all the analysis has to run on Linux, I would prefer a utility/tool that runs on Linux.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

她如夕阳 2024-09-03 08:22:09

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

这是一种实现方法。

摘要

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

详细示例

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

    $ i686-pc-mingw32-objdump -h trek.exe

    trek.exe:文件格式 pei-i386

    部分:
    Algn 中的 Idx 名称大小 VMA LMA 文件
    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 跳过=2 计数=2963 if=trek.exe of=code.bin
    $ dd bs=512 跳过=2975 计数=347 if=trek.exe of=data.bin

    请注意,我已将文件偏移量和节大小从十六进制转换为十进制,以用作 skipcount,但我使用的块大小为 512 dd 中的字节以加快处理速度(例如:0x0400 = 1024 字节 = 2 块@ 512 字节)。

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

    cat 代码.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”)
    章节{
    .文本0x401000:
    {
    包含“code.ld”;
    }
    .数据0x576000:
    {
    包含“data.ld”;
    }
    .bss 0x5A2000:
    {
    。 = 。 + 0x0E7800;
    }
    }

  5. 使用 GNU ld 运行链接器脚本以生成 ELF 文件。请注意,由于我使用的是 64 位 Linux,因此我必须使用模拟模式 elf_i386,否则将生成 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 端栈可用

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

It is possible to rebuild an EXE as an ELF binary, but the resulting binary will segfault very soon after loading, due to the missing operating system.

Here's one method of doing it.

Summary

  1. Dump the section headers of the EXE file.
  2. Extract the raw section data from the EXE.
  3. Encapsulate the raw section data in GNU linker script snippets.
  4. Write a linker script to build an ELF binary, including those scripts from the previous step.
  5. Run ld with the linker script to produce the ELF file.
  6. Run the new program, and watch it segfault as it's not running on Windows (and it tries to call functions in the Import Address Table, which doesn't exist).

Detailed Example

  1. Dump the section headers of the EXE file. I'm using objdump from the mingw cross compiler package to do this.

    $ i686-pc-mingw32-objdump -h trek.exe
    
    trek.exe:         file format pei-i386
    
    Sections:
    Idx Name          Size      VMA       LMA       File off  Algn
      0 AUTO          00172600  00401000  00401000  00000400  2**2
                      CONTENTS, ALLOC, LOAD, READONLY, CODE
      1 .idata        00001400  00574000  00574000  00172a00  2**2
                      CONTENTS, ALLOC, LOAD, DATA
      2 DGROUP        0002b600  00576000  00576000  00173e00  2**2
                      CONTENTS, ALLOC, LOAD, DATA
      3 .bss          000e7800  005a2000  005a2000  00000000  2**2
                      ALLOC
      4 .reloc        00013000  0068a000  0068a000  0019f400  2**2
                      CONTENTS, ALLOC, LOAD, READONLY, DATA
      5 .rsrc         00000a00  0069d000  0069d000  001b2400  2**2
                      CONTENTS, ALLOC, LOAD, READONLY, DATA
    
  2. Use dd (or a hex editor) to extract the raw section data from the EXE. Here, I'm just going to copy the code and data sections (named AUTO and DGROUP in this example). You may want to copy additional sections though.

    $ 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
    

    Note, I've converted the file offsets and section sizes from hex to decimal to use as skip and count, but I'm using a block size of 512 bytes in dd to speed up the process (example: 0x0400 = 1024 bytes = 2 blocks @ 512 bytes).

  3. Encapsulate the raw section data in GNU ld linker scripts snippets (using the BYTE directive). This will be used to populate the sections.

    cat code.bin | hexdump -v -e '"BYTE(0x" 1/1 "%02X" ")\n"' >code.ld
    cat data.bin | hexdump -v -e '"BYTE(0x" 1/1 "%02X" ")\n"' >data.ld
    
  4. Write a linker script to build an ELF binary, including those scripts from the previous step. Note I've also set aside space for the uninitialized data (.bss) section.

    start = 0x516DE8;
    ENTRY(start)
    OUTPUT_FORMAT("elf32-i386")
    SECTIONS {
        .text 0x401000 :
        {
            INCLUDE "code.ld";
        }
        .data 0x576000 :
        {
            INCLUDE "data.ld";
        }
        .bss 0x5A2000 :
        {
            . = . + 0x0E7800;
        }
    }
    
  5. Run the linker script with GNU ld to produce the ELF file. Note I have to use an emulation mode elf_i386 since I'm using 64-bit Linux, otherwise a 64-bit ELF would be produced.

    $ ld -o elf_trek -m elf_i386 elf_trek.ld
    ld: warning: elf_trek.ld contains output sections; did you forget -T?
    $ file elf_trek
    elf_trek: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), 
              statically linked, not stripped
    
  6. Run the new program, and watch it segfault as it's not running on Windows.

    $ gdb elf_trek
    (gdb) run
    Starting program: /home/quasar/src/games/botf/elf_trek 
    
    Program received signal SIGSEGV, Segmentation fault.
    0x0051d8e6 in ?? ()
    (gdb) bt
    \#0  0x0051d8e6 in ?? ()
    \#1  0x00000000 in ?? ()
    (gdb) x/i $eip
    => 0x51d8e6:    sub    (%edx),%eax
    (gdb) quit
    

    IDA Pro output for that location:

    0051D8DB ; size_t stackavail(void)
    0051D8DB proc    stackavail near
    0051D8DB         push    edx
    0051D8DC         call    [ds:off_5A0588]
    0051D8E2         mov     edx, eax
    0051D8E4         mov     eax, esp
    0051D8E6         sub     eax, [edx]
    0051D8E8         pop     edx
    0051D8E9         retn
    0051D8E9 endp    stackavail
    

For porting binaries to Linux, this is kind of pointless, given the Wine project.
For situations like the OP's, it may be appropriate.

大海や 2024-09-03 08:22:09

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

示例

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

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

要查看支持的运行格式,

strip --info

我使用 mxe 中的 strip 命令,该命令在我的系统上实际上名为 /选择/mxe/usr/bin/i686-w64-mingw32.static-strip

I've found a simpler way to do this. Use the strip command.

Example

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

The -O elf32-i386 has it write out the file in that format.

To see supported formats run

strip --info

I am using the strip command from mxe, which on my system is actually named /opt/mxe/usr/bin/i686-w64-mingw32.static-strip.

剩一世无双 2024-09-03 08:22:09

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

我的意思是说:将 i586-mingw32msvc-gcc 直接编译为 ELF 格式二进制文件(而不是您当前获得的 PE)是否适合您的需求。有关如何在另一个方向上执行操作的说明,请参见 这里 - 我想这会有点hacky,但完全有可能让这个工作在另一个方向上为你工作(我必须承认我还没有尝试过)。

I don't know whether this totally fits your needs, but is it an option for you to cross-compile with your MinGW version of gcc?

I mean do say: does it suit your needs to have i586-mingw32msvc-gcc compile direct to ELF format binaries (instead of the PEs you're currently getting). A description of how to do things in the other direction can be found here - I imagine it will be a little hacky but entirely possible to make this work for you in the other direction (I must admit I haven't tried it).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文