Lobsters

Why do we need ud2 when int 6 is right there?

int 6을 쓸 수 있는데 왜 ud2가 필요할까요?

x86의 ud2와 int 6은 모두 2바이트지만 예외 처리 방식이 다릅니다. ud2는 잘못된 명령어를 가리키는 fault를 일으키지만 int 6은 다음 명령어 주소를 보고하는 trap이며, 사용자 모드에서는 int 6 호출 권한도 차단됩니다.

에디터 노트

ud2와 int 6의 차이는 명령어 길이가 아니라 예외 프레임에 기록되는 주소와 실행 권한에 있습니다. 특히 fault 처리기가 문제를 일으킨 명령어를 검사해 에뮬레이션할 수 있다는 설명은 int 6으로 대체할 때 생기는 혼선을 구체적으로 보여줍니다. 글은 운영체제가 사용자 모드의 int 6 호출을 막는다고 설명하지만, 운영체제별 예외 처리 구현이나 권한 설정 차이는 다루지 않습니다.

AI 요약

ud2는 아키텍처에서 정의하지 않은 명령어로, 실행하면 잘못된 명령어 예외인 #UD를 발생시킵니다. 같은 2바이트 길이의 int 6을 대신 쓰면 안 되는 이유는 둘이 예외 처리기에 전달하는 명령어 주소가 다르기 때문입니다.

Fault와 trap의 차이

fault는 문제가 생긴 명령어의 주소를 예외 처리기에 전달합니다. 운영체제가 문제를 고친 뒤 해당 명령어를 다시 실행할 수 있다는 전제를 둡니다. 페이지 폴트가 나면 메모리를 불러온 뒤 재시도하는 경우가 그 예입니다. 반면 trap은 이미 끝난 연산을 알리며 다음 명령어의 주소를 전달합니다. 소프트웨어 인터럽트인 int 6도 trap이므로 int 6 다음 명령어 주소가 저장됩니다.

int 6으로 #UD를 흉내 낼 수 없는 이유

#UD 처리기는 예외 프레임의 명령어 주소가 잘못된 명령어를 가리킨다고 예상합니다. 하지만 int 6을 호출하면 다음 명령어 주소가 들어갑니다. 처리기가 그 주소의 명령어를 확인하면 정상 명령어인데도 #UD가 발생한 것으로 보여 혼란이 생깁니다. 처리기는 오래된 프로세서에 없는 명령어를 에뮬레이트할 때도 fault가 난 명령어를 확인할 수 있습니다.

보호 모드에서는 인터럽트 디스크립터 테이블이 각 인터럽트를 명시적으로 호출할 수 있는 권한 수준도 정합니다. 운영체제는 사용자 모드 프로그램이 int 6을 호출하지 못하게 막아 이런 혼선을 방지합니다. 따라서 #UD를 발생시키려면 실제로 정의되지 않은 명령어를 실행해야 합니다.

원문: Microsoft Old New Thing / 번역·요약: Trawling