'Stealth' Process (2)

컴컴한해커·2025년 1월 21일

리버스 엔지니어링

목록 보기
18/18

📌 Global API Hooking

📢 조건

  1. 현재 실행 중인 모든 프로세스에 대해 API 후킹
  2. 앞으로 실행될 모든 프로세스에 대해 API 후킹

📢 프로세스 생성 API

  1. kernel32.CreateProcess()
    : 새로운 프로세스를 생성할 때 사용되는 API
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 모두 후킹에 사용해야한다.

  1. WinExec(),ShellExecute(), system()
    : 프로세스를 실행시키는 프로세스
    --> 내부적으로 CreateProcess() API를 실행시킨다.
    --> CreateProcess() API를 후킹하는 것이 low-level hooking에 해당하므로 더 성공률이 높다.

📢 소스 코드 분석

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 함수도 후킹하고 있다.

📢 핫 패치 방식의 API 후킹

핫 패치 : 프로세스가 실행중인 상태에서 라이브러리를 프로세스 메모리에서 일시적으로 변경하는 것

기존 5바이트 코드 패치 방식은 반복적인 훅/언훅 과정으로 인해 성능이 저하될 뿐만 아니라, 멀티스레드에서 Run-Time Error가 발생할 수 있다. 에러의 이유는 한 스레드에서 코드를 실행하려고 할 때, 다른 스레드가 같은 코드에 쓰기 시도를 하면서 충돌이 발생할 수 있기 때문이다.

핫 패치 방식은 7바이트 코드 패치 방식으로 보통 코드 시작전 주소에 의미 없는 명령어들이 있는데 그 부분을 채우면서 시작하는 방식이다. 이렇게 되면 EIP가 바로 다음 줄 코드이기 때문에 훅/언훅 과정이 필요가 없게 된다.

📢 핫 패치 방식의 고려 사항

제약 조건(NOP * 5 + MOV EDI,EDI)이 만족되지 않으면 방식이 성립이 안되므로 5바이트 코드 패치 기법을 사용해야 한다.

📢 CreateProcess API의 특징 및 한계

  1. kernel32.CreateProcessA와 kernel32.CreateProcessW를 모두 후킹한다.
  2. 이 때 CreateProcess API들은 모두 내부적으로 CreateProcessInternal API들을 호출한다. 이 말은 즉, CreateProcessInternal API들이 low-level-hooking 방법이다.
  3. CreateProcess로 생성된 프로세스들에게도 자동적으로 바로 API 후킹을 걸어야 하는데, 아주 짧은 시간 동안 자식 프로세스가 후킹되지 않은 채로 실행 될 수 있다.

📢 Ntdll.ZwResumeThread() API

DWORD ZwResumeThread(
  [in] HANDLE ThreadHandle,
  [out] PULONG SuspendCount OPTIONAL
);

ZwResumeThread API는 윈도우 Native API로, undocumented API이다. 해당 API는 프로세스가 생성된 후, 메인 스레드 실행 직전에 호출되는 함수이다. 이 함수로 API 후킹을 하면 자식 프로세스가 하나도 실행되지 않은 상태에서 API를 후킹할 수 있다.

0개의 댓글