>운영 및 유지보수 >안전 >GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

WBOY
WBOY앞으로
2023-05-14 12:13:141449검색

0x01 서문

운영 체제는 일반적으로 프로그램 작동 효율성을 높이기 위해 동적 연결을 사용합니다. 동적 연결의 경우 링크 라이브러리의 모든 함수는 프로그램이 로드될 때 함께 로드되지 않으며, 대신 프로그램이 실행될 때 요청 시 로드되지 않습니다. 프로그램이 삶에로드됩니다. 이 디자인은 프로그램 작동의 부드러움을 향상시키고 메모리 공간을 줄일 수 있습니다. 또한 최신 운영 체제에서는 코드 세그먼트 수정이 허용되지 않고 데이터 세그먼트만 수정이 허용되므로 GOT 테이블과 PLT 테이블이 탄생했습니다.

0x02 GOT 테이블과 PLT 테이블의 예비 탐색

예제를 간단히 살펴보겠습니다

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

scanf@plt

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

을 따라가면 세 줄의 코드가 있음을 알 수 있습니다.

jmp 一个地址
push 一个值到栈里面
jmp 一个地址

함수 이름만 보세요. 이것이 scanf 함수의 plt 테이블이라는 것을 알면 plt가 무엇에 사용되는지 서두르지 말고 먼저 첫 번째 jmp가 무엇으로 점프하는지 살펴보겠습니다. .

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

사실 이것은 plt 테이블에 해당하는 함수의 got 테이블인데, 0x201020의 값이 push 명령의 주소이고 그 외의 곳은 0이라는 것을 알 수 있습니다. 이때 우리는 묻고 싶은 질문:

1. 테이블과 plt 테이블이 있는데 요점이 무엇인가요? 왜 여기저기 뛰어다니나요?

2. got 테이블과 plt 테이블 사이에는 어떤 연관성이 있나요?

질문이 있는 경우 먼저 답변을 읽고 확인하세요. 운영 체제는 일반적으로 프로그램 작동 효율성을 높이기 위해 동적 연결을 사용하며 코드 세그먼트에 다시 쓸 수 없다는 점을 이해해야 합니다.

위의 예에서 우리는 scanf —> scanf의 plt 테이블 —> scanf의 got 테이블을 호출하는 것을 볼 수 있습니다. 현재로서는 got 테이블의 값에 대해 신경 쓰지 않습니다. got 테이블에서 얻을 수 있다는 생각. 프로그램을 로드하고 실행하기 위한 실제 scanf 함수를 찾으세요.

그렇게 생각하면 이는 간접 주소 지정 프로세스가 됩니다

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

데이터 세그먼트를 얻는 작은 코드 조각을 호출하여 PLT(Procedure Linkage Table) 프로세스 연결 테이블 저장소라는 함수 주소를 저장합니다. 데이터 세그먼트 함수 주소의 GOT(Global Offset Table) 글로벌 오프셋 테이블이라고 합니다. 그런 생각을 한 후에 우리는 내부의 세부 사항을 주의 깊게 이해할 수 있습니다.

0x03 GOT 테이블과 PLT 테이블을 다시 살펴보겠습니다

이러한 일반적인 프로세스를 이해한 후, 이를 어떻게 호출하는지 단계별로 살펴보겠습니다. 해결해야 할 몇 가지 의문점이 있습니다.

1. got 테이블에 대해 scanf 함수의 실제 주소를 알고 계십니까?

2. got 테이블과 plt 테이블의 구조는 무엇인가요? 먼저 plt 테이블을 살펴보겠습니다. scanf@plt 테이블의 세 번째 코드 줄은 jmp의 주소입니다. 실제로 이것이 프로그램 PLT 테이블의 시작 부분입니다. (plt[0]) 그렇습니다.

push got[1]
jmp **got[2]

뒤에는 각 기능에 대한 plt 테이블이 옵니다. 이번에는 이 신비한 GOT 테이블을 다시 한번 살펴보겠습니다GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

이 두 가지(printf, scanf 함수의 push 0xn 주소, 해당 plt 테이블의 두 번째 코드 주소)를 제외하고, 다른 got[ 1], got[2]는 0입니다. 그러면 plt 테이블이 0인 got 테이블을 가리키는 것은 무엇입니까? 우리는 조건에 뒤떨어져 있기 때문에 최신 운영 체제에서는 코드 세그먼트 수정을 허용하지 않으며, 쓰기 저장되는 데이터 세그먼트만 허용합니다. 보다 전문적인 이름은 런타임 재배치입니다. 프로그램을 실행하면 이전 주소와 저장된 내용이 바뀌기 전에 링크 중 내용을 저장하고 비교해 보도록 하겠습니다

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

② 寻找printf的plt表
③ jmp到plt[0]
④ jmp got[2] -> 0x00000
⑤⑥ printf和scanf的got[3] got[4] -> plt[1] plt[2]的第二条代码的地址
⑦⑧ 证实上面一点

프로그램을 실행하고 scanf

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

It에서 중단점을 설정해 보세요. 이때 scanf@plt 테이블이 변경된 것을 확인할 수 있습니다. got[4]

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

아직 push 0x1의 주소이고 여기까지 디버깅을 계속하면 got[4] 주소가 있습니다. 수정되었습니다

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

이제 묻고 싶은데 여기가 어디죠?

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법그런 다음 got[2]에서 <_dl_fixup>을 호출하여 got[3]의 주소를 수정합니다.

那么问题就来了,刚才got[2]处不是0吗,怎么现在又是这个(_dl_runtime_resolve)?这就是运行时重定位。

其实got表的前三项是:

got[0]:address of .dynamic section 也就是本ELF动态段(.dynamic段)的装载地址
got[1]:address of link_map object( 编译时填充0)也就是本ELF的link_map数据结构描述符地址,作用:link_map结构,结合.rel.plt段的偏移量,才能真正找到该elf的.rel.plt
got[2]:address of _dl_runtime_resolve function (编译时填充为0) 也就是_dl_runtime_resolve函数的地址,来得到真正的函数地址,回写到对应的got表位置中。

那么此刻,got表怎么知道scanf函数的真实地址?

这个问题已经解决了。我们可以看一下其中的装载过程:

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

GOT 테이블과 PLT 테이블을 깊이 이해하는 방법

说到这个,可以看到在_dl_runtimw_resolve之前和之后,会将真正的函数地址,也就是glibc运行库中的函数的地址,回写到代码段,就是got[n](n>=3)中。也就是说在函数第一次调用时,才通过连接器动态解析并加载到.got.plt中,而这个过程称之为延时加载或者惰性加载。

到这里,也要接近尾声了,当第二次调用同一个函数的时候,就不会与第一次一样那么麻烦了,因为got[n]中已经有了真实地址,直接jmp该地址即可。

위 내용은 GOT 테이블과 PLT 테이블을 깊이 이해하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제