elf 형식의 바이너리 실행 파일을 malloc을 통해 로드 한후 실행시키기
간단한 라이브러리를 쓰는 파일 하나를 만듭니다.
########## a.c ############
#include
int main(){
printf("test!\n");
return 0;
}
###########################
그리고 컴파일 합니다. gcc a.c -> 그 결과물은 물론 a.out 이겠지요.
물론 a.out을 실행시키면 잘 됩니다. test!
다음은 이 파일을 로드 하는 로더 파일을 만듭니다.
########### load.c #############
fout = fopen("a.out","rb");
unsigned char *c = (unsigned char*)mmap(NULL, file_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
fread(ptr, 1, file_size, fout);
memcpy(c, ptr, 11546);
이제 C에는 a.out의 내용이 담겨져 있습니다.
a.out의 헤더를 분석해서 엔트리 포인트를 구합니다. 메인 함수의 위치를 구하여 c의 위치부터 off_set을 더합니다.
main_fun = (int (*)(void))(c + (hdr->e_entry) - 0x8048000 + 0xB0);
여기서 0x8048000은 가장주소의 시작이고 hdr->e_entry는 start의 위치입니다. 그리고 0xB0는 entry : start 부터 main 까지의 off_set 입니다. 따라서 main_fun 는 현재 정확히 main을 가르킵니다.
main_fun()으로 실행을 시키면 세그멘테이션 오류가 발생합니다. 당연히 위의 계산이 틀린듯 보이지만 그렇지 않습니다.
실제 a.out에서 printf() 라인만 삭제하고(다이나믹 링킹을 사용하지 않는다면) return 30; 으로 고친다음에
컴파일 새로 해서
int c = main_fun();
printf("%d",c);
해보면 30이 찍힙니다. 즉 실행이 된다는겁니다.
그래서 elf 를 분석해 보았습니다.
main에서 printf를 부르면 plt로 가고 plt에서 GOT+4와 GOT+8를 실행시키는데 이 GOT+4와 GOT+8은
심볼을 해석하는 코드와 해당 루틴에 대한 위치가 들어있다고 합니다. 그런데 이 정보는 로드 타임에 다이나믹 링커에 의해
값이 정해지기 때문에 malloc에 의해서는 이 값을 바꿀수가 없습니다. 그럼 일단 malloc으로 데이타를 로드 한 다음
그 위치까지 가서 binary rewriting을 해야 한다는 결론에 이르렀는데 .. 그 다음이 문제인것이..
다이나믹 링커에 대한 정보가 너무 부족해서 어떻게 그 GOT+4 와 GOT+8을 쓰는지도 잘 모르겠고
실제 이런 방식이 맞는지도 의심이 듭니다.
가장 원천적으로는 이런 malloc으로 표준 C 라이브러릴 쓰는 stub 코드의 실행이 가능한지도 의심이 듭니다.
저와 비슷한 고민을 하신분들이 있으시면 도움을 받았으면 합니다!
끝까지 읽어주셔셔 감사합니다.
아래 내용을
아래 내용을 참조하시기 바랍니다.
http://www.linuxforums.org/misc/understanding_elf_using_readelf_and_objdump_3.html
dynamic linking을 사용하고 있을 때는 dynamic linker가 수행하는 일을 로딩한 프로그램에서 수행해 줘야 합니다. GOT에 주소가 초기화 되어 있지 않을 것이므로 참조하는 주소 부분에 현재의 호출 함수에 대한 주소를 입력해 줘야 제대로 동작합니다. 예를 들어 printf라고 한다면 현재의 프로그램에서 printf 함수의 주소를 강제로 GOT 영역에 넣어주면 됩니다.
댓글 달기