앙 규무링^^
PE file(3)
이번에는 직접 실습을 통해서 PE file의 IAT 입력 순서를 볼 예정입니다 :3
PE file(1), (2)에 이어서 봐야 이해됨 그럼 출바아알
IMAGE_IMPORT_DESCRIPTOR
PE file은 자신이 어떠한 라이브러리를 IMPORT하고 있는지 위의 구조체에 명시하고 있습니더.
구조체의 코드는 다음과 같습니다.
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics;
DWORD OriginalFirstThunk; // INT(Import Name Table) address (RVA)
};
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name; // library name string address (RVA)
DWORD FirstThunk; // IAT(Import Address Table) address (RVA)
} IMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint; // ordinal
BYTE Name[1]; // function name string
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
일반적으로 여러 개의 라이브러리를 임포트하기 때문에 라이브러리 개수만큼 위 구조체의 배열 형식으로 존재하며, 구조체 배열의 마지막은 null로 끝납니다.
- 구조체 중요 멤버들(주소들은 RVA 값임)
항목 | 의미 |
OriginalFirstThunk | INT(Import Name Table)의 주소 |
Name | Library 이름 문자열의 주소 |
FirstThunk | IAT(Import Address Table)의 주소 |
그렇다면 이제 PE 로더가 임포트 함수 주소를 IAT에 입력하는 기본적인 순서!
IAT 입력 순서 :3
1. IID의 Name 멤버를 읽어서 라이브러리의 이름 문자열을 찾아냄 (ex : 'KERNEL32.dll')
2. 해당 라이브러리를 LoadLibrary() 함수를 써서 로딩함.
-> LoadLibrary('KERNEL32.dll')
3. IID의 OriginalFirstThunk 멤버를 읽어서 INT 주소를 얻음.
4. 그 INT 주소에서 배열의 값을 한개씩 읽어들이면서 해당 IMPORT_BY_NAME 주소를 얻어냄
5. IMPORT_BY_NAME의 hint/name 항목을 이용해 해당 함수의 시작주소를 얻음
-> GetProcAddress('GetCurrentThreadId')
6. IID의 FisrtThunk(IAT)를 읽어서 IAT의 주소를 얻어낸다.
7. 해당 IAT 배열 값에 위에서 구한 함수 주소를 입력.
8. INT가 NULL을 만날 때까지 위의 4~7 과정을 반복함.
자... 무슨말이냐... Name을 읽어 dll 이름을 획득 -> 그 이름을 LoadLibrary() 함수 안에 넣어서 dll 핸들 획득 -> IID에서 INT를 획득하고 거기서 하나씩 읽어내면서 IBN 획득 -> IBN의 hint/name과 dll핸들(아까획득)을 이용해 함수를 돌림
GetProcAddress() 여기서 내가 원하는 함수의 시작주소를 얻게됨 -> IID에서 IAT 주소를 획득 -> 끝으로 IAT 배열값 위에서 구해놨던 함수의 시작주소를 입력함 -> 이렇게 NULL을 만날때까지 모든 dll에 대해서 수행
휴... 끝
notepad.exe를 이용한 실습을 진행해보자.
-
'Reversing' 카테고리의 다른 글
리버싱 7 (0) | 2019.04.05 |
---|---|
리버싱 6 (2) | 2019.04.04 |
PE File(2) (0) | 2019.04.03 |
PE File(1) (0) | 2019.04.02 |
리버싱 5 (0) | 2019.04.02 |