월별 글 목록: 2005년 4월월

해쉬 DB

c로배우는 알고리즘(1) 이제규 (세화 출판사)에 수록된 hash 알고리즘 소스를 정리하여
만든 것입니다.

스핀락추가부분을 추가하였고, 드라이버에서 사용할 수 있도록 메모리할당함수를 수정했습니다.

사용예를 추가했습니다.

실제 사용시 많이 복잡한 것 같네요….

다운로드

typedef void (*isrp_t)(unsigned long a);

NAVER 지식 검색에서.. ( doraq@bcline.com )

typedef void (*isrp_t)(unsigned long a);

이건 unsigned long a 를 인자로 받고 리턴값은 없는 형태의 함수를
함수포인터로 표현한 건데요. 그 앞에 typedef를 넣어 해당 타입을
isrp_t 라는 이름으로 선언한겁니다.
즉 isrp_t 라는건 위에 설명한 저러저러한 함수포인터 라는 거죠.

extern isrp_t vecconnect (isrp_t f, int lev0, int lev1);

그래서 이것 또한 vecconnect 라는 함수가 외부모듈에 있다는 extern선언인데,
첫번째 인자가 위에서 선언한 함수포인터구요,
두번째 세번째는 int 네요.
그리고 리턴값또한 isrp_t 형식의 함수포인터구요.

결론은…
함수포인터는 표현이 길고 복잡하므로 typedef로 간단하게 표기를 줄여서
짧고 간단하게 만든후,
다른 함수의 입력 인자와 리턴값의 형으로 써먹었다… 입니다.

드라이버 모니터

드라이버 스튜디오에는 소아(SoftICE)이외에도 많은 유용한 툴이 있는데..
그중 자주 사용하는 프로그램중에 Driver Monitor 라는 툴이 있음

드라이버를 열기 -> 실행 -> 종료 -> 닫음 을 할 수 있으며 레지스트리 서비스에 등록후
실행 시켜주는 프로그램임.

소아 사용법

시간이 있으면 문서를 잘 정리해서 올리려고 했는데..
그냥 자주 사용하는 단축키에 대해서만 올림

1. 기본 설정 (프로그램 -> Compuware DriverStudio -> Settings -> SoftICE Initialization

1.1 (General)창크기 설정
Initialization string:
LINES 65;WIDTH 150;SET FONT 2;WT;WT 8;WS;WS 8;WD;WD 8;WC 16;X;

Video memory size
6144 KB

1.2 (Symbols)소아 실행시 마다 로딩할 심볼 등록
Adds : nms 파일 추가
nms 파일이 없는 경우 Symbol Retriever 이용해서 드라이버(예 : ndis.sys)의 심볼 파일 저장

및 nms 파일로 변환 가능

2. 소아 실행

1.1 Start SoftICE 실행
1.2 Symbol Loader 실행
디버깅할 드라이버의 심볼을 로드(*.sys 파일 오픈후 translate 후 Loading)

3. 소아 사용

1.1 창이동
마우스로도 가능하나 단축키가 편한 경우가 있음
ALT + R : Register 창 이동
ALT + D : Data 창 이동
ALT + T : Thread 창 이동
ALT + C : Code 창 이동
ALT + S : CallStack 창 이동
ALT + W : Watch 창 이동

1.2 창 생성및 창 닫음
기본적으로 5개의 창이 생성되어 있는데 이를 추가 및 삭제 할 수 있음
wr : Register 창 생성/닫음 (Toggle)
wd : Data 창 생성/닫음 (Toggle)
wt : Thread 창 생성/닫음 (Toggle)
wc : Code 창 생성/닫음 (Toggle)
ws : Callstack 창 생성/닫음 (Toggle)
ww : Watch 창 생성/닫음 (Toggle)

1.3 창 넓이 조정
마우스로도 가능하나 단축키 사용 가능
ww 5 : Watch 창을 라인 5 크기로 변경

1.4 심볼 로딩 정보 보기
table : 로딩된 심볼 이름 보임 (활성화 심볼은 굵은 프른색 글씨)

1.5 심볼 변경
table XXX : 로딩된 심볼중 XXX 심볼을 활성화

1.6 심볼 보기
sym : 로딩된 심볼의 export 함수를 보여줌

1.7 심볼에 포함된 파일명 보기
file : 심볼에 포함된 소스 파일들을 보여줌

1.8 소스 파일 보기
file XXX.c : XXX.c 파일의 소스를 보여줌 (Tab 키로 자동 완성 기능 사용 가능함)

1.9 브레이크 포인트 관련
bpx 함수명 : 함수의 시작 위치에 브레이크 포인트가 잡힘
bpx .XX : XX 라인에 브레이크 포인트가 잡힘
bl : 브레이크 포인트 위치 리스트가 보임
bc XXX : 브레이크 포인트 해제 (모두 해제시는 bc *)

1.10 : 소스의 ASM 파일 보기
src : 토글 방식으로 소스 파일 보기 ASM 파일 보기

1.11 : 메모리 보기
DD XXX : XXX 위치의 메모리 보여주기

1.12 : 검색
ss XXX : XXX 문자열을 소스파일에서 검색함

1.13 : 소스디버깅
p : 한 라인씩 Step 이동
t : 함수 내부로 이동

1.14 : Watch 보기
Watch XXX : XXX 변수 값을 watch 창에 보여줌.
구조체인 경우 watch 창에서 해당 변수에서 엔터를 치거나 마우스로 ‘+’를 클릭

1.15 재부팅
hboot : 시스템을 재부팅

소아 디폴트 설정

소아(SoftIce)를 사용해보니.. 정말… 굳…
우선 속도 면에서 WinDbg 와 비교가 안된다는..
UI 도 익숙해지니.. 정말 편하고… ㅋㅋㅋ

참고로 기본 세팅으로 소아를 실행하면 창 크기가 작은데… 크게 늘리는 방법

설정부분에서
Initialization string:
LINES 65;WIDTH 150;SET FONT 2;WT;WT 8;WS;WS 8;WD;WD 8;WC 16;X;

Video memory size
6144

해주면 커다란 창으로 사용 가능..

TDI Filter Driver 동적 언로딩 가능한가??

보통 필터 드라이버를 만드는 경우 하위 장치객체에 Attach 시키는 방법과, DriverObject의 Major Function 을 Hook 하는 방법중
선택하여 사용하게 된다.(일반적으로 전자는 Filter 드라이버라고, 후자는 Hook 드라이버라고 말하기도 한다.)

그동안 TDI Filter Driver를 Attach 방식을 사용한 필터드라이버로 개발해 왔었다.
(TDI Attach 드라이버인 경우 동적으로 언로딩 시 블루스크린이 발생함)
하지만 SysInternals 의 TDIMon 을 보면 Attach 방식이 아닌 Hook 방식을 사용한 것으로 보인다.
(왜 그랬을까?)
아마 언로딩 문제 때문이라고 할 수 있는데, 그 이유는 아래와 같다.

우리가 만든 TDI Filter Driver 윗단에 Afd.sys (TDI Client)가 있는데, 여기서 사용된 알고리즘을 이해하여야 한다.
간단히 말하면…
1. 소켓단에서 바인딩 할 때 파일 객체를 엔드포인트에 대한 파일 객체를 얻는다.
2. 파일오브젝트를 이용하여 장치 객체를얻는다.
3. 하위로 내려 보낼 경우 위에서 얻어진 장치 객체로 CallDriver를 한다.

즉, 소켓이 열릴때 마다 하위 장치 객체를 얻는데, 우리가 만든 필터 드라이버가 있는 경우, 우리 필터 드라이버의 장치 객체를 소켓이 얻게 된다는 것이다. 이 경우 통신(Send, Receive 등)이 이루어 지고 있는 상황에서 우리 드라이버가 언로딩 되어 버린다면,
소켓이 이미 알고 있는 장치객체가 사라져 버리게 된는 것이고, 이를 알았다 해도 이미 연결 된 상태에서 이 부분을 재설정 하지 않는다. 이로 인해서 블루스크린이 발생하는 것이다.

그러므로 TDI Filter Driver는 Hook 방식을 사용하든가, 동적 언로딩이 안되게 하던가, afd.sys를 리프레시 해주던가 하여야 할것이다.
(아마 Hook 방식이 최선의 방법이 될 것이다)

소프트아이스로 드라이버 소스디버깅 방법

[소프트아이스로 드라이버 소스디버깅 방법]

1. 소아용심벌파일(nms) 생성 및 로딩
–> Symbol Loader 프로그램을 실행시킨다.
–> 메뉴에서 file->open 에서 소스디버깅할 드라이버(ex, test.sys)를 선택한다.
–> 메뉴에서 module->translate 선택 : 이것은 test.sys를 통해 test.nms 파일을 생성한다.
–> 메뉴에서 module->load 선택 : 이것은 test.nms 파일을 로딩한다.

다른 방법 : nmsym 명령을 통해서 소아용심벌파일(nms)생성하고, open에서 소아용심벌파일(nms)열고 module->load 선택해도 가능하다.
nmsym으로 소아용심벌파일(nms)생성할 때 드라이버(sys)파일을 인자로 사용해야한다.
(만약 windbg용심벌파일(sym)을 인자로 사용하면 안된다. 즉 “nmsynm test.sym” 와 같이 하면 잘못된 소아용심벌파일(nms)생성된 것이다. 따라서 심벌로딩시 에러가 발생한다.
즉, 소아용심벌파일(nms)는 windbg용심벌파일(sym)을 통해서 생성하는 것이 아니고 pdb 파일을 통해서 생성하는 것이다.)

2. 소아의 디버깅 모드에서 소스코드에서 브레이크포인트 설정방법
–> 소스디버깅할 심벌 활성화
table 명령 : 현재 로딩된 심벌들을 모두 보여준다. 이때 심벌죽 굵은 글씨로 된것이 설정할 수 있는 심벌이다.
만약 활성화할 심벌이 굵은 글씨로 안되어 있을 때는 “table 활성화할심벌명” 라고 명령한다.)

–> 소스코드에서 브레이크포인트 설정하기
“file” 명령으로 소스파일을 연다. 이 명령은 현재 활성화된 심벌에 대한 소스파일들을 보여준다.
(“file *” 명령은 심벌에 대한 모든소스파일들을 보여주고 “file 소스파일명” 하면 소스파일명의 내용을 코드뷰창에 보여준다.)

–> “bpx 심벌명” 으로 브레이크 포인트 설정한다.

드라이버 로딩 & 드라이버 언로딩

드라이버 로딩 및 언로딩에 사용하기 위한
StartDriver() 와 StopDriver()함수입니다. (MSDN 참조)

OpenService(), StartService().. DeleteService() 등등이 사용되어집니다.
테스트 해보시고 문제점이 있으면 코멘트 부탁 드립니다.

BOOL
StartDriver(LPCTSTR ServiceName,
LPCTSTR Description,
LPCTSTR DriverPath,
DWORD dwStartType)
{
SERVICE_STATUS ServiceStatus;
DWORD dwStartTickCount = 0;
DWORD dwWaitTime = 0;
DWORD dwOldCheckPoint = 0;

SC_HANDLE SCManagerHandle = NULL;
SC_HANDLE SCServiceHandle = NULL;

SCManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(SCManagerHandle == NULL)
{
return FALSE;
}

SCServiceHandle = OpenService(SCManagerHandle,
ServiceName,
SERVICE_ALL_ACCESS);
if(SCServiceHandle == NULL)
{
SCServiceHandle = CreateService(SCManagerHandle,
ServiceName,
Description,
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
dwStartType,
SERVICE_ERROR_NORMAL,
DriverPath,
NULL,
NULL,
NULL,
NULL,
NULL);
if(SCServiceHandle == NULL)
{
CloseServiceHandle(SCManagerHandle);
return FALSE;
}
}

if(StartService(SCServiceHandle, 0, NULL) == FALSE)
{
CloseServiceHandle(SCServiceHandle);
CloseServiceHandle(SCManagerHandle);
return FALSE;
}

if (QueryServiceStatus(SCServiceHandle, &ServiceStatus) == FALSE)
{
CloseServiceHandle(SCServiceHandle);
CloseServiceHandle(SCManagerHandle);
return FALSE;
}

dwStartTickCount = GetTickCount();
dwOldCheckPoint = ServiceStatus.dwCheckPoint;

while(ServiceStatus.dwCurrentState == SERVICE_START_PENDING)
{
dwWaitTime = ServiceStatus.dwWaitHint / 10;

if(dwWaitTime < 1000)
{
dwWaitTime = 1000;
}
else if(dwWaitTime > 10000)
{
dwWaitTime = 10000;
}

Sleep(dwWaitTime);

if(QueryServiceStatus(SCServiceHandle, &ServiceStatus) == FALSE)
{
break;
}

if(ServiceStatus.dwCheckPoint > dwOldCheckPoint)
{
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ServiceStatus.dwCheckPoint;
}
else
{
if(GetTickCount() – dwStartTickCount > ServiceStatus.dwWaitHint)
{
break;
}
}
}

CloseServiceHandle(SCServiceHandle);
CloseServiceHandle(SCManagerHandle);

if(ServiceStatus.dwCurrentState == SERVICE_RUNNING)
{
return TRUE;
}

return FALSE;
}

BOOL
StopDriver(LPCTSTR ServiceName)
{
SC_HANDLE SCServiceHandle = NULL;
SC_HANDLE SCManagerHandle = NULL;

SCManagerHandle = OpenSCManager(NULL,
NULL,
SC_MANAGER_ALL_ACCESS);

if(SCManagerHandle == NULL)
{
return FALSE;
}

SCServiceHandle = OpenService(SCManagerHandle, ServiceName, SERVICE_ALL_ACCESS);

if(SCServiceHandle == NULL)
{
CloseServiceHandle(SCManagerHandle);
return FALSE;
}

if(ControlService(SCServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus) == TRUE)
{
Sleep(1000);

while(QueryServiceStatus(SCServiceHandle, &ServiceStatus) == TRUE)
{
if (ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
{
Sleep(1000);
}
else
{
break;
}
}

if(ServiceStatus.dwCurrentState != SERVICE_STOPPED)
{
CloseServiceHandle(SCServiceHandle);
CloseServiceHandle(SCManagerHandle);
return FALSE;
}
}

if(DeleteService(SCServiceHandle) == TRUE)
{
CloseServiceHandle(SCServiceHandle);
CloseServiceHandle(SCManagerHandle);
return TRUE;
}

CloseServiceHandle(SCServiceHandle);
CloseServiceHandle(SCManagerHandle);
return FALSE;
}