일부 보안 제품의 경우 자사 프로세스들을 보호하기 위해 여러가지 방법들을 사용합니다.
그 중 가장 많이 사용되는 방법중 하나가 SSDT 후킹입니다. 그런데 이 방법은 64비트 윈도우에서는 패치가드로 인해 사용할 수 없죠.
물론 패치가드를 무력화 또는 우회하는 기법들도 계속 발전하고 있지만 안정성은 보장할 수 없습니다.
이번 포스팅에서는 기본적으로 제공되는 방법으로 간단히 프로세스를 보호하는 방법에 대해 끄적여 보겠습니다.
우선 어떤 행동으로부터 특정 프로세스를 보호할지 생각해보죠.
가장 우선 막아야할 행동으로는 프로세스 종료시키기와 해당 프로세스 가상 메모리 변조를 들 수 있습니다.
API로 예를 들면 TerminateProcess와 WriteProecssMemory 라고 할 수 있습니다.
물론 유저레벨에서 글로벌 후킹을 통해 수행할 수 있겠지만 그런 무식한 방법은 버리죠.
nt 커널에서 익스포트하고 있는 ObRegisterCallbacks 를 이용하면 쉽게 구현 가능합니다.
이전에 소개해드린 프로세스 실행 차단 콜백과 유사하다고 생각하시면 됩니다.
이 DDI는 x86, x64에서 모두 사용가능하다는 장점이 있습니다. 단점은 Vista sp1과 Windows 2008 이후 운영체제에서만 가능하단 점입니다.
ObRegisterCallback은 프로세스 오브젝트와 쓰레드 오브젝트의 Pre / Post Operation 시점에 콜백을 받게 해주는 역할을 합니다. 핸들 생성 혹은 복사 모두에 대해 콜백을 받을 수 있습니다.
우리가 관심을 가질 부분은 Pre 시점 콜백입니다.
Pre 시점 콜백의 원형은 요렇게 생겼습니다. (http://msdn.microsoft.com/en-us/library/ff557745(VS.85).aspx)
OB_PREOP_CALLBACK_STATUS ObjectPreCallback(
__in PVOID RegistrationContext,
__in POB_PRE_OPERATION_INFORMATION OperationInformation
);
이중 두번째 파라미터를 보면 되겠습니다.
typedef struct _OB_PRE_OPERATION_INFORMATION {
OB_OPERATION Operation;
union {
ULONG Flags;
struct {
ULONG KernelHandle:1;
ULONG Reserved:31;
};
};
PVOID Object;
POBJECT_TYPE ObjectType;
PVOID CallContext;
POB_PRE_OPERATION_PARAMETERS Parameters;
} OB_PRE_OPERATION_INFORMATION, *POB_PRE_OPERATION_INFORMATION;
이 구조체의 필드중 Parameters 필드를 조작하면 우리가 원하는 결과를 얻을 수 있습니다.
해당 OB_PRE_OPERATION_PARAMETERS 구조체는 Create / Duplicate 정보를 담고 있습니다.
각 operation에 따라 처리를 해주면 되죠.
일반적으로 OpenProcess등을 통해 핸들을 생성할 경우 Create 쪽 정보를 보면 됩니다.
OB_PRE_OPERATION_PARAMETERS 구조체의 Create 쪽 필드의 구조체는 요렇게 생겼습니다.
typedef struct _OB_PRE_CREATE_HANDLE_INFORMATION {
ACCESS_MASK DesiredAccess;
ACCESS_MASK OriginalDesiredAccess;
} OB_PRE_CREATE_HANDLE_INFORMATION, *POB_PRE_CREATE_HANDLE_INFORMATION;
OriginalDesiredAccess 필드는 operation을 요청할 당시에 지정된 ACCESS_MASK입니다.
우리는 OriginalDesiredAccess 정보를 바탕으로 DesiredAccess 필드를 조작하면 되겠습니다.
간단한 테스트용 드라이버를 만들어서 실제 보호를 해보도록 하겠습니다.
Windows 7 x64 머신에 메모장을 하나 실행시켜두고 이 메모장 프로세스를 보호해보죠.
해당 메모장 프로세스에 로드된 DLL 정보들도 잘 나옵니다.
이제 이 메모장을 보호해보죠.
프로세스 오브젝트의 Pre Operation 콜백을 등록하고 이 콜백은 대강 요렇게 구성했습니다.
ObjectPreCallback(
IN PVOID pRegistrationContext,
IN POB_PRE_OPERATION_INFORMATION pOperationInformation
)
{
HANDLE pid = PsGetProcessId((PEPROCESS)pOperationInformation->Object);
if (pid == (HANDLE)2824)
{
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
}
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_OPERATION) == PROCESS_VM_OPERATION)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_OPERATION;
}
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_READ) == PROCESS_VM_READ)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_READ;
}
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_WRITE) == PROCESS_VM_WRITE)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_WRITE;
}
}
}
return OB_PREOP_SUCCESS;
}
프로세스 ID는 하드코딩했습니다. ㅋㅋ
ACCESS_MASK중 보호 프로세스를 건드릴만한 것중 일부를 제거하도록 구성했습니다.
요렇게 해서 드라이버를 타겟 머신에 로드 후 프로세스 익스플로러로 메모장을 보면 요렇게 됩니다.
DLL 정보가 나오지 않습니다~!
Kill 시도를 해볼까요.
보호되었습니다.^^
더 재미난 일들도 할 수 있습니다. 한번 해보세요^^
그럼 즐프하세요~
[출처] x64 에서 프로세스 보호|작성자 꿀보