이 질문은 내가 전에 물어 본 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
과 동일하지만, 또 다른 main
및 func1
을 추가로 갖는다.
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
와 섹션 이름을 접두어 있습니다.)
그때 생성하는 몇 가지 코드를 작성 새로운 실행 파일 (일부 코드는 objcopy
과 Security Warrior
에서 빌려 왔습니다.) 새로운 실행 파일이 있어야합니다
example-target
의 모든 섹션과example-embed
example-target
의 모든 기호와example-embed
코드의 모든 심볼을 포함하는 심볼 테이블의 모든 섹션을 내가 쓴 :
이 코드는 무엇을 요약하면, 그것은 2 입력 파일 (ibfd
및 embedbfd
) 출력 파일 (obfd
)을 생성합니다.
- 복사 형식/아치/마하/파일 플래그 및
ibfd
에서obfd
- 이
ibfd
및obfd
에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
입니다 : 내가 익숙하지 않다
#define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_section)
:
BFD_ASSERT (elf_dynsymtab (abfd) == 0);
elf_dynsymtab
가 elf-bfd.h
에서 매크로입니다 ELF 레이어,하지만이 동적 인 기호 테이블을 읽는 문제 (또는 아마도 그것은 prese 아니라고 말하고 믿습니다. nt). 당분간, 필자는 필요하지 않으면 ELF 레이어에 직접 도달하지 않아도되도록 노력하고 있습니다. 누구든지 내 코드에서 또는 개념적으로 내가 뭘 잘못하고 있는지 말할 수 있습니까?
유용 할 경우 링커 명령 생성 또는 예제 바이너리의 컴파일 된 버전에 대한 코드를 게시 할 수도 있습니다.
나는 이것이 매우 큰 질문이라는 것을 알고 있으며, 이러한 이유 때문에 나를 도와 줄 수있는 사람에게 올바르게 보상하고 싶습니다. 누군가의 도움으로이 문제를 해결할 수 있다면 500+ 보너스를 드리겠습니다.
왜이 작업을 수행하려고합니까? 동기 부여 란 무엇입니까? 두 바이너리의 소스 코드를 갖고 있습니까?다소 어리석은 IMHO 인 것 같습니다. –
@EdHeal 상단의 링크 된 질문을 다른 질문에 표시합니다. 여기에는 몇 가지 이유가 있습니다. –
@EdHeal : 대상을 가져 와서 사용자 정의 루틴을 그 안에 삽입하는 정적 실행 가능 편집기 (예 : 'example-embed'의 역할)를 만들고 나서 정적으로 새 이진 코드를 정적으로 우회하여 원본을 연결합니다. 코드를 삽입 한 코드 (이미 디스어셈블러/CFG 분석 엔진을 작성한 상태이며 임의의 지침을 편집하여이 주입이 퍼즐의 마지막 부분이기도합니다). 신경 써야 할 usecases를 위해 우리는 사용자 정의 루틴의 소스 코드에 액세스 할 수 있지만 대상은 액세스 할 수 없다고 가정 할 수 있습니다. –