source

실행 가능한 . .을 빌드합니다.

goodcode 2022. 8. 21. 14:08
반응형

실행 가능한 . .을 빌드합니다.

그래서 아마 다들 알고 있을 거예요. glibc는/lib/libc.so.6버전 정보를 인쇄하고 종료하는 일반 실행 파일과 같이 셸에서 실행할 수 있습니다.이것은 .so에서 진입점을 정의함으로써 이루어집니다.경우에 따라서는, 이것을 다른 프로젝트에도 사용하는 것이 흥미로울 수도 있습니다.유감스럽게도 ld's -e 옵션으로 설정할 수 있는 로우 레벨 진입점은 약간 로우 레벨입니다.다이나믹 로더를 사용할 수 없기 때문에 적절한 라이브러리 함수를 호출할 수 없습니다.이 때문에 glibc는 이 엔트리 포인트에서 네이키드시스템콜을 통해 write() 시스템콜을 구현합니다

여기서 궁금한 것은 어떻게 하면 다른 .so의 함수에 접근할 수 있도록 그 엔트리 포인트에서 완전한 다이내믹 링커를 부트스트랩할 수 있을까 하는 것입니다.

이것에 대한 서포트를 다음에 추가하고 싶다고 생각하고 있습니다.pam_cap.so이 질문을 찾았습니다.@Euccessed Russian이 자신의 포스트에 대한 팔로업에서 언급했듯이, 받아들여진 답변은 어느 순간 작동을 멈췄다.이 작업을 다시 수행하는 방법을 찾는 데 시간이 걸렸으므로, 다음은 작업한 예입니다.

이 작업 예에서는 5개의 파일을 사용하여 대응하는 테스트에서의 동작 방법을 보여 줍니다.

먼저 이 사소한 프로그램을 고려합니다(이것을 가리킵니다).empty.c):

int main(int argc, char **argv) { return 0; }

컴파일하면 다음과 같이 시스템의 동적 기호가 어떻게 해결되는지 알 수 있습니다.

$ gcc -o empty empty.c
$ objcopy --dump-section .interp=/dev/stdout empty ; echo
/lib64/ld-linux-x86-64.so.2
$ DL_LOADER=/lib64/ld-linux-x86-64.so.2

이 마지막 행은 나중에 사용할 수 있도록 셸 변수를 설정합니다.

다음으로 샘플 공유 라이브러리를 구축하는2개의 파일을 나타냅니다.

/* multi.h */
void multi_main(void);
void multi(const char *caller);

그리고.

/* multi.c */
#include <stdio.h>
#include <stdlib.h>
#include "multi.h"

void multi(const char *caller) {
    printf("called from %s\n", caller);
}

__attribute__((force_align_arg_pointer))
void multi_main(void) {
    multi(__FILE__);
    exit(42);
}

const char dl_loader[] __attribute__((section(".interp"))) =
    DL_LOADER ;

(업데이트 2021-11-13:강제 정렬은 코드가 SSE와 호환되도록 하기 위한 것입니다. SSE가 없으면 디버깅이 어렵습니다.glibc SIGSEGV크래시)

다음과 같이 컴파일하여 실행할 수 있습니다.

$ gcc -fPIC -shared -o multi.so -DDL_LOADER="\"${DL_LOADER}\"" multi.c -Wl,-e,multi_main
$ ./multi.so
called from multi.c
$ echo $?
42

그래서 이거는.so독립 실행형 바이너리로 실행할 수 있습니다.다음으로 공유 객체로 로드할 수 있는지 확인합니다.

/* opener.c */
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    void *handle = dlopen("./multi.so", RTLD_NOW);
    if (handle == NULL) {
        perror("no multi.so load");
        exit(1);
    }
    void (*multi)(const char *) = dlsym(handle, "multi");
    multi(__FILE__);
}

즉, shared-object를 동적으로 로드하고 여기서 함수를 실행합니다.

$ gcc -o opener opener.c -ldl
$ ./opener
called from opener.c

마지막으로 이 공유 객체에 대해 링크합니다.

/* main.c */
#include "multi.h"

int main(int argc, char **argv) {
    multi(__FILE__);
}

여기서는 다음과 같이 컴파일하여 실행합니다.

$ gcc main.c -o main multi.so
$ LD_LIBRARY_PATH=./ ./main
called from main.c

(주의:multi.so표준 시스템 라이브러리 위치에 있지 않습니다.런타임이 공유 객체 파일을 검색하는 위치를 덮어쓸 필요가 있습니다.LD_LIBRARY_PATH환경변수)를 참조해 주세요.

업데이트 2: 모든 GLIBC에서 동작하는 Andrew G Morgan의 약간 더 복잡한 솔루션을 참조하십시오(이 솔루션은 다음에서도 사용됩니다).libc.so.6 '아까부터'라고 거죠../libc.so.6(이렇게 기동하면 버전 정보가 출력됩니다).

업데이트 1: 이 기능은 새로운 GLIBC 버전에서는 사용할 수 없게 되었습니다.

./a.out: error while loading shared libraries: ./pie.so: cannot dynamically load position-independent executable

2009년 원본 답변:

를를 with with with with with with with with with with with 로 공유 -pie옵션을 사용하면 원하는 모든 것을 얻을 수 있습니다.

/* pie.c */
#include <stdio.h>
int foo()
{
  printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
  return 42; 
}
int main() 
{ 
  printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
  return foo(); 
}


/* main.c */
#include <stdio.h>

extern int foo(void);
int main() 
{ 
  printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
  return foo(); 
}


$ gcc -fPIC -pie -o pie.so pie.c -Wl,-E
$ gcc main.c ./pie.so


$ ./pie.so
in main pie.c:9
in foo pie.c:4
$ ./a.out
in main main.c:6
in foo pie.c:4
$

는 P.S. glibc를 합니다.write(3)다른 콜처가 없기 때문에(이미 최저 레벨입니다).이것은 실행할 수 있는 것과는 무관합니다.libc.so.6.

이 가지고합니다.ld -edlopen()다이내믹 링커의 나머지 부분을 검색하여 부트스트랩하는 함수 패밀리.이 부분은 .dlopen() 또는 가 있는 ( 「」, 「」 인터페이스를 합니다).mmap()가 하고과 마찬가지로.libc도 하고 있습니다.

아, 네, 네, 그렇습니다. 소스 glibc 소스)를만 해도ld-linux작업 규모를 평가하기에 충분한 소스 코드).휴대성의 악몽이 될 수도 있습니다.가 Linux를 에는 큰 수 .ld-linuxOpenSolaris, FreeBSD 등에서 링크가 어떻게 이루어졌는지(모르겠습니다).

언급URL : https://stackoverflow.com/questions/1449987/building-a-so-that-is-also-an-executable

반응형