본 내용은 이전 포스트에서 이어지는 내용입니다.
* 참고!
모든 소스 코드는 MS Visual C++ 2008 Express Edition 으로 개발 되었으며, Windows XP SP3 & Windows 7 환경에서 테스트 되었습니다.
Global API Hooking
Global API Hooking 이란 1) 현재 실행중인 모든 프로세스와 2) 앞으로 실행될 모든 프로세스에 대해서 API Hooking 을 시키는 것입니다.
지난번에 설명한 예제 프로그램(HideProc.exe, stealth.dll)은 global hooking 이 아닙니다. 위에서 설명한 2) 번 조건이 만족되지 않기 때문입니다.
HideProc.exe 를 실행 하여 notepad.exe 프로세스를 은폐시켜도 이후에 Process Explorer (혹은 task manager) 를 실행시키면 이들 프로세스에서는 notepad.exe 프로세스를 볼 수 있습니다.
그 이유는 HideProc.exe 실행 이후에 생성된 프로세스들에게는 stealth.dll 파일이 (자동으로) 인젝션 되지 않기 때문입니다.
이러한 문제를 해결하기 위한 다양한 방법이 있을 수 있습니다.
그 중에서 또 다른 API 를 Hooking 하여 Global API Hooking 을 구현하는 방법에 대해서 설명 드리겠습니다.
새로운 프로세스가 생성되려면 kernel32!CreateProcess() API 를 사용해야 합니다. WinExec(), ShellExecute(), system() 등의 API 도 내부적으로는 CreateProcess() 를 호출합니다.
__in_opt LPCTSTR lpApplicationName,
__inout_opt LPTSTR lpCommandLine,
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in BOOL bInheritHandles,
__in DWORD dwCreationFlags,
__in_opt LPVOID lpEnvironment,
__in_opt LPCTSTR lpCurrentDirectory,
__in LPSTARTUPINFO lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
);
* 출처 : http://msdn.microsoft.com/en-us/library/ms682425(VS.85).aspx
따라서 현재 실행중인 모든 프로세스에 stealth.dll 을 인젝션 하고, stealth.dll 에서 CreateProcess() API 를 후킹하면 이후 실행되는 프로세스에게도 자동으로 stealth.dll 을 인젝션 시키도록 만들 수 있습니다.
다시 설명 드리면 모든 프로세스는 부모 프로세스에서 (CreateProcess() 를 이용하여) 생성시켜주기 때문에 부모 프로세스의 CreateProcess() API 를 후킹하여 자식 프로세스에게 stealth.dll 을 인젝션 하도록 만들면 됩니다. (보통 부모 프로세스는 explorer.exe 가 될 것입니다.)
어떤가요? 좋은 아이디어 이지요?
이와 같이 Global API Hooking 의 개념은 어렵지 않습니다.
하지만 CreateProcess() API 를 후킹하면 아래와 같이 고려해야 할 사항들이 있습니다.
2) CreateProcessA(), CreateProcessW() 는 각각 내부적으로 CreateProcessInternalA(), CreateProcessInternalW() 를 호출합니다. 실제 MS 제품들 중에서 일부는 CreateProcessInternalA/W 를 직접 호출하기도 하지요. 따라서 좀 더 정확히 Global API Hooking 을 구현하기 위해서는 이 두 함수를 더 후킹해줘야 합니다.
3) 후킹 함수(NewCreateProcess) 는 원본 함수(CreateProcess) 를 호출 한 후 생성된 자식 프로세스에 대해서 API 를 후킹 해야 합니다. 따라서 아주 짧은 시간동안 자식 프로세스가 후킹 되지 않은 채로 실행될 수 있습니다.
많은 리버싱 선배님들에 의하여 kernel32!CreateProcess() 보다 더 후킹하기 좋은 함수가 발견 되었습니다.
바로 ntdll!ZwResumeThread() API 입니다.
IN HANDLE ThreadHandle,
OUT PULONG SuspendCount OPTIONAL
);
* 유저 모드에서는 NtXXX 계열과 ZwXXX 계열은 동일합니다.
* 출처 : http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Thread/NtResumeThread.html
ZwResumeThread() 는 프로세스가 생성 된 후 메인 스레드 실행 직전에 호출되는 함수입니다. 따라서 이 함수 하나만 후킹하면 자식 프로세스의 코드가 하나도 실행되지 않은 상태에서 API 를 후킹시킬 수 있습니다.
단점은 ZwResumeThread() 는 undocumented API 라서 언제 바뀔지 알 수 없으며, 그만큼 안정성을 보장 할 수 없습니다. 따라서 ZwResumeThread() 같은 undocumented API 를 후킹 할 때는 OS 가 패치되면서 변경될 수 있다는 것을 항상 염두에 두어야 합니다. 하위 버전에서는 잘 되던 후킹이 최신 버전에서는 갑자기 안 되는 일이 많기 때문입니다.
실습
* 참고
위 stealth2.dll 는 CreateProcess 후킹 버전입니다.
ZwResumeThread 후킹 버전을 원하시는 분께서는 따로 요청해 주시면 보내드리겠습니다.
실습을 간단히 하기 위해서 은폐 프로세스를 notepad.exe 로 고정하였습니다. 참고하시기 바랍니다.
<Fig. 1>
실행 중인 모든 프로세스에 stealth2.dll 파일을 인젝션 시킬 예정입니다. 따라서 모든 프로세스에서 공통적으로 인식할 수 있는 path 인 %SYSTEM% 폴더에 stealth2.dll 파일을 복사합니다.
#2. HideProc2.exe –hide 실행
<Fig. 2>
기존 HideProc.exe 와 비교해서 실행 파라미터가 변경되었습니다. 은폐 프로세스 이름이notepad.exe 로 하드코딩 되어있습니다.
#3. ProcExp.exe & notepad.exe 실행
Process Explorer(혹은 작업관리자) 와 notepad 를 여러 개 실행 해 주세요.
위 그림을 보시면 ProcExp.exe 와 notepad.exe 프로세스가 각각 2개씩 실행되고 있습니다.
하지만 ProcExp.exe 에서는 notepad.exe 프로세스가 은폐되어 있습니다.
추가로 ProcExp.exe 를 몇 개 더 실행해 보시기 바랍니다. 마찬가지로 새로 생성된 ProcExp.exe 프로세스에서도 notepad.exe 프로세스가 은폐되어서 보이지 않을 것입니다.
#4. HideProc2.exe –show 실행
Global API Hooking 을 해제 합니다.
이제 Process Explorer(혹은 작업관리자) 에서 notepad.exe 프로세스가 보일 것입니다.
소스 코드
# HideProc2.cpp
HideProc2.cpp 는 기존 HideProc.cpp 에서 실행 파라미터를 줄인 것뿐이므로, 기존 설명을 참고하시면 되겠습니다.
# stealth2.cpp
stealth2.cpp 는 기존 stealth.cpp 에서 은폐 프로세스 이름을 "notepad.exe" 로 하드 코딩 하였고, global hooking 을 위해서 CreateProcessA() API 와 CreateProcessW() API 를 후킹 하는 코드가 추가 되었습니다.
DllMain()
{
char szCurProc[MAX_PATH] = {0,};
char *p = NULL;
// HideProc2.exe 프로세스에는 인젝션 되지 않도록 예외처리
GetModuleFileName(NULL, szCurProc, MAX_PATH);
p = strrchr(szCurProc, '\\');
if( (p != NULL) && !_stricmp(p+1, "HideProc2.exe") )
return TRUE;
SetPrivilege(SE_DEBUG_NAME, TRUE);
{
case DLL_PROCESS_ATTACH :
// hook
hook_by_code("kernel32.dll", "CreateProcessA",
(PROC)NewCreateProcessA, g_pOrgCPA);
hook_by_code("kernel32.dll", "CreateProcessW",
(PROC)NewCreateProcessW, g_pOrgCPW);
hook_by_code("ntdll.dll", "ZwQuerySystemInformation",
(PROC)NewZwQuerySystemInformation, g_pOrgZwQSI);
break;
// unhook
unhook_by_code("kernel32.dll", "CreateProcessA",
g_pOrgCPA);
unhook_by_code("kernel32.dll", "CreateProcessW",
g_pOrgCPW);
unhook_by_code("ntdll.dll", "ZwQuerySystemInformation",
g_pOrgZwQSI);
break;
}
return TRUE;
}
위 DllMain() 함수를 보시면 CreateProcessA, CreateProcessW 를 후킹하는 코드가 추가되었습니다.
NewCreateProcessA()
CreateProcessA() API 의 후킹 함수인 NewCreateProcessA() 코드를 살펴 보겠습니다. (NewCreateProcessW() 코드도 거의 동일합니다.)
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
)
{
BOOL bRet;
FARPROC pFunc;
// unhook
unhook_by_code("kernel32.dll", "CreateProcessA", g_pOrgCPA);
// original API 호출
pFunc = GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateProcessA");
bRet = ((PFCREATEPROCESSA)pFunc)(lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
// 생성된 자식 프로세스에 stealth2.dll 을 인젝션 시킴
if( bRet )
InjectDll2(lpProcessInformation->hProcess, STR_MODULE_NAME);
// hook
hook_by_code("kernel32.dll", "CreateProcessA",
(PROC)NewCreateProcessA, g_pOrgCPA);
return bRet;
}
코드는 매우 단순합니다.
일단 후킹을 풀고 원본 함수를 실행해서 생성된 자식 프로세스에 stealth2.dll 을 인젝션 시킵니다.
그 후 다음 실행을 위해서 다시 후킹해 줍니다.
제 글을 꾸준히 읽어오셨다면 쉽게 이해하실 수 있으실 겁니다.
한가지 눈여겨 볼 사항은 인젝션 함수인 InjectDll2() 입니다.
기존 InjectDll() 함수는 프로세스 ID (PID) 를 이용하여 프로세스 핸들을 얻어 인젝션 시키는 방법이었습니다. (OpenProcess() API 이용)
하지만 위의 경우는 CreateProcessA() API 를 호출하면서 자연스럽게 자식 프로세스의 핸들(lpProcessInformaiton->hProcess)을 얻을 수 있습니다. 이 내용도 같이 참고하시면 좋을 것 같습니다.
+---+
지금까지 Global API Hooking 에 대해서 알아보았습니다.
시스템 전체 프로세스에 대해서 후킹을 하는 기술이기 때문에 예상치 못한 에러가 발생할 수 있습니다. 따라서 사전에 꼼꼼한 테스트가 필요합니다. 그리고 undocumented API 를 후킹할 때는 현재 OS 버전에서 예상대로 동작하는지 반드시 확인하셔야 합니다.
다음번에는 API Hooking 시리즈의 마지막 테마인 Code Injection 기법에 대해서 설명드리도록 하겠습니다.
많이 기대해 주세요.
ReverseCore
위 글이 도움이 되셨다면 추천(VIEW ON) 부탁 드려요~
'study' 카테고리의 다른 글
진법 변환 (2진수, 10진수, 16진수) (23) | 2012.03.06 |
---|---|
API Hooking - '스텔스' 프로세스 (4) (58) | 2010.01.17 |
API Hooking - '스텔스' 프로세스 (3) (50) | 2009.12.30 |
API Hooking - '스텔스' 프로세스 (2) (32) | 2009.12.16 |
API Hooking – '스텔스' 프로세스 (1) (23) | 2009.12.13 |
API Hooking - Tech Map (14) | 2009.09.29 |
API Hooking - 리버싱의 '꽃' (25) | 2009.09.22 |
DLL Injection - 다른 프로세스에 침투하기 (4) (33) | 2009.07.30 |
DLL Injection - 다른 프로세스에 침투하기 (3) (10) | 2009.07.17 |
DLL Injection - 다른 프로세스에 침투하기 (2) (117) | 2009.07.17 |
DLL Injection - 다른 프로세스에 침투하기 (1) (17) | 2009.07.06 |
- 이전 댓글 더보기
-
kmslife 2011.04.15 18:02
안녕하세요.
질문이 있어서 이렇게 글을 올립니다.
첨부되어 있는 프로그램으로 실행은 잘 되는데요
문제는 vs2008로 만들어진 프로그램들, 그리고 vs2008 툴 자체는 위 dll을 injection 시키면
프로그램 자체가 실행되지 않습니다.
vs2003이나, 그외 프로그램들은 잘 동작하는데 말이죠
ASLR기능 인가 찾아 보았지만 제 pc의 환경은 xp sp3환경이어서 문제가 되지는 않을 것 같습니다.
원래 vs2008관련되어서는 dll injection 기능이 동작하지 않는것인가요?
동작하게 하려면 어떻게 해야 할지요?-
reversecore 2011.04.20 10:41 신고
안녕하세요.
지금 제 환경은 Win7 64bit, WinXP SP3 32bit 인데요.
말씀하신 VS2008 은 없어서 Visual C++ 2008 Express (VCExpress.exe 프로세스)에 테스트 해본 결과 정상동작 하네요.
VS2008 로 제작된 파일에 인젝션 시키면 동작 안한다고 하셨는데요.
그 파일을 제게 보내주시면 테스트 해보겠습니다.
실행 파일을 zip 압축 하신 후 확장자를 zipx 로 변경하셔서 아래 메일로 보내주시기 바랍니다.
reversecore@gmail.com
감사합니다.
-
-
jjengae 2011.09.28 20:06
스텔스 프로세스(2)에서 올려주셨던 HideProc.exe는 XP기반에서만 작동하는 것 같더라구요
윈도우 7(Enterprise 32bit)에서 vmware-vmx.exe라는 프로세스를 숨기기 하고 싶은데
이번에 포스팅에 올려주신 파일은 notepad.exe로 고정되어 있는것 같아서요
제가 임의의 프로세스를 숨기려면 어떤 부분을 수정해서 어떻게 컴파일 해야 하는건가요?
.exe와 .dll은 한번도 컴파일해보지 않아서...
또, 수정하려면 무조건 Visual Studio가 설치되어 있어야 하는건가요?
기초 지식 없이 이렇게 물어봐서 죄송합니다
가능하시다면 jjengae@nate.com 으로 메일 부탁드릴게요-
reversecore 2011.09.28 20:36 신고
안녕하세요.
위 예제에서 은폐프로세스 이름은 notepad.exe 로 하드코딩 되어 있습니다.
소스코드에서 "notepad.exe" 문자열을 "vmware-vmx.exe" 문자열로 수정 후 빌드 하시면 됩니다.
Visual C++ 을 한번도 사용해보지 않으셨다면 조금 어려움이 있을 수 있습니다.
감사합니다.
-
-
jjengae 2011.09.29 23:32
빌드를 해야된다고 하셔서 VS2008 설치했습니다.
"notepad.exe"를 수정해야 한다고 하시는건 "stealth2.cpp"에 있는 내용을 수정하고 빌드해야 된다는 말씀이시죠?
"HideProc2.cpp"는 "멀티 바이트 문자 집합" 설정하고 컴파일 했더니 debug폴더에 실행파일이 생성되더군요. 문제는 stealth2.cpp 파일입니다.
여차여차해서 stealth2.cpp 파일을 컴파일 하려고 프로젝트 생성시에 응용프로그램 종류에서 콘솔 응용프로그램 대신 "DLL"로 셋팅하고 멀티바이트 문자 집합으로 설정했더니 오류가 나지 않더군요.
근데 컴파일 후에 나타나는 창이 무엇인지 잘 모르겠습니다. "디버그 세션이 사용할 실행 파일"이라는 창이 뜨고 "실행 파일 이름"과 "프로젝트에 액세스할 수 있는 URL"을 입력하라고 하는데 그것을 무엇으로 해야할지 잘 모르겠습니다.
요약하자면 stealth2.cpp 파일을 어떻게 .dll로 컴파일하는지 좀 알려주시면 감사하겠습니다.
혹시 .dll로 컴파일하는 포스팅은 없는건가요? 시간 되신다면 vmware-vmx.exe로 적용하여 jjengae@nate.com으로 보내주시면 감사하겠습니다. ㅜㅜ
도움 주시면 감사하겠습니다. -
-
jjengae_father CPP 2011.10.06 22:32
안녕하셰요.
메일 확인하니 주소가 틀렸어요.
VS키고 dll프로젝트를 하나 창조하지요.
다음 dll main에서 stealth2.cpp를 코피하다놓고 빌드하면 되겠지요. -
셔벳클록 2012.12.02 17:52
CreateRemoteThread() 가 잘 안먹히는 경우 어떻게 하는게 좋을까요?
Sleep(2000)을 넣으면 전역후킹이 되긴 하는데,
예를 들어 시작메뉴에서 프로그램을 시작시키면
시작메뉴에서 일정 시작 렉을 보이네요.
환경은 xp sp3를 깔았습니다.-
reversecore 2012.12.02 19:07 신고
안녕하세요.
CreateRemoteThread() 가 안먹히는 경우가 몇 가지 있습니다.
그래서 NtCreateThreadEx() 를 사용(Vista 이상)하기도 하지요.
Sleep() 을 넣으면 전역후킹이 된다는 말씀이 잘 이해가 안되는데요.
실행중 뚜렷한 딜레이가 발생한다면 구조를 좀 변경하는 것이 좋을 것 같습니다. (물론 전역 후킹 자체가 시스템에 부하를 주는 방식이라 어느정도의 딜레이는 감수해야 합니다.)
감사합니다. -
셔벳클록 2012.12.04 09:56
노트패드 같은건 올려놓으신 소스코드로 충분히 전역후킹이 잘되는데요,
윈도우 미디어나 다른 프로그램 같은경우 잘 안되더라구요??
(해당 라이브러리가 인젝션 되지 않았더라구요)
그래서 찾아보니까, 적당한 딜레이를 주면 전역후킹이 된다고 하더라구요?
( http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=50&MAEULNo=20&no=507700&ref=507700 )
실제도 잘 먹힌거 같구요.
단순히 일정시간 지연 후 전역후킹만 되면 괜찮겠는데..
렉까지 잠깐동안 발생해서 말이죠.. 제 지식수준으로는 잘 이해가 안되었구요..
http://blog.naver.com/siam18/172501113 에 첨부를 올렸는데
실행해보하고 프로그램을 열면, 시작메뉴나 탐색기가 잠깐 멈춤니다
(세 파일을 c:\에 놓고, 실행파일을 실행시키면 injection되고, Ejection시는 practice.exe -unexe입니다) -
reversecore 2012.12.04 22:02 신고
안녕하세요.
일반적인 DLL Injection 의 경우 Sleep() 의 유무와 상관없이 잘 먹혀야 정상입니다.
인젝션된 DLL 에서 다시 인젝션하는 구조인가요?
제가 디버깅을 좀 해본 후 답변 달아드리도록 하겠습니다.
감사합니다.
-
-
-
reversecore 2014.05.13 11:08 신고
안녕하세요.
제 책의 34장 소스코드를 보시면 됩니다.
소스코드 다운 경로 : http://reversecore.tistory.com/104
감사합니다.
-
-
cr 2014.07.02 14:46
안녕하세요. 현재 책을 도서관에서 빌려 보고있습니다. 한 가지 질문드릴게 있는데.
IE를 사용하며 파일 업로드 같은 행동을 할 때 FileDialog가 불려지는데, IE에 dll을 심은 후 이 FileDialog가 불려질 때마다 자동으로 메세지박스를 띄운다던지 행동을 취하고 싶습니다.
해서 Process Explorer로 살펴보았더니 FileDialog event명은 db!rwWriterEvent 더군요.
여기까지만 파악이되고 정작 이 event가 작동할 때 마다 어떻게 체크해야할 지 감이 잘 오지 않네요.
책의 어느 부분을 보면 도움이 될 까요 ?