この質問は私が以前に尋ねたanother questionから続く。要するに、完全にリンクされた2つの実行可能ファイルを1つの完全にリンクされた実行可能ファイルにマージする試みです。違いは、前の質問では、オブジェクトファイルを完全にリンクされた実行可能ファイルにマージすることです。これは、手動で再配置を処理する必要があるためです。2つのバイナリ実行可能ファイルをマージするにはどうすればよいですか?
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");
}
私の目標は、最終的な実行可能ファイルを生成するために、これらの2つの実行をマージすることで、私は以下のファイルで持っているもの
example-target
と同じですが、さらにmain
とfunc1
があります。
BFDライブラリの観点からは、各バイナリはセクションのセットから構成されています(とりわけ)。私が直面した最初の問題の1つは、これらのセクションが競合するロード・アドレスを持っていたということです(それをマージすると、セクションが重複するようになります)。
これを解決するために、example-target
をプログラムで分析して、各セクションのロードアドレスとサイズの一覧を取得しました。私はexample-embed
について同じことを行い、example-embed.c
のためにlinker commandを動的に生成するためにこの情報を使用しました。すべてのセクションがexample-target
のいずれのセクションとも重複しないアドレスで確実にリンクされています。したがって、example-embed
は実際にはこのプロセスで2回完全にリンクされています.1回はセクション数とサイズを決定し、もう一度セクション違反がないと保証するためにexample-target
とリンクします。私のシステムで
、生産リンカのコマンドは次のとおりです。
-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
(私はセクション名の衝突を避けるためにobjcopy --prefix-sections=.new example-embedobj
を使用して.new
でセクション名を接頭辞ことに注意してください。)
私はその後、生成するいくつかのコードを書きました新しい実行可能ファイル(objcopy
とSecurity Warrior
の両方からいくつかのコードを借用)。新しい実行可能ファイルが持っている必要があります。
example-target
のすべてのセクションとexample-embed
example-target
からすべてのシンボルとexample-embed
コードのすべてのシンボルが含まれているシンボルテーブルのすべてのセクションを私は書いた:
#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;
}
このコードが何を要約すると、2つの入力ファイル(ibfd
およびembedbfd
)を使用して出力ファイル(obfd
)を生成します。
- コピー形式/アーチ/マッハ/ファイルフラグと
ibfd
からobfd
- にアドレスを開始
obfd
にibfd
とembedbfd
の両方からのセクションを定義します。 BFDは、開始する前にすべてのセクションが作成されることを要求するため、セクションの集団は別々に発生します。 - 両方の入力BFDのプライベートデータを出力BFDにマージします。 BFDは多くのファイル形式よりも一般的な抽象化であるため、基本的なファイル形式で必要とされるすべてを包括的にカプセル化することはできません。
- シンボルテーブル
ibfd
とembedbfd
で構成されるシンボルテーブルを作成し、これをシンボルテーブルobfd
に設定します。このシンボルテーブルは、後で再配置情報の作成に使用できるように保存されます。 ibfd
からobfd
までのセクションをコピーします。セクションの内容をコピーするだけでなく、このステップでは、再配置テーブルの作成と設定も行います。
上記のコードでは、一部の行は/******** */
でコメントアウトされています。これらの行はexample-embed
のマージを処理します。コメントアウトされている場合、obfd
は単にibfd
のコピーとして作成されます。私はこれをテストし、それは正常に動作します。しかし、いったん私はこれらの行をコメントしたら、問題が発生し始めます。
完全マージを行う非コメント版では、出力ファイルが生成されます。この出力ファイルはobjdump
で検査でき、両方の入力のセクション、コード、シンボルテーブルがすべてあることがわかります。しかし、objdump
は、と文句を言う:私のシステムでは
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
の1708
は次のとおりです。
BFD_ASSERT (elf_dynsymtab (abfd) == 0);
elf_dynsymtab
は用elf-bfd.h
でマクロです:
#define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_section)
私は精通していませんよELF層ですが、これはダイナミックなシンボルテーブルを読むことに問題があると思います。 nt)。当面は、必要な場合を除いて、ELFレイヤーに直接到達する必要はありません。誰かが私のコードで、あるいは概念的に間違っていることを教えてくれますか?
もし有用であれば、私はリンカコマンド生成用のコードまたはサンプルバイナリのコンパイル済みバージョンを投稿することもできます。
私は、これは非常に大きな問題であり、このような理由のために、私はきちんとそれで私を助けることができている人を報いたいことを実現します。私が誰かの助けを借りてこれを解決することができれば、私は500以上のボーナスを授与させていただきます。
なぜこれをやろうとしていますか?動機は何ですか? 2つのバイナリのソースコードはありますか?むしろ愚かなIMHOのようだ。 –
@EdHealトップにあるリンクされた質問を他の質問にしてください。これにはいくつかの根拠があります。 –
@EdHeal:私はターゲットを取り、それにユーザ定義のルーチンを挿入する(example-embedの役割を果たす)静的実行可能エディタを作成しています。そして、新しいバイナリのコードを静的に元に戻す(私はすでに逆アセンブラ/ CFG解析エンジンを作成しており、この注入がパズルの最後の部分であるように任意の指示を編集することもできます)。私が気にする必要がある用途のために、ユーザが定義したルーチンのソースコードにアクセスできるが、ターゲットはアクセスできないと仮定することができます。 –