언어에도 패턴이 있듯이 어셈블리에도 패턴이 있다. 긴 어셈블리라도 패턴을 익히면 쉽게 해석할 수 있다.
컴파일러가 자동으로 생성해내는 코드를 필터링 해야한다. 기본적인 예로 함수의 진입점과 종료점에서 나타나는 코드가 있다.
push ebp
mov ebp, esp
진입시
mov esp, ebp
pop ebp
종료시
진입시 push하는 레지스터는 함수내에서 사용하겠다는 의미이다. 기존의 값을 보관하기 위한 과정이다. 종료시에 void 형태의 함수를 제외하고는 eax에 결과값을 넣는다.
함수의 호출 규약에는 4가지가 있다. 어셈블리를 보고 호출 규약을 판단할 수 있다.
1.__cdecl
함수 외부에서 스택을 보정하는 것이 특징이다. 보정의 크기를 통해 변수의 크기를 확인할 수 있다.
2.__stdcall
함수 내부에서 스택을 보정한다. ret x 형태를 가진다. x 크기만큼 스택을 보정하면서 함수를 빠져나온다. Win32API의 방식이다.
3.__fastcall
인자 전달을 스택을 이용하지 않고 ecx와 edx 레지스터를 사용한다. 레지스터를 사용하기 때문에 빠르다. 2개 이하의 인자를 갖는 빈번히 사용되는 함수에 사용하기 적합하다. 함수호출 이전에 ecx, edx에 값을 넣는 형태이면 __fastcall 이다.
4.__thiscall
C++ 클래스에서 사용되는 방법이다. 현재 객체의 포인터를 ecx에 전달한다. 전달된 ecx를 기준으로 오프셋을 더해 멤버함수나 변수를 사용한다. 스택처리 방법은 __stdcall과 동일하다. 다만 클래스에서 사용된다는 특징이 있다.
if문 패턴
비교후 점프 패턴을 띈다.
예. cmp
jz
반복문
비교후 점프 패턴에 더해 반복적으로 수행하기 위해 다시 돌아오는 코드 카운터를 증가시키는 코드가 있다.
예. label 1 add ~~~
cmp
jg
jmp label1
구조체와 api
스택의 증감을 통해 할당되는 변수나 구조체의 크기를 확인할 수 있다. 함수 호출 이전의 push 과정을 통해 어떠한 인자를 갖는 함수 있지 유추할 수 있다. 디스어셈블러 프로그램을 이용할 경우 어떤 api인지 알려준다.
컴파일러가 자동으로 생성해내는 코드를 필터링 해야한다. 기본적인 예로 함수의 진입점과 종료점에서 나타나는 코드가 있다.
push ebp
mov ebp, esp
진입시
mov esp, ebp
pop ebp
종료시
진입시 push하는 레지스터는 함수내에서 사용하겠다는 의미이다. 기존의 값을 보관하기 위한 과정이다. 종료시에 void 형태의 함수를 제외하고는 eax에 결과값을 넣는다.
함수의 호출 규약에는 4가지가 있다. 어셈블리를 보고 호출 규약을 판단할 수 있다.
1.__cdecl
함수 외부에서 스택을 보정하는 것이 특징이다. 보정의 크기를 통해 변수의 크기를 확인할 수 있다.
2.__stdcall
함수 내부에서 스택을 보정한다. ret x 형태를 가진다. x 크기만큼 스택을 보정하면서 함수를 빠져나온다. Win32API의 방식이다.
3.__fastcall
인자 전달을 스택을 이용하지 않고 ecx와 edx 레지스터를 사용한다. 레지스터를 사용하기 때문에 빠르다. 2개 이하의 인자를 갖는 빈번히 사용되는 함수에 사용하기 적합하다. 함수호출 이전에 ecx, edx에 값을 넣는 형태이면 __fastcall 이다.
4.__thiscall
C++ 클래스에서 사용되는 방법이다. 현재 객체의 포인터를 ecx에 전달한다. 전달된 ecx를 기준으로 오프셋을 더해 멤버함수나 변수를 사용한다. 스택처리 방법은 __stdcall과 동일하다. 다만 클래스에서 사용된다는 특징이 있다.
if문 패턴
비교후 점프 패턴을 띈다.
예. cmp
jz
반복문
비교후 점프 패턴에 더해 반복적으로 수행하기 위해 다시 돌아오는 코드 카운터를 증가시키는 코드가 있다.
예. label 1 add ~~~
cmp
jg
jmp label1
구조체와 api
스택의 증감을 통해 할당되는 변수나 구조체의 크기를 확인할 수 있다. 함수 호출 이전의 push 과정을 통해 어떠한 인자를 갖는 함수 있지 유추할 수 있다. 디스어셈블러 프로그램을 이용할 경우 어떤 api인지 알려준다.
댓글
댓글 쓰기