프로세스(Program) 보호

안티 디버깅과 프로세스 보호는 약간 차이가 있다. 안티 디버깅은 디버깅을 하지 못하도록 하여 프로그램의 실행 내용을 분석하지 못하도록 방해하는 행위로, 프로세스 보호와도 혼용하기도 하지만, 프로세스 보호는 후킹과 같은 외부 프로세스에서 해당 프로그램의 데이터를 조작하지 못하도록 방지하는 기능이라 할 수 있다. 쉽게 얘기하면 정당한 경로로 함수를 호출했는지를 확인하는, 안티 디버깅의 2차적 보안 기능인 셈이다. 안티 디버깅은 디버깅을 차단하는 기능으로 이것만으로는 후킹과 같은 인젝션 기능을 막지 못한다. 따라서 안티 디버깅과는 별개로 생각하면 된다(물론 이 역시 디버깅으로 분석하여 뚫을 수 있다. 따라서 디버깅 행위에 대한 보호가 먼저 이루어져야 한다).

이 기능은 후킹시 프로세스를 보호하고자 한다면, 어느 지점을 보호해야 하는지에 대해 알아 볼 수 있다. 여러분이 만든 프로그램이 후킹으로 인해 외부에서 내부 중요 함수가 호출되는 것을 막을 수 있는 방법이 어떤 것이 있는지 알아보도록 하자.

1 스레드 ID

우리는 앞서 후킹에 대해서 배우는데, 우리가 알고 있는 후킹 방법 중 다른 스레드에서 함수를 호출한 경우 이를 탐지하여 실행을 막는 기능에 대해 알아보자. 먼저 현재 스레드 ID를 기억하였다가 이를 이용해 활용하는 프로그램을 만들어 보자.

threaddetected.cpp
#include
<stdio.h>

#include
<windows.h>

#include
<conio.h>

// 실행 초기 현재 실행하는 프로그램의 스레드ID를 기억한다.

DWORD g_dwThreadID = GetCurrentThreadId();

void Check()

{

// Check함수를 해당 스레이드와 다른 스레드ID로 실행하는지 확인한다.

DWORD c_dwThreadID = GetCurrentThreadId();

if(c_dwThreadID != g_dwThreadID)

{

printf(“*Another thread ID call detected\n”);

printf(“*Current thread ID is : %d \n”, c_dwThreadID);

printf(“Original thread ID is : %d \n”, g_dwThreadID);

exit(0xF230BE05);

}

else

printf(“safe\n”);

}

void main()

{

while(true)

{

Sleep(1000);

Check();

}

return;

}

[예제] 스레드 ID 탐지 프로그램 Threaddetected

이제 후킹 Dll을 만들어 외부에서 Check 함수를 호출해 보자. 이를 위해서는 먼저 Threaddetected 프로그램 Ollydbg로 역분석해서, 해당 프로그램이 사용하는 주소를 알아보도록 하자.

프로세스(Program) 보호

[그림] Check 함수 호출 메모리 주소를 확인하자

얼핏 보면 0x4110D2가 Check 함수를 호출하는 것 같다. 하지만 이를 Step into(F7키)를 이용해 확인해 보면 JMP 명령을 통해 실제 함수 위치가 어디인지 알 수 있다.

[그림] 실제 호출 주소는 0x411390이다

이제 Check함수가 호출하는 메모리 주소가 0x411390이라는 것을 확인하였다. 이 Check 함수를 외부에서 호출할 수 있는 Dll을 만들어 인젝션을 하여야 한다.

Callhook라는 Dll을 만들어보자.

callhook.cpp
#include
<windows.h>

DWORD WINAPI MyThread(LPVOID);

DWORD g_threadID;

HMODULE g_hModule;

// 사전에 조사한 함수의 메모리 주소를 이용하여 호출을 대신한다.

// 함수 호출 규약에서 배웠듯이 프로그램 Check 프로그램과 동일한 호출 규약을 이용하여 호출하도록 하자.

void
__cdecl Callhook()

{

typedef
void (__cdecl *pCallAddress)();

// 조금 전 조사한 메모리 주소를 입력한다. 아래 주소는 운영체제마다 바뀔 수 있다.

pCallAddress Check = (pCallAddress)(0x00411390);

Check();

}

INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)

{

Switch(Reason)

{

case DLL_PROCESS_ATTACH:

g_hModule = hDLL;

DisableThreadLibraryCalls(hDLL);

CreateThread(NULL, NULL, &MyThread, NULL, NULL, &g_threadID);

break;

case DLL_THREAD_DETACH:

break;

}

return TRUE;

}

DWORD WINAPI MyThread(LPVOID)

{

while(true)

{

// F1키를 누루면 CallHook()을 이용하여 Check()함수를 호출 한다.

if(GetAsyncKeyState(VK_F1) & 1)

{

Callhook();

}

// 프로그램에 무리를 주지 않기 위해 삽입한다.

Sleep(100);

}

FreeLibraryAndExitThread(g_hModule, 0);

return 0;

}

[예제] 외부에서 함수를 호출하는 Callhook

위 Dll을 작성한 후 빌드하고 먼저 Threaddetected프로그램을 실행하자.

그리고 Threaddetected 프로그램의 PID를 작업관리자를 이용해 확인하고, InjectionDll을 이용하여 우리가 작성한 Dll을 인젝션 시키도록 하자. 필자 머신의 후킹할 프로그램 PID는 2192이다.

injectiondll –i 2192 Callhook.dll

정상적으로 인젝션 되었다면 아래와 같은 성공 문구가 나타난다.

[그림] 인젝션이 정상적으로 완료되었다.

이제 실습 준비가 마무리되었다. F1키를 누르면 우리가 만든 Callhook.dll에 의해서 Check 함수가 호출되고, Threaddetect 프로그램은 사전에 구해놓은 스레드 ID와 비교 후 값이 맞지 않으면 다른 스레드 ID에서 실행한 것으로 판단하고 프로그램을 아래와 같이 종료하게 된다.

[그림] 현재 스레드와 함수를 호출한 스레드를 확인 후 다른 경우 종료

2 스택 영역

프로세스와 스레드는 개별적으로 사용하는 메모리 영역이 존재한다. 즉 고유한 메모리 영역인 스택과 자신만의 메모리 공간을 이용한다는 특성을 이용해 후킹을 통해 함수를 호출하는지를 감지하고 실행할 수 있다.

그럼 스레드 고유 영역 중 스택 주소를 이용한 방법을 알아 보자. 필자는 스레드별 가지는 스택 기본 주소를 이용하여 현재 스레드에서 실행하였는지를 확인하였다.

stackbasecheck.cpp
#include
<stdio.h>

#include
<windows.h>

DWORD g_dwStackBase;

// 현재 스레드의 스택 베이스 주소를 얻어온다.

DWORD CurrentStackBase()

{

__asm {

// TEB 주소로 접근한다.

MOV EAX,DWORD PTR FS:[0x18]

// StackBase 주소값을 확인한다.

XOR EAX, 0x4

SUB EBX, EBX

XOR EBX, [EAX]

MOV g_dwStackBase, EBX

};

return(g_dwStackBase);

}

// 기존 확인해 놓았던 스레드 스택 주소와 현재 콜을 진행한 스레드의 스택 주소를 확인하여 비교하기 위해 스택 주소를 다시 확인 한다.

DWORD HookCheck()

{

DWORD dwStackBase;

__asm {

MOV EAX,DWORD PTR FS:[0x18]

XOR EAX, 0x4

SUB EBX, EBX

XOR EBX, [EAX]

MOV dwStackBase, EBX

};

return(dwStackBase);

}

void Check()

{

if(HookCheck() != g_dwStackBase)

{

printf(“Another thread Call detected\n”);

exit(0x0AD132D5);

}

else

printf(“safe\n”);

}

void main()

{

CurrentStackBase();

while(true)

{

Sleep(1000);

// Check() 함수를 후킹할 경우 기존 스레드에서 실행하였는지 스택주소를 이용하여 확인한다.

Check();

}

return;

}

[예제] 스택주소를 통해 확인하는 Stackbasecheck 예제

위 프로그램을 컴파일 한 후 파일을 열러 보면 아래 메인 코드를 만날 수 있다.

[그림] Check 함수 호출 주소

이 역시 동일하게 Check 함수의 실제 호출 주소를 위해 Step into(F7키)를 진행한다.

[그림] 실제 Check 호출은 0x411910에서 이루어진다

ThreadID 체크 용도로 사용한 Callhook에서 Check 함수의 호출 주소를 변경한 이후 진행해 보자. Stackbasecheck 프로그램을 먼저 실행하고 작업 관리자에서 해당 PID를 확인한 이후 Callhook.dll을 인젝션하도록 하자.

인젝션이 완료되었다면, F1키를 눌려 실행하면 아래와 같이 다른 스택 주소를 가진 정상적이지 않은 호출이라는 것을 탐지하게 된다.

[그림] 기본 스택 주소가 다르다는 것을 탐지하였다

이외에도 프로세스별 메모리에 로드되는 주소를 이용한 방법도 있고, 프로그램의 함수 호출 주소를 이용할 수도 있다. 그리고 프로그램의 위치를 확인할 수 없도록 PEB 등의 정보를 삭제하는 방법, 메모리 할당을 해제하는 방법 등도 존재하므로 확인해보기 바라며, 아래 안티 디버깅 관련 하여 도움이 될 만한 자료를 추가하니 확인하기 바란다.

http://www.codeproject.com/Articles/30815/An-Anti-Reverse-Engineering-Guide

3 DKOM

DKOM((Direct Kernel Object Manipulation)이란 커널 개체를 직접 조작하는 방법을 말한다.

이 방법을 이용하여 프로세스를 숨기거나 접근을 차단할 수 있고, 이 외에도 스레드, 드라이버 숨기기 및 권한 상승과 같은 방법을 이용할 수 있는데, DKOM 기법을 이용하면, 커널 개체 관리자를 거치지 않고 직접 개체를 수정하기 때문에 권한 체크 없이 실행되어 탐지가 어렵다. 하지만 그만큼 커널에 심각한 오류를 불러올 수도 있으므로, 운영체제 버전별 차이를 이해하고 커널 구조를 잘 알고 이용하해야 한다.

그럼 여기에서는 일반적으로 많이 알려준 DKOM 기법 중 프로세스를 숨기는 기법에 대해 알아보도록 하자. 단 여기에서도 커널 개체이기 때문에 일반 프로세스가 아닌 드라이버로 개발해야 한다. 이 역시 책의 범위는 넘어가기 때문에 포함하지 않고 Windbg를 이용하여 DKOM에 대한 원리 설명에 집중하도록 하겠다. 소스코드는 인터넷에서 약간의 노력을 기울이면 쉽게 찾아낼 수 있을 것이다. 그럼 계속 진행해보자. 운영체제에서 프로세스의 리스트를 알아내기 위해 사용하는 함수가 바로 ZwQuerySystemInformation 함수이다. 이는 2부에서 확인한 EPROCESS 구조체에서 ActiveProcessLinks 개체를 통해 Doubly Linked List 형태(FLINK와 BLINK 방식의 이중 연결 형태의 멤버를 가진 LIST_ENTRY 구조체)로 관리되는데, DKOM, 즉 이 커널 개체의 연결을 끊어서 프로세스를 숨기게 된다.

[그림] EPROCESS의 LIST_ENTRY 연결을 끊어 프로세스 정보를 감춘다

이는 어떻게 가능할까?

먼저 현재 구동 중인, 숨기고하 하는 프로세스의 정보를 가지고 있는 EPROCESS의 주소는 PsGetCurrentProcess 함수를 이용하여 찾을 수 있다.

이를 Windbg를 이용하여 어셈블리 해보면, 아래와 같이 이는 FS레지스터의 오프셋 0x124 위치에 저장되어 있어 있으며 이를 통해, KTHREAD 주소를 구하거나 EPROCESS 구조체의 주소도 구할 수 있게 된다.

0: kd> u nt!PsGetCurrentProcess

nt!PsGetCurrentProcess:

8052d302 64a124010000 mov eax,dword ptr fs:[00000124h]

8052d308 8b4044 mov eax,dword ptr [eax+44h]

단 주의할 점은 우리는 앞서 FS 레지스터를 이용하여 프로세스 보호를 이용하였다. 하지만 FS 레지스터는 사용하는 모드에 따라 다음과 같이 바뀌므로 주의를 기울여야 한다.

유저모드의 FS 레지스터는 _TEB (Thread Environment Block)를 가리키고, 커널 모드의 FS 레지스터 _KPCR (Kernel’s Process Control Region)를 가리키는데, 이 같은 차이가 있는 이유는 유저모드에서는 FS 레지스터의 세그먼트 셀렉터 값을 0x38을 사용하게 되고, 커널 모드에서는 0x30를 사용하기 때문에 사용에 앞서 커널 모드인지 유저모드인지 인지하고 이용하여야 엉뚱한 값을 가져오는 것을 방지할 수 있고, 셀렉터 값은 임의로 변경할 수 없다(따라서 커널 모드에서 동작하는 드라이버로 개발하여야 한다). 그럼 커널 모드에서 위 PsGetCurrentProcess가 어떻게 EPROCESS를 찾는지 Windbg를 이용해 확인해 보자.

// 커널 모드에서는 FS레지스터가 30h으로, _KPCR를 가리키게 된다. 이를 기준으로 124h에 위치한 값을 따라가보자.

0: kd> dt _KPCR

nt!_KPCR

+0x000 NtTib : _NT_TIB

+0x01c SelfPcr : Ptr32 _KPCR

+0x020 Prcb : Ptr32 _KPRCB

+0x024 Irql : UChar

+0x028 IRR : Uint4B

+0x02c IrrActive : Uint4B

+0x030 IDR : Uint4B

+0x034 KdVersionBlock : Ptr32 Void

+0x038 IDT : Ptr32 _KIDTENTRY

+0x03c GDT : Ptr32 _KGDTENTRY

+0x040 TSS : Ptr32 _KTSS

+0x044 MajorVersion : Uint2B

+0x046 MinorVersion : Uint2B

+0x048 SetMember : Uint4B

+0x04c StallScaleFactor : Uint4B

+0x050 DebugActive : UChar

+0x051 Number : UChar

+0x052 Spare0 : UChar

+0x053 SecondLevelCacheAssociativity : UChar

+0x054 VdmAlert : Uint4B

+0x058 KernelReserved : [14] Uint4B

+0x090 SecondLevelCacheSize : Uint4B

+0x094 HalReserved : [16] Uint4B

+0x0d4 InterruptMode : Uint4B

+0x0d8 Spare1 : UChar

+0x0dc KernelReserved2 : [17] Uint4B

+0x120 PrcbData : _KPRCB

// 124h는 _KPRCB에 포함되는 값으로 나타난다. 그럼 계속해서 _KPRCB를 확인해 보자.

0: kd> dt _KPRCB

ntdll!_KPRCB

+0x000 MinorVersion : Uint2B

+0x002 MajorVersion : Uint2B

+0x004 CurrentThread : Ptr32 _KTHREAD

+0x008 NextThread : Ptr32 _KTHREAD

+0x00c IdleThread : Ptr32 _KTHREAD

// 현재 스레드의 정보인 _KTHREAD의 위치를 확인할 수 있었다. 그럼 오프셋 44h에 어떤 값이 들어 있는지 계속 확인해 보자.

0: kd> dt -r _KTHREAD

ntdll!_KTHREAD

+0x000 Header : _DISPATCHER_HEADER

+0x000 Type : UChar

+0x001 Absolute : UChar

+0x002 Size : UChar

+0x003 Inserted : UChar

+0x004 SignalState : Int4B

+0x008 WaitListHead : _LIST_ENTRY

+0x000 Flink : Ptr32 _LIST_ENTRY

+0x004 Blink : Ptr32 _LIST_ENTRY

+0x010 MutantListHead : _LIST_ENTRY

+0x000 Flink : Ptr32 _LIST_ENTRY

+0x000 Flink : Ptr32 _LIST_ENTRY

+0x004 Blink : Ptr32 _LIST_ENTRY

+0x004 Blink : Ptr32 _LIST_ENTRY

+0x000 Flink : Ptr32 _LIST_ENTRY

+0x004 Blink : Ptr32 _LIST_ENTRY

+0x018 InitialStack : Ptr32 Void

+0x01c StackLimit : Ptr32 Void

+0x020 Teb : Ptr32 Void

+0x024 TlsArray : Ptr32 Void

+0x028 KernelStack : Ptr32 Void

+0x02c DebugActive : UChar

+0x02d State : UChar

+0x02e Alerted : [2] UChar

+0x030 Iopl : UChar

+0x031 NpxState : UChar

+0x032 Saturation : Char

+0x033 Priority : Char

+0x034 ApcState : _KAPC_STATE

+0x000 ApcListHead : [2] _LIST_ENTRY

+0x000 Flink : Ptr32 _LIST_ENTRY

+0x004 Blink : Ptr32 _LIST_ENTRY

+0x010 Process : Ptr32 _KPROCESS

[실습] EPROCESS 위치 확인

따라서 우리가 원하는 값을 찾기 위해 먼저 윈도우 XP의 EPROCESS에서 ActiveProcessLinks 구조체의 위치를 확인하자(필자는 윈도우 XP로 진행하였지만, 비스타 혹은 윈도우 7으로 진행해도 된다).

// _EPROCESS의 구조체를 확인해 보면, 88h위치에 ActiveProcessLinks 구조체가 위치하고 있음을 확인할 수 있다.

0: kd> dt _EPROCESS -r

ntdll!_EPROCESS

+0x000 Pcb : _KPROCESS ß _KPROCESS는 _EPROCESS의 첫번째 멤버로 _EPROCESS 포인터와 동일하다.

+0x000 Header : _DISPATCHER_HEADER

+0x000 Type : UChar

+0x001 Absolute : UChar

+0x002 Size : UChar

+0x003 Inserted : UChar

+0x004 SignalState : Int4B

+0x008 WaitListHead : _LIST_ENTRY

+0x010 ProfileListHead : _LIST_ENTRY

+0x000 Flink : Ptr32 _LIST_ENTRY

+0x004 Blink : Ptr32 _LIST_ENTRY

…중략

+0x004 HighPart : Int4B

+0x000 u : __unnamed

+0x000 LowPart : Uint4B

+0x004 HighPart : Int4B

+0x000 QuadPart : Int8B

+0x080 RundownProtect : _EX_RUNDOWN_REF

+0x000 Count : Uint4B

+0x000 Ptr : Ptr32 Void

+0x084 UniqueProcessId : Ptr32 Void

// EPROCESS 기준 0x88 위치에 0x8 크기로 위치하고 있다.

+0x088 ActiveProcessLinks : _LIST_ENTRY

+0x000 Flink : Ptr32 _LIST_ENTRY

+0x000 Flink : Ptr32 _LIST_ENTRY

+0x004 Blink : Ptr32 _LIST_ENTRY

+0x004 Blink : Ptr32 _LIST_ENTRY

+0x000 Flink : Ptr32 _LIST_ENTRY

+0x004 Blink : Ptr32 _LIST_ENTRY

[실습] EPROCESS에서 ActiveProcessLinks 구조체 확인

그럼 Windbg를 이용하여 커널 디버깅상황에서 Cmd.exe를 실행하고 이 Cmd.exe를 감춰 보도록 보자.

// Cmd.exe 프로세스 정보를 확인하기 위해 프로세스 리스트를 확인하자.

kd> !process 0 0

**** NT ACTIVE PROCESS DUMP ****

PROCESS 81fb99c8 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000

DirBase: 00039000 ObjectTable: e1000d10 HandleCount: 409.

Image: System

PROCESS 81d67020 SessionId: none Cid: 01a4 Peb: 7ffdb000 ParentCid: 0004

DirBase: 09ce1000 ObjectTable: e12f2080 HandleCount: 17.

Image: smss.exe

…중략

PROCESS 81dec3c0 SessionId: 0 Cid: 07ac Peb: 7ffde000 ParentCid: 06ec

DirBase: 1011c000 ObjectTable: e1863d60 HandleCount: 73.

Image: ctfmon.exe

PROCESS 81df0748 SessionId: 0 Cid: 00b8 Peb: 7ffdf000 ParentCid: 06ec

DirBase: 11d1e000 ObjectTable: e1b5d188 HandleCount: 34.

Image: Cmd.exe

PROCESS 81b49930 SessionId: 0 Cid: 00c4 Peb: 7ffde000 ParentCid: 00b8

DirBase: 11e9b000 ObjectTable: e174ad78 HandleCount: 40.

Image: conime.exe

// 확인한 Cmd.exe의 프로세스 정보를 통해 ActiveProcessLinks 정보를 확인하자.

kd> dt _EPROCESS 81df0748

ntdll!_EPROCESS

+0x000 Pcb : _KPROCESS

+0x06c ProcessLock : _EX_PUSH_LOCK

+0x070 CreateTime : _LARGE_INTEGER 0x1cd3e0a`b6ae42e0

+0x078 ExitTime : _LARGE_INTEGER 0x0

+0x080 RundownProtect : _EX_RUNDOWN_REF

+0x084 UniqueProcessId : 0x000001d0 Void

+0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x80563358 – 0x81cffc98 ]

+0x090 QuotaUsage : [3] 0x960

+0x09c QuotaPeak : [3] 0xba8

+0x0a8 CommitCharge : 0x163

…중략

// dl 명령을 이용하면, 이중 연결 리스트를 쉽게 확인할 수 있다. 조금 전에 확인한 ActiveProcessLinks의 주소를 입력하여 전체 리스트를 확인하자. 실제 이 주소는 PsActiveProcessHead와 동일한 주소를 가리킨다.

kd> dl 80563358

80563358 81fb9a50 81dc9568 00000001 f45dda6c

81fb9a50 81d670a8 80563358 00000000 00000000

81d670a8 81d42c90 81fb9a50 00000280 00001468

81d42c90 81d601b0 81d670a8 00001680 00013bc0

81d601b0 81d2e0a8 81d42c90 0000a990 0000fe70

81d2e0a8 81de0b98 81d601b0 00001ab8 00006078

81de0b98 81e49788 81d2e0a8 000027e8 0000aacc

81e49788 81ce1550 81de0b98 00000cb0 00005450

81ce1550 81dfd510 81e49788 00001a80 0000ac50

81dfd510 81cdda10 81ce1550 00003a28 0000a544

81cdda10 81d99d88 81dfd510 0000f468 0001e788

81d99d88 81e29620 81cdda10 00000db0 00007b34

81e29620 81bbb938 81d99d88 000018c0 0000a4c8

81bbb938 81bab5a0 81e29620 00001630 0000acbc

81bab5a0 81ecba48 81bbb938 00002a88 000115c4

81ecba48 81dc64e8 81bab5a0 00000be0 00007c80

81dc64e8 81df07d0 81ecba48 00000910 000079d0

// Cmd.exe의 ActiveProcessLinks 정보로써 이 연결 리스트 위 아래의 정보를 수정해 잘라야 한다.

81df07d0
81b499b8 81dc64e8 000009b0 00008028

81b499b8 81cf14c8 81df07d0 00000a78 0000835c

81cf14c8 81cffc98 81b499b8 00008718 00007b50

81cffc98 81ac6148 81cf14c8 00001b20 00009988

81ac6148 81aeaab8 81cffc98 00000690 00003c64

81aeaab8 81aea460 81ac6148 00000960 00007464

81aea460 81aef7a8 81aeaab8 00001450 0000a468

81aef7a8 81d5fc98 81aea460 00001e00 0000f6d0

81d5fc98 81d12e28 81aef7a8 000017c8 00009c78

81d12e28 81dc9568 81d5fc98 00000848 000088c0

81dc9568 80563358 81d12e28 00000de8 000095e8

// 위 PsActiveProcessHead 리스트에서 오프셋 88h를 빼면 EPROCESS 주소로써 연결 리스트가 관리되고 있음을 알 수 있다.

kd> dt _EPROCESS ImageFileName 81df07d0-88

ntdll!_EPROCESS

+0x174 ImageFileName : [16] “Cmd.exe”

// 그럼 앞뒤 프로세스는 어떤 것이 있는지 확인해 보자.

kd> dt _EPROCESS ImageFileName 81b499b8-88

ntdll!_EPROCESS

+0x174 ImageFileName : [16] “ctfmon.exe”

kd> dt _EPROCESS ImageFileName 81ecba48-88

ntdll!_EPROCESS

+0x174 ImageFileName : [16] “conime.exe”

// 그럼 우리가 제거하고자 하는 Cmd.exe의 ActiveProcessLinks 인 81df07d0를 제거하기 위해 그 앞과 뒤쪽의 ActiveProcessLinks로 연결해 주도록 하자.

[그림 30] Cmd.exe의 연결 리스트에서 제외

// ed 명령을 이용하여 PsActiveProcessHead의 리스트 상에서 제거한다.

kd> ed 81dc64e8 81b499b8

kd> ed 81b499b8+4 81ecba48

[실습] ActiveProcessLinks를 이용한 프로세스 숨기기

이제 Windbg에서 실행(g키)를 눌러 디버기(디버깅을 당하는 가상머신)를 실행하면, 아래와 같이 Cmd.exe를 작업 관리자에서 확인할 수 없다.

[그림] Cmd.exe를 감추었다

PID를 ETHREAD 구조체를 통해서 구할 수도 있을 것이다. 이외에 프로세스를 숨기는 방법으로 Handle Table의 링크를 끊거나, UniqueProcessId 값 변경, ETHREAD에 대한 참조값 삭제 등을 이용하여 가능하다. 그리고 Windbg를 이용해서 문제점을 찾아, 새로운 DKOM을 발견 할 수도 있을 것이니, 이를 위해 커널 내부구조를 더욱 자세히 이해할 필요가 있다.

ActiveProcessLinks를 이용한 프로세스 숨기기의 개발 코드가 궁금한 분은 다음 링크를 확인하면, 유용할 것이다.

DKOM Question ( EPROCESS Access )

http://forum.cheatengine.org/viewtopic.php?p=5223968&sid=8206ed545cf928c64fff577065980105

Dkom Process Hider

http://www.rohitab.com/discuss/topic/23880-dkom-process-hider

Facebook Comments

Leave A Reply

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.