윈도우충 콘치가 에러를 만났을 때(feat. SEH) – 01

By conchi | December 18, 2016

SEH Overwrite Part #01




부제 : 위도우충 아님 윈도우임 윈도우(궁서체)


위도ㅇ…. 아니 윈도우(즈)충 콘치가 승선 후 최초로 나름 진지하고 근엄하게 SEH에 대해 이야기해보려 한다는 엣헴엣헴!

…은 뻥

빨리 귤 세개 정도 집어들고 이불속으로 들어가셈
야매킹의 야매글이 시작되려 한다능 둥둥!





(위도우충 아님 윈도우(즈)임 윈도우 오해 ㄴㄴ함;)

안녕하세요 여러분!! 되게 오랫만인듯 합니다 ‘ㅅ’a
아 요즘 왜이렇게 글이 뜸했냐구요?
그건 와타시가 좀 바쁘기도 했고… 사실 글을 막 싸질러 놓고 치우질 않아서…(콘적콘적)…..
헤헤!

그나저나 분명 지난번에
“안녕하세여 여러분들~ 왕콘치는 여러분들과 오래토록 함께 하기 위해 장기적인 컨텐츠로 가기로 했어요!”
…해놓고서 뜬금없이 다른 시리즈로 나타났네요.

왜 그런거냐구여?
왕콘치의 악성코드 연구소 1편에도 보면 나오지만 저는 전문적으로 분석을 하는 물고기가 아니라서… 글을 쓰는 것 외에 이런저런 일들을 하는데요, 뭔가를 하다가 갑자기 여기에 꽂혀버렸어여 ㅠㅠㅠ…는 이런 저런 문제를 풀던 중 Power of XX 2014 본선에 출제된 Windows 환경에서의 포너블 문제를 발견하게 된 것이 시작이었슴당!



그 문제를 풀던 중 위의 짤과 같은 운명적은 느낌을 받고는 이번 편을 시작하게 되었습니다.
(뜬금없이 결론부터 말하자면 문제…는 아직도 푸는중…;ㅁ;…미래의 내가 풀어줄거라 믿는중!!)

전 사실 저 문제 풀면서 SEH란 개념을 처음 알게 되었거든요. 중요한 개념이지만, 저는 설명고자라 과연 제가 얼마나 잘 풀어낼지가 의문이네요.


제가 개떡같이 말해도 찰떡같이 알아서 잘들 이해해 주시면 감쟈하겠습니다(?)
제가 보장하지만 이거 개념 진짜 개핵꿀잼임…. ㄹㅇ… 오버워치보다 더 재밌다는..!!
(오버워치 경쟁전 점수가 계속해서 떨어지는 중이라 이러는건 절대 아님 믿어주셈)


라고 과거의 제가 글을 써 뒀네요.
하..-ㅅ- 과거의 나레기에게 명치킥을 날려주고 싶당 ㅎㅎ…
이 글 초안 쓰고나서 뭔가 찝찝하고 고구마를 300개 먹은 것 마냥 답답한 기분에 이런저런 책을 뒤지고, 자료들을 뒤져가며 다시 글을 쓰고 있습니다.

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ사실 글쓰면서 지금 과거의 나에게 어이가 없어서 미친사람 처럼 웃고있음 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ망할인간




당부의 말씀

  • 야매스럽지만 최대한 정성스럽게 쓰는 중입니다. 저의 정성은 야매력과 비례하는걸로(?)
  • 저는 윈도우를 사랑합니다 하뜌하뜌
  • SEH에 대한 좋은자료는 많이 있습니다.
  • 바스티온 안합니다 질문 안받아요 -ㅅ-a
  • 드.디.어 커널에 대한 이야기를 하기 시작합니다. 다들 긴장하시라는
  • 하지만 아직은 이불속에서 귤까먹으면서 볼만한 수준이니 걱정 ㄴㄴ해
  • 역시나 제 글이 불편하신분들은 짤만 주워가도 괜찮습니다. 저는 개쿨하니까여.
  • 는 상처받을꺼니까 나한테 말하진 마셈..
  • 여튼! 겨울은 귤이 맛있는 계절임! 이불속으로 귤을 3개정도 들고 들어가서 폰을 켜셈


저와같은 윈알못(윈도우즈를 알지못하는 닝겐) 분들을 위해, 지금부터 SEH가 뭔지 썰을 풀어보도록 하겠습니당!


사전지식 – 커널모드/유저모드


아니 시작부터 대놓고 커널타령을 하다니 넘나 허들이 높은 것 아닌가여?



우선 커널모드가 뭔지, 유저모드가 무엇인지 맛만 보고 가도록 합시다.

윈도우에서는 커널모드와 유저모드, 이렇게 두가지의 모드를 제공합니다.

우리가 사용하는 모드는 당연히도 유저모드에요.
리눅스에서 루트권한(#)과 일반 유저권한($)이 분리되어 있는것 처럼 윈도우에서도 권한이 분리되어 있답니다.

왜 이렇게 귀찮게 권한이 분리 되어있냐!
하면 당연하게도 접근할 수 있는 영역에 제한을 두기 위함이겠죠.
실제로 유저모드와 커널모드는 접근할 수 있는 영역 자체가 다릅니다.
시스템에 치명적인 영향을 미칠 수 있는 부분은 커널모드로 제어를 하고, 그렇지 않은 부분은 유저모드에서 제어를 하는거죠.

음.. 쉽게 이야기하자면 유저 애플리케이션 코드는 유저모드에서,
시스템 서비스나, 디바이스 드라이버와 같은 운영체제 코드는 커널 모드에서 실행됩니다.
커널모드에서 실행되는 녀석들은 모든 시스템 메모리와 모든 CPU 인스트럭션에 접근이 허가되기 때문에 유저모드에서 보다 할 수 있는것이 더 많아집니다.

어떤일들을 더 많이 할 수 있는지에 대해서는 다음에 커널에 대해 자세히 이야기 할 때 알아보도록 하고, 지금은

윈도우에는 커널모드와 유저모드가 있는데 , 각각 모드에 따라 접근할 수 있는 영역이 다르다!!
커널모드는 운영체제에 관한 중요한 코드들이 돌아가고
유저모드에서는 그냥 우리가 만드는 코드같은것들이 돌아가나보다!
우리는 유저모드에서 작업을 하고 있다!

정도로만 알아두고 넘어가도 되지 않을까 싶습니다 룰루 !




SEH가 뭐에여?


라고 물으신다면 SEH가 SEH지 뭐겠어요 촤하하…
…열심히 설명해보도록 하겠습니다(쭈굴)

SEH라고 부르지만 사실 요 녀석의 풀네임은 Structured Exception Handler 입니다.
굳이 한글로 이름을 부르자면 구조적 예외처리 핸들러(?) 가 되겠네요.
이름에서도 추측이 가능하시겠지만 예외처리에 관여하는 핸들러 되겠습니다.

이 녀석은 예외처리기와 종료처리기 두 가지의 용도로 사용이 됩니다.

각각 어떤 의미인지는 조금 뒤에 다시 설명하기로 하고 이 녀석의 참 역할에 대해 이야기 해 볼게요.

개발자적 관점으로 보았을때 SEH는 시스템을 보다 더 안정적으로 만들어 주는데 한 몫 하는 녀석입니다. 왜냐하면 이녀석은 작성된 코드를 수행중에 무언가 문제가 발생하면 시스템이 바로 알려주는, 이름 그대로 예외를 처리해주는 역할을 하는 녀석이거든요.


Q. 그럼 코딩하다가 나타나는 이 에러또한 SEH인가여??


A. 뭔가 창이 띕@@! 하고 뜨니까 예외처리 당한거 같고 그러지 않나염 ‘ㅅ’a

하지만 이녀석은 C++예외처리입니다.
C++예외처리는 예외처리의 또 다른 방식이며, 자체적인 예외에여.



얘를 보세요, 위에 에러메시지랑 다르게 생겼자나여. 얘가 바로 구조적 예외처리를 통해 나타난 놈입니다. 둘은 예외를 처리한다는 목적은 같지만, 다른 점이 있지요.

C나 C++예외처리에서는 컴파일러가 제공하는 __catch와 __throw, __try와 __except와 같은 키워드를 사용합니다.

하지만 때로는 컴파일러의 힘으로 해결되지 못하는 에러들이 발생하기도 하지요.
이럴때 바로 우리의 OS느님이 직접 나서게 됩니다(뚜둔!)
Windows에서는 이런식으로 예외가 발생했을때, 예외를 발생시킨 스레드가 예외를 처리할 수 있게 해주고 있는데 우리는 이를 SEH라 부릅니다.

windows 에서의 예외들은 각각의 인터럽트 번호를 가지게 됩니댜 ‘ㅅ’a


인터럽트?

CPU가 프로그램을 실행하고 있는데 예외상황이 발생하여 처리가 필요한 경우, CPU에게 이 사실을 알려 처리할 수 있게 해달라고 찡찡거리는 걸 의미함 (출처 : 위키백과)


요 번호들을 이용해서 Windows 커널에서는 어떤 예외가 발생했는지 체크하고 해결을 하기위해 나서게 되여. 커널로 넘어갈때의 당시 레지스터 값들은 모두 스택에 얌전히 저장되고, 얌전히 저장된 값들은 구조화된 에러 핸들러에서 사용하게 됩니다.

이렇게 만들어진 값들을 트랩 프레임(Trap Frame)이라고 불러요.

트랩프레임이 만들어지고난 후 운영체제는 내부 함수인 KiDispatchException라는 함수를 호출합니다.

워호우.. 함수 이름이 점점 수상해지네요. 이 함수에대해선 다음에 알아보기로 하고(총총)


저 정체불명의 함수를 통해 에러가 발생한 스레드를 잠시 스탑시키고, 유저레벨의 디버거에게 “야 여기 에러남 -_-+” 하고 에러가 발생하였음을 알립니다.

이렇게 메세지 전달이 끝나고 나면 Windows는 예외가 발생한 스레드의 스택에 아까 저장해두었던 트랩 프레임 내용들을 써준 후, 유저레벨의 ntdll에 있는 KiUserExceptionDispatcher함수가 호출될 수 있도록 실행흐름을 바꾸고 제 역할을 끝냅니다.

뭔가 어려운 이름의 함수들이 등장했는데 이들은 이름에서 느껴지듯이 Exception에 관여 하는 그런 녀석들이라고만 알고 자세한 내용은 다음번에 알아보도록 해요 :D

그런데 뭔가 SEH라 하면.. FS:[0]이니 이런말이 많은데 이런건 다 어디다 팔아먹고 어려운 소리만 하고 있는걸까요 ‘ㅅ’a…

잠시 ㄱㄷ 해봐염 지금 설명해드림




FS레지스터는 무슨 상관인데 맨날 SEH하면 튀어나오나여??


우리 혹시 시스템 공부 처음 시작하면 레지스터 달달 외우는거 이거하나여?
그때 막 CS, DS, SS, ES, FS, GS 얘들 본거 기억하세요?


그중에서 항상 FS와 GS레지스터는 뭐 여분의 레지스터니, 거의 사용되지 않니 하잖아요. 사실 FS는 중대한 임무를 맡고 무쓸모인척 하는 스파이 레지스터에요….는 뻥!

유저모드에서 FS레지스터는 TEB(Thread Environment Block)를 가리키고 있어요. (그럼 커널모드에서는 다른곳을 가리키고 있다는 의미겠지요 ㅎ후훟 커널모드에서는 KPCR을 가리키는데 이걸 이야기하고있자면 글이 산으로 갈테니 전 이만)


무튼!
뭔가 간지나지 않나여ㅋㅋㅋㅋ
TEB는 이름 그대로 스레드에 대한 정보들을 가득 담고 있는 구조체 입니다.

이런 FS레지스터의 첫번째에 그러니 FS:[0]되는 부분에는 EXCEPTION_REGISTRATION_RECORD의 포인터가 담겨있어 에러 핸들러를 찾을 수 있도록 해주는 녀석입니다.

얘들은 다수의 리스트로 만들어져있어서, “음.. 내가 찾던 에러가 아니군!” 하면 다음 리스트로 넘어가고 넘어가고 넘어가고 이런식으로 동작을해요.

그래서 SEH를 이야기 할때는 체인 형태라고 많이들 이야기를 하고 그러죠 후후




근데 이걸 이용해서 어떻게 포너블 문제를 풀고(?) 한다는걸까요?
이건 단지 에러를 처리하는 윈도우즈의 큰 그림일 뿐인데 ‘ㅅ’…a…



이건 다음편에서 실제 실습과 함께 알아보도록 해요 :3 말로 설명하는거보단 간지나는 실습과 함께 보는게 훨씬 더 꿀잼이라능!

‘ㅅ’…! 그럼 조만간 다음편에서 다시 보는걸로 !! 뿅!

comments powered by Disqus