Notice
Recent Posts
Recent Comments
Link
- lumenFC 축구 동호회
- 마샤블
- 웍스프레소
- 소셜@나눔<소셜미디어나눔연구소>
- 리버스코어
- LAIN
- LAIN 이사한 블로그
- TeamCR@K
- Sunnyday
- 보안 걱정이
- 리버싱 학습
- securityfirst_jo
- Practical Security Blog
- 세상, 그 유쾌한 전장
- 악성코드관련블로그
- Back to the Mac
- 패킷분석입문
- PacketInside / 네트워크 패킷 분석 블로그
- 침해사고분석 :: 네이버 블로그
- 소프트웨어 기술자경력관리시스템
- JK.Moon
- 자바 온라인학습
- Ezbeat의 도서관
- Dreams of a Final Journey
- IT eBooks - Free Download - Bi…
- Index of /madchat/coding/rever…
- Security Insight
- Reversing war game
- 고길고기
- clamav
- zerowine
- FORENSIC-PROOOF
- jquery 예제
- 조대협의블로그
- 국가과학기술인력개발원 교육포털 사이트
- 빅데이터, splunk
- 지식을 연주하는 사람
- malware analysis system
- 건국대토익스피킹
- 소프트웨어개발 및 협업도구
kisoo
SEH(Structured Exception Handler) 활용하기 본문
01.About Programming /12.Default knowledge
SEH(Structured Exception Handler) 활용하기
JamesK78 2009. 5. 11. 13:09C언어를 사용하다 보면 예외처리 부분이 상당히 미흡하다는 것을 알 수 있습니다. C++은 언어 차원에서 try, catch라는 예외처리 문법을 제공해 주고 있습니다.
C언어는 C 표준 라이브러리에 있는 setjmp(), longjmp() 함수를 사용하여 예외처리를 할 수 있지만 상당히 구식이라 직관적이지도 못하고 사용하기도 불편합니다.
그래서 C언어에서는 Structured Exception Handler(SEH)라는 예외처리 방식을 사용할 수 있습니다. SEH는 Microsoft Visual C++ 컴파일러 차원에서 제공하는 예외처리 문법입니다. 물론 윈도우상에서만 사용할 수 있습니다.
__try 부분에 예외를 검사할 코드를 넣습니다. 예외가 발생하면 __except 부분에서 지정한 코드가 실행되게 됩니다. 예외도 종류가 엄청 많은데, __except의 괄호 안에 예외 검사식을 넣어줘야 합니다.
위 예제의 경우 널 포인터에 값을 대입하고 있습니다. 이 코드를 실행하면 메모리 접근 위반 예외가 발생하고 __except 부분의 코드가 실행됩니다. 괄호안의 부분이 메모리 접근 위반 예외인지 판단하는 부분인데, GetExceptionCode() 함수로 현재 발생한 예외 코드를 구해옵니다. 그리고 그 예외가 EXCEPTION_ACCESS_VIOLATION (메모리 접근 위반 예외)인지 검사하고 맞으면 __except 블록 안의 코드를 실행하고 아니면, 상위 예외 처리 핸들러에게 넘깁니다.
위 예제는 GetExceptionCode() 함수를 이용하여 예제코드를 ExceptionFilter() 함수에 넘기고 각 코드에 맞는 예외의 원인을 수정하도록 되어 있습니다.
world를 Value로 나누었는데 Value는 0입니다. 그래서 EXCEPTION_INT_DIVIDE_BY_ZERO예외가 발생하였고, ExceptionFilter() 함수에서는 이 예외 코드에 맞게 Value에 1을 대입하여 주었습니다. 그리고 EXCEPTION_CONTINUE_EXECUTION를 리턴하여 예외가 발생한 부분에서 코드를 계속 실행하게 됩니다.
이 ExceptionFilter()에 여러가지 다른 예외 코드를 추가해서 처리할 수 있습니다. 물론 여기에 추가되지 않은 예외가 발생하면 EXCEPTION_EXECUTE_HANDLER가 리턴되고 __except의 부분이 실행됩니다.
이번에는 __finally의 사용입니다. __finally 부분은 __try 부분이 실행에 성공하던 예외가 발생하던 무조건 실행됩니다.
주로 사용되는 패턴은 __try 부분에서 동적 메모리 등을 할당했을때 __finally 부분에서 메모리가 할당 되었으면 해제하는 식입니다. __finally는 무조건 실행되기 때문에 메모리를 할당 했더라도 어떤 예외가 발생하여 프로그램이 중단되면 __finally 부분에서 할당한 메모리를 해제 할 수 있습니다.
비슷한 패턴으로는 크리티컬 섹션이나, 뮤텍스등 동기화 객체를 사용할 때, 객체를 획득한 상태에서 예외가 발생했더라도 __finally 부분에서 획득한 동기화 객체를 해제 할 수도 있습니다.
__try 안에서 return을 하더라도 __finally 부분이 실행되고 값을 리턴 합니다.
이 __finally는 __except와는 동시에 사용할 수 없습니다. 무조건 __try, __finally 혹은 __try, __except로만 사용할 수 있습니다.
C언어는 C 표준 라이브러리에 있는 setjmp(), longjmp() 함수를 사용하여 예외처리를 할 수 있지만 상당히 구식이라 직관적이지도 못하고 사용하기도 불편합니다.
그래서 C언어에서는 Structured Exception Handler(SEH)라는 예외처리 방식을 사용할 수 있습니다. SEH는 Microsoft Visual C++ 컴파일러 차원에서 제공하는 예외처리 문법입니다. 물론 윈도우상에서만 사용할 수 있습니다.
void tryexcept()
{
__try
{
int *world = NULL;
*world = 8; // 널 포인터에 값 대입
printf("hello try %d\n", *world);
}
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
printf("EXCEPTION_ACCESS_VIOLATION\n");
}
}
__try 부분에 예외를 검사할 코드를 넣습니다. 예외가 발생하면 __except 부분에서 지정한 코드가 실행되게 됩니다. 예외도 종류가 엄청 많은데, __except의 괄호 안에 예외 검사식을 넣어줘야 합니다.
위 예제의 경우 널 포인터에 값을 대입하고 있습니다. 이 코드를 실행하면 메모리 접근 위반 예외가 발생하고 __except 부분의 코드가 실행됩니다. 괄호안의 부분이 메모리 접근 위반 예외인지 판단하는 부분인데, GetExceptionCode() 함수로 현재 발생한 예외 코드를 구해옵니다. 그리고 그 예외가 EXCEPTION_ACCESS_VIOLATION (메모리 접근 위반 예외)인지 검사하고 맞으면 __except 블록 안의 코드를 실행하고 아니면, 상위 예외 처리 핸들러에게 넘깁니다.
- EXCEPTION_EXECUTE_HANDLER (1)는 __except 블록 안의 코드를 실행합니다.
- EXCEPTION_CONTINUE_SEARCH (0)는 __except 블록 안의 코드를 실행하지 않고 상위 예외 처리 핸들러에게 넘깁니다.
- EXCEPTION_CONTINUE_EXECUTION (-1)은 예외를 무시하고 예외가 발생한 부분 부터 코드를 다시 실행합니다. 하지만 예외가 발생한 원인을 해결해 주지 못하면 무한루프에 빠집니다.
이 매크로들은 excpt.h에 정의되어 있습니다.
__except의 괄호 안에 모든 예외의 종류를 다 적어줄 순 없는 노릇입니다. 그래서 예외 코드를 판별하여 각각 처리해주는 함수를 만들어 사용할 수 있습니다. 여기서 예외의 원인을 수정하여 EXCEPTION_CONTINUE_EXECUTION를 리턴하면 코드를 계속 실행 할 수 있습니다.
int Value = 0;
DWORD ExceptionFilter(DWORD ExceptionCode)
{
switch (ExceptionCode)
{
case EXCEPTION_INT_DIVIDE_BY_ZERO:
{
// 예외가 발생한 원인을 수정
Value = 1;
return EXCEPTION_CONTINUE_EXECUTION;
}
case EXCEPTION_ACCESS_VIOLATION:
{
// 예외가 발생한 원인을 수정
return EXCEPTION_CONTINUE_EXECUTION;
}
// 다른 여러가지 예외 코드를 처리
//case EXCEPTION_XXX
default:
return EXCEPTION_EXECUTE_HANDLER;
}
}
void tryexceptfilter()
{
__try
{
int world = 10;
world = world / Value;
}
__except (ExceptionFilter(GetExceptionCode()))
{
printf("EXCEPTION !\n");
}
}
위 예제는 GetExceptionCode() 함수를 이용하여 예제코드를 ExceptionFilter() 함수에 넘기고 각 코드에 맞는 예외의 원인을 수정하도록 되어 있습니다.
world를 Value로 나누었는데 Value는 0입니다. 그래서 EXCEPTION_INT_DIVIDE_BY_ZERO예외가 발생하였고, ExceptionFilter() 함수에서는 이 예외 코드에 맞게 Value에 1을 대입하여 주었습니다. 그리고 EXCEPTION_CONTINUE_EXECUTION를 리턴하여 예외가 발생한 부분에서 코드를 계속 실행하게 됩니다.
이 ExceptionFilter()에 여러가지 다른 예외 코드를 추가해서 처리할 수 있습니다. 물론 여기에 추가되지 않은 예외가 발생하면 EXCEPTION_EXECUTE_HANDLER가 리턴되고 __except의 부분이 실행됩니다.
이번에는 __finally의 사용입니다. __finally 부분은 __try 부분이 실행에 성공하던 예외가 발생하던 무조건 실행됩니다.
void tryfinally()
{
__try
{
printf("hello try\n");
}
__finally
{
printf("hello finally\n");
}
}
주로 사용되는 패턴은 __try 부분에서 동적 메모리 등을 할당했을때 __finally 부분에서 메모리가 할당 되었으면 해제하는 식입니다. __finally는 무조건 실행되기 때문에 메모리를 할당 했더라도 어떤 예외가 발생하여 프로그램이 중단되면 __finally 부분에서 할당한 메모리를 해제 할 수 있습니다.
비슷한 패턴으로는 크리티컬 섹션이나, 뮤텍스등 동기화 객체를 사용할 때, 객체를 획득한 상태에서 예외가 발생했더라도 __finally 부분에서 획득한 동기화 객체를 해제 할 수도 있습니다.
__try 안에서 return을 하더라도 __finally 부분이 실행되고 값을 리턴 합니다.
이 __finally는 __except와는 동시에 사용할 수 없습니다. 무조건 __try, __finally 혹은 __try, __except로만 사용할 수 있습니다.
Comments