이번에는 Break Point에 대해서 공부한 내용을 기록하였다.
프로그램 실행 중에 일시적으로 멈추는 지점을 얘기한다. 보통 프로그램을 디버깅할 때 사용하며 중단하는 방식에는 2가지 (Software breakpoint, Hardware Breakpoint)가 있다.
software breakpointㄴ는 가장 흔하게 사용되는 방식이다. 디버거가 실행 가능한 코드 자체를 일시적으로 수정하여 작동한다.
- 디버거는 브레이크포인트를 설정한 명령어의 opcode를 백업
- 해당 메모리 주소의 코드를 특정 명령어
(INT3 = 0xCC)로 대체- CPU가 대체된
0xCC명령어를 실행하면 소프트웨어 인터럽트가 발생,운영체제를 거쳐 디버거에게 제어권이 넘어감.- 디버거는 프로그램을 중지시키고 개발자에게 현재 상태(레지스터, 메모리, 변수 등)를 보여줌.
- 계속 실행 시 디버거는 우너래 코드를 복구
주요 특징
먼저 간단한 C 코드를 작성해 보았다.

출력 중간에 assembly 코드를 삽입해 보았다.
OllyDbg 프로그램을 이용하여 디버깅 하였다.
먼저 직접 Breakpoint를 설정하게 되면

이렇게 빨간색으로 표시가 되며 실행을 하게 되면 해당 위치에서 RIP가 멈추게 된다. 프로그램에서는 직접 보이지 않지만 Opcode를 CC로 변경하여 멈추고 다시 실행하면 복원하게 된다.
이번에는 코드에서 추가한 Breakpoint에서 멈추는지 확인해 보자
아까 멈춘 부분에서 다시 실행을 하면

해당 위치에서 멈추게 된다. 멈춘 곳 바로 위에는 INT3가 존재하는 것을 볼 수 있다. INT3가 위치한 곳에서 바로 멈추지 않은 이유는 정확히는 알지 못하지만, OllyDbg에서 인터럽트를 처리하는 방식때문으로 예상한다.
디버거에서 설정한 Breakpoint의 경우 Opcode를 덮어쓰기 하였기 때문에, 복원 후 다시 해당 위치에서 실행해야 한다.
소프트웨어로 추가한 경우에는 덮어쓰기를 하지 않았기 때문에, 멈춘 것에서 다시 실행할 필요가 없기 때문에, RIP를 인터럽트된 부분에서 증가한 것이라 생각한다.
이번에는 hardware breakpoint에 대해서 알아보자. hardware breakpoint는 CPU 레벨에서 설정하는 breakpoint로, 디버그 레지스터는 특별한 레지스터가가 제공되며, 이 레지스터에 직접 조건을 거는 방식으로 breakpoint를 설정할 수 있다.
이 방식은 opcode를 수정하지 않기 때문에 바이너리의 변화가 없다. 그렇기 때문에 체크섬을 구하는 리버싱 방지 기술로는 차단할 수 없다. 또 여러 가지 조건의 breakpoint를 만들어낼 수 있다.
이러한 편리한 기능을 제공하지만, 단점도 존재한다. DR 레지스터 자체가 8개밖에 없고 (DR0~DR7) breakpoint 용도로 사용 가능한 레지스터는 DR0 ~ DR3 4개뿐이다. 따라서 조건을 걸 수 있는 개수는 스레드 하나당 최대 4개이며, 최대 크기도 4바이트에 불과하다.
위에서 사용한 코드를 동일하게 사용하였다.

C 코드에서 printf를 3번 호출하였다. 자세히 보면 main 함수 내부에 call문이 3개가 존재하는데, Hello를 출력하는 call문만 다른 것을 확인할 수 있다. 이는
World, Finished 출력은 new line이 있어 puts를 사용한 것을 볼 수 있다. puts 명령어에 hardware breakpoint를 걸어보자
call문을 누르고 enter를 누르면
해당 위치로 이동하고 여기서 한 번더 이동하면

실제 함수가 동작하는 곳으로 이동하게 된다. 여기서 처음 함수 에필로그 부분에 우클릭 하여

breakpoint 설정이 가능하다.

앞서 설명한 조건을 지정할 수 있다. 이렇게 지정하여 실행하게 되면

해당 위치에서 2번 멈추는 것을 확인할 수 있다.
이번에는 실제 hardware breakpoint를 걸었을 때, 레지스터값을 출력해 보았다.

사용한 코드이며 Gemini의 도움을 받아 작성하였다. main함수에 bp를 걸었는데 OllyDbg에서 main을 찾기 쉽게 하려고 추가하였다.
hardware breakpoint를 사용하지 않고 실행하게 되면

이렇게 뜨게 된다. 이번에는 DumpDebugRegisters 함수를 호출하기 전에 hardware breakpoint를 걸어보자

C 코드 상에서 n = 100부분에 breakpoint를 걸었고, 실행해 보면

위 사진의 주소가 DR0에 저장돼 있는 것을 확인할 수 있다.
하드웨어 브레이크와 그 종류 2가지를 알아 보았다. 하드웨어 브레이크는 코드를 분석하기 위해 주로 사용한다. 그렇기 때문에 공격자나 방어자는 브레이크포인터 사용 여부를 탐지를 하기도 한다.
소프트웨어 브레이크포인트의 경우 0xCC를 탐지하며,
하드웨어 브레이크포인트의 경우 위와 같이 레지스터의 값을 이용하여 탐지할 수 있다.