일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- NT Optional Header
- Windows 11
- Buffer Overflow
- oh-my-zsh
- powerlevel10k
- attack vector
- SQL Injection
- DOS Header
- DOS Stub
- zsh theme customization
- 리버싱 핵심원리
- NT File Header
- Tutorial
- sctf 2021
- PE file format
- docker
- Windows
- IMAGE_IMPORT_DESCRIPTOR
- WSL
- GetProcAddress()
- web
- BOF
- samsung ctf
- stack based buffer overflow
- PE Header
- ubuntu
- IMAGE_EXPORT_DIRECTORY
- NT Header
- RVA
- Windows Terminal
Archives
- Today
- Total
나만의 메모노트
[리버싱 핵심원리] DLL Injection 본문
DLL Injection
- 실행 중인 다른 프로세스에 특정 DLL 파일을 강제로 삽입하는 기술
- 다른 프로세스에서 LoadLibrary() API를 통해 특정 DLL Loading
- 강제 삽입된 DLL의 DLLMain() 함수 호출
- 삽입된 DLL은 해당 프로세스의 메모리에 대한 접근권한을 가짐
- 기능 개선, 버그 패치, 메시지 후킹, API 후킹 등 사용자가 원하는 다양한 일을 수행
- 현재 악성코드에 의해 악용되고 있음
- DLL Injection 구현방법
- 원격 스레드 실행 - CreateRemoteThread() API
- 레지스트리 이용 - AppInit_DLLs
- 메시지 후킹 - SetWindowsHookEx() API
- 그 외 여러 가지 다양한 기법 존재
notepad.exe DLL Injection
CreateRemoteThread() API를 이용한 DLL Injection
STEP 1.
- Open Process() API 이용하여 대상 프로세스 핸들 구하기
HANDLE OpenProcess(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwProcessId
);
// Sample_InjectDLL()
if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
return FALSE;
매개변수 (parameter) | 설명 |
dwDesiredAccess | 접근 권한을 의미하며, 대체로 PROCESS_ALL_ACCESS를 사용한다. |
bInheritHandle | 상속 여부를 나타내는 것으로 해당 프로세스에 의해 생성된 자식 프로세스가 핸들을 상속받기 위해 True를 반환한다. |
dwProcessld | 0 또는 NULL 입력 시 모든 프로세스에 접근 가능하며, 특정 프로세스에 접근할 경우 해당 프로세스의 PID를 입력한다. |
STEP 2.
- 대상 프로세스 메모리에 Injection할 DLL 경로 작성하기 위해 VirtualAllocEx() API를 이용하여 상대방 프로세스 메모리 공간에 버퍼 할당 후 WriteProcess Memory() API를 이용하여 DLL 경로 문자열을 입력
- VirtualAllocEx() API
- 해당 프로세스 가상메모리 공간을 할당 받고자 할 때 사용
- WriteProcessMemory() API
- VirtualAllocEx() API
VirtualAllocEx() API
LPVOID VirtualAllocEx(
HANDLE hProcess,
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
// Sample_InjectDLL()
pRemoteBuf = VirtualAllocEx(
hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
매개변수 (parameter) | 설명 |
hProcess | 대상 핸들이며, 대상이 되는 가상메모리 공간을 할당 받을 수 있다. |
lpAddress | 할당 받을 메모리 주소이며, NULL일 경우 비어 있는 공간에 자동 할당 된다. |
dwSize | 할당 받을 메모리 크기(Byte)이며, NULL일 경우 Page 크기만큼 할당 받는다 |
flAllocationType | 할당 받은 메모리의 현재 타입을 지정한다. (MEM_RESERVE, MEM_COMMIT, MEM_RESET) |
flProtect | 할당 받은 메모리에 대한 접근 권한 |
WriteProcessMemory() API
BOOL WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T *lpNumberOfBytesWritten
);
// Sample_InjectDLL()
WriteProcessMemory(
hProcess, pRemoteBuf, (LPVOID)szDllName, dwBufSize, NULL);
매개변수 (parameter) | 설명 |
hProcess | PROCESS_VM_WRITE 및 PROCESS_VM_OPERATION 접근권한을 가진 대상 프로세스 |
lpBaseAddress | VirtualAllocEx() API로부터 얻은 메모리 시작 주소 |
lpBuffer | Injection할 DLL 파일의 경로 |
nSize | DLL 파일 경로 문자열 길이(Terminating NULL 포함) |
*lpNumberOfBytesWritten | 특정 프로세스로 전송된 바이트 수에 대한 포인터 변수 lpNumberOfBytesWritten이 NULL이면 parameter 무시됨 |
STEP 3.
- LoadLibrary() API를 호출하기 위한 주소 구하기
- ASCII 문자열 버전에 따라 LoadLibraryA() 혹은 LoadLibraryW()로 치환
// Sample_InjectDll()
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(
GetModuleHandle("kernel32.dll"),
"LoadLibraryA"
);
-
- GetModuleHandle() API를 통해 DLL 핸들값을 가져오고 GetProcAddress() API를 통해 DLL 주소값을 가져옴
- 대상 프로세스에 로딩된 kernel32.dll과 InjectDll.exe에 의해 로딩된 kernel32.dll의 메모리 시작 위치는 동일
- Windows OS에서 Kernel32.dll은 프로세스마다 같은 주소에 로딩됨
STEP 4.
- 대상 프로세스에 원격 스레드 실행
- 대상 프로세스에 LoadLibrary() API를 호출하기 위해 CreateRemoteThread() API를 사용
HANDLE CreateRemoteThread(
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
// Sample_InjectDLL()
hThread = CreateRemoteThread(
hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL
);
매개변수 (parameter) | 설명 |
hProcess | 스레드를 생성할 프로세스의 핸들 (PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION, PROCESS_VM_WRITE 및 PROCESS_VM_READ 접근 권한 포함) |
lpThreadAttributes | 새 스레드에 대한 보안 설명자를 지정하고 하위 프로세스가 반환된 핸들을 상속 할 수 있는지 여부를 결정하는 SECURITY_ATTRIBUTES 구조에 대한 포인터, lpThreadAttributes가 NULL이면 스레드가 기본 보안 설명자를 가져오고 핸들을 상속할 수 없음. 스레드에 대한 기본 보안 설명자의 ACL(액세스 제어 목록)은 작성자의 기본 토큰에서 가져옴 |
dwStackSize | 스택의 초기 크기(Byte), 시스템은 해당 해당 값을 가장 가까운 page로 반올림, Parameter가 0이면 새 스레드는 실행 파일의 기본 크기를 사용 |
lpStartAddress | 스레드에 의해 실행될 LPTHREAD_START_ROUTINE 유형의 application-defined 함수에 대한 포인터로 원격 프로세스에서 스레드의 시작 주소를 나타냄 해당 함수는 원격 프로세스에 존재해야함 (LoadLibrary() 주소) |
lpParameter | Parameter에 대한 포인터 (Injection할 DLL 경로) |
dwCreationFlags | 스레드 생성을 제어하는 플래그 |
lpThreadId | 대상 스레드의 ID |
'Security > Reversing' 카테고리의 다른 글
[리버싱 핵심원리] PE File Format (5) (0) | 2021.08.01 |
---|---|
[리버싱 핵심원리] PE File Format (4) (0) | 2021.08.01 |
[리버싱 핵심원리] PE File Format (3) (0) | 2021.08.01 |
[리버싱 핵심원리] PE File Format (2) (0) | 2021.08.01 |
[리버싱 핵심원리] PE File Format (1) (0) | 2021.07.31 |