[현재 실행되고 있는 메모리 주소를 알아오기]
1. 레지스터
현재 실행되고 있는 메모리 주소는 eip 레지스터에 저장되어 있다. 이 주소를 얻기 위해서는 여러가지 방법이 있는데, 여기서 소개할 내용은 단순히 어셈블리만으로 얻어오는 방법이다.
eip 레지스터의 내용을 얻어오기 위해서 가장 먼저 생각해 볼 수 있는 것은 mov 연산자를 사용하는 것이다. 하지만, mov 연산자 등으로는 eip 에 접근할 수 엇기 때문에, 다른 편법을 사용하여야 한다.
2. call instruction
call 명령은 함수를 호출하기 위한 명령이다. call 은 jmp 와 다르게, 실행 된 후 ret 명령을 만나면 호출된 주소로 되돌아와야 한다. 이 되돌아오기 위한 주소를 저장하는 곳은 바로 스택인데, call 을 하게 되면, 자기자신의 주소를 stack 에 push 하는 효과를 낳는다.
이 특징을 가지고 eip 의 주소를 알아낼 수 있다.
3. 간단한 구현
call GETEIP
GETEIP:
pop eax
이렇게 구현 하였을 경우, eax 에 eip 갓이 들어가게 된다. 하지만 얻은 값은 pop eax 의 위치가 되므로, 실제로 pop eax 뒤의 주소를 알아내어 무언가를 쓰려고 한다면, 디스어셈블하여 pop eax 가 얼만큼을 차지하는 지 알아내야 한다.
위의 것을 디스어셈블하면 다음과 같다.
E8 00 00 00 00 5F
여기서, E8 00 00 00 00 은 call 명령이며, 5F 가 pop 명령이다. 즉, 구해진 eax + 1 이 우리가 원하는 현재 명령 다음에 실행될 주소를 가지고 있는 것이다.
여기서 +1 은 매우 중요한데, 이것이 이 코드가 꼭 하드코딩되어야 하며 프로세스 아키텍쳐가 변경될 경우(pop 명령의 길이) 코드를 변경하여야 하는 단점이 있다.
이러한 제약사항을 효과적으로 제거한 것이 다음의 구현이다.
4. 좀 더 좋은 구현
BEGIN:
jmp GETEIP3
GETEIP2:
pop eax
jmp GETEIPEND
GETEIP3:
call GETEIP2
GETEIPEND:
이렇게 하였을 경우 GETEIPEND 의 주소를 GETEIP2: 에서 구할 수 있다. eax 값을 그대로 사용하면 된다. (디스어셈블 하여 직접 확인한 후 하드 코딩 할 필요가 없다)
[요약]
eip 의 값을 얻어내는 방식을 알아보았다. 이 방법을 사용하여 실행도중 자기자신을 변경하거나 하는 일들을 할 수 있게 된다. 이 방법으로 eip 를 얻어내는 것은 x86 기반의 cpu 에서만 가능하며, stack 을 꼭 사용하여야 한다.
1. 레지스터
현재 실행되고 있는 메모리 주소는 eip 레지스터에 저장되어 있다. 이 주소를 얻기 위해서는 여러가지 방법이 있는데, 여기서 소개할 내용은 단순히 어셈블리만으로 얻어오는 방법이다.
eip 레지스터의 내용을 얻어오기 위해서 가장 먼저 생각해 볼 수 있는 것은 mov 연산자를 사용하는 것이다. 하지만, mov 연산자 등으로는 eip 에 접근할 수 엇기 때문에, 다른 편법을 사용하여야 한다.
2. call instruction
call 명령은 함수를 호출하기 위한 명령이다. call 은 jmp 와 다르게, 실행 된 후 ret 명령을 만나면 호출된 주소로 되돌아와야 한다. 이 되돌아오기 위한 주소를 저장하는 곳은 바로 스택인데, call 을 하게 되면, 자기자신의 주소를 stack 에 push 하는 효과를 낳는다.
이 특징을 가지고 eip 의 주소를 알아낼 수 있다.
3. 간단한 구현
call GETEIP
GETEIP:
pop eax
이렇게 구현 하였을 경우, eax 에 eip 갓이 들어가게 된다. 하지만 얻은 값은 pop eax 의 위치가 되므로, 실제로 pop eax 뒤의 주소를 알아내어 무언가를 쓰려고 한다면, 디스어셈블하여 pop eax 가 얼만큼을 차지하는 지 알아내야 한다.
위의 것을 디스어셈블하면 다음과 같다.
E8 00 00 00 00 5F
여기서, E8 00 00 00 00 은 call 명령이며, 5F 가 pop 명령이다. 즉, 구해진 eax + 1 이 우리가 원하는 현재 명령 다음에 실행될 주소를 가지고 있는 것이다.
여기서 +1 은 매우 중요한데, 이것이 이 코드가 꼭 하드코딩되어야 하며 프로세스 아키텍쳐가 변경될 경우(pop 명령의 길이) 코드를 변경하여야 하는 단점이 있다.
이러한 제약사항을 효과적으로 제거한 것이 다음의 구현이다.
4. 좀 더 좋은 구현
BEGIN:
jmp GETEIP3
GETEIP2:
pop eax
jmp GETEIPEND
GETEIP3:
call GETEIP2
GETEIPEND:
이렇게 하였을 경우 GETEIPEND 의 주소를 GETEIP2: 에서 구할 수 있다. eax 값을 그대로 사용하면 된다. (디스어셈블 하여 직접 확인한 후 하드 코딩 할 필요가 없다)
[요약]
eip 의 값을 얻어내는 방식을 알아보았다. 이 방법을 사용하여 실행도중 자기자신을 변경하거나 하는 일들을 할 수 있게 된다. 이 방법으로 eip 를 얻어내는 것은 x86 기반의 cpu 에서만 가능하며, stack 을 꼭 사용하여야 한다.