본문 바로가기

My Study/Reversing

예외처리를 사용한 안티리버싱

저번 글에서 예외처리에 대한 내용을 설명했었습니다. 
이번에는 예외처리를 사용한 안티리버싱 기법에 대해서 알아보겠습니다.

보통 프로그램을 분석할 때는 디버거에 연결 시켜서 분석을 하게 됩니다. 프로그램에서 예외가 났을 경우 해당 예외는 디버거에서 처리하게 되어 있습니다. 즉, 개발자가 만들어놓은 예외루틴으로 가지 않게 된다는 것입니다.

제가 만들어 놓은 코드를 보시겠습니다.

빨간색 네모친 부분이 개발자가 만들어 놓은 예외루틴입니다. 예외발생 옵션이 EXCEPTION_EXECUTE_HANDLER이므로 예외가 발생하면 예외루틴으로 바로 넘어오게 됩니다.
 
파일을 정상 실행 시켜보겠습니다.

int 3에서 EXCEPTION_BREAKPOINT예외가 발생했고 예외루틴으로 넘어왔습니다. 정상적인 실행결과 입니다.

이제 디버거모드로 실행시켜보겠습니다.

__try루틴에서 예외를 발생시키고 있음에도 불구하고 예외처리 루틴으로 들어오지 않게 됩니다.
디버거 자체적으로 예외처리를 해버린 것입니다.
하지만 위같은 경우는 예외를 INT 3으로 발생시켰습니다. 
디버거는 기본적으로 INT 3이 발생하면 중단점으로 생각하고 예외처리를 하지 않습니다.
아래 코드를 보시면 이해가 가실 것입니다.

어셈블리 코드로 보시겠습니다.

INT 3에서 예외를 발생시키지만 그 아래 JMP명령어로 인해 개발자가 만들어 놓은 예외처리 루틴은 뛰어넘게 됩니다.

이러한 방법을 사용해 디버거에서 실행 중인지 정상 작동 중인지를 판단할 수 있는 것입니다.

그러면 개발자가 만들어 놓은 예외처리 루틴으로 가는 방법은 없냐??? 그건 아닙니다. 디버거에서 개발자가 만들어 놓은 예외처리 루틴으로 가게 해주면 됩니다. INT 3 명령어를 실행 후 SEH chain을 봐보겠습니다.

주소를 보니 개발자가 만들어 놓은 예외처리 루틴이 보입니다. 그러면 해당 주소에 브포를 걸고
Shift + F9를 누르시면 개발자가 만들어 놓은 예외처리 루틴으로 들어올 수 있습니다.

예외처리 루틴을 따라서 들어오게 되면 위와 같이 코드가 존재하게 됩니다.
그러면 ECX에 들어있는 주소로 가보겠습니다.

성공입니다. 개발자가 만들어 놓은 예외처리 루틴으로 들어왔습니다.

이렇게 개발자가 강제적으로 예외를 발생시키는 코드를 넣어두고 예외처리하는 곳에 원하는 코드를 넣어두게 되면
리버서나 크래커는 디버거로 분석 중에는 개발자가 만들어 놓은 예외처리 코드로 못들어가도록 하는 효과입니다.

이러한 안티리버싱 기법을 우회하려면 수시로 SEH chain을 체크를 하는 방법이 있을 수 있겠습니다.