일단. 

구성은 
드라이버소스(C) : 컴파일하면 .sys 파일이 생성됨
APP소스(API쓰니까 CPP?) : 생성한 드라이버를 사용하는 소스. 

app에서 드라이버로 인자를 전달하면 드라이버가 받은 인자를 판단하여 Hello World를 찍어주는 과정입니다.

처음 디바이스 드라이버를 접하는 사람들한테 좋은 블로그여서 소개합니다.  

원본 : http://blog.naver.com/PostView.nhn?blogId=shshrka001&logNo=20058872164&categoryNo=3&parentCategoryNo=0&viewDate=&currentPage=2&postListTopCurrentPage=1&isAfterWrite=true&userTopListOpen=true&userTopListCount=5&userTopListManageOpen=false&userTopListCurrentPage=2

 


디바이스 드라이버 제작--도입  디바이스 드라이버1 

2008/12/20 23:14

복사http://blog.naver.com/shshrka001/20058872164

오늘부터 DDK (Device driver Development Kits) 으로 기본적인 드라이버를 빌드하는과정에 대해서 작성해보려고 합니다.

 

이유는 ,, 제가 처음 디바이스 드라이버 책을 사고,,  IOCTL메시지로 디바이스를 동작하는데, 한달이 걸렷기 때문입니다.

 

아마 누구가 옆에서 도와줫더라면 3일도 안걸렷을;;

 

그리고 이 글이 마무리 되는대로 기본적인 키보드나 마우스 필터 드라이버 제작 과정을 처음부터 올릴려고 합니다.

 

예상 되는 기한은...  저도 모릅니다. ㅋ

 

소켓 프로그래밍 내용도 작성 해야하고(이미 멀티 스레드활용 예제 까지 구현했으나 글쓰기의 귀차니즘 때문에 올리지못하는;;)

 

놀아야?? 하기도 합니다. ㅋ 연말인대 ㅋ

 

어쩻든 내일부터 하나씩 올릴예정입니다.

 

누구나 이 영역에 쉽게 접할수 있도록 그림과 함깨 올릴것입니다.

 

아마 누군가가 네이버 검색중에 이 글을 발견해서 유용하게 쓸 수 있었다면 전 만족합니다. ^^

디바이스 드라이버 빌드를 위한 준비물  디바이스 드라이버1 

2008/12/22 13:58

복사http://blog.naver.com/shshrka001/20058946306

첨부파일 (2)

모든 종류의 프로그래밍에 있어서, 일단은 Hello World 를 찍어 보는것이 시작이라고 생각합니다.

 

우리가 하려는 디바이스 드라이버를 빌드 하는것, 더 자세히 말하면 WDM드라이버를 빌드 하는것을

(이제부터는 간단하게 빌드 라고만 하겠습니다.)

을 하려면

 

ddk(Devicedriver Development Kits)와 그 안에 포함된 툴들 ::링크(http://www.microsoft.com/whdc/devtools/ddk/default.mspx) 프리웨어 입니다.

예전에는 시디에 구워서 판매 했다고 하네요..  이제는 걍 다운로드 됩니다.

 

컴파일러(vc6.0이상)  이건 다 있으실겁니다.

 

그리고 테스트를 위한

Dbgview 프로그램(완전필수) (게시글에 첨부)

드라이버 로드 프로그렘(프로그램이 있기는 하나, 이건 직접 만들어 봅시다.) (게시글에 첨부)

 

 

등이 필요하고 배움이 깊어질수록 더 많은 첨단 장비(?) 들이 필요하게 될겁니다.

 

이제 기초적인 준비물이 다 준비 되었고, ddk사용법에 대해 봅시다~!

Hello Device --빌드하기  디바이스 드라이버1 

2008/12/22 15:04

복사http://blog.naver.com/shshrka001/20058949763

첨부파일 (2)

우선 앞에의 준비물 편에서 보여드린 장비를 어텋게든 준비하셧으면.. 네 이지 빌드를 해봐야 겠지요... 아무거라도 일단 빌드가 되는것을 확인 하셔야 아마 이해가 되실겁니다.. 물론 이미 다 아시는분들고 계시지만 모르는 분들이 이 게시글을 보았다고 가정 하겠습니다.

 

우선 첨부에 있는 자료를 다운 받아서 밑에 그림에 있는것 처럼 해보시면 아마 빌드가 될것입니다. 그리고 결과물로 MSNBCVID.sys라는 드라이버를 얻으실수 있겠지요..

 


 

1.

우선 첨부를 다운 받으셔서 아무대나 간단한곳에 압축을 풉니다. 압축풀고 폴더명은 아무렇게나 하셔도 됩니다.(단 공백이 들어가면 않됩니다.) 용량이 1.56KB밖에 않되군요..

 

 

2.

압축을 푸시면 아마 파일 3개가 있으실겁니다. 이 파일들은 이름이 변경되어서는 않됩니다.

 

 

 

 

3.

 

앞서서 작성한 게시글 준비물 중에 DDK.iso라는것을 다운 받아서 설치한 후에 이용가능한 유틸입니다.

(데몬이나, 등으로 설치하세요)

 

여기서 OS 별로 다른 툴을 사용하는데요, 윈 2000미만은 않된다네요..  그리고 비스타 쓰시는분은 모르겠습니다. ㅋㅋ아마 암거나 해도 이상없겠지요?

 

 

4.

실행 하시고 나면, 아까 압축을 푸신 디렉토리의 경로명으로 디렉토리를 이동합니다.

사용방법은 대부분 알것 같지만..

 

cd 디렉토리

 

입니다.

 

그리고 절때 절때 절때 경로명으로 전달되는 문자열 중에서 공백이 있으면 않됩니다.

예를 들어서 cd C:\영화 일드\111

이럴경우 컴파일시 에러가 발생합니다.

 

 

5.

컴파일 명령어인 build를 입력 하시면 빌드가 됩니다.

 

 

 

6-1.

빌드에 성공한모습

 

 

6-2.

빌드에 실패한모습.

(~~줄)에서 ;이 빠진 문법오류 라고 하네요.

 

 

7.

못보던 폴더 2개와 txt형식의 로그파일이 하나 생성된모습

 

8.

새롭게 생긴 폴더 속에 빌드 결과물이 있습니다.

Hello Device --빌드하기2  디바이스 드라이버1 

2008/12/22 15:39

복사http://blog.naver.com/shshrka001/20058952346

첨부파일 (2)

앞에 글을 읽으셧다면 빌드를 해보셧거나 할줄 아실겁니다. 아마

 

그럼 111 폴더에 있는 파일들을 하나하나 분석해보겠습니다.~!

 

앞에 글에 있는것과 같은 파일을 하나 첨부합니다.

basic.c 는 뭐하는건지 보면 바로 답이 나오고..

 

남은

MAKEFILE와

SOURCES

는 컴파일러 에게 이것저것을 알려주는 파일입니다.

 

확장자가 없습니다.

 

메모장으로 만들고 확장자를 붙이지 않고 저장 하시면 됩니다.

 

소스파일은 c언어로만 (c++문법 제외)만들어야 한다고 일단은 생각해두시는 편이 낳을지도 모르겠습니다.

 

외부에서 호출되는 DriverEntry함수가 c++로 구성되면 c++언어 특유의 다형성 때문에 맹글링 문제가 발생하는데, 이것때문에 외부에서 DriverEntry을 찾기가 힘들어 집니다.

 

dll에서 외부로 익스포트 되는 함수를 c로 만드는 이유와 같습니다.

다형성은 c++고유의 기능이기 때문입니다.

 

 

어쨋든..

 

매모장을 이용해서 두 파일을 MAKEFILE 과 SOURCES 을 열면

 

 

 

이렇게 문자 몇게가 있습니다.

 

SOURCES 에서

 

TARGETNAME=MSNBCVID

이 값은 드라이버의 이름입니다.

출력되는 파일의 결과물의 이름이기도 합니다.

이 이름은 드라이버의 바이너리에 하드코딩 되기 때문에, 이름을 MSNBCVID.sys 에서_MSNBCVID22.sys으로 바꾼다고 해서

드라이버의 이름이 바뀌지 않습니다.

 


TARGETPATH=OBJ

컴파일된 드라이버가 나오는 위치

 

TARGETTYPE=DRIVER

컴파일 옵션인데,DRIVER 라는 값을 주면 드라이버를 컴파일 할 수 있다.

ddk로 다른 유저모드의 실행파일을 컴파일 할수도 있는데, 여기 값을 달리하면 된다.

(그 값은 모른다.;; 그냥할수 있다고 들었기 때문. ㅋ) 


SOURCES= basic.c

이것은 소스파일의 이름이다.

SOURCES 와 같은 디렉토리에 있어야 한다?(아마)

SOURCES= basic.c \basic2.c \basic3.c ...\basic.c

형식으로 다중파일을 지원한다.

 

MAKEFILE에서

!INCLUDE $(NTMAKEENV)\makefile.def

라는 문자열을 포함 해야 하는데..

뭐하는건지는 모르겠고,, 필요하다고 한다.

 

그리고 #뒤에 있는글은 주석인데..

이걸 수정할 일이 없다보니까.

어디서 구한걸 계속 돌려쓰게 되고 이글 쓰려 열어보니까 이런 주석이 달려 있네요..

 

------------------------------------------------------------------------

이제 앞번 게시물에서 다운로드 받은 파일분석을 마감 지어 보았습니다.

 

고급 기능이 많기는 하지만 일단 여기까지  (모르기 때문)

 

도움이 되었으면 합니다, ㅎ

Hello Device --드라이버 설치(동적로딩)  디바이스 드라이버1 

2008/12/22 16:25

복사http://blog.naver.com/shshrka001/20058955531

첨부파일 (2)

이번 게시물 시리즈의 중요한 목표가 이 드라이버가 Hello Device를 찍어내는것을 보는것입니다.

 

자세한 분석은 뒤에서 하고 일단 보여주기 위주로 글을 쓸 생각입니다.

 

분석까지 같이 하면, 저 입장에서는 뜬구름 잡는 이야기가 되는것 같다는 생각이 들어서입니다.

 

어쨋든,

 

드라이버를 로딩 하는 방법중 하나인 SCManager를 이용한 실행중 로딩에 대해서 써보겟습니다.

 

말이 SCManager을 사용한다는것이지..  지금은 일단 만들어진 툴을 이용해서 로딩 하겠습니다.

 

물론 나중에 SCM함수를 이용해서 로드 언로드를 해볼건데,, 그건 그때 이야기하고

 

지금은 툴을 그냥 편히 쓰렵니다.

 

받으신 파일 Dbgview와 INSTDRV를 실행 시키킨 모습니다.

(첨부는 다 준비물 편에서 첨부 해둔것들입니다. 받으셧다면 또 받을 필요 없습니다.)

 

 

Dbgview은 그냥 켜놓기만 하면 시스템 전역에서 날라오는 디버그 메시지를 알아서 잡아서 표시합니다.

 

 

INSTDRV에 방금 컴파일한 따끈따끈한 .sys파일의 완전경로를 넣고

 

install과 start를 눌러주시면,

 

설치와 디바이스의 실행이 될겁니다.

 

참고로 start를 누르는 시점에 DriverEntry 함수가 호출됩니다.

 

앞번에서 컴파일한 소스코드에는 DriverEntry 함수에

DbgPrint("드라이버 생성 성공"); 이라는 인자를 가진 

DbgPrint함수를 호출하가 때문에,

 

디버깅 뷰를 통해서 함수가 로드 되었는지를 감시할수 있습니다.

 

어쨋든 실행결과는 다음과 같습니다.

 

 

이제 다음 글에서 이렇게 생성한 드라이버의 핸들을 얻어와서, 이 드라이버를 작동시켜 보겟습니다.

Hello Device --드라이버 핸들 얻기  디바이스 드라이버1 

2008/12/22 22:10

복사http://blog.naver.com/shshrka001/20058975191

첨부파일 (1)

먼저글에 드라이버를 로딩 하는것 까지 작성 했습니다.

 

이제 로드 된 드라이버를 직접 핸들을 얻어 보겠습니다.

 

글 제일 밑에 ↑ 소스 원본있습니다. 긁으시려면 밑으로 ㅎ

 

소스코드에서 보시면 크게

1.CreateFile으로 핸들을 얻고,

2.그 핸들을 이용해서 DeviceIoControl으로 디바이스에 명령을 전달하고,

3.핸들을 닫아버립니다.

 

그리곤 종료가 됩니다.

 

명령어로 1이 전달이 되었는데,(보통은 메크로를 정의해놓고 사용합니다. 하지만 짧은 예제 이니만큼 그냥 상수를 직접 사용했습니다.)

 

이렇게 전달 되어진 명령어로 디바이스는 뭔가를 하겠지요..

 

만약 입력버퍼나 출력버퍼를 요구한다면  DeviceIoControl함수의 인자값에 버퍼의 주소를 전달하면 될거고요.

 

이렇게 전달되는 메시지의 해석은 전적으로 드라이버의 책임입니다.

 

어떠한 메시지가 전달되든 사용자모드 app나 커널은 어떤 참견도 하지 않습니다.

 

이제 전달된 메시지가 뭘 했는지 보겠습니다.

음 뭔가를 하고 디버그 메시지를 남겼네요..

 

편집한다고 몇번 출력하다보니까 아주 도배가 되어버린.. 다른 곳에서 온 메시지 들도 있네요.

 

이제 간단하게 핸들을 얻어서 앞에서 만든 드라이버를 사용해보았습니다.

 

기껏 사용한다는것이 문자열이나 출력하는것 정도입니다. ㅜㅜ

 

다음글에서는 드라이버의 소스코드를 분석해보겠습니다.

 

첨부파일은 드라이버를 위에서 소계한 코드가 컴파일된것입니다.

(앞에글에서 다운로드르 받지 않았으면 실행이 되지 않습니다.)

 

 

 

 

 

 

 

 

--------------------------

 

사진에 있는 코드

 

---------------------------

#include <stdio.h>
#include <windows.h>

void main()
{

HANDLE Divece_Handle=CreateFile(\\\\.\\MFD,
        GENERIC_READ|GENERIC_WRITE,
        0,
        0,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        0
        );
 

 if(int(Divece_Handle) == -1)
  {
   printf("디바이스의 핸들을 얻는것에 실패 했습니다.\n");
   printf("에러코드:%d\n",GetLastError());
  }
 else
  {
   printf("디바이스의 핸들을 얻는것에 성공 했습니다.\n");
   DWORD bR;
   DeviceIoControl(Divece_Handle,//핸들
           1,//보내는 명령어
       //(원칙은 정의된 메크로를 사용하는것이다.)
          NULL,//입력 버퍼
             NULL,//그 크기
          NULL,//출력 버프
          NULL,//그 크기
           &bR,
    //메크로로 정의된 실행 결과 코드가 출력될 버퍼
            NULL //그냥 NULL
          );
   
   CloseHandle(Divece_Handle);
  }
 getchar();
}

Hello Device --드라이버 소스 분석  디바이스 드라이버1 

2008/12/22 23:04

복사http://blog.naver.com/shshrka001/20058978211

디바이스 드라이버가 뭔가요? 라고 물으면


"간단하게 말해서 사용자 모드 프로그램의 요청에 의해 커널영역에서 일을 하는 서비스"

라고 답변 하고싶습니다.

계략적인 동작방식은

1.우선 서비스가 어떤방법으로든 로딩이되고(이시점에서 DriverEntry함수 호출)

 

2.로딩이 된 드라이버를 사용자모드app가 CreateFile로 핸들을 구합니다.

 

3.ReadFile,WriteFile,DiveceIoControl,등의 함수가 보내는 명령?을 처리합니다.

 

이런식의 동작을 합니다.
4.드라이버가 언로드 될때, 제거 루틴(주로 OnUnload라고 명명)이 호출 됩니다.

 

3번에서 이런 명령들을 처리하기 위해서 커널의 IO관리자는 IRP라는 구조체를 사용합니다.

즉 사용자가 뭐라고 명령(ReadFile,WriteFile,DiveceIoControl,등등 함수사용) 하면,커널은 IRP에 명령을 담아서 드라이버로 전달합니다.

그러면 드라이버는 그 명령을 처리할수 있도록 루틴을 준비 해야 합니다.

 

이제 드라이버의 소스코드를 분석 해보겠습니다.

 

풀소스 입니다.

 

하는것도 없는소스이지만, 별로 짧지는 않네요

 

기본적인 명령어를 모두 처리는 할수 있습니다.

 

대부분이 그냥 넘겨버리기는 하지만요.

 

루틴별 분석은 2개쯤 나누어서 올리도록 하겠습니다.

 

 

----------------------------------------------------

소스 txt

 

/*
Made by KSR (shshrka001)
예제: Hello Device!!
08-12-20
*/

#include "ntddk.h"


//디바이스의 이름이 채워진 버퍼
WCHAR DeviceName[]=L"\\Device\\MMF_MyFirstDevice";
WCHAR symLinkName[]=L"\\??\\KSR081220";
PDEVICE_OBJECT g_RootkitDevice;

NTSTATUS DispatchRootion( IN PDEVICE_OBJECT theDriverObject,
       IN PIRP Irp)
{
   //관심없는 루틴 처리
   Irp->IoStatus.Status= STATUS_SUCCESS;
   IoCompleteRequest(Irp,IO_NO_INCREMENT);
   return STATUS_SUCCESS;
}

VOID OnUnload(IN PDRIVER_OBJECT pDriverObject)
{
   //언로드 루틴
   //드라이버를 제거 할때 호출
             UNICODE_STRING Name;
             /* 심볼 링크 삭제*/
             RtlInitUnicodeString( &Name, symLinkName);
    //symLinkName을 유니코드로 만든다.
             IoDeleteSymbolicLink(&Name);
             /* 디바이스 객체 삭제*/
             IoDeleteDevice(pDriverObject->DeviceObject);
             DbgPrint("드라이버 언로드");
}

 

NTSTATUS My_IOCTL(IN PDEVICE_OBJECT theDriverObject,IN PIRP Irp)
{
   //사용자 정의 명령어 처리 루틴
   PIO_STACK_LOCATION IrpStack;
   ULONG Commend_Me;
   IrpStack=IoGetCurrentIrpStackLocation(Irp);
   Commend_Me=IrpStack->Parameters.DeviceIoControl.IoControlCode;
   switch(Commend_Me)
   {
    case 1:
     DbgPrint("기본적인 예제: Hello Device!!출력");
     DbgPrint("축하합니다.");
     break;
    case 2:
     DbgPrint("받은 명령어->%d",Commend_Me);
     break;
    case 3:
     DbgPrint("받은 명령어->%d",Commend_Me);
     break;
    default:
     DbgPrint("받은 명령어->%d은 처리 불가능한 명령어 코드 
       입니다.",Commend_Me);
     break;

   }
   IoCompleteRequest( Irp, IO_NO_INCREMENT );
   return STATUS_SUCCESS;
}
NTSTATUS DispatchCreate (IN PDEVICE_OBJECT pDevObj,IN PIRP pIrp) 
{   
   //CreateFile에 대응 되는 루틴
   //프로세스에서 핸들을 얻을때마다 호출됨
   pIrp->IoStatus.Status = STATUS_SUCCESS;
   pIrp->IoStatus.Information = 0; 
   IoCompleteRequest( pIrp, IO_NO_INCREMENT );
   return STATUS_SUCCESS;
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject,
      IN PUNICODE_STRING theRegistryPath )
{
   //시작 함수 DriverEntry 드라이버를 Start할때 호출
   int i;
   NTSTATUS status11;
   UNICODE_STRING NameString;
   UNICODE_STRING Sym_NameString;

   //사용할 이름을 전부 유니코드로 만든다.
   RtlInitUnicodeString(&NameString,DeviceName);
   RtlInitUnicodeString(&Sym_NameString,symLinkName);


   //루틴을 등록한다.
    for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++)
    {
      theDriverObject->MajorFunction[i]=DispatchRootion;
    }
   //관심있는 루틴을 따로 처리
   theDriverObject->DriverUnload  = OnUnload; 
   theDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=My_IOCTL;
   theDriverObject->MajorFunction[IRP_MJ_CREATE] =DispatchCreate;
   //디바이스를 등록한다.
   status11=IoCreateDevice(theDriverObject,0,&NameString,
         0x00001234,0,TRUE,&g_RootkitDevice);
    if(status11==STATUS_SUCCESS)
    {
     DbgPrint("드라이버 생성 성공");

    }
    else
    {
     DbgPrint("드라이버 생성 실패");
     return STATUS_SUCCESS;
    }
   //상징적 이름을 준다.
   status11=IoCreateSymbolicLink(&Sym_NameString,&NameString);
    if (!NT_SUCCESS(status11)) 
    {
     IoDeleteDevice(g_RootkitDevice);
     DbgPrint("SymbolicLink 초기화 실폐");
     return STATUS_SUCCESS;
    }
   DbgPrint("SymbolicLink 초기화 성공");
   return STATUS_SUCCESS;
}

드라이버 로드 언로드 Class!!! (INSTDRV)모티브  디바이스 드라이버1 

2009/02/01 14:21

복사http://blog.naver.com/shshrka001/20061198826

첨부파일 (2)

드라이버 로드하는 툴로 이걸 많이 사용하던데..

 

막상 자기가 로드할라면 귀찬아지므로..

 

위의 툴에 있는 버튼이랑 같은 기능을 가지는 맴버 함수를 포함하는 class를 하나 만들었다..

 

(다른사람이 이걸 또만드는 비생산적인 일을 하지않기 위해?)

 

사용법은... 아주 간단한데..

 

public에 있는 함수들에 주석된거만 봐도 아실것같다. ㅋ(사실 주석없어도 안다.)

 

그리고 내용은 위에 INSTDRV프로그램의 버튼눌르는거랑 완전 같을거같다. 아마?

 

드라이버 파일의 경로를 전달하는 방법은 생성자를 오버로딩 한다는것에 주목하기 바란다.

성공시 ture, 실패시 false

 

!!: 드라이버의 이름하고, 드라이버 파일 이름은 다를수가 있습니다.  드라이버의 이름은 드라이버 파일 바이너리에 포함되어서 한번 빌드하면 그 뒤로는 일반적인 방법으로는 못 바꿉니다..  반면에 이름은 너무쉽게 바꿀수 있죠..

그래서 드라이버이름=파일이름에서 .sys뺀것 이라고는 생각하지 마세요..(물론 저같은 경우는 파일이름이랑 드라이버 이름이랑 같게 만들지만..)  아 그리고 파일이름이랑 드라이버 이름이랑 다르면 인자 하나 받는 생성자는 사용하실수 없습니다. 밑에 주석처리 된것처럼요..

 

활용>>

 

void main()
{
Road_Driver a("C:\\Documents and Settings\\jj\\바탕 화면\\hidusb.sys","hidusb");

//Road_Driver a("hidusb");
Sleep(1000);
a.InstallDevice();
Sleep(1000);
a.StartDriver();
Sleep(5000);
a.StopDriver();
Sleep(5000);
a.RemoveDriver();
}

'WINDDK' 카테고리의 다른 글

CreateFile함수 상세 설명  (0) 2011.10.18
AND