<악성코드 분석공부>/<WinAPIs>

[WinAPI] 프로세스 순회해보자

gosoeungduk 2021. 8. 13. 02:29
반응형

#WinAPI #프로세스 탐색


1. EnumProcesses(DWORD *lpidProcess, DWORD cb, LPDWORD lpcbNeeded);

#include <Psapi.h> 로 불러와서 실행가능하다. 현재 실행 중인 프로세스들의 PID 를 불러와서 배열에 저장한다.

[인자설명]

  • lpidProcess : 실행 중인 프로세스들의 PID 를 저장할 DWORD 배열이다.
  • cb : 첫 번째 인자 배열의 사이즈이다.
  • lpcbNeeded : 전체 프로세스 PID 들의 총 바이트를 저장할 DWORD 변수이다. ( DWORD(4) * 프로세스들의 수 ) = ( 총 바이트 )

2. HANDLE OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);

PID 에 따라 프로세스 핸들을 리턴한다.

[인자설명]

  • dwDesiredAccess : 프로세스를 불러올 권한이다. process_access_right 에 상세 권한 설명이 되어있다. PROCESS_ALL_ACCESS 는 IDA 에서 확인하면 0x1F0FFF 이니 유의. 만약 함수 caller 가 SeDebugPrivilege 권한이 허용된 상태라면, 보안 설정에 상관없이 모든 권한을 갖는다.
  • bInheritHandle : TRUE 값을 가지고있을 경우에 return 된 프로세스 핸들이 본 프로세스의 자식프로세스에 상속된다. 대부분은 FALSE 이다.
  • dwProcessId : 핸들을 생성할 프로세스의 PID 이다.

3. BOOL EnumProcessModulesEx( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded, DWORD dwFilterFlag);

핸들로 받은 프로세스가 실행하고(갖고있고) 있는 모듈들을 lphModule 배열에 저장한다. 해당 배열의 0 번째 인덱스에는 프로세스 정보가 그대로 박혀있다. 이것으로 순회 하면서 현재 탐색 중인 프로세스가 어떤 건지 구분 가능하다. (다음 인덱스 부터는 프로세스에서 사용하는 여러가지 DLL 들이 박혀있다. 예를 들면, KERNEL32.DLL 이라던지...)

[인자설명]

  • hProcess : OpenProcess 에서 나온 핸들
  • lphModule : 모듈 목록을 받아올 HMODULE 배열
  • cb : lphModule 배열의 사이즈
  • lpcbNeeded : 총 모듈의 바이트를 받아올 DWORD 변수
  • dwFilterFlag : 32비트용 함수인 EnumProcessModulesEx 에서 인자가 하나 추가 되었는데, dwFilterFlag 는 어떤 비트의 모듈만 불러올지 필터를 정하는 인자인 듯하다. 아래 4개 중 하나는 무조건 있어야한다.

filters

4. DWORD GetModuleBaseNameA( HANDLE hProcess, HMODULE hModule, LPSTR lpBaseName, DWORD nSize);

3 번 함수에서 얻어낸 모듈정보에서 해당 모듈들의 이름을 가져오는 간단한 함수이다.

[인자설명]

  • hProcess : 프로세스 핸들
  • hModule : 3번에서 얻어낸 모듈 배열 중에서 모듈 하나의 값
  • lpBaseName : 모듈이름이 저장될 문자열 변수
  • nSize : lpBaseName 사이즈

용례

typedef BOOL(__stdcall *EnumProcessModulesEx)(HANDLE, HMODULE *, DWORD, DWORD *, DWORD);
typedef DWORD(__stdcall *GetModuleBaseNames)(HANDLE, HMODULE, TCHAR *, DWORD);
typedef BOOL(__stdcall *EnumProcesses)(DWORD *, DWORD, LPDWORD);

int main(){
    HINSTANCE hModule = LoadLibrary(L"psapi.dll");
    EnumProcessModulesEx EnumProcessModule = (EnumProcessModulesEx)GetProcAddress(hModule, "EnumProcessModulesEx");
    GetModuleBaseNames GetModuleBaseName = (GetModuleBaseNames)GetProcAddress(hModule, "GetModuleBaseNameA");
    EnumProcesses EnumProcess = (EnumProcesses)GetProcAddress(hModule, "EnumProcesses");
    // main 함수 이어서...
}

우선 #include <Psapi.h> 으로 함수들을 불러올 수도 있지만, 대부분의 악성코드는 LoadLibrary 을 통해 동적으로 dll 을 가져온다.

그리고 typedef 로 함수 원형을 선언해놓고 GetProcAddress 함수로 원하는 함수를 dll 모듈에서 불러온다.

    // main 함수 이어서...

    DWORD myProcs[100000], countBytes;
    int numOfProcs;
    EnumProcess(myProcs, sizeof(myProcs), &countBytes);
    numOfProcs = countBytes / sizeof(DWORD);
    printf("전체프로세스 수는 %d 개\n", numOfProcs);

    for (int i = 0; i < numOfProcs; i++) {
        TCHAR modName[1024] = { 0, };
        if (myProcs[i]) {
            winlogon = OpenProcess(0x410, FALSE, myProcs[i]);
            if (winlogon && EnumProcessModule(winlogon, hMods, sizeof(hMods), &cb,0x2)) {
                // winlogon.exe in Windows 10. 
                // So, Use EnumProcessModulesEx function and Build Malware to 64 bit env.
                // 성공 시, return value is not 0. 실패 시, return value is 0.
                GetModuleBaseName(winlogon, hMods[0], modName, 1024);
                if(!strcmp((const char*)modName,"winlogon.exe")|| !strcmp((const char*)modName, "WinLogon.exe")){
                    // printf("%s\n", modName);
                    printf("WinLogon.exe PID: %d\n", winlogon_pid);
                    winlogon_pid = myProcs[i];
                    CloseHandle(winlogon);
                    break;
                }
            }
        }
    }

EnumProcesses 함수에서 얻어온 countBytes 를 DWORD 로 나누어서 프로세스 개수를 얻어온다. 그리고 프로세스 하나씩 OpenProcess 로 열면서 winlogon.exe 프로세스를 탐색한다. 그게 전부이다. critical 한 system 프로세스를 찾는 경우가 많다.

참고

프로세스 모듈 열거법

반응형