'EnterCriticalSection'에 해당되는 글 2건

  1. 2011.05.18 Analysis about Pydbg Snapshot (1)
  2. 2010.03.28 [Padocon 2010 ] Crakme 200 ExcuteMe 풀이

2011.05.18 16:31 System

[+] Introduction


 Pydbg. 요즘들어 주목 받고 있는 Script 언어 중 하나인 Python의 Debugging Module 입니다.

Python 언어 자체가 심플하고 이해하기 쉽기 때문에 이를 이용하나 Pydbg도 상당히 접근하기 용이합니다.

물론 Python의 고질적인 문제인 속도는 안고 가야 할 문제입니다만..

이번 포스팅에서는 Pydbg의 Snapshot 기능이 가지고 있는 문제점에 대해서 써볼까 합니다.

Snapshot 기능에 대해 간단히 설명하자면 말그대로 특정 지점의 정보를 Snapshot 찍듯이 찍고

Restore를 통해 찍은 시점으로 돌아가는 거라고 보시면 되겠네요.

예를 들어서 금요일 저녁에 Snapshot을 찍어놓고 

일요일 저녁에 저장해뒀던 Snapshot으로 Restore 하는거죠.

...


<Fig0. 울지마라>

상당히 유용한 기능입니다.

특정 루틴을 반복하는데 좋겠죠? 

아무튼 해당 기능을 사용하는데 약간 문제가 있는데요,

첫번째는 Pydbg File 자체를 수정하지 않고 일어나는 문제점을 해결 하는 방법이고

두번째는 Pydbg File 자체를 수정하는 방법입니다.

간단하기로는 후자가 간단합니다. 단 두글자만 수정하면 끝나요.

포스팅은 전자에 중점을 두고 기술하도록 하겠습니다.




[+] Problem


snapshot의 사용방법은 간단합니다.

pydbg의 객체의 process_snapshot() method를 호출해주면 되죠

복구는 process_restore() 입니다.

그리고 해당 method를 호출해주기 전에

모든 thread를 멈추고 snapshot해야 한다고 pydbg의 제작자 pedram amini 가 명시하고 있습니다

그러니까 이런 식으로 해야겠죠.

SnapShot

dbg.suspend_all_threads()

dbg.process_snapshot()

dbg.resume_all_threads()


Restore 

dbg.suspend_all_threads()

dbg.process_restore()

dbg.resume_all_threads()



예제를 통해 문제를 살펴보죠.

간단한 문자열을 출력하는 다음과 같은 코드가 있습니다.

여기서는 puts를 이용하였으나, printf 문도 동일한 문제가 일어납니다.


*해당 문제는 VS2010의 msvcr100.dll 에서는 발생하지 않습니다만

Windows의 기본 C- Runtime Libary인 msvcrt.dll 을 썼을때는 해당 문제가 발생합니다.

확인해보면  msvcr100.dll에서는 별도의 예외처리가 들어갑니다. 

해당 예외 원인은 뒤에서 설명하도록 하죠.




<Fig1.  예제 프로그램>

Friday nigth에 snapshot 을 찍고

Sunday night 에 restore를 해보면

정상적으로 작동하지 않는걸 확인해볼 수 있습니다.

<Fig2. 정상적으로 출력되지 않고 종료된 모습>
 
나머지도 출력이 되지 않는걸로 봐선 Handling 되지 않는 예외가 발생하여 프로그램이

죽었다고 보면 되겠죠.

발생하는 예외의 Call Stack을 확인해보면

EnterCriticalSection 이후에 발생하는 것을 볼 수 있습니다.

예외가 나는 경우를 확인해보면 항상 같은 곳에서 발생하지는 않습니다만

EnterCriticalSection 함수에 진입하고 나서 발생하는것은 변함이 없습니다.

EnterCriticalSection?

동기화를 위해 사용되는 방법중 임계영역[  Critical Section ] 을 이용하는데 사용되는 함수입니다.

단일 Thread 프로그램인데 무슨 동기화냐 하시는분이 계실지도 모르겠는데

기본적인 Console 출력 함수들은 모두 동기화 작업을 거칩니다. 



왜 이런 문제가 발생할까요?


[+] Analysis


예외 원인을 보면 Access Violation이 주로 일어납니다.

일단 Snapshot method가 호출되었을 때 저장되는 내용을 한번 살펴보겠습니다.


<Fig3. 각 Thread의 Context를 get_thread_context를 통해 저장한 모습>

Context에는 어떤 내용이 저장되는고 하니

<Fig4. WinNT.h에 있는 CONTEXT Structure의 구조>
 

해당 함수에서는 CPU Register를 저장합니다. 

이후 메모리를 돌며 쓰기가 불가능한 곳과 실행파일 이미지를 제외한 영역을 저장합니다.


 <Fig5. 쓰기 가능한 메모리 영역을 저장하는 부분>

 바로 이곳이 문제입니다.

 stack 값이나 Register 영역 값은 모두 정상적으로 복구되는데 실행 파일 이미지에 저장되는 변수는 그대로 남아있는 것입니다.

 즉, data 영역에 저장되는 전역변수가 문제가 될 수 있다는 거죠.

Critical Section의 구조를 살펴봅시다.

<Fig6. Critical Section 구조체의 모습>

첫번째 member를 보면  _RTL_CRITICAL_SECTION_DEBUG 이라는 Linked List 형태의 구조체를 가리키고 있는

포인터 임을 확인 할 수 있습니다.

자 그렇다면 정리해봅시다.

전역변수로 지정된 Critical Section 구조체는 Restore 되어도 변하지 않습니다.

그대로 남아있다는 소리죠.

그런데 해당 구조체가 가리키고 있는 _RTL_CRITICAL_SECTION_DEBUG 구조체는 

Restore 되면 Snapshot 될 때의 상태로 돌아가게 됩니다.

즉 , InitializeCriticalSection이 호출되기 전 상태로 돌아간다는 말입니다.

여기서 문제가 일어납니다.

전역 변수를 참조해보았을때 , 이미 Initialize 된 Critical Section 이 있는 것을 확인됩니다.

이를 사용했더니 실제로는 Initialize 되지 않는 Critical Section 이라는 거죠.

그 포인터가 가리키는 쓰레기 값을 가지고 연산을 했으니 Error가 나는게 당연했겠죠?

여기서 프로그램마다 메모리 값이 다르니 예외가 발생하는 곳도 달랐을 겁니다.

정리하자면, 해당 변수는 정상적으로 Restore 되지 않았는데 가리키는 영역은 Restore 되었다는 거죠.

물론 EnterCritialSection 안에서 나는건 공통적입니다만..

위 사항은 Console 출력 함수에서 적용되는 문제입니다.

Image 영역에 있는 메모리에 있는 변수에 접근하는 모든 것이 문제가 될 수 있습니다.

예를 들면 File Pointer 연산이 있겠죠




 [+] Solution  

 
1.  Snapshot을 찍을때 Image 영역까지 합니다.
 
가장 심플하고 간단하죠.

모든 전역변수도 정상적으로 변경이 되구요

Pedram Amini가 왜 Image 영역을 막아뒀는지는 모르겠습니다만

pydbg를 보면 필요하면 해제하라고 명시되어있습니다.

흠.. 다른 문제가 생길 수 있을지는 좀 더 봐야 할거 같네요.


2. 해당 변수의 snapshot 상태로 직접 돌려준다.

Console 출력 함수들의 경우 해당 Critical Section 영역을 0으로 덮어버리면 알아서 다시 할당하기 때문에

문제가 일어나지 않습니다.

File Pointer의 경우 현재 위치를 가리키고 있는 포인터를 원하는 위치로 돌려주는 식으로 우회가 가능하겠습니다.

좀 번거롭죠. 사용하는 함수마다 이렇게 해 줘야 하는 불편함이 있구요.



3. Image 영역에 쓰는 변수에 접근하지 않는다.

.... 

네 피하면 되는겁니다.

핵심적인 부분만 Snapshot , Restore 합니다. 

지역변수 연산만 한다면 이 방법이 먹히겠죠.

어떠한 수정도 없지만 그만큼 한계가 있는 방식입니다.



<Fig7. 이게 꿈이라고 말하지 말아주세요>

 


Posted by LinkC

2010.03.28 19:45 WarGame


지난번에 이어서 crackme 풀이에 들어갑니다

실행해 보면 아무것도 뜨지 않습니다

트레이에도 남지 않는군요

프로세스를 확인해보면

멀쩡히 있는 것을 확인해 볼 수 있습니다



말그대로 이걸 실행 시켜야 하는데

Resource를 로드 하는 부분이 있어서

Resource Hacker로 들여다보니

다음과 같은 Dialog가 있었습니다




음 역시 패스 워드는 쉽게 드러나진 않는군요

프로그램 내부에서 연산 되서

저 Password 에 출력되는게 틀림없어 보입니다

Tracing 하면서 어디서 막히나 찾아보면

다음과 같은 루틴을 찾아낼 수 있습니다




멀티 스레드를 이용했군요

모든 스레드가 정상적으로 종료될때까지 무한정 대기 합니다

Timeout 을 0으로 바꿔줘서 우회하게 되면..



저번 문제와 비슷합니다

또 저 패스워드 부분을 연산하는 루틴이 따로 존재하고

올바른 값이 주어져야 저

패스워드가 올바르게 보이겠죠

저번 문제와 다르게 우리가 일반적으로 프로그램 상에서

입력해 줄 수 있는 부분은 없습니다

그렇다면 남은건 스레드 부분이라고 생각해서

스레드 실행 부분을 지정하는 함수 부분을 살펴보았습니다



LeaveCriticalSection 이 보이는군요

임계 영역을 해제하는 함수입니다

EnterCriticalSection 도 앞서 실행되겠죠

아무래도 한 스레드에서 Enter 한 Critical 영역을

다른 스레드가 참조해서 무한 대기 상태로 빠지지 않나 생각했습니다



일단 쭉 훑어보면

모든 스레드는 402020 함수를 각기 다른 인자로 호출하는데

LeaveCriticalSection 함수 인자로 미뤄보아 아무래도

402020 인자로 들어가는 ECX는 임계 영역의 주소를 나타내는거 같군요

각기 다른 영역을 Critical 영역으로 잡는데

무한 대기 상태에 빠지는걸 보면

다음 함수가 해결의 키 함수가 되겠네요

함수 내용입니다



Sleep  뒤에 익숙한 인자로 402020 함수를 호출합니다

저 인자들은 각각 2,3번째 스레드의 Critical 영역의 주소인걸 기억하시나요?

일단 전체적인 구조를 C로 나타내보면



Leave 를 호출해주지만..

이 스레드가 모두 실행 되고 다른 스레드가 실행 되길 바라는건 좀 억지가 있죠

Sleep의 시간을 0으로 줘도 다른 스레드로 넘어가 버리구요

그럼 Sleep 함수가 실행되지 않도록 NOP으로 채워줍시다



혹은 402020 의 EnterCriticalSection 부분을 무력화시켜도 될 것 같네요

아무튼 이런 식으로 각 스레드가 제대로 실행 되도록 하면

DeadLock 에 걸리지 않고 끝나게 됩니다





Posted by LinkC
이전버튼 1 이전버튼

블로그 이미지
LinkC

태그목록

Tistory Cumulus Flash tag cloud by BLUEnLIVE requires Flash Player 9 or better.

공지사항

Yesterday32
Today19
Total315,771

달력

 « |  » 2018.08
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

최근에 받은 트랙백

글 보관함


. .