티스토리 뷰
우선 이 코드는 MASM 코드로 작성된 것을 보고 작성했으며, 이를 C언어로 그대로 바꿔서 작성했습니다. "리버싱 핵심원리"에 나와있는 코드는 현재 Windows 10 환경에서 제대로 동작하지 않는것을 확인했습니다.
우선 MASM 코드를 살펴보고 분석해보자.
[ iat32.asm ]
[15] : Import Address Table (FirstThunk) 상에서 Argument로 전달되는 Target API
가 저장된 주소를 반환한다. 이 부분을 그대로 PatchAddress로 전달해 패치한다.
[16] : lpOrgProc에 저장된 주소가 가리키는 참조값을 lpNewProc으로 패치한다.
lpOrgProc에 저장된 주소가 가리키는 참조값에는 원래 API의 실제코드가 있다.
[17, 18] : Target API를 대체할 Hooking API이다.
[21, 24] : lpIAT로 시작하는 변수에는 IAT상에 해당 API가 존재하는 주소가 저장된다.
즉, 이 주소의 참조값을 변조해야하고, 복원해야한다.
[22, 25] : lpApi로 시작하는 변수에는 변조되고나면 IAT에서 사라질 Target API의 라이브러리
상에서의 실제주소를 저장한다. 변조되지 않은 실제 Target API을 호출하기 위함.
이 코드는 C언어로 작성했을 때 DllMain 함수에 들어갈 내용이다.
[45] : 현재 모듈의 시작주소를 읽어온다. (RVA를 VA로 변경할 때 사용한다.)
[48] : IAT상에서 변조하기 위한 Target API의 위치를 반환받는다.
[52] : 반환받은 Target API의 IAT상 위치를 인자로 넣고, 두번째 인자로 변경할 Hooking Function의
주소를 넣어 IAT상 위치의 참조값을 Hooking Function으로 패치한다.
위에서 설명했지만 GetFunctionTable 함수는 Target API가 IAT상에 위치하는 주소를 반환하는 함수이다. 이 주소자체를 패치하는 것이 아니라 이 주소가 참조하는 곳을 패치해야 한다는 점을 꼭 기억하자!!!
[76-77] : IAT 상에서 Target API가 몇 번째 Index에 위치하는지 Count하는 변수다.
[82-84] : hModule에서 0x3C를 더한만큼에 저장된 주소는 e_lfanew가 저장되어 있는데,
이 참조값을 다시 hModule에 저장하면 NT_Header의 주소가 나온다.
[88-95] : Import Data Directory의 IMPORT에 오기 위해서 0x80을 더하는 과정이다.
(세부적인 내용은 주석을 확인하면 알 수 있다.)
[98, 99] : 해당 부분은 IMAGE_DATA_DIRECTORY 구조체 배열인데, 이중에서 2번째 인덱스이다.
그 구조체에서 IMPORT의 RVA를 가져오는 위 구조체의 방법은 IMAGE_DATA_DIRECTORY
구조체의 VirtualAddress 변수를 사용하는 것이다. 여기에 hModule을 더하면 VA가 된다.
[101] : 그러면 저장되는 ebx는 IMAGE_IMPORT_DESCRIPTOR 구조체 배열이 저장된 주소가 된다.
해당 구조체 배열의 첫 번째 Elements로 형변환 하기위해 assume 명령어를 사용한다.
(IMAGE_IMPORT_DESCRIPTOR는 IMPORT된 DLL들의 정보를 담은 구조체이다.)
[104-107] : IMAGE_IMPORT_DESCRIPTOR 구조체의 Name 변수를 통해 해당 Element의
DLL Name을 읽어와서 내가 원하는 DLL 이름인지 비교한다. (MASM에선 왜 Name1...?)
[109-112] : 일치하는 DLL을 찾았으면 해당 DLL의 IMAGE_IMPORT_DESCRIPTOR의 멤버 변수인
OriginalFirstThunk(RVA값)을 VA값으로 변경하고 이 배열을 순환한다.
이 때 이 배열의 자료형은 IMAGE_IMPORT_BY_NAME 구조체 배열이다.
(OriginalFirstThunk 는 Import Name Table로 Import된 API의 이름 배열이다.)
[113-115] : 이 배열의 인자를 가져오고 IMAGE_IMPORT_BY_NAME으로 형변환한다.
[117] : IMAGE_IMPORT_BY_NAME의 멤버 변수인 Name을 사용해 내가 찾는 API인지 확인한다.
(또 왜 MASM에서는 Name1인지 모르게따....)
[118-123] : 내가 찾는 API가 맞다면 IMPORT_IMPORT_DESCRIPTOR 구조체의 멤버 변수인
FirstThunk(IAT의 주소)를 VA로 변환한 후 dwCount를 더한 주소를 반환한다.
PatchAddress는 lpOrgProc 주소가 참조하는 위치(4Byte)를 lpNewProc으로 패치해주는 함수이다. C언어에서는 VirtualQuery API 호출없이 진행이 가능했다. 별다른 코드가 없기 때문에 설명은 넘어간다.
Hook Function이다. lpApiMessageBoxW 를 사용해 기존의 API를 호출한다는 것을 확인할 수 있다.
Injector.asm 및 iat32.asm 코드 다운로드 받기(EXE,DLL포함)
[ 출처 ]
'Reversing > Assembly' 카테고리의 다른 글
[Assembly] MIPS로 작성한 Bubble Sort 예제코드 (1) | 2020.04.08 |
---|---|
[Assembly] 순서없이 배우는 MIPS 개념정리. (1) | 2020.04.08 |
[MASM] MASM으로 구현하는 32Bit Trampoline API Hooking (0) | 2020.03.16 |
[MASM] MASM으로 작성한 SetWindowsHookEx을 이용한 DLL Injection. (0) | 2020.03.11 |
[MASM] MASM(Microsoft Assembler) 시작하기 (x32, x64) (0) | 2020.03.10 |