BOOL CreateProcessA(
[in, optional] LPCSTR lpApplicationName,
[in, out, optional] LPSTR lpCommandLine,
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] BOOL bInheritHandles,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCSTR lpCurrentDirectory,
[in] LPSTARTUPINFOA lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
BOOL CreateProcessW(
[in, optional] LPCWSTR lpApplicationName,
[in, out, optional] LPWSTR lpCommandLine,
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] BOOL bInheritHandles,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCWSTR lpCurrentDirectory,
[in] LPSTARTUPINFOW lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
이 때 CreateProcessA는 ASCII 버전, CreateProcessW는 유니코드 버전 --> 두 API 모두 후킹에 사용해야한다.
stealth2.cpp --> DllMain
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
char szCurProc[MAX_PATH] = {0,};
char *p = NULL;
// HideProc2.exe 프로세스에는 인젝션 되지 않도록 예외처리
GetModuleFileNameA(NULL, szCurProc, MAX_PATH);
p = strrchr(szCurProc, '\\');
if( (p != NULL) && !_stricmp(p+1, "HideProc2.exe") )
return TRUE;
// change privilege
SetPrivilege(SE_DEBUG_NAME, TRUE);
switch( fdwReason )
{
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;
case DLL_PROCESS_DETACH :
// 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;
}
stealth.cpp와 비교했을 때, ZwQuerySystemInformation뿐만 아니라, CreateProcess 함수도 후킹하고 있다.
핫 패치 : 프로세스가 실행중인 상태에서 라이브러리를 프로세스 메모리에서 일시적으로 변경하는 것
기존 5바이트 코드 패치 방식은 반복적인 훅/언훅 과정으로 인해 성능이 저하될 뿐만 아니라, 멀티스레드에서 Run-Time Error가 발생할 수 있다. 에러의 이유는 한 스레드에서 코드를 실행하려고 할 때, 다른 스레드가 같은 코드에 쓰기 시도를 하면서 충돌이 발생할 수 있기 때문이다.
핫 패치 방식은 7바이트 코드 패치 방식으로 보통 코드 시작전 주소에 의미 없는 명령어들이 있는데 그 부분을 채우면서 시작하는 방식이다. 이렇게 되면 EIP가 바로 다음 줄 코드이기 때문에 훅/언훅 과정이 필요가 없게 된다.
제약 조건(NOP * 5 + MOV EDI,EDI)이 만족되지 않으면 방식이 성립이 안되므로 5바이트 코드 패치 기법을 사용해야 한다.
DWORD ZwResumeThread(
[in] HANDLE ThreadHandle,
[out] PULONG SuspendCount OPTIONAL
);
ZwResumeThread API는 윈도우 Native API로, undocumented API이다. 해당 API는 프로세스가 생성된 후, 메인 스레드 실행 직전에 호출되는 함수이다. 이 함수로 API 후킹을 하면 자식 프로세스가 하나도 실행되지 않은 상태에서 API를 후킹할 수 있다.