mov eax, ffffffffh
shl eax, 20h
.
eax is ffffffffh...
KernelCallbackTable에 존재하는 __ClientLoadLibrary의 경우
SetWindowsHookEx를 이용한 dll injection시 호출되어지고
내부에서 LoadLibraryExW를 호출하여 dll를 로드하게 되어있다.
SetWindowsHookEx를 통한 dll인젝션 차단의 경우 LoadLibraryExW를 모니터링 하여
user32에서 호출되었는지 확인하는 것으로 차단할 수 있다고
많은 블로그들에 나와있는 이유가 여기에 있다.
C++의 함수 호출 형태를 보면 3가지(_cdecl / _stdcall / _fastcall)가 있는것을 알것이다.
3가지를 간략히 정리해 보면
1. _cdecl
- 파라미터 전달은 오른쪽에서 왼쪽 방향으로 스택을 이용
- 파라미터 해제는 호출한 함수가 정리(그러므로 가변인자가 가능)
2. _stdcall
- 파라미터 전달은 오른쪽에서 왼쪽 방향으로 스택을 이용
- 파라미터 해제는 불려진 함수 내에서 정리
3. _fastcall
- 처음 두개를 레지스터(ecx, edx)를 이용하고 나머지 파라미터를 오른쪼에서 왼쪽으로 스택을 이용
- 파라미터 해제는 불려진 함수 내에서 정리
위와 같이 정리해 볼수 있다.
그럼 int sum(int a, int b)함수를 3가지로 구현해서 직접 확인해 보자.
첫번째로 아래 코드는 RETN시 스택을 정리 해주기 위한 부분이 없다. 이를 통해서 _cdecl을 이용해 구현한 함수 임을 파악해 볼 수 있다.
다음 코드를 보면 RETN 8을 통해 스택을 정리 해주는 것을 알 수 있다. 또한 ecx, edx를 사용하지 않았으므로 이는 _stdcall을 통해서 구현한 함수 임을 파악이 가능하다.
마지막으로 아래 코드를 보면 ECX와 EDX를 이용하 였다는 것을 알 수 있다. 하지만 _fastcall의 경우 불려진 함수 내에서 스택을 정리한다고 되어있는데 RETN시 스택을 정리 하는 부분이 없어 의아해 할 수 있다. 이는 ECX와 EDX레지스트만 이용하였기 때문에 스택을 정리 해줄 필요가 없기 때문이다. 아래의 함수는 _fastcall임을 알 수 있다.
위와같이 calling convetion을 이해하고 어셈코드의 구조를 파악하고 있다면 리버싱 단계에서 해당 함수의 calling convetion을 파악하고 코드화 하는데 휠씬 도움이 될것 이다.
Image Base Relocation
기준재배치..(exe파일은 예외)
pe파일이 메모리에 로드될 경우 .exe파일의 경우 가장 먼저 로드될 것이기 때문에 원하는 번지(0x00400000)에 로드될 수 있다.
하지만 .dll일 경우 하나의 실행파일에 여러개의 dll이 로드될 수 있으므로 원하는 번지(0x01000000)에 로드되긴 어렵다.
그럴때를 위해 pe파일에는 relocation정보를 담아두고 로드되기 원하는 번지와 실제 로드된 번지의 차이인 delta를 기준으로
재배치를 수행하게 된다.
이 재배치 정보는 IMAGE_OPTIONAL_HEADER의 Data Directory에 존재하고 인덱스값은 winnt.h에
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 라고 정의되어 있다.
또한 재배치섹션의 처음 시작정보를 담을 구조체는 아래와 같이 정의되어 있고
//
// Based relocation format.
//
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;
DWORD SizeOfBlock;
// WORD TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
위의 구조체 이후에 word데이터가 뒤따라 오게된다. 뒤따라 오는 word데이터는 상위 4bit는 타입정보를 하위 12bit는 오프셋값을 가진다.
VirtualAddress는 Rva를 담고있다. 따라서 재배치가 필요한 데이터는 (VirtualAddress + 오프셋) 한 값이 가리키는 데이터가 재배치가 필요한 값이다. (((VirtualAddress + 오프셋 이 가리키는값) - imageSize) + 실제 로드된 베이스번지) 를 하게 되면 재배치 정보고 완성되게 된다.