디버거와 gdb 간단 실습

Hansu Park·2023년 9월 8일

디버거

디버거에 대해 알아보자.

우리가 보통 IDE를 통해 코딩을 하게 되면 실행 옆에 있는 벌레 모양 아이콘을 만나게된다. 이는 디버깅을 위한 아이콘이다. 디버깅은 실행과는 다르게 오류를 찾아 제거하기 위해 존재하며, 프로그램을 중단점에서 중지시키고 데이터 상태, 콜 스택 상태 등을 확인할 수 있고 표현식을 평가할 수 있다.

실행과 비교하였을 때, 최적화가 진행되지 않고 모니터링을 위한 오버헤드가 생겨 성능은 떨어진다.

디버거의 종류

C/C++계열의 디버거로는 GNU* 프로젝트의 디버거인 GDB가 있고, Java 계열의 디버거로는 JPDA가 있다. Intellij, CLion 등의 IDE에서도 이러한 디버거들을 내장하여 디버깅 기능을 제공하고 있다.

*GNU: 자유 소프트웨어 프로젝트로 GCC 등을 포함하고 있다.

원격 디버깅

보통 어플리케이션을 개발하여 배포하게 된다면, 로컬 환경이 아닌 리눅스 기반 클라우드 환경에서 어플리케이션을 실행한다. 운영체제가 다름에 따라 다른 버그가 발생할 수 있고, 이러한 상황(원격에 있는 코드)에 디버깅을 하기 위해 Intellij, CLion 등의 IDE에서는 원격 디버깅을 지원한다. 자세한 내용은 링크를 참고하자.

예제

gdb를 활용하여, 실제 흐름에 존재하지 않던 코드를 실행해보자.

#include <stdio.h>

void dont_use_sh()
{
    system("/bin/sh");
}

void should_use_bash()
{
    system("/bin/bash");
}

int main(int argc, char **argv)
{
    void (*func)();

    func = should_use_bash;
    func();

    return 0;
}

위 코드는 func에 should_use_bash를 할당한 후 실행시켜 /bin/bash 라는 명령어를 실행시키는 코드이다. (system()이 명령어를 실행하는 역할을 한다.)

이를 디버거를 활용하여 dont_use_sh를 대신 할당하여 실행하도록 하여보자.

사용할 gdb 명령어 정리

  • b : 중단점 설정
  • r : 프로그램 실행
  • n : 다음 코드로 이동
  • display : 변수 상태 출력
  • info address: 주소 출력

예상 결과

sh를 실행했을 경우 ps -ef를 통해 확인되는 프로세스 목록이 다를 것이다.

초기 상태

기존 코드를 실행시켰을 때 상태

(/bin/bash가 한 번 더 실행된 모습이다.)

동작과정

  1. 코드를 빌드하였다.

  2. gdb실행 후 main에 중단점을 걸었다.

  3. r을 눌러 실행한 후 func 호출 직전까지 이동하였다.

  4. 선언된 함수의 주소를 확인하였다.

  5. set 명령어를 통해 func에 할당된 주소를 shoud_use_bash에서 dont_use_sh로 변경하였다.

  6. 터미널이 바뀜을 확인하였고, ps -ef를 통해 확실히 확인하였다. (/bin/sh가 실행 중!)

0개의 댓글