#include <ntddk.h>

 

typedef struct ServiceDescriptorEntry
{
 unsigned int* ServiceTableBase;
 unsigned int* ServiceCounterTableBase;
 unsigned int NumberOfServices;
 unsigned char* ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;

__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;

typedef NTSTATUS (*NTOPENPROCESS)(PHANDLE ProcessHandle,
          ACCESS_MASK DesiredAccess,
          POBJECT_ATTRIBUTES ObjectAttributes,
          PCLIENT_ID ClientId OPTIONAL);

NTOPENPROCESS OrigNtOpenProcess = NULL;

NTSTATUS HookNtOpenProcess (PHANDLE ProcessHandle,
       ACCESS_MASK DesiredAccess,
       POBJECT_ATTRIBUTES ObjectAttributes,
       PCLIENT_ID ClientId OPTIONAL)
{
 NTSTATUS ntReturn = STATUS_SUCCESS;
 DbgPrint("HookNTOpenProcess\n");

 ntReturn = OrigNtOpenProcess(ProcessHandle,
  DesiredAccess,
  ObjectAttributes,
  ClientId);

 return ntReturn;
}

VOID HookServiceTable()
{
 OrigNtOpenProcess = (PVOID) InterlockedExchangePointer(
  (PVOID*) &KeServiceDescriptorTable.ServiceTableBase[0x7A], HookNtOpenProcess);
}


VOID DRIVERUnload(IN PDRIVER_OBJECT DriverObject)
{
 __asm{
  cli
  push eax
  mov eax, cr0
  and eax,0xfffeffff
  mov cr0, eax
  pop eax
 }
 DbgPrint("CR0 WP bit disabled\n");

 InterlockedExchangePointer(
  (PVOID*) &KeServiceDescriptorTable.ServiceTableBase[0x7A], OrigNtOpenProcess);

 __asm{
  push eax
  mov eax, cr0
  or eax, NOT 0xfffeffff
  mov cr0, eax
  pop eax
  sti
 }
 DbgPrint("CR0 WP bit enabled\n");

 DbgPrint("Hook Unloaded\n");


}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject ,
      IN PUNICODE_STRING RegistryPath)
{
 DriverObject->DriverUnload=DRIVERUnload;

 __asm{
  cli
  push eax
  mov eax, cr0
  and eax,0xfffeffff
  mov cr0, eax
  pop eax
 }
 DbgPrint("CR0 WP bit disabled\n");

 HookServiceTable();

 __asm{
  push eax
  mov eax, cr0
  or eax, NOT 0xfffeffff
  mov cr0, eax
  pop eax
  sti
 }
 DbgPrint("CR0 WP bit enabled\n");
 return STATUS_SUCCESS;
}



사실 이것을  드라이버 작성법도 올바르게 모르는 내가 혼자 다했다고 하면 , 뻥인게 확실할것이고..
각종 서적에 나와있는 방법들과  ,인터넷 사이트들을 뒤져가면서..(물론 이런 종류의 코드는 널리 알려진지 꽤나 오래됐지만)
초보의 입장에서 직접 쳐보면서 원리를 이해하고자 나름대로 노력하였다. (다행히도 나름대로 90%정도는 이해한것 같다!)

C언어를 처음배울 때 ,  뭣도 모르고  printf ,` #include ,` int main(void)  등을 사용하지 않았는가?
그와 비슷한 것이라고 보면 될듯...

드라이버가 로드되면,
ntoskrnl 이 export 하고있는   SDT 테이블을 얻어와서 , InterLockedExchangePointer 함수를 이용해서 포인터를 교환해버리는 방식이다. 즉 , Hook된 NtOpenProcess가 호출되게끔 되는것이다. 위 코드 상에서는 , 특별히 다른 작업은 수행안하고 , 오리지널 NtOpenProcess를 호출하고 있다.
물론 , 언로드되면  기존의 백업해두었던 포인터를 다시 원래대로 돌려놓는 방식..

그런데 , 요즘 이 방법이 먹힐거라고 보면 큰 오산이다.
이유인 즉슨, 근래 대부분의 보안프로그램들은 ,  API 내부적으로 호출하는 함수들 또한 후킹을 하고있기 때문이다.

NtOpenProcess가  내부적으로  호출하고있는 함수들의 목록은 다음과 같다.

0: kd> uf -c nt!NtOpenProcess
nt!NtOpenProcess (805cd408)
  nt!NtOpenProcess+0xa (805cd412):
    call to nt!_SEH_prolog (8053db90)
  nt!NtOpenProcess+0x4e (805cd456):
    call to nt!ExRaiseDatatypeMisalignment (80616090)
  nt!NtOpenProcess+0x7c (805cd484):
    call to nt!ExRaiseDatatypeMisalignment (80616090)
  nt!NtOpenProcess+0x116 (805cd51e):
    call to nt!SeCreateAccessState (805f2dc4)
  nt!NtOpenProcess+0x132 (805cd53a):
    call to nt!SeSinglePrivilegeCheck (805f9cde)
  nt!NtOpenProcess+0x17d (805cd585):
    call to nt!ObOpenObjectByName (805bd8f2)
  nt!NtOpenProcess+0x18b (805cd593):
    call to nt!SeDeleteAccessState (805f2b86)
  nt!NtOpenProcess+0x1e2 (805cd5ea):
    call to nt!PsLookupProcessThreadByCid (805d502e)
  nt!NtOpenProcess+0x1f4 (805cd5fc):
    call to nt!SeDeleteAccessState (805f2b86)
  nt!NtOpenProcess+0x202 (805cd60a):
    call to nt!PsLookupProcessByProcessId (805d50ea)
  nt!NtOpenProcess+0x224 (805cd62c):
    call to nt!ObOpenObjectByPointer (805bdc78)
  nt!NtOpenProcess+0x232 (805cd63a):
    call to nt!SeDeleteAccessState (805f2b86)
  nt!NtOpenProcess+0x23e (805cd646):
    call to nt!ObfDereferenceObject (8052868e)
  nt!NtOpenProcess+0x246 (805cd64e):
    call to nt!ObfDereferenceObject (8052868e)
  nt!NtOpenProcess+0x27e (805cd686):
    call to nt!_SEH_epilog (8053dbcb)


만약 보안솔루션이나 기타 루트킷등에서 내부 함수들까지 싹다 후킹해버리면 , 여간 귀찮은게 한두가지가 아닐듯 하다..

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
by Sone 2009.08.19 00:16

흔히 , 자신이 사용하고 있는 컴퓨터 내부에는  부품이 어떤것이 있는가

를 잘 모르고  컴퓨터를 사용하는 경우가 많다. (초보자인 경우가  대부분 그러하다.)

 

이때 ,  잘못해서 윈도우를  재설치 하거나할때 ,  드라이버를 잡아주는 과정에서  많이 어려움을 겪는다.

모델명을 모를경우  대부분   컴퓨터 본체를 뜯어서  그래픽카드의 모델명이 무엇인지 일일이 확인해야 하는 불편함이 있다.

 

부품중에서도   VGA는   컴퓨터 메인보드의  ROM과 같이   바이오스가 탑재되어 있다.

이러한 바이오스는 부팅할때 , 메모리에 그 정보가 올라가게 되는데 , 항상 일정한 위치에 탑재되게 된다.

 

물론 ,  바이오스가 존재하지 않는  다른 사운드카드라던가 , 랜카드 같은 것들은  덤프를 통해서 정보를 알아낼수가 없을것이다. (추측)

 

우리는   부팅할때  VGA의 바이오스가 메모리에 올라간다는 사실만으로 ,  그래픽카드 드라이버를 설치하지 않았더라도,

또는   컴퓨터 본체를 번거롭게 뜯어서  모델명을 확인하지 않고도,

그래픽카드가  어떠한 종류인지를  자세하게 알아낼 수 있다.

 

 

 

 

 

 

시작 - 실행 - cmd  입력 후 엔터

( 또는  보조프로그램에 있는 "명령프롬프트" 를 실행해도 된다. )

( 또는  윈도우키+R 을 누른뒤   cmd 입력 후 엔터 )

 

 

 

 

 

 

 

 

위와 같이 화면이 나올것이다.

 

이제 여기서  debug  라고 입력하고 엔터를 누른다.

 

 

 

 

 

윈도우에 탑재되어있는  디버그 명령을 이용해서  메모리 주소에 접근할 것이다.

위와 같이  '  -  '  마이너스 프롬프트가 나오면 정상적으로  디버깅모드로 들어간 것이다.

 

간단히  디버그 명령어 몇개를 알아보기 위해서   ?  를 입력하고 엔터를 누른다.

 

 

 

 

 

갖가지 명령어들이 있는데   a 는 assemble을 할수있고 ,  d는 dump  ,   c는 compare ,  s  는  search 등등의 기능들이 있다.

우리는 여기서  d = dump 의  기능을 써서 그래픽카드 정보를 알아낼 것이다.

 

정보를 알아내기전에 ,  심심해서 또 다른것도 알아볼겸 ,   r 을 누르고  엔터를 쳐본다.

 

 

 

 

r은   CPU내에 있는  레지스터의 정보를  보여주는 기능이다.

어큐물레이터 레지스터(AX) , 베이스 레지스터(BX) , 카운터 레지스터(CX) , 데이타 레지스터(DX) , 스택 포인터(SP) , 베이스 포인터(BP) , 소스 인덱스(SI) ,

데스티네이션 인덱스(DI) ,   데이타 세그먼트(DS), 엑스트라 세그먼트(ES) , 코드 세그먼트(CS) , 인스트럭션 포인터(IP) , 각종 플래그   등의 상태값을 보여준다.

 

여기서는 각종 레지스터의 값들을   2바이트  16비트 형으로 보여주고 있지만,

32비트로 본다면 ,   앞에다가  Extend 라는 이름의 약자를 따서  E를 붙여주게 된다.

따라서 이때는  EAX,EBX,ECX,EDX,ESP,EBP,ESI,EDI  로 명칭한다.

 

이러한 레지스터들은   데이터를 처리할때  임시로 정보를 기억하는 곳이다.

 

 

 

이제 대충 debug 의 기능을  훑어본것 같으니  ,  그래픽카드 정보를  본격적으로 알아보자.

 

dc000:0   이라고 입력 후 엔터를 눌러준다.

 

 

 

 

 

위와 같이  이상한  문자들이 출력될 것이다.

 

한두번정도 d 를 더 입력해주게 되면...

 

 

 

 

 

 

위와 같이   우리가 컴퓨터를 부팅할때  VGA의 바이오스 내용이  메모리로 올라갔던  정보가   덤프되어져서 나오게 된다.

 

 

필자는   ATI RadeonHD 3850  256MB GDDR3  PCI-Express 방식의 VGA를 쓰고있다.

 

자세히 보면   RV670 . PCI_EXPRESS.DDR3......GDDR3_8Mx32 256bit 256MB  669e/829m   이라고 나와있는것을 확인할 수 있다.

 

여기서 그래픽카드의 정보를 유추해보자면,

 

RV670 = ATI Radeon HD3850의  코드명

PCI_EXPRESS = PCI-Express 16x 방식의 슬롯에 꽂혀있고  작동한다.

GDDR3 = GDDR3 방식의  그래픽메모리를 사용한다.

8Mx32 =  8MB GDDR3 메모리 칩이  32개 박혀있는것을 뜻한다. 즉 256MB 이다. (실제로 32개가 박혀있진 않을것이고 , 다른 구조일것이다)

256bit = 256비트 메모리 버스로 동작한다.

256MB =  그래픽메모리는 256 메가바이트 이다.

669e / 829m =   그래픽엔진 칩은  669Mhz로 작동하고 ,  메모리 칩은 829Mhz (GDDR3이므로 실제 대역폭은 2배인 1658Mhz) 로 작동한다.

 

 

필자같은경우 ,  위 정보를 토대로 드라이버를 설치할려면 , 

http://www.amd.com 으로 이동하여서  , Support  메뉴에 있는   드라이버 관련 메뉴를 클릭하면,

드라이버를 다운받을 수 있을것이다.

 

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
by Sone 2008.11.29 22:23
| 1 |

티스토리 툴바