Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert PE(Portable Executable) format to ELF in 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

like image 499
Aman Jain Avatar asked Apr 02 '10 18:04

Aman Jain


People also ask

How is ELF file generated?

The ELF file is built for an x86-64 bit machine. There are two important pieces of information present in the ELF header. One is the ELF program header part and the other is the ELF section header part. When a program is compiled, different things are generated after compilation.

Can I run an ELF file in Linux?

To use some code from an object file, we need to find it first. As I've leaked above, object files are actually ELF files (the same format as Linux executables and shared libraries) and luckily they're easy to parse on Linux with the help of the standard elf.

What executable format does Linux use?

The standard Linux executable format is named Executable and Linking Format ( ELF). It was developed by Unix System Laboratories and is now the most widely used format in the Unix world.

What is ELF file in Linux?

ELF is the standard binary format on operating systems such as Linux. Some of the capabilities of ELF are dynamic linking, dynamic loading, imposing run-time control on a program, and an improved method for creating shared libraries.


2 Answers

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.

like image 68
Tim Avatar answered Oct 26 '22 23:10

Tim


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.

like image 26
Daniel Hanrahan Avatar answered Oct 27 '22 00:10

Daniel Hanrahan