2012-03-15 6 views
8

이 질문은 내가 전에 물어 본 another question에서 온 것입니다. 간단히 말해서, 이것은 완전하게 링크 된 두 개의 실행 파일을 하나의 완전히 링크 된 실행 파일로 병합하려는 나의 시도 중 하나입니다. 차이점은 이전 질문에서는 객체 파일을 전체 링크 된 실행 파일에 병합하는 것으로 처리하는 것이 더 어렵다는 것입니다. 이는 내가 수동으로 재배치를 처리해야한다는 것을 의미하기 때문입니다.두 바이너리 실행 파일을 병합하려면 어떻게합니까?

나는 다음과 같은 파일입니다 무슨 :

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"); 
} 

내 목표는 것입니다 최종 실행 파일을 생성하기 위해이 두 실행 파일을 병합하는 것입니다 example-target과 동일하지만, 또 다른 mainfunc1을 추가로 갖는다.

BFD 라이브러리의 관점에서 볼 때 각 바이너리는 여러 섹션 중에서 구성됩니다 (다른 것들 중에서). 내가 직면 한 첫 번째 문제 중 하나는 이러한 섹션에 충돌하는로드 주소가 있다는 것입니다 (예를 들어, 병합 할 경우 섹션이 겹칠 수 있습니다).

이 문제를 해결하기 위해 프로그래밍 방식으로 example-target을 분석하여 각 섹션의로드 주소 및 크기 목록을 가져 왔습니다. 그런 다음 example-embed에 대해 동일한 작업을 수행했으며이 정보를 사용하여 example-embed.c에 대해 linker command을 동적으로 생성하여 모든 섹션이 example-target에있는 섹션과 겹치지 않는 주소에 연결되도록했습니다. 따라서 example-embed은 실제로이 프로세스에서 두 번 완전히 연결됩니다. 한 번에 몇 개의 섹션과 크기가 있는지 확인하고 다시 한번 섹션 충돌이없는 것으로 보장하기 위해 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 

(I이 섹션 이름의 충돌을 피하기 위해 objcopy --prefix-sections=.new example-embedobj를 사용하여 .new와 섹션 이름을 접두어 있습니다.)

그때 생성하는 몇 가지 코드를 작성 새로운 실행 파일 (일부 코드는 objcopySecurity Warrior에서 빌려 왔습니다.) 새로운 실행 파일이 있어야합니다

  • example-target의 모든 섹션과 example-embed
  • example-target의 모든 기호와 example-embed

코드의 모든 심볼을 포함하는 심볼 테이블의 모든 섹션을 내가 쓴 :

이 코드는 무엇을 요약하면, 그것은 2 입력 파일 (ibfdembedbfd) 출력 파일 (obfd)을 생성합니다.

  • 복사 형식/아치/마하/파일 플래그 및 ibfd에서 obfd
  • ibfdobfdembedbfd 모두에서 섹션을 정의에 주소를 시작합니다. BFD는 시작하기 전에 모든 섹션이 작성되도록 요구하기 때문에 섹션의 채우기가 별도로 발생합니다.
  • 입력 BFD의 개인 데이터를 출력 BFD에 병합하십시오. BFD는 많은 파일 형식보다 일반적인 추상화이기 때문에 기본 파일 형식에 필요한 모든 것을 포괄적으로 캡슐화 할 수있는 것은 아닙니다.
  • ibfdembedbfd의 기호 표로 구성된 결합 된 기호 표를 작성하고이를 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.c1708입니다 : 내가 익숙하지 않다

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

:

BFD_ASSERT (elf_dynsymtab (abfd) == 0); 

elf_dynsymtabelf-bfd.h에서 매크로입니다 ELF 레이어,하지만이 동적 인 기호 테이블을 읽는 문제 (또는 아마도 그것은 prese 아니라고 말하고 믿습니다. nt). 당분간, 필자는 필요하지 않으면 ELF 레이어에 직접 도달하지 않아도되도록 노력하고 있습니다. 누구든지 내 코드에서 또는 개념적으로 내가 뭘 잘못하고 있는지 말할 수 있습니까?

유용 할 경우 링커 명령 생성 또는 예제 바이너리의 컴파일 된 버전에 대한 코드를 게시 할 수도 있습니다.


나는 이것이 매우 큰 질문이라는 것을 알고 있으며, 이러한 이유 때문에 나를 도와 줄 수있는 사람에게 올바르게 보상하고 싶습니다. 누군가의 도움으로이 문제를 해결할 수 있다면 500+ 보너스를 드리겠습니다.

+3

왜이 작업을 수행하려고합니까? 동기 부여 란 무엇입니까? 두 바이너리의 소스 코드를 갖고 있습니까?다소 어리석은 IMHO 인 것 같습니다. –

+1

@EdHeal 상단의 링크 된 질문을 다른 질문에 표시합니다. 여기에는 몇 가지 이유가 있습니다. –

+0

@EdHeal : 대상을 가져 와서 사용자 정의 루틴을 그 안에 삽입하는 정적 실행 가능 편집기 (예 : 'example-embed'의 역할)를 만들고 나서 정적으로 새 이진 코드를 정적으로 우회하여 원본을 연결합니다. 코드를 삽입 한 코드 (이미 디스어셈블러/CFG 분석 엔진을 작성한 상태이며 임의의 지침을 편집하여이 주입이 퍼즐의 마지막 부분이기도합니다). 신경 써야 할 usecases를 위해 우리는 사용자 정의 루틴의 소스 코드에 액세스 할 수 있지만 대상은 액세스 할 수 없다고 가정 할 수 있습니다. –

답변

1

왜이 모든 작업을 수동으로합니까? 모든 기호 정보 (이진 코드를 정상적으로 편집하려는 경우에 필요함)를 감안할 때 실행 파일을 별도의 객체 파일 (예 : 함수 당 하나의 객체 파일)로 분할하는 것이 더 쉽지는 않을 것입니다. 편집하고 다시 링크 하시겠습니까?

+0

어떻게 실행 파일을 소스 코드없이 오브젝트 파일로 나눌 수 있습니까? 필자는 기호 정보가 포함 된 개체에 대해 사용할 수 있다고 가정 할 수 있지만 대상에 대해서는 사용할 수 없습니다. (이 가정을 먼저 사용하면 괜찮을 수 있지만). –

+0

ELF 실행 파일은 재배치 정보와 기호 테이블을 모두 유지할 수 있습니다. 두 조각이 모두 존재할 때 심볼 테이블이 데이터 또는 코드인지 여부를 나타내는 것처럼 실행 파일을 오브젝트 파일로 분할하는 것이 비교적 간단합니다. 또한 왜 * 실행 파일 *을 병합하려고합니까? 오브젝트 파일을 삽입하는 것이 더 쉬울 것입니다. – zvrba

+0

재배치를 더 이상 다루지 않아도되므로 실행 파일을 병합하려고했습니다. 더 쉬울 것이라고 생각했기 때문입니다. 대신 객체 파일을 삽입 할 방법을 찾지 못했습니다. 실행 파일을 오브젝트 파일로 분할하는 방법은 무엇입니까? 관심을 가져 주셔서 감사합니다. –