2011-04-22 3 views
3

일부 추가 로깅 코드를 정적으로 링크 된 (android arm linux) 실행 파일에 병합하려고합니다.추가 코드를 실행 파일에 병합하십시오. (arm-linux)

(일반적인 추적 방법이 작동하지 않는 것처럼 보입니다. 흥미로운 일을하기 전에 clone()을 실행하기 직전인데, strace가이를 따라 잡기 만하면됩니다.)

새 코드에 점프 명령을 삽입하기 위해 기존 코드를 편집하는 것이 테스트되고 작동하는 경우 기존 코드를 방해하지 않는 방식으로 실행 파일에 새 코드를 병합하는 것이 문제입니다. 실행 가능한 페이지로로드됩니다.

나는 모든 추가 코드를 하나의 오브젝트 파일 섹션에 압축 할 수 있었지만 objcopy (또는 심지어 ld)를 사용하여 올바르게로드 될 수있는 방법으로 병합하는 방법을 알아낼 수 없었다. - 내가 기존로드 세그먼트를 이동하거나, 추가로 추가 할 하나를 추가하려면 & 크기를 조정해야합니다.

공유 라이브러리에 코드를 추가하는 것은 이미 연결되어 있고 현재 실행 가능한 정적 실행 파일에 필요한 스텁을 추가 할 수있는 방법이 될 수 있습니다 (점프 지침에서 스텁의 알려진 위치를 16 진수로 편집합니다) 그러면 런타임 링커가 추가 된 코드를 가리킬 것입니다.)

+0

내가하고 싶은 모든 것에 반드시 필요한 것은 아니며, 꽤 일반적인 방법을 원합니다. 하지만 syscalls를 인코딩 할 수있는 충분한 공간이있을 수 있습니다. 외부 파일의 실행 가능 페이지를 mmap()하고 시작 코드를 편집하여 16 진수로 점프합니다. –

+0

왜 커널을 다시 컴파일하지 않습니까? –

+0

@Turbo J 커널 코드가 아닙니다. 사용자 코드를 모니터하기 위해 커널을 인스트루먼트하는 것은 대체 플래시 위치에서 커널을 부팅 할 수없는 장치에서 과감하고 정확한 커널의 소스가 아직 릴리스되지 않은 경우에는 어렵습니다 (장치가 켜지 기 전에 완료되어야 함). 판매). –

답변

1

이것은 멋지 지 않아서 더 좋은 아이디어에 흥미가 있습니다. 그러나 기본적으로 내가 할 수 있었던 것을 요약 해 보았습니다.

이것은 원래의 엘프의 패딩에 삽입 된 작은 부트 스트랩 페이로드의 두 가지 접근법으로 실제 작업을 수행하기 위해 임의로 큰 바이너리 블롭을 mmap()합니다.

부 : 부트 스트랩 페이로드

는 기본적으로 나는 .ARM.exidx 섹션 (코드 세그먼트의 상단에로드하는)와 .preinit_array 섹션 사이에 패딩에 적은 양의 코드를 삽입합니다. 이 코드는 다른 바이너리 BLOB 및 mmap()을 읽기 전용으로 열고 하드 코딩 된 가상 주소에서 실행 가능하므로 안전합니다.

삽입 된 코드를 기본 실행 파일의 일부로로드하려면 elf 파일에서로드 세그먼트의 크기를 수정해야합니다.이 경우 0x54에서 시작하는 두 번째 phdr 구조체입니다. 0x64 (0x54 + 0x20)의 p_filesz와 0x68 (0x54 + 0x24)의 p_memsz가 모두 변경되었습니다.

또한 삽입 된 코드를 가리 키도록 오프셋 0x18의 elf 헤더에서 e_entry 시작 주소를 변경했습니다. 삽입 된 코드는 설정을 끝내면 이전 시작 주소로 점프합니다 (실제로는 큰 페이로드에서 스테이지 2 설정으로 이동 한 후 원래 위치로 이동합니다).

마지막으로 내가 더 큰 페이로드의로드 주소에서 내 교체를 가리 키도록 트랩에 원하는 기능의 정적으로 링크 된 콜 스텁을 변경 난의 mmap()에 보내고

파트 II :. 큰에게 페이로드

내 경우에는 syscalls를 특정 조건이 충족 될 때 기록되는 기능으로 대체합니다. 메인 실행 파일은 정적으로 링크되어 있기 때문에, 이것도 마찬가지 여야합니다 - 또는 더 간단하게 C 라이브러리를 사용할 수 없습니다. 대신 어셈블리 언어를 사용하여 기본 I/O에 대한 syscall을 실행합니다. 실행 파일로로드하지 않고서는 영구적 인 로컬 변수 스토리지가 없다는 것을 알았습니다. 시작시에 로컬 변수를 저장하는 익명 페이지 인 - 주로 로깅하는 파일의 fd와 장치 드라이버 fd의 작업 어느 것이 기록되어야하는지.

이 부분을 컴파일하는 것은 조금 비 효과적입니다. gcc에 -S 스위치로 어셈블리를 컴파일 한 다음 모든 섹션 키워드를 제거합니다. 그런 다음 gcc를 통해 객체를 어셈블하고 생성합니다. 엔트리 포인트 (-e)로 첫 번째 함수의 이름을 지정하고 0x8000 시작 오프셋을 제거하는 일반적인 링커 스크립트의 사용자 정의를 사용하여 링커를 실행합니다. 그러나 헤더 (이 경우 128 바이트)로 인해 일부 오프셋이 여전히 존재합니다. 픽스 업을 보존하기 위해 링크 된 엘프의 내용을 바이너리 블롭으로 objcopy하고,/dev/zero에서 128 바이트를 dd로 나눈다. 그리고 처음에는 cat을 사용한다 ....

내가 말했듯이 우아하지 않아서 더 나은 아이디어를 얻을 수 있습니다.