GEMS

GEMS 2권 스택와인딩(stack winding)

알쿠미 2016. 2. 4. 17:49

스택 와인딩(stack winding)?

C/C++ 프로그래밍 기법으로는 불가능하거나 구현하기 힘든 어떠한 일을 프로그램의 스택을 조작하는 방식으로(어셈블리 코드를 이용해서) 해결하는 매우 강력한 기법이다.


임시적 반환(Temporary Return)?


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
.586
.model flat
.data
buffer dd ?
file_handle dd ?
filesize dd ?
.code
 
_TempRetEg:
 
    call fn0
    call fn1
    ;
    ;    이전
    ;
    pop edx
    call edx
    ;
    ;
    ;
    call fn2
    call fn3
    ret
 
    A: call _TempRetEg
    ret
 
end
 
cs
MyFunc라는 함수가 _TempRetEg를 호출한다고 한다면 _TempRetEg는 fn0와 fn1을 차례대로 호출하고

pop edx, call dex 를 만나게 된다.


25행의 CALL 명령을 CPU가 처리하는 방식은

- 명령이 있는 행의 다음 행(26) 주소가 스택에 쌓이며, 그 후 8행으로 JUMP가 일어난다.

- 16행에 의해 스택에 있는 주소가 뽑아져 나와서 edx라는 CPU 레지스터에 저장된다.

(17줄은 그 주소를 호출하는 것이다.)

위에서 말하는 주소는 MyFunc가 이 루틴을 호출했던 곳 바로 다음 지점이다.


MyFunc가 반환되면(return 문이나 함수의 끝에 도달해서), 비슷한 과정을 통해 다시 _TempRetEg의 21 행으로 돌아간다.

그 후 fn2와 fn3이 호출된 뒤 26행의 ret에 의해 다시 어떤 주소로 돌아간다.

이 어떤 주소는 MyFunc함수를 호출했던 곳 바로 다음 주소이다.

이렇게 스택의 값들을 조작하면 함수 호출과 반환 방식을 임의로 바꿀 수 있다.

ex) fn0가 파일을 열고, fn1이 버퍼를 할당하고 메모리에 읽어들이고, fn2가 그 메모리를 해제하고, fn3이 파일을 닫는다고 하면, MyFunc는 메모리나 파일에 대한 마무리 작업에 대해 신경을 쓰지 않아도 된다.

즉, 파일을 열고 메모리 읽고, 메모리 해제하고 파일을 닫는과정이 모두 하나의 단일한 코드 블럭안에 들어가게 되는것이다.

MyFunc는 그냥 _Temp_RetEg만 호출하고, 버퍼를 사용하고 반환하면 된다.


일단 여기까지 간단한게 보고 다음에 다시 보도록하자.