Page tree
Skip to end of metadata
Go to start of metadata

Excuse the ads! We need some help to keep our site up.

List

PIE(Position Independent Executable)

Description

  • PIE(Position Independent Executable)는 위치 독립 코드로 이루어진 실행 가능한 바이너리 입니다.

Example

Source code

#include <stdio.h>
 
char *gBuf = "Lazenca.0x0";
 
void lazenca() {
	printf("Lazenca.0x1\n");
}
 
void main(){
	printf("[.data]    : %p\n",gBuf);
	printf("[Function] : %p\n",lazenca);
}

Build PIE file

lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ gcc -o NoPIE PIE.c 
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ gcc -fPIE -pie -o PIE PIE.c 

Check the protection techniques of binary files.

checksec.sh

  • Checksec.sh에서 다음과 같은 결과를 출력합니다.
    • NoPIE : "No PIE"

    • PIE : "PIE enabled"
checksec.sh --file NoPIE
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ checksec.sh --file NoPIE
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   NoPIE
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ 
checksec.sh --file PIE
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ checksec.sh --file PIE
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX enabled    PIE enabled     No RPATH   No RUNPATH   PIE
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$

Compare PIE and NonPIE.

Address

  • 다음은 PIE가 적용되지 않은 파일입니다.
    • PIE가 적용되지 않았기 때문에 프로그램을 실행할 때마다 전역 변수와 사용자 정의 함수의 주소가 변경되지 않습니다.
NoPIE
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ ./NoPIE 
[.data]    : 0x400634
[Function] : 0x400566
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ ./NoPIE 
[.data]    : 0x400634
[Function] : 0x400566
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ ./NoPIE 
[.data]    : 0x400634
[Function] : 0x400566
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$
  • 다음은 PIE가 적용된 파일입니다.
    • PIE가 적용되었기 때문에 프로그램을 실행할 때마다 전역 변수와 사용자 정의 함수의 주소가 매번 달라집니다.
PIE
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ ./PIE 
[.data]    : 0x563d12821884
[Function] : 0x563d128217b0
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ ./PIE 
[.data]    : 0x55cbbaae3884
[Function] : 0x55cbbaae37b0
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ ./PIE 
[.data]    : 0x55f7c9a1e884
[Function] : 0x55f7c9a1e7b0
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$

Code

  • 다음과 같이 PIE가 적용된 바이너리와 적용되지 않은 바이너리의 차이점을 확인할 수 있습니다.
    • PIE가 적용되지 않은 바이너리의 경우 코드 영역의 값이 고정된 주소값 입니다.
    • 하지만 PIE가 적용된 바이너리의 경우 코드 영역의 값이 고정된 주소 값이 아닌 offset 값입니다.
      • 해당 offset 값을 이용해 할당된 메모리 영역에 동적으로 위치 할 수 있습니다.
    • 다음과 같이 동적으로 사용됩니다.
      • 할당받은 메모리 영역(0x555555554000) + .text 영역의 main함수 코드의 offset 값(0x7c3) = main 함수의 시작 주소(0x00005555555547c3)
NoPIE
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ gdb -q ./NoPIE
Reading symbols from ./NoPIE...(no debugging symbols found)...done.
gdb-peda$ disassemble main
Dump of assembler code for function main:
   0x0000000000400577 <+0>:	push   rbp
   0x0000000000400578 <+1>:	mov    rbp,rsp
   0x000000000040057b <+4>:	mov    rax,QWORD PTR [rip+0x200abe]        # 0x601040 <gBuf>
   0x0000000000400582 <+11>:	mov    rsi,rax
   0x0000000000400585 <+14>:	mov    edi,0x40064c
   0x000000000040058a <+19>:	mov    eax,0x0
   0x000000000040058f <+24>:	call   0x400440 <printf@plt>
   0x0000000000400594 <+29>:	mov    esi,0x400566
   0x0000000000400599 <+34>:	mov    edi,0x40065d
   0x000000000040059e <+39>:	mov    eax,0x0
   0x00000000004005a3 <+44>:	call   0x400440 <printf@plt>
   0x00000000004005a8 <+49>:	nop
   0x00000000004005a9 <+50>:	pop    rbp
   0x00000000004005aa <+51>:	ret    
End of assembler dump.
gdb-peda$
PIE
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ gdb -q ./PIE
Reading symbols from ./PIE...(no debugging symbols found)...done.
gdb-peda$ disassemble main
Dump of assembler code for function main:
   0x00000000000007c3 <+0>:	push   rbp
   0x00000000000007c4 <+1>:	mov    rbp,rsp
   0x00000000000007c7 <+4>:	mov    rax,QWORD PTR [rip+0x200872]        # 0x201040 <gBuf>
   0x00000000000007ce <+11>:	mov    rsi,rax
   0x00000000000007d1 <+14>:	lea    rdi,[rip+0xc4]        # 0x89c
   0x00000000000007d8 <+21>:	mov    eax,0x0
   0x00000000000007dd <+26>:	call   0x650 <printf@plt>
   0x00000000000007e2 <+31>:	lea    rsi,[rip+0xffffffffffffffc7]        # 0x7b0 <lazenca>
   0x00000000000007e9 <+38>:	lea    rdi,[rip+0xbd]        # 0x8ad
   0x00000000000007f0 <+45>:	mov    eax,0x0
   0x00000000000007f5 <+50>:	call   0x650 <printf@plt>
   0x00000000000007fa <+55>:	nop
   0x00000000000007fb <+56>:	pop    rbp
   0x00000000000007fc <+57>:	ret    
End of assembler dump.
gdb-peda$ 

How to detect PIE in the "Checksec.sh" file

Binary

  • 다음과 같은 방법으로 바이너리의 Canary 설정여부를 확인합니다.
    • 'readelf' 명령어를 이용해 해당 파일의 ELF Header 정보를 가져와 PIE 설졍여부를 확인합니다.
    • "Type:"의 값이 "EXEC"일 경우 PIE가 적용되지 않았다고 판단합니다.
    • "Type:"의 값이 "DYN"일 경우 PIE가 적용되었을 가능성이 있다고 판단합니다.
      • 'readelf' 명령어를 이용해 해당 파일의 "Dynamic section" 정보를 가져와 "DEBUG" section이 있으면 PIE가 적용되었다고 판단합니다.
Checksec.sh - line 170
  # check for PIE support
  if readelf -h $1 2>/dev/null | grep -q 'Type:[[:space:]]*EXEC'; then
    echo -n -e '\033[31mNo PIE       \033[m   '
  elif readelf -h $1 2>/dev/null | grep -q 'Type:[[:space:]]*DYN'; then
    if readelf -d $1 2>/dev/null | grep -q '(DEBUG)'; then
      echo -n -e '\033[32mPIE enabled  \033[m   '
    else   
      echo -n -e '\033[33mDSO          \033[m   '
    fi
  else
    echo -n -e '\033[33mNot an ELF file\033[m   '
  fi 
NoPIE
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ readelf -h ./NoPIE |grep 'Type:[[:space:]]*EXEC'
  Type:                              EXEC (Executable file)
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ 
PIE
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ readelf -h ./PIE |grep 'Type:[[:space:]]*DYN'
  Type:                              DYN (Shared object file)
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ readelf -d ./PIE |grep '(DEBUG)'
 0x0000000000000015 (DEBUG)              0x0
lazenca0x0@ubuntu:~/Documents/Definition/protection/PIE$ 

Process

  • 다음과 같은 방법으로 프로세서의 Canary 설정여부를 확인합니다.
    • Binary의 확인 방식과 비슷하며, 전달되는 파일의 경로가 다음과 같이 다릅니다.
      • Ex) /proc/<PID>/exe
Checksec.sh - line 256
  # check for PIE support
  if readelf -h $1/exe 2>/dev/null | grep -q 'Type:[[:space:]]*EXEC'; then
    echo -n -e '\033[31mNo PIE               \033[m   '
  elif readelf -h $1/exe 2>/dev/null | grep -q 'Type:[[:space:]]*DYN'; then
    if readelf -d $1/exe 2>/dev/null | grep -q '(DEBUG)'; then
      echo -n -e '\033[32mPIE enabled          \033[m   '
    else   
      echo -n -e '\033[33mDynamic Shared Object\033[m   '
    fi
  else
    echo -n -e '\033[33mNot an ELF file      \033[m   '
  fi

Related information

  • N/a