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 veexample-embed
example-target
tüm semboller veexample-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
denobfd
ibfd
veobfd
içinembedbfd
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
veembedbfd
sembolü tablosunun oluşan kombine bir sembol tablo oluşturun veobfd
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
'danobfd
'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.
Bunu neden yapmaya çalışıyorsunuz? Motivasyon nedir? İki ikilinin kaynak koduna sahip misiniz?Oldukça aptal IMHO görünüyor. –
@EdHeal Bağlantılı soruyu baştan aşağıya bir mantığa sahip olan diğer sorusuna bakın. –
@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. –