0. 자세한 설명은 Reference에 적혀 있는 곳에 있으니 들어가서 확인하기 바람.

 

 

1. Return to dl resolve

 

 Lazy binding을 이용해 필요한 함수를 호출하는 기법임.

 

 따라서 Lazy binding을 이용해 동적라이브러리를 사용하는 바이너리에서 해당 기법을 사용할 수 있음.

 

 

 

2. Flow

 

 함수호출 시 해당 함수의 plt로 넘어가게 되는데

 

 plt  _dl_runtime_resolve() → _dl_fixup() → _dl_lookup_symbol_x() → do_lookup_x()→ check_match() 순으로 호출됨.

 

 

3. 알아야될 점

 

 기타 자세한 사항은 위에도 말했다시피 다른 곳에서도 제대로 잘 나와있으므로 생략.

 

 Codegate 2015 yocto를 풀면서 느낀 점은 

 

 plt를 호출 할때 stack frame을 대강

 이렇게 만들어준다.

 

 중요한 부분은 reloc_offset과 Elf32_Rel 구조체, Elf32_Sym 구조체의 관계이다.

 

 reloc_offset은 plt에 들어가서 lazy binding이 되어있지 않을 시에 push value를 해주고 dl_resolve를 실행하게 되는데

 

 이때 value가 reloc_offset이다. 

 

 reloc_offset의 값은 .rel.plt header에서 호출하려는 함수의 Elf32_Rel의 offset을 나타내기 때문에

 

 addr_.rel.plt + reloc_offset == 호출하려는 함수의 Elf32_Rel이 된다.

 

 이렇게 Elf32_Rel을 찾으면 해당 구조체의 Elf32_Addr은 함수의 got주소, Elf32_Word중 상위바이트에 Elf32_Sym의 주소가  저장되어 있다.

 

 (Elf32_Word >> 8) * 16을 한 값은 .dynsym header에서 호출하려는 함수의 Elf32_Sym의 offset을 나타낸다.

 

 따라서 addr_.dynsym + (Elf32_Word >> 8) * 16 == 호출하려는 함수의 Elf32_Sym이 된다.

 

 이렇게 Elf32_Sym 구조체를 찾으면 첫 4바이트가 .dynstr에서의 offset이 돼서 함수의 이름이 저장되어 있다.

 

 이렇게 구한 함수의 값은 hashing을 한 후 libc에서 각 함수에 대한 해쉬값과 비교를 하여 일치하면 함수의 주소를 할당해준다.

 

 

 해당 기법은 reloc_offset을 조작하는 것부터 시작해서 Fake Elf32_Rel와 Fake Elf32_Sym 구조체를 만든다.

 

 또 system이나 exec 계열의 함수의 이름과 '/bin/sh'과 같이 필요한 인자들도 stackframe에 저장한다.

 

 이렇게 호출하려는 함수 string을 최종적으로 Fake Elf32_Sym의 첫 4바이트(st_name)가 가리키게 하면 되는 기법이다. 

 

 

 요약하면

 

 reloc_offset으로 Elf32_Rel을 찾고

 

 Elf32_Rel로 Elf32_Sym을 찾고

 

 Elf32_Sym으로 function 문자열을 찾아내는 것을 이용해

 

 호출하고 싶은 함수의 문자열을 stack frame에 넣어서

 

 fake 구조체를 만들고 최종적으로 Elf32_Sym->st_name에 호출하고 싶은 함수의 문자열을 가리키도록 하면 

 

 GAME SET.

 

 

 

 

 

[Reference]

https://www.lazenca.net/display/TEC/01.Return-to-dl-resolve+-+x86

+ Recent posts