2012-03-15 44 views
8

Bu soru another question'dan daha önce sordum. Kısacası, bu tam olarak bağlantılı iki yürütülebilir dosyayı tek bir tam bağlantılı yürütülebilir dosyada birleştirmeme girişimlerimden biridir. Aradaki fark, bir nesne dosyasının, tam olarak bağlantılı bir yürütülebilir dosya ile birleştirilmesi ile ilgilidir.İki ikili yürütülebilir dosyayı nasıl birleştiririm?

Aşağıdaki dosyalarıdır var Ne:

example-target.c:

#include <stdlib.h> 
#include <stdio.h> 

int main(void) 
{ 
    puts("1234"); 
    return EXIT_SUCCESS; 
} 

example-embed.c:

#include <stdlib.h> 
#include <stdio.h> 

/* 
* Fake main. Never used, just there so we can perform a full link. 
*/ 
int main(void) 
{ 
    return EXIT_SUCCESS; 
} 

void func1(void) 
{ 
    puts("asdf"); 
} 

Amacım bir son yürütülebilir üretmek için bu iki yürütülebilir birleştirmek olduğunu example-target ile aynıdır, ancak ek olarak başka bir main ve func1 vardır.

BFD kütüphanesinin bakış açısına göre, her bir ikili bir dizi bölümden oluşur (diğer şeyler arasında). Karşılaştığım ilk sorunlardan biri, bu bölümlerin çatışan yük adreslerine sahip olmasıydı (eğer onları birleştirirsem, bölümler çakışırdı).

Bunu çözmek için ne yaptım, bölümlerin her birinin yük adresi ve boyutlarının bir listesini almak için program aracılığıyla example-target'u analiz etmekti. Daha sonra example-embed için aynısını yaptım ve example-embed.c için linker command oluşturmak için bu bilgileri kullandı. Bu, tüm bölümlerinin example-target'daki bölümlerden herhangi biriyle çakışmayan adreslere bağlanmasını sağlar. Bu nedenle, example-embed, aslında bu süreçte iki kez tam olarak bağlanmıştır: bir kez kaç tane bölüm ve ne büyüklükte olduklarını belirlemek ve bir kez daha example-target ile herhangi bir bölüm çatışması olmadığını garantilemek. Benim sistemde

, üretilen bağlayıcı komut şudur:

-Wl,--section-start=.new.interp=0x1004238,--section-start=.new.note.ABI-tag=0x1004254, 
--section-start=.new.note.gnu.build-id=0x1004274,--section-start=.new.gnu.hash=0x1004298, 
--section-start=.new.dynsym=0x10042B8,--section-start=.new.dynstr=0x1004318, 
--section-start=.new.gnu.version=0x1004356,--section-start=.new.gnu.version_r=0x1004360, 
--section-start=.new.rela.dyn=0x1004380,--section-start=.new.rela.plt=0x1004398, 
--section-start=.new.init=0x10043C8,--section-start=.new.plt=0x10043E0, 
--section-start=.new.text=0x1004410,--section-start=.new.fini=0x10045E8, 
--section-start=.new.rodata=0x10045F8,--section-start=.new.eh_frame_hdr=0x1004604, 
--section-start=.new.eh_frame=0x1004638,--section-start=.new.ctors=0x1204E28, 
--section-start=.new.dtors=0x1204E38,--section-start=.new.jcr=0x1204E48, 
--section-start=.new.dynamic=0x1204E50,--section-start=.new.got=0x1204FE0, 
--section-start=.new.got.plt=0x1204FE8,--section-start=.new.data=0x1205010, 
--section-start=.new.bss=0x1205020,--section-start=.new.comment=0xC04000 

(ı bölüm adı çatışmaları önlemek için objcopy --prefix-sections=.new example-embedobj kullanılarak .new ile bölüm adları öneki unutmayın.)

Sonra oluşturmak için bazı kodlar yazdım Yeni bir yürütülebilir dosya (bazı kodları hem objcopy ve Security Warrior kitabından ödünç aldı). Yeni çalıştırılabilir olmalıdır:

  • example-target tüm bölümleri ve example-embed
  • example-target tüm semboller ve example-embed

kod tüm sembolleri içeren bir simge tablosu tüm kesimlerini Ben ise yazdı:

#include <stdlib.h> 
#include <stdio.h> 
#include <stdbool.h> 
#include <bfd.h> 
#include <libiberty.h> 

struct COPYSECTION_DATA { 
    bfd *  obfd; 
    asymbol ** syms; 
    int  symsize; 
    int  symcount; 
}; 

void copy_section(bfd * ibfd, asection * section, PTR data) 
{ 
    struct COPYSECTION_DATA * csd = data; 
    bfd *    obfd = csd->obfd; 
    asection *  s; 
    long    size, count, sz_reloc; 

    if((bfd_get_section_flags(ibfd, section) & SEC_GROUP) != 0) { 
     return; 
    } 

    /* get output section from input section struct */ 
    s  = section->output_section; 
    /* get sizes for copy */ 
    size  = bfd_get_section_size(section); 
    sz_reloc = bfd_get_reloc_upper_bound(ibfd, section); 

    if(!sz_reloc) { 
     /* no relocations */ 
     bfd_set_reloc(obfd, s, NULL, 0); 
    } else if(sz_reloc > 0) { 
     arelent ** buf; 

     /* build relocations */ 
     buf = xmalloc(sz_reloc); 
     count = bfd_canonicalize_reloc(ibfd, section, buf, csd->syms); 
     /* set relocations for the output section */ 
     bfd_set_reloc(obfd, s, count ? buf : NULL, count); 
     free(buf); 
    } 

    /* get input section contents, set output section contents */ 
    if(section->flags & SEC_HAS_CONTENTS) { 
     bfd_byte * memhunk = NULL; 
     bfd_get_full_section_contents(ibfd, section, &memhunk); 
     bfd_set_section_contents(obfd, s, memhunk, 0, size); 
     free(memhunk); 
    } 
} 

void define_section(bfd * ibfd, asection * section, PTR data) 
{ 
    bfd *  obfd = data; 
    asection * s = bfd_make_section_anyway_with_flags(obfd, 
      section->name, bfd_get_section_flags(ibfd, section)); 
    /* set size to same as ibfd section */ 
    bfd_set_section_size(obfd, s, bfd_section_size(ibfd, section)); 

    /* set vma */ 
    bfd_set_section_vma(obfd, s, bfd_section_vma(ibfd, section)); 
    /* set load address */ 
    s->lma = section->lma; 
    /* set alignment -- the power 2 will be raised to */ 
    bfd_set_section_alignment(obfd, s, 
      bfd_section_alignment(ibfd, section)); 
    s->alignment_power = section->alignment_power; 
    /* link the output section to the input section */ 
    section->output_section = s; 
    section->output_offset = 0; 

    /* copy merge entity size */ 
    s->entsize = section->entsize; 

    /* copy private BFD data from ibfd section to obfd section */ 
    bfd_copy_private_section_data(ibfd, section, obfd, s); 
} 

void merge_symtable(bfd * ibfd, bfd * embedbfd, bfd * obfd, 
     struct COPYSECTION_DATA * csd) 
{ 
    /* set obfd */ 
    csd->obfd  = obfd; 

    /* get required size for both symbol tables and allocate memory */ 
    csd->symsize = bfd_get_symtab_upper_bound(ibfd) /********+ 
      bfd_get_symtab_upper_bound(embedbfd) */; 
    csd->syms  = xmalloc(csd->symsize); 

    csd->symcount = bfd_canonicalize_symtab (ibfd, csd->syms); 
    /******** csd->symcount += bfd_canonicalize_symtab (embedbfd, 
      csd->syms + csd->symcount); */ 

    /* copy merged symbol table to obfd */ 
    bfd_set_symtab(obfd, csd->syms, csd->symcount); 
} 

bool merge_object(bfd * ibfd, bfd * embedbfd, bfd * obfd) 
{ 
    struct COPYSECTION_DATA csd = {0}; 

    if(!ibfd || !embedbfd || !obfd) { 
     return FALSE; 
    } 

    /* set output parameters to ibfd settings */ 
    bfd_set_format(obfd, bfd_get_format(ibfd)); 
    bfd_set_arch_mach(obfd, bfd_get_arch(ibfd), bfd_get_mach(ibfd)); 
    bfd_set_file_flags(obfd, bfd_get_file_flags(ibfd) & 
      bfd_applicable_file_flags(obfd)); 

    /* set the entry point of obfd */ 
    bfd_set_start_address(obfd, bfd_get_start_address(ibfd)); 

    /* define sections for output file */ 
    bfd_map_over_sections(ibfd, define_section, obfd); 
    /******** bfd_map_over_sections(embedbfd, define_section, obfd); */ 

    /* merge private data into obfd */ 
    bfd_merge_private_bfd_data(ibfd, obfd); 
    /******** bfd_merge_private_bfd_data(embedbfd, obfd); */ 

    merge_symtable(ibfd, embedbfd, obfd, &csd); 

    bfd_map_over_sections(ibfd, copy_section, &csd); 
    /******** bfd_map_over_sections(embedbfd, copy_section, &csd); */ 

    free(csd.syms); 
    return TRUE; 
} 

int main(int argc, char **argv) 
{ 
    bfd * ibfd; 
    bfd * embedbfd; 
    bfd * obfd; 

    if(argc != 4) { 
     perror("Usage: infile embedfile outfile\n"); 
     xexit(-1); 
    } 

    bfd_init(); 
    ibfd  = bfd_openr(argv[1], NULL); 
    embedbfd = bfd_openr(argv[2], NULL); 

    if(ibfd == NULL || embedbfd == NULL) { 
     perror("asdfasdf"); 
     xexit(-1); 
    } 

    if(!bfd_check_format(ibfd, bfd_object) || 
      !bfd_check_format(embedbfd, bfd_object)) { 
     perror("File format error"); 
     xexit(-1); 
    } 

    obfd = bfd_openw(argv[3], NULL); 
    bfd_set_format(obfd, bfd_object); 

    if(!(merge_object(ibfd, embedbfd, obfd))) { 
     perror("Error merging input/obj"); 
     xexit(-1); 
    } 

    bfd_close(ibfd); 
    bfd_close(embedbfd); 
    bfd_close(obfd); 
    return EXIT_SUCCESS; 
} 

bu kod ne yaptığını özetlemek gerekirse, bu 2 giriş dosyaları alır (ibfd ve embedbfd) bir çıkış dosyası oluşturmak için (obfd).

  • Kopya biçimi/kemer/mak/dosya bayrakları ve ibfd den obfd
  • ibfd ve obfd için embedbfd hem bölümler tanımlar için başlangıç ​​adresi. Bölümlerin popülasyonu ayrı olarak gerçekleşir çünkü BFD, tüm bölümlerin herhangi bir başlangıç ​​yapılmadan önce yaratıldığını bildirir.
  • Her iki giriş BFD'nin özel verilerini BFD çıkışına birleştirin. BFD, birçok dosya formatının üzerinde ortak bir soyutlama olduğundan, temel dosya formatının gerektirdiği her şeyi kapsamlı bir şekilde kapsamaya muktedir değildir.
  • ibfd ve embedbfd sembolü tablosunun oluşan kombine bir sembol tablo oluşturun ve obfd sembolü tablosu olarak bu ayarlayın. Bu sembol tablosu kaydedilir, böylece daha sonra yer değiştirme bilgileri oluşturmak için kullanılabilir.
  • Bölümleri ibfd'dan obfd'a kopyalayın. Bölüm içeriğinin kopyalanmasının yanı sıra, bu adım ayrıca yer değiştirme masasını oluşturmak ve ayarlamakla ilgilenir. Yukarıdaki kodda

, bazı satırlar /******** */ ile yorumlanmıştır. Bu satırlar, example-embed'un birleştirilmesiyle ilgilenir. Eğer yorumlanırsa, obfd, ibfd'un bir kopyası olarak basitçe inşa edilir. Bunu test ettim ve iyi çalışıyor. Ancak, bu satırları yorumladıktan sonra problemlerin başlamasına başlıyorum.

Tam birleştirme işlemini gerçekleştiren uncommented sürümüyle, yine de bir çıkış dosyası oluşturur. Bu çıktı dosyası, objdump ile denetlenebilir ve her iki girdinin tüm bölümlerine, kodlarına ve sembol tablolarına sahip olduğu bulundu. Ancak, objdump ile yakınır: Benim sistemde

BFD: BFD (GNU Binutils for Ubuntu) 2.21.53.20110810 assertion fail ../../bfd/elf.c:1708 
BFD: BFD (GNU Binutils for Ubuntu) 2.21.53.20110810 assertion fail ../../bfd/elf.c:1708 

, elf.c ait 1708: Ben aşina değilim

#define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_section) 

:

BFD_ASSERT (elf_dynsymtab (abfd) == 0); 

elf_dynsymtab için elf-bfd.h bir makro olduğunu ELF katmanı, ama bunun dinamik sembol tablosunu okuyan bir problem olduğuna inanıyorum (ya da belki de bunun önkoşul olmadığını söylüyorum) nt). Bu süre boyunca, gerekmedikçe doğrudan ELF katmanına inmek zorunda kalmamayı deniyorum. Kimse bana ne yanlış yaptığımı söyler mi, ne kodumda ne de kavramsal olarak mı?

Yararlıysa, aynı zamanda, örnek ikili dosyalarının linker komut üretimi veya derlenmiş sürümleri için de kodu gönderebilirim.


Bu çok büyük bir soru olduğunu fark ve bu nedenle, düzgün onunla bana yardım edebilir kimseyi ödüllendirmek istiyoruz. Bunu birisinin yardımıyla çözebilirsem 500+ bonus vermekten mutluluk duyarım.

+3

Bunu neden yapmaya çalışıyorsunuz? Motivasyon nedir? İki ikilinin kaynak koduna sahip misiniz?Oldukça aptal IMHO görünüyor. –

+1

@EdHeal Bağlantılı soruyu baştan aşağıya bir mantığa sahip olan diğer sorusuna bakın. –

+0

@EdHeal: Bir hedef alabilen, kullanıcı tanımlı rutinleri (örnek gömülü rolün rolünü) enjekte edebilen ve sonra orijinali bağlamak için yeni ikili kodun statik yolunu saptayan statik bir çalıştırılabilir editör yapıyorum Enjekte edilen kod için kod (zaten bir disassembler/CFG analiz motoru yazdım ve ayrıca bu enjeksiyonun bulmacanın son parçası olması için keyfi talimatları da düzenleyebiliyorum). Dikkat etmem gereken usecaslar için, kullanıcı tanımlı rutinin kaynak koduna erişebildiğimiz, ancak hedefe erişemediğimiz varsayılabilir. –

cevap

1

Tüm bunlar el ile nasıl yapılır? Tüm sembol bilgisine sahip olduğunuza göre (eğer ikiliyi akılcı bir şekilde düzenlemek istiyorsanız), yürütülebilir dosyayı ayrı nesne dosyalarına ayırmak daha kolay olmaz (örneğin, işlev başına bir nesne dosyası). düzenleme ve yeniden bağlanma?

+0

Bir yürütülebilir dosya kaynak kod olmadan bir nesne dosyasına nasıl bölünebilir? Gömülü nesne için sembol bilgisinin mevcut olduğunu, ancak hedef için mevcut olmadığını varsayabilirim (ilk önce bu varsayımla çalışabilirsem, bu iyi olurdu). –

+0

ELF yürütülebilir dosyaları hem yer değiştirme bilgilerini hem de sembol tablosunu koruyabilir. Her iki parça mevcut olduğunda, sembol tablosunun bir sembolün veri mi yoksa kod mu olduğunu da belirttiği gibi, yürütülebilir dosyayı nesne dosyalarına bölmek nispeten kolaydır. Ayrıca, neden * executables * birleştirmeye çalışıyorsunuz? Bir nesne dosyasını enjekte etmek daha kolay olurdu. – zvrba

+0

Yürütülebilirleri birleştirmeye çalışıyorum çünkü artık yeniden yerleştirme ile uğraşmam gerekmediğinden daha kolay olacağını düşündüm. Bunu denediğimde bir nesne dosyası enjekte etmenin bir yolunu bulamadım. Yürütülebilir dosyaları nesne dosyalarına bölmeyi nasıl başarabilirim? İlginiz için teşekkürler btw. –

İlgili konular