• http://www.secret.pe.kr/19218
  • http://www.secret.pe.kr/19223
  • http://www.secret.pe.kr/19250
  • http://www.secret.pe.kr/5186
  • http://www.secret.pe.kr/4975
  • http://www.secret.pe.kr/5249

2017.12
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            







조회 수 : 35373
2012.02.22 (11:15:29)
본 문서는 파워해커에서 제작되었으며 무단배포를 허용함..

<Virtual HID Mouse Driver 연구>

저자: AmesianX
제작: powerhacker.net
제작년도: 2009년 1월 15일

 

[서문]

본 문서의 시작에 앞서 목적에 대해 언급한다. 이 문서는 두가지 목적을 위해서 작성되어졌다.
첫번째는 모르는 부분에대한 새로운 연구나 공부를 시도할때 참고할 수 있는 공부방식(Style)에 대한 설명이고, 두번째는 Virtual HID Mouse Driver 를 제작할때 참고해야할 전초를 다지기위한 목적으로 구성되어 있다. 이렇게 기술문서를 공개하는 이유에는 여러가지가 있지만 무엇보다 이 기술이라는 분야는 언젠가는 자신이 알고있는 오늘의 기술이 내일의 쓰레기가 된다. 일찌감치 알고있는 정보들은 공개하고 더 높은 곳으로 계속 뛰어오를때 진정으로 아무도 가보지못한 고지에 오른 것이다. 그래야 스스로가 발전하는 길이고 바로 모두가 발전하는 길일 것이다. 고지는 점령 당하라고 있는 것이다. 언제까지 정적인 비공개노선으로 점령당하길 기다리고 있을 것인가? 앞으로는 더욱더 가속화될 것이다.


[기술을 습득하는 공부방법]

어떤 새로운 기술을 알고싶다면 최대한 동일기능이 구현된 많은 소스들을 수집하라. 그리고 그 차이점을 소스분석을 통해서 캣치하라. 아마 대부분은 소스분석을 깊게 들어가지 않아도 차이점이 눈에 띄게 될 것이다. 그러나.. 아쉽게도 Virtual HID Mouse 에 대한 소스는 인터넷에서 거의 찾기 힘들 것이다. 물론, 공식적인 샘플들을 찾아낼 수 있지만 필자처럼 커널지식보다 유저레벨 어플리케이션 조작만 파온 사람은 그 유명업체들의 공식샘플을 보고도 감을 잡아내기는 하늘에 별따기처럼 어렵다. 즉, 프로그래밍 = 개념 이라는 공식이 있기 때문에 이 개념만 잡고나면 프로그래밍은 껌씹기나 마찬가지다. 개념을 잡는 요령이 있다면 그것은 바로 앞에서 언급한 동일기능 소스의 차이점을 분석해내는 것이다. 그렇기 때문에 매우 제한된 소스(공식소스들)를 갖고 시작하는 것은 전혀 이해를 이끌어내지 못한다. 최대한 고갈되었다고 생각될 정도로 많은 설명이나 소스들을 검색해서 찾아내야 한다. 이때 사용할 수 있는 방법은 구해낸 소스들의 일부 시그너처(Signature)를 검색키워드로 사용하는 것이다. 이런식으로 최대한 많은 정보들을 뽑다보면 선구자들의 질문들을 찾아낼 수 있다. 바로, 그 질문들에서 핵심개념들을 뽑아낼 수 있다. 자주 언급되는 사항이 바로 그 핵심일 것이다. 어떻게보면 "미네르바" 인지 "미네로하이바" 인지 그 친구처럼 철저한 검색기술로 무장한 채로 짜집기의 달인이 되어야만 할 필요가 있다. 만약 충분히 많이 찾아서 더이상 찾아낼 것 조차 없다고 느끼고 등골이 휘어지는 고통을 여러번 견뎌내었다면 이제 얻어낸 것들을 대상으로 비교분석을 취한다. 그렇게 되면 중요 키포인트가 눈에 보이게 될 것이다. 왜 이렇게 해야 하냐면 답은 간단하다. 스스로 엄청난 고통을 감뇌하면서 충분히 검색을 했는데 다 내용이 거기서 거기인 경우가 99.9% 일 것이다. 왜? 그것은 삽질하는 프로그래머가 택한 프로그래밍 방법론은 달라도 전체적인 흐름은 재밌게도 한가지밖에 없으니까. 이게 답이다.

"어라? 다 똑같은 소리만 짓거리고 있잖아? 뭔가 좀 더 구체적인 것을 달라고!!"

이 소리가 나올때 이미 정답은 구해진 것이나 마찬가지다. 다 똑같은 소리를 짓거린다거나 똑같은 소스에 차이점은 있지만 원하는 것이 아니라고 생각될때 사실상 그것이 원하는 것일 확률이 태반이다. 그 이상의 짜집기(Copy & Paste) 능력은 밥을 숫갈로 퍼서 먹는 것이다. 그런데 필자같은 사람은 퍼서 먹여주는 것을 원한다. 왜? 프로그래밍이 나온 이유가 무엇인가? 로보트를 만들려고 기를 쓰는거보면 모르겠는가? 인간에게 숫갈로 밥을 퍼먹여 주려는게 궁극적인 목적아닌가? 프로그래머는 인간이 아니었나? (하기사 혹자는 로보트
라고도 부릅디다..) 프로그래머는 좀 퍼서 먹여주면 어디가 덧나는가? 짜증나게 약올리는 시스템 프로그래머들이여 퍼먹여주지 않으면 스스로 밥숫갈 놓게되는 날이 온다. 인터넷시대에서 정보라는 것은 물 흐르듯 흐를수 밖에 없기 때문에 빨리 털고 높은 곳으로 뛰지않으면 숫가락 놓을 준비를 해야 할 것이다. 오늘의 신기술이 내일의 쓰레기가 되는 시대에서 서로 돕지않으면 혼자 살아남기 힘들다. 외국애들 보라 오픈소스로 자기의 기술을 다 까발리고 있으면서도 항상 최첨단 기술을 걷고 있는 것을 보면 우리가 얼마나 어리석은지 진정 모르냐 이말이다.

외국애들은 오픈소스를 통해서 시너지라는 것을 이용하고 있다. 물론, 수 많은 개발자들이 다 참가해서 오픈소스가 완성될 것이라고 착각하면 그건 열라 바보이다. 유명 보안 오픈소스인 Nessus 개발자의 고충이 섞인 글을 읽어보았는가? 오픈소스임에도 불구하고 자기혼자만 개발해 왔다고 써있었다. 대부분의 오픈소스들이 마찬가지라고 보면 될 것이다. 다만, 시너지효과로 인해 개발자 1명이 해낼수 있는 능력이 100명 1000명 수준으로 증폭되었기에 프로젝트가 맥을 이어갈 수 있는 것이다. 즉, 게임용어로 말하면 "버프"(버프를 모르진 않겠지..) 를 받은 것이다. 그렇게 되면 소수의 엘리트 파워가 오픈소스에 집중되는 일반유저의 관심만큼 증폭되기 때문이다. 단순히 눈에보이는게 전부라고 생각한다면 큰 것을 놓치게된다. (아니라고? 아님말고.. 허위사실 유포로 감금되어야 하나.. ㅎㅎ)

[현 상황]

현 상황에서는 Virtual HID Mouse 가 Auto Mouse 나 MACRO 라는 시장에서 대안으로 대두된 상태라 x시장에서도 드라이버의 판매가 이루어지고 있는 상황이다. 참고로 이 기술이나 드라이버를 판매자체는 사실 법적인 문제의 소지가 없다. 왜냐면 이 Virtual HID Mouse 기술은 범용기술이기 때문이다. 이 기술이 사용되고있는 쪽은 예를들면 조이스틱을 에뮬레이션하거나(용산에가면 조이스틱 판다..) 블루투스 마우스를 사용하도록 해주거나 혹은 그에 버금가는 마우스 업체들이 주로 보유하고있는 자체기술에서 많이 볼 수 있다. 이건 우리가 늘상 접하는 일반분야에서 말한것 뿐이고 무엇보다 가장 많이 사용되고 있는 곳은 임베디드 산업에서일 것이다. 그러므로 이 기술을 파는 것은 전혀 문제가 될 수 없다. 이 기술자체는 Microsoft 사에서 공식적으로 WinDDK 에 예제와 함께 배포하고 있다는 사실을 알만한 사람들은 이미 다 알고있겠다. 단지 그 이상의 자세한 정보를 찾기가 어렵고 Microsoft 사에서 제공하는 기술정보를 알기위해서 밑받침(선행) 되어야할 정보가 없다는 것이 문제점이다. 그래서 기존에 커널 드라이버를 개발하던 사람들이나 천국이지 필자같은 미천한 어플프로그래머들한테는 짜증만 나게 할 뿐이다. 이 중간에 생략된 정보들이 무엇인지 알아내야 한다. 그것이 유저레벨이라는 미천한 신분에서 커널레벨이라는 귀족신분으로 도약할 수 있는 길이다. 테스트환경 만드는게 짜증나서 공부하지 않았다가 완전 독박 쓴 기분이기에 좀 고약한 말투가 나온다. (기분 상하는 커널레벨의 고급 독자는 당장 이 문서를 접기 바란다. 필자도 커널레벨을 공부해야 윈도우를 진정으로 아는 것이라는 대에 이견이 없다. 다만, 오래전부터 블루스크린과 친구를 맺고싶지 않았을 뿐이다. 이거 참.. 뻘쭘하게 커널과 "절친노트" 라도 찍어야하나..)
===================================================================================================================

현재, 인터넷에는 몇몇의 기술 정보이외에는 관련된 기술적 자료를 찾아볼 수 없다고 해도 과언이 아니다. 진짜 짜증나도록 자료가 없다. 이해를 할 수 있을만한 한글로된 기술자료는 극적으로 한개를 찾을 수 있었다. 먼저, Virtual HID Mouse 를 찾아보면 가장먼저 접하게 되는 사이트가 있다. 까마귀라는 한국사람이 자신이 만들었다고하는 Virtual HID Mouse 가 검색이 된다. 블로그의 글 내용인데 사실 저수준을 다루는 고급개발자가 아니면 볼게없다.. (왜? 필자같은 어플프로그래밍 수준은 못알아 먹으니까.. + 안갈켜주니까
-_-;) 그리고 MSDN 이 검색되고 vhidmini 라는 것이 검색된다. 또한, 짱개 사이트의 vhidmouse 라는 소스와 hidmouse 라는 소스도 검색된다. 근데.. 오래전에 GxxxGuard 라는 소스가 인터넷에 떴다는 그 몹쓸 짱개사이트였다. 구현을 하기 위해서는 vhidmini 라는 소스가 그중에서 제일 유력한 후보가 될 것이고 나머지 vhidmouse 와 hidmouse 는 소스를 구하는데 한참이나 걸릴 것이다. 일단, 대충 둘러서 정보를 캣치해야한다. 다음은 이미 다들 알고있겠지만 SoftICE 라는 걸작을 만들어낸 "Numega Soft" 라는 회사의 Virtual HID Mouse 공식샘플의 일부소스이다. 아쉽게도 이 소스는 Windows 9x 계열에서 작동되는 드라이버이므로 NT 계열에서는 사용할 수 없다. 하지만 캣치할 수 있는 중요한 내용이 포함되어 있다. 위에서 언급한 것중에 vhidmouse 라는 것이다. 다음은 vhidmouse 소스 중의 일부분이다.

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

// vmoudev.cpp -  virtual mouse device for HID example    
//=============================================================================    
//    
// Compuware Corporation    
// NuMega Lab    
// 9 Townsend West    
// Nashua, NH 03060  USA    
//    
// Copyright (c) 1998 Compuware Corporation. All Rights Reserved.    
// Unpublished - rights reserved under the Copyright laws of the    
// United States.    
//    
//=============================================================================    
   
// This module implements the device class of the virtual HID    
// mouse minidriver.    
   
#include <KHID.H>    
#include "vmoudev.h"    
#include "hidmouse.h"    
   
KTrace T("",TRACE_MONITOR, TraceAlways, BreakNever, KUstring(L"HidMouse"));   
   
#define SCALEX 3    
#define SCALEY 3    
   
// The HID report descriptor for this device    
// (taken from USB/HID specification)    
   
HID_REPORT_DEscRIPTOR MouseHidReportDesc[] = {   
    0x05, 0x01, // Usage Page (Generic Desktop),     
    0x09, 0x02, // Usage (Mouse),      
    0xA1, 0x01, // Collection (Application),        
    0x09, 0x01, // Usage (Pointer),         
    0xA1, 0x00, // Collection (Physical),           
    0x05, 0x09, // Usage Page (Buttons),            
    0x19, 0x01, // Usage Minimum (01),          
    0x29, 0x03, // Usage Maximun (03),          
    0x15, 0x00, // Logical Minimum (0),             
    0x25, 0x01, // Logical Maximum (1),             
    0x95, 0x03, // Report Count (3),            
    0x75, 0x01, // Report Size (1),         
    0x81, 0x02, // Input (Data, Variable, Absolute),    ;3 button bits          
    0x95, 0x01, // Report Count (1),            
    0x75, 0x05, // Report Size (5),         
    0x81, 0x01, // Input (Constant),            ;5 bit padding          
    0x05, 0x01, // Usage Page (Generic Desktop),            
    0x09, 0x30, // Usage (X),           
    0x09, 0x31, // Usage (Y),           
    0x15, 0x81, // Logical Minimum (-127),          
    0x25, 0x7F, // Logical Maximum (127),           
    0x75, 0x08, // Report Size (8),             
    0x95, 0x02, // Report Count (2),            
    0x81, 0x06, // Input (Data, Variable, Relative),    ;2 position bytes (X & Y)       
    0xC0,       // End Collection,    
    0xC0        // End Collection    
    };     
   
// HardwareID for the virtual mouse.     
   
WCHAR HardwareID[]={L"ROOT\NUMEGA_VIRTUAL_HID_MOUSE
본 문서는 파워해커에서 제작되었으며 무단배포를 허용함..

<Virtual HID Mouse Driver 연구>

저자: AmesianX
제작: powerhacker.net
제작년도: 2009년 1월 15일

 

[서문]

본 문서의 시작에 앞서 목적에 대해 언급한다. 이 문서는 두가지 목적을 위해서 작성되어졌다.
첫번째는 모르는 부분에대한 새로운 연구나 공부를 시도할때 참고할 수 있는 공부방식(Style)에 대한 설명이고, 두번째는 Virtual HID Mouse Driver 를 제작할때 참고해야할 전초를 다지기위한 목적으로 구성되어 있다. 이렇게 기술문서를 공개하는 이유에는 여러가지가 있지만 무엇보다 이 기술이라는 분야는 언젠가는 자신이 알고있는 오늘의 기술이 내일의 쓰레기가 된다. 일찌감치 알고있는 정보들은 공개하고 더 높은 곳으로 계속 뛰어오를때 진정으로 아무도 가보지못한 고지에 오른 것이다. 그래야 스스로가 발전하는 길이고 바로 모두가 발전하는 길일 것이다. 고지는 점령 당하라고 있는 것이다. 언제까지 정적인 비공개노선으로 점령당하길 기다리고 있을 것인가? 앞으로는 더욱더 가속화될 것이다.


[기술을 습득하는 공부방법]

어떤 새로운 기술을 알고싶다면 최대한 동일기능이 구현된 많은 소스들을 수집하라. 그리고 그 차이점을 소스분석을 통해서 캣치하라. 아마 대부분은 소스분석을 깊게 들어가지 않아도 차이점이 눈에 띄게 될 것이다. 그러나.. 아쉽게도 Virtual HID Mouse 에 대한 소스는 인터넷에서 거의 찾기 힘들 것이다. 물론, 공식적인 샘플들을 찾아낼 수 있지만 필자처럼 커널지식보다 유저레벨 어플리케이션 조작만 파온 사람은 그 유명업체들의 공식샘플을 보고도 감을 잡아내기는 하늘에 별따기처럼 어렵다. 즉, 프로그래밍 = 개념 이라는 공식이 있기 때문에 이 개념만 잡고나면 프로그래밍은 껌씹기나 마찬가지다. 개념을 잡는 요령이 있다면 그것은 바로 앞에서 언급한 동일기능 소스의 차이점을 분석해내는 것이다. 그렇기 때문에 매우 제한된 소스(공식소스들)를 갖고 시작하는 것은 전혀 이해를 이끌어내지 못한다. 최대한 고갈되었다고 생각될 정도로 많은 설명이나 소스들을 검색해서 찾아내야 한다. 이때 사용할 수 있는 방법은 구해낸 소스들의 일부 시그너처(Signature)를 검색키워드로 사용하는 것이다. 이런식으로 최대한 많은 정보들을 뽑다보면 선구자들의 질문들을 찾아낼 수 있다. 바로, 그 질문들에서 핵심개념들을 뽑아낼 수 있다. 자주 언급되는 사항이 바로 그 핵심일 것이다. 어떻게보면 "미네르바" 인지 "미네로하이바" 인지 그 친구처럼 철저한 검색기술로 무장한 채로 짜집기의 달인이 되어야만 할 필요가 있다. 만약 충분히 많이 찾아서 더이상 찾아낼 것 조차 없다고 느끼고 등골이 휘어지는 고통을 여러번 견뎌내었다면 이제 얻어낸 것들을 대상으로 비교분석을 취한다. 그렇게 되면 중요 키포인트가 눈에 보이게 될 것이다. 왜 이렇게 해야 하냐면 답은 간단하다. 스스로 엄청난 고통을 감뇌하면서 충분히 검색을 했는데 다 내용이 거기서 거기인 경우가 99.9% 일 것이다. 왜? 그것은 삽질하는 프로그래머가 택한 프로그래밍 방법론은 달라도 전체적인 흐름은 재밌게도 한가지밖에 없으니까. 이게 답이다.

"어라? 다 똑같은 소리만 짓거리고 있잖아? 뭔가 좀 더 구체적인 것을 달라고!!"

이 소리가 나올때 이미 정답은 구해진 것이나 마찬가지다. 다 똑같은 소리를 짓거린다거나 똑같은 소스에 차이점은 있지만 원하는 것이 아니라고 생각될때 사실상 그것이 원하는 것일 확률이 태반이다. 그 이상의 짜집기(Copy & Paste) 능력은 밥을 숫갈로 퍼서 먹는 것이다. 그런데 필자같은 사람은 퍼서 먹여주는 것을 원한다. 왜? 프로그래밍이 나온 이유가 무엇인가? 로보트를 만들려고 기를 쓰는거보면 모르겠는가? 인간에게 숫갈로 밥을 퍼먹여 주려는게 궁극적인 목적아닌가? 프로그래머는 인간이 아니었나? (하기사 혹자는 로보트
라고도 부릅디다..) 프로그래머는 좀 퍼서 먹여주면 어디가 덧나는가? 짜증나게 약올리는 시스템 프로그래머들이여 퍼먹여주지 않으면 스스로 밥숫갈 놓게되는 날이 온다. 인터넷시대에서 정보라는 것은 물 흐르듯 흐를수 밖에 없기 때문에 빨리 털고 높은 곳으로 뛰지않으면 숫가락 놓을 준비를 해야 할 것이다. 오늘의 신기술이 내일의 쓰레기가 되는 시대에서 서로 돕지않으면 혼자 살아남기 힘들다. 외국애들 보라 오픈소스로 자기의 기술을 다 까발리고 있으면서도 항상 최첨단 기술을 걷고 있는 것을 보면 우리가 얼마나 어리석은지 진정 모르냐 이말이다.

외국애들은 오픈소스를 통해서 시너지라는 것을 이용하고 있다. 물론, 수 많은 개발자들이 다 참가해서 오픈소스가 완성될 것이라고 착각하면 그건 열라 바보이다. 유명 보안 오픈소스인 Nessus 개발자의 고충이 섞인 글을 읽어보았는가? 오픈소스임에도 불구하고 자기혼자만 개발해 왔다고 써있었다. 대부분의 오픈소스들이 마찬가지라고 보면 될 것이다. 다만, 시너지효과로 인해 개발자 1명이 해낼수 있는 능력이 100명 1000명 수준으로 증폭되었기에 프로젝트가 맥을 이어갈 수 있는 것이다. 즉, 게임용어로 말하면 "버프"(버프를 모르진 않겠지..) 를 받은 것이다. 그렇게 되면 소수의 엘리트 파워가 오픈소스에 집중되는 일반유저의 관심만큼 증폭되기 때문이다. 단순히 눈에보이는게 전부라고 생각한다면 큰 것을 놓치게된다. (아니라고? 아님말고.. 허위사실 유포로 감금되어야 하나.. ㅎㅎ)

[현 상황]

현 상황에서는 Virtual HID Mouse 가 Auto Mouse 나 MACRO 라는 시장에서 대안으로 대두된 상태라 x시장에서도 드라이버의 판매가 이루어지고 있는 상황이다. 참고로 이 기술이나 드라이버를 판매자체는 사실 법적인 문제의 소지가 없다. 왜냐면 이 Virtual HID Mouse 기술은 범용기술이기 때문이다. 이 기술이 사용되고있는 쪽은 예를들면 조이스틱을 에뮬레이션하거나(용산에가면 조이스틱 판다..) 블루투스 마우스를 사용하도록 해주거나 혹은 그에 버금가는 마우스 업체들이 주로 보유하고있는 자체기술에서 많이 볼 수 있다. 이건 우리가 늘상 접하는 일반분야에서 말한것 뿐이고 무엇보다 가장 많이 사용되고 있는 곳은 임베디드 산업에서일 것이다. 그러므로 이 기술을 파는 것은 전혀 문제가 될 수 없다. 이 기술자체는 Microsoft 사에서 공식적으로 WinDDK 에 예제와 함께 배포하고 있다는 사실을 알만한 사람들은 이미 다 알고있겠다. 단지 그 이상의 자세한 정보를 찾기가 어렵고 Microsoft 사에서 제공하는 기술정보를 알기위해서 밑받침(선행) 되어야할 정보가 없다는 것이 문제점이다. 그래서 기존에 커널 드라이버를 개발하던 사람들이나 천국이지 필자같은 미천한 어플프로그래머들한테는 짜증만 나게 할 뿐이다. 이 중간에 생략된 정보들이 무엇인지 알아내야 한다. 그것이 유저레벨이라는 미천한 신분에서 커널레벨이라는 귀족신분으로 도약할 수 있는 길이다. 테스트환경 만드는게 짜증나서 공부하지 않았다가 완전 독박 쓴 기분이기에 좀 고약한 말투가 나온다. (기분 상하는 커널레벨의 고급 독자는 당장 이 문서를 접기 바란다. 필자도 커널레벨을 공부해야 윈도우를 진정으로 아는 것이라는 대에 이견이 없다. 다만, 오래전부터 블루스크린과 친구를 맺고싶지 않았을 뿐이다. 이거 참.. 뻘쭘하게 커널과 "절친노트" 라도 찍어야하나..)
===================================================================================================================

현재, 인터넷에는 몇몇의 기술 정보이외에는 관련된 기술적 자료를 찾아볼 수 없다고 해도 과언이 아니다. 진짜 짜증나도록 자료가 없다. 이해를 할 수 있을만한 한글로된 기술자료는 극적으로 한개를 찾을 수 있었다. 먼저, Virtual HID Mouse 를 찾아보면 가장먼저 접하게 되는 사이트가 있다. 까마귀라는 한국사람이 자신이 만들었다고하는 Virtual HID Mouse 가 검색이 된다. 블로그의 글 내용인데 사실 저수준을 다루는 고급개발자가 아니면 볼게없다.. (왜? 필자같은 어플프로그래밍 수준은 못알아 먹으니까.. + 안갈켜주니까
-_-;) 그리고 MSDN 이 검색되고 vhidmini 라는 것이 검색된다. 또한, 짱개 사이트의 vhidmouse 라는 소스와 hidmouse 라는 소스도 검색된다. 근데.. 오래전에 GxxxGuard 라는 소스가 인터넷에 떴다는 그 몹쓸 짱개사이트였다. 구현을 하기 위해서는 vhidmini 라는 소스가 그중에서 제일 유력한 후보가 될 것이고 나머지 vhidmouse 와 hidmouse 는 소스를 구하는데 한참이나 걸릴 것이다. 일단, 대충 둘러서 정보를 캣치해야한다. 다음은 이미 다들 알고있겠지만 SoftICE 라는 걸작을 만들어낸 "Numega Soft" 라는 회사의 Virtual HID Mouse 공식샘플의 일부소스이다. 아쉽게도 이 소스는 Windows 9x 계열에서 작동되는 드라이버이므로 NT 계열에서는 사용할 수 없다. 하지만 캣치할 수 있는 중요한 내용이 포함되어 있다. 위에서 언급한 것중에 vhidmouse 라는 것이다. 다음은 vhidmouse 소스 중의 일부분이다.

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

// vmoudev.cpp -  virtual mouse device for HID example    
//=============================================================================    
//    
// Compuware Corporation    
// NuMega Lab    
// 9 Townsend West    
// Nashua, NH 03060  USA    
//    
// Copyright (c) 1998 Compuware Corporation. All Rights Reserved.    
// Unpublished - rights reserved under the Copyright laws of the    
// United States.    
//    
//=============================================================================    
   
// This module implements the device class of the virtual HID    
// mouse minidriver.    
   
#include <KHID.H>    
#include "vmoudev.h"    
#include "hidmouse.h"    
   
KTrace T("",TRACE_MONITOR, TraceAlways, BreakNever, KUstring(L"HidMouse"));   
   
#define SCALEX 3    
#define SCALEY 3    
   
// The HID report descriptor for this device    
// (taken from USB/HID specification)    
   
HID_REPORT_DEscRIPTOR MouseHidReportDesc[] = {   
    0x05, 0x01, // Usage Page (Generic Desktop),     
    0x09, 0x02, // Usage (Mouse),      
    0xA1, 0x01, // Collection (Application),        
    0x09, 0x01, // Usage (Pointer),         
    0xA1, 0x00, // Collection (Physical),           
    0x05, 0x09, // Usage Page (Buttons),            
    0x19, 0x01, // Usage Minimum (01),          
    0x29, 0x03, // Usage Maximun (03),          
    0x15, 0x00, // Logical Minimum (0),             
    0x25, 0x01, // Logical Maximum (1),             
    0x95, 0x03, // Report Count (3),            
    0x75, 0x01, // Report Size (1),         
    0x81, 0x02, // Input (Data, Variable, Absolute),    ;3 button bits          
    0x95, 0x01, // Report Count (1),            
    0x75, 0x05, // Report Size (5),         
    0x81, 0x01, // Input (Constant),            ;5 bit padding          
    0x05, 0x01, // Usage Page (Generic Desktop),            
    0x09, 0x30, // Usage (X),           
    0x09, 0x31, // Usage (Y),           
    0x15, 0x81, // Logical Minimum (-127),          
    0x25, 0x7F, // Logical Maximum (127),           
    0x75, 0x08, // Report Size (8),             
    0x95, 0x02, // Report Count (2),            
    0x81, 0x06, // Input (Data, Variable, Relative),    ;2 position bytes (X & Y)       
    0xC0,       // End Collection,    
    0xC0        // End Collection    
    };     
   
// HardwareID for the virtual mouse.     
   
WCHAR HardwareID[]={L"ROOT\\NUMEGA_VIRTUAL_HID_MOUSE\0"};   
WCHAR DeviceID[]  ={L"ROOT\\NUMEGA_VIRTUAL_HID_MOUSE\0"};   
   
HID_DEVICE_ATTRIBUTES DeviceAttributes = {   
    sizeof(HID_DEVICE_ATTRIBUTES),     
    MY_VENDOR_ID,   
    MY_PRODUCT_ID,   
    VERSION_NUMBER   
    };

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

위와 같이 HID_REPORT_DEscRIPTOR 라는 것을 볼 수 있는데, 처음에는 이게 뭔지 모른다. 감도 안온다. 그러므로 그 관점을 그대로 두고 다음으로 넘어가서 다른 소스들을 보자. (처음엔 원래 모르겠지.. 나만그런가.. -_-; 제길..)

인터넷에서 검색하면 위의 소스와 MSDN (Microsoft 사의 공식샘플과 설명문서) 을 먼저 보게 될 것이다. 그러면 당연히 vhidmini 라는 것도 접하게 된다. 소스는 인터넷에서 파는 놈들도 있으니 그냥 찾기는 좀 짜증이 날 것이다. Microsoft 사의 홈페이지에서 WinDDK 를 받으라. 그 안에 VHidMini 라는 샘플이 들어있다. 그놈을 보면 다음과 같이 생겨먹은 부분에 주목하자.

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

        if (NT_SUCCESS(ntStatus)) {
            //
            // Use default "HID Descriptor" (hardcoded). We will set the 
            // wReportLength memeber of HID descriptor when we read the 
            // the report descriptor either from registry or the hard-coded 
            // one.
            //

            deviceInfo->HidDescriptor = DefaultHidDescriptor;

            //
            // Check to see if we need to read the Report Descriptor from
            // registry. If the "ReadFromRegistry" flag in the registry is set
            // then we will read the descriptor from registry using routine 
            // ReadDescriptorFromRegistry(). Otherwise, we will use the 
            // hard-coded default report descriptor.
            //

            queryStatus = CheckRegistryForDescriptor(DeviceObject);

            if(NT_SUCCESS(queryStatus)){
                //
                // We need to read read descriptor from registry
                //
                
                queryStatus = ReadDescriptorFromRegistry(DeviceObject);
            
                if(!NT_SUCCESS(queryStatus)){
                    DebugPrint(("Failed to read descriptor from registry\n"));
                    ntStatus = STATUS_UNSUCCESSFUL;
                }

            }

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

Microsoft 에서 MSDN 의 설명을 먼저 읽어본 뒤 위의 소스주석부분을 보자. 다음과 같이 친절하게 설명해주고 있다.

            // Check to see if we need to read the Report Descriptor from
            // registry. If the "ReadFromRegistry" flag in the registry is set
            // then we will read the descriptor from registry using routine 
            // ReadDescriptorFromRegistry(). Otherwise, we will use the 
            // hard-coded default report descriptor.

설명에 써있듯이 자기네는 그냥 하드코딩 했으니까 ReadFromRegistry 를 참고하면 다른 디바이스를 등록할 수 있단다. 처음 접할땐 사전지식이 없기에 "이게 뭔 개소리야?" 라고 생각이 들 것이다. (? 반응이 없으면 나만그런거 같다.. ㅎ)

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

그렇다면 이제 개소리는 집어치우고 다음을 보자.

-->  https://www.osronline.com/showthread.cfm?link=138652

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

Radly
xxxxxx@daryllee.com

This being my first driver project, and an unusual one at that, there's a lot to get my
head wrapped around. My intent is to produce a virtual HID device (mouse emulation) that
uses a complex non-HID physical device as the input medium. I'm using the VHidMini sample
from the WDK hid folder as a starting point, and I'm now at the point where I need to transform
the sample's report format into a mouse format. I notice with confusion that the report descriptor
in vhidmini.inf is different from that in vhidmini.h, with no explanation in vhidmini.htm as
to why they are different. Does anyone here have any insight on that?


어떤 놈이 필자가 생각하는 것과 동일한 구현을 해볼려고 삽질중에 무시무시한 고급개발자들과 해커들이 몰린다는 osronline 에 질문을 던져놓고 있다. 이 소리는 무엇인가? 필자도 결국 저 문제에 봉착하게 될 날이 온다는 시나리오를 미리 발견한 것이다. 그러므로 주의 깊게 읽어볼 필요가 있다. 여기서 얻어낼 수 있는 정보는 sample's report format 이란 것과 report descriptor 라는 두가지 내용이다. 원래부터 찾기힘든 정보들에는 동문서답 내지는 "내가 니 밥처먹는데 밥숫가락으로 퍼먹여주랴?" 정도의 댓글이 달리는데 그래도 이 글의 답글중에 괜찮은 답글이 있다. 근데.. 여전히 찾기힘든 정보만큼이나 짤막하게 달아놓는다. 이런사람이 있다는 것은 희망이고 곧 빛이다. 다음의 답글을 읽어보자.

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

allen zhang
xxxxxx@sina.com
RE: VHidMini report descriptor(s)

see the follow source code and the ReadDescriptorFromRegistry function, You should be understand it.

deviceInfo->HidDescriptor = DefaultHidDescriptor;
queryStatus = CheckRegistryForDescriptor(DeviceObject);
if(NT_SUCCESS(queryStatus)) {
    queryStatus = ReadDescriptorFromRegistry(DeviceObject);
    ...

 

입에서 욕은 나온다. 왜? 말할라면 다 말하던가 아니면 동문서답이나 하고 가던가 감칠맛나게 소스 네줄 뿌리고 튀다니.. 그래도 고맙다. 지식을 갈구하는 자에게는 이것조차 선물이다. 제길.. 현자라면 푸념할때가 아닌거 같다. 여기서 뭔가 개념을 잡을 수 있는 정보를 캣치해야만 한다. 이 글에서 외국아가(짱개류 외국애인지 allen zhang 이구나.. 역시 중국은 AUTO 에 강한가보다..) 말하기를 소스코드를 보란다. 그 안에 ReadDescriptorFromRegistry 를 보라고 권하면서 일부 소스를 긁어서 보여준다. 글은 짧지만 분명 소스를 열어봤기에 긁어서 붙여줬을테니 아쉬워도 고마운 행동이다.

여기서 보라고 한 소스가 바로 위에서 VHidMini 샘플의 일부분이라고 뿌린 부분이다. 즉, 이 부분의 내용은 최초 질문자의 글에서 캣치한 sample's report format 와 report descriptor 라는 부분에대한 응답이다. 즉, 이 함수의 이름으로부터 알 수 있듯이 레지스트리로부터 디스크립터를 읽어들인다는 것에 바로 Virtual HID Mouse 의 핵심구현이 얽혀있다는 것을 시사한다는 점을 알 수 있다. 그런데 필자도 단지 이두개만 가지고 감을 잡지는 못했다. 왜냐면, 커널을 깊이 공부한 적이 없는 사람이 이 두가지의 자료만을 토대로 감을 잡아낼 수 있겠는가? 그렇다면 그건 천재이거나 영어를 모국어처럼 잘하는 사람일게 분명하다. 필자는 남보다 항상 두배로 삽질을 하는데 머리가 남들보다 딸려서 그렇다. 자료도 항상 두배로 찾아야 한다. 결정적으로 힌트가 되었던 것은 역시 국내사이트인데 드라이버 개발정보를 알려주는 곳인 driveronline.org 에서의 힌트와 임베디드 계통의 KELP 사이트에서 였다.

http://driveronline.org/bbs/view.asp?tb=beusb&GotoPage=1&s_bulu=memo&s_key=pnp&no=1491
-------------------------------------------------------------------------------------------------------------

Re] Re] Re] USB 가상 키보드, 마우스 드라이버
·작성일     2007.10.02:10.40 (화)
· 작성자     Woof
· 조 회 605

pnp 를 이용해서든지 해서 가상적인 usb 장치가 인식이 되면 일반적인 usb 장치를 다루듯이 이용하시면 됩니다. 일반적으로 실제 장치들은  Windows에서 제공하는 기본적인 드라이버로도 동작하기 때문에 필요가 없지만 이와 같은 경우에는 간단하게 자기 드라이버를 열어서 인식된 장치 device와 통신하는 드라이버 정도는 필요하겠지요. 뭐, usb라서 따로 드라이버없이 application으로도 충분히 가능한건데 다들 위와 같은 방법을 이용하더군요. 새로나온 umdf 등을 이용하면 더 간단하고 새로나온 것에 대한 공부도 하면서 재미나게 할 수 있을지도 모르겠네요. 위 에서 말한 대부분의 경우 라고 한 것의 예를 간단히 들어보면 자신의 드라이버를 올리고 해당 드라이버에서 application과 통신 device를 생성한 뒤에 pnp를 이용해서 가상적인 usb 장치를 만들고 그것과 통신하는 길?을 적당히 만들어서 이용하시면 됩니다. sample에서는 가상적인 장치 인식이 바로 usb나 그런 부분이 아니였던 것 같은데 적당히 고치면 되겠지요.

위에도 썻지만, 잘 찾으면 다 만들어진 코드 어디 있을 것 같습니다. 저도 한번 찾으려다가 그냥 sample에 있어서 말았는데. :|  해당 usb 드라이버를 이용해서" 라는 부분에 대해서 물어보셔서 이 부분만 따로 답을 달면 해당 usb device를 제어(control)하는 드라이버를 지칭했습니다.  또 처음에 말한 것 처럼 class관련 드라이버에 대해서는 생각할 필요가 없습니다. 역시 위에 쓴 것 처럼 어디에 쓰실지 궁금하네요. 가상 키입력등은 S/W나 그런 자동화 테스트에 이용하기도 하고 꽤 여러군데서 쓰기는 하는데 안좋지는 않지만 뭐 . 그런데도 쓰여서 :|

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


최초 질문자가 어떻게 구현해야 하냐고 질문하자 pnp 를 통해서 가상적인 usb 를 인식시킨 다음에 적당히 device 와 통신시키라고 한다. 자세한 내용은 말해주지 않고 Microsoft 에서 제공하는 샘플로도 구현이 가능할 것이라는 내용과 어딘가에는 이미 다 만들어진 소스가 있을텐데 찾아보라고 한다. 이말 믿고 인터넷에서 찾아헤메다가는 마누라가 집나가도 모를것이다. 답변에서 보듯이 이 사람은 진짜 적당히 답글을 달고 있는 사람이라는 점을 주의해야 한다.

이 사람의 힌트와 통찰력이 Microsoft 사의 샘플에서 존재하는 핵심이라는 점을 알 수 있다. 일단, 정보는 머리속에 꼬깃꼬깃 담아두고 계속 다음 검색으로 넘어가면서 본인의 마음속에 답이 한가지로 수렴되도록 정보들을 계속 얻어 내어보자. 이쯤되면 정상적인 사이트를 뒤지는 것이 힘들어진다. 왜냐면 너무 정보가 부족하기 때문이리라. 고로 컨트롤러를 제어하는 것을 찾아본다. 예를들면 USB HID 조이스틱 드라이버 같은 것을 찾아내는 것이다.

다음과 같은 좋은 예가 있었다.

http://www.redcl0ud.com/files/XBCD_all_src.cab

XBOX 의 6축 조이스틱 패드를 윈도우에서 사용할 수 있도록 해주는 소스였다. 검색을 할때는 기존에 얻었던 소스에서 일부 특이하게 보일만한 함수를 키워드로 검색하면 운좋게 찾을 수 있다. 소스를 보면 너무 길고 난해하고 이해하기 힘들뿐이다. 당연히 커널관련 지식이 깊지않은 이상 어떻게 분석하고싶어도 그럴 도리가 없다. 그러므로 파일구성을 보는 것이 전부이다. 여기서 또한가지 힌트를 얻을 수 있다.

XBCD_control.c
XBCD_driver.c
XBCD_driver.h
XBCD_hid.h
XBCD_report.h

위와 같은 파일구성에서 driver 나 control 소스를 보기전에 report 라는 눈에 띄는 놈이 있다. 이 헤더파일의 내용을 보게되면 다음과 같은 것이 적혀있다.

-------------------------------------------------------------------------------------------------------------
char ReportDescriptor[213] = {
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x04,                    // USAGE (Joystick)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,                    //   PHYSICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x01,                    //   USAGE (Button 1)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x02,                    //   USAGE (Button 2)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x03,                    //   USAGE (Button 3)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x04,                    //   USAGE (Button 4)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x05,                    //   USAGE (Button 5)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x06,                    //   USAGE (Button 6)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x07,                    //   USAGE (Button 7)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x08,                    //   USAGE (Button 8)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x09,                    //   USAGE (Button 9)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0a,                    //   USAGE (Button 10)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0b,                    //   USAGE (Button 11)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0c,                    //   USAGE (Button 12)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x75, 0x04,                    //   REPORT_SIZE (4)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x81, 0x01,                    //   INPUT (Cnst,Ary,Abs)
    0x75, 0x10,                    //   REPORT_SIZE (16)
    0x16, 0x01, 0x80,              //   LOGICAL_MINIMUM (-32767)
    0x26, 0xff, 0x7f,              //   LOGICAL_MAXIMUM (32767)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x7f,              //   PHYSICAL_MAXIMUM (32767)
    0x05, 0x01,                    //   USAGE_PAGE (Generic Desktop)
    0x95, 0x02,                    //   REPORT_COUNT (2)
    0x09, 0x30,                    //   USAGE (X)
    0x09, 0x31,                    //   USAGE (Y)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x02,                    //   USAGE_PAGE (Simulation Controls)
    0x95, 0x02,                    //   REPORT_COUNT (2)
    0x09, 0xba,                    //   USAGE (Rudder)
    0x09, 0xbb,                    //   USAGE (Throttle)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x01,                    //   USAGE_PAGE (Generic Desktop)
    0x09, 0x39,                    //   USAGE (Hat switch)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x07,                    //   LOGICAL_MAXIMUM (7)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0x3b, 0x01,              //   PHYSICAL_MAXIMUM (315)
    0x65, 0x14,                    //   UNIT (Eng Rot:Angular Pos)
    0x75, 0x04,                    //   REPORT_SIZE (4)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,                    //   PHYSICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0d,                    //   USAGE (Button 13)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0e,                    //   USAGE (Button 14)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0f,                    //   USAGE (Button 15)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x10,                    //   USAGE (Button 16)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x00,              //   PHYSICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, 0x03,                    //   REPORT_COUNT (3)
    0x05, 0x00,                    //   USAGE_PAGE (Not Defined)
    0x09, 0x00,                    //   USAGE (Undefined)
    0x09, 0x01,                    //   USAGE (Undefined)
    0x09, 0x02,                    //   USAGE (Undefined)
    0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
    0xc0                           // END_COLLECTION
};
-------------------------------------------------------------------------------------------------------------

그리고 이 홈페이지에서 최대한 얻을 수 있는 것은 다 캣치해야 하는 http://www.redcl0ud.com/xbcd.html 홈페이지의 마지막쯤에 보면 http://www.redcl0ud.com/files/USBView.cab 라는 것이 있다. 그리고 캡춰사진이 있는데 핵심사항으로 체크를 해둔 부분이 있다. idVendor, idProduct 라는 부분에 체크를 해두고 있다. 그리고 USBView 에서 보여주는 내용이 모냐면 바로 Device Descriptor 였다. 오호라.. 내친김에 이 사이트에서는 USB 드라이버를 제작하는 방법까지 설명하는 링크를 걸어두고 있었다.

http://euc.jp/periphs/xbox-controller.en.html

이 링크인데 제목은 "Inside XBox Controller" 라고 되어있다. 대충 무슨내용이 있는지 열거하자면..

-------------------------------------------------------------------------------------------------------------
<Inside Xbox Controller>
...

<Overview>
...

<USB Device Model>
...

<Descriptors>

Here are descriptor dumps of the hub, the gamepad and the memory unit.

    * Descriptors of the integrated hub
    * Descriptors of the gamepad (American)
    * Descriptors of the memory unit

<Vendor/Product IDs>

The vendor ID is 0x045e (Microsoft). Product IDs are as follows:
ID    product
0x001c    integrated hub
0x0202    gamepad (American)
0x0280    memory unit
0x0284    DVD remote receiver
0x0285    gamepad (Japanese)

It is not recommended to distinguish Xbox gamepads by vendor/product IDs because third-party controllers may
have their own vendor/product IDs.

<Device Class>
...

<HID Report Format>
Input Report
The input report is 20-byte.
헤더그림

Output Report
The output report (rumble control) is 6-byte. 
헤더그림

<Example of HID Report Descriptor>
The Xbox gamepad lacks the HID report descriptor that describes the input/output report formats. Based on the
above report formats I have tried writing the report descriptor for your information. This is a mere example;
neither official nor verified. Accuracy is not guaranteed.

    * Text format
    * Binary format
    * HID Descriptor Tool format (to be loaded into HID Descriptor Tool) 
---------------------------------------------------------------------------------------------------------------

위와 같은 내용들이 있었다. 상당히 많은 삘을 주고있다. 누가봐도 HID Descriptor 와 HID Report Format 그리고 Input Report 와 Output Report 를 통해서 통신한다는 아주 기본적인 컨셉(개념)은 머리가 아니라(T.T) 가슴에 와닿을 것이다. (젠쟝.. 가슴에만 담아두마.. -_-;) 일단, 이쯤에서 XBCD 소스는 닫아둔다. 언제 이거 분석하고 앉아있는가.. 최종컨셉이 다르기 때문에 힌트만 뽑아먹고 닫아두는 것이다. 애초에 만들려고 한건 Virtual HID Mouse 인데 이건 그 컨셉이 아니기에 대충 훑어보고 넘겨야 한다. 또 다른 소스들을 보자. 마구잡이로 검색하면서 받아둔 소스중에 앞에서 처음에 말했던 hidmouse 라는 소스를 한번 진단해보자.. -_-;

(PIC 를 이용한 마우스 제작소스)
파일을 열어보니 원하는게 아닌듯 보였는데 알고보니 PIC 용이었다. 운 좋게도 필자는 PIC18x 롬라이터를 갖고 있어서 이 소스가 뭔지 알 수 있었다. 오래전에 친구의 부탁으로 PIC18x 칩에 어셈블리를 롬라이팅 하는 프로그램을 만들어준 적이 있어서 무슨 소스인지 금방 알 수 있었다. 요새는 PIC 프로그래밍에도 C 가 쓰이고 PIC 는 PLC 대체용으로 쓰이기도 한다. 그런데 PIC 로 USB 모듈을 부착하고 마우스로 제작이 가능한거 같았다. 어쨌거나 원하는 내용은 아니었지만 생각해보면 가장 중요한 것이 물리적인 장치 아닌가? 물리적인 장치에서는 기존에 찾은 소스들이나 검색내용들과 어떤 차이가 있는지 알아볼 필요도 있다.
http://www.pudn.com/downloads128/sourcecode/comm/detail543439.html

hidmouse 라는 소스에서 파일구성을 보면 특이한 놈이 있다.
usb_descriptors.c 라는 소스가 있는데 여태까지 눈여겨왔던 descriptor 라는 단어가 보일 수 밖에 없다.

-------------------------------------------------------------------------------------------------------------
/* Device Descriptor */
ROM USB_DEVICE_DEscRIPTOR device_dsc=
{
    0x12,    // Size of this descriptor in bytes
    USB_DEscRIPTOR_DEVICE,                // DEVICE descriptor type
    0x0200,                 // USB Spec Release Number in BCD format
    0x00,                   // Class Code
    0x00,                   // Subclass code
    0x00,                   // Protocol code
    USB_EP0_BUFF_SIZE,          // Max packet size for EP0, see usb_config.h
    MY_VID,                 // Vendor ID
    MY_PID,                 // Product ID: Mouse in a circle fw demo
    0x0003,                 // Device release number in BCD format
    0x01,                   // Manufacturer string index
    0x02,                   // Product string index
    0x00,                   // Device serial number string index
    0x01                    // Number of possible configurations
};

... 중략 ...

//Class specific descriptor - HID mouse
ROM struct{BYTE report[HID_RPT01_SIZE];}hid_rpt01={
    {0x05, 0x01, /* Usage Page (Generic Desktop)             */
    0x09, 0x02, /* Usage (Mouse)                            */
    0xA1, 0x01, /* Collection (Application)                 */
    0x09, 0x01, /*  Usage (Pointer)                         */
    0xA1, 0x00, /*  Collection (Physical)                   */
    0x05, 0x09, /*      Usage Page (Buttons)                */
    0x19, 0x01, /*      Usage Minimum (01)                  */
    0x29, 0x03, /*      Usage Maximum (03)                  */
    0x15, 0x00, /*      Logical Minimum (0)                 */
    0x25, 0x01, /*      Logical Maximum (0)                 */
    0x95, 0x03, /*      Report Count (3)                    */
    0x75, 0x01, /*      Report Size (1)                     */
    0x81, 0x02, /*      Input (Data, Variable, Absolute)    */
    0x95, 0x01, /*      Report Count (1)                    */
    0x75, 0x05, /*      Report Size (5)                     */
    0x81, 0x01, /*      Input (Constant)    ;5 bit padding  */
    0x05, 0x01, /*      Usage Page (Generic Desktop)        */
    0x09, 0x30, /*      Usage (X)                           */
    0x09, 0x31, /*      Usage (Y)                           */
    0x15, 0x81, /*      Logical Minimum (-127)              */
    0x25, 0x7F, /*      Logical Maximum (127)               */
    0x75, 0x08, /*      Report Size (8)                     */
    0x95, 0x02, /*      Report Count (2)                    */
    0x81, 0x06, /*      Input (Data, Variable, Relative)    */
    0xC0, 0xC0}
};/* End Collection,End Collection            */

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

hidmouse 의 소스는 분석하지 않고 특징적인 몇개의 파일만 열어보고 위의 부분에 주목하고 닫아 버린다. 역시 컨셉은 물리 마우스가 아니라 가상 마우스이기 때문이다. 가상 마우스는 연결되면 오른쪽 아래의 트레이에 연결되었다고 풍선글이 떠야 하는 형태로 진행되어야 하는 것이 머리속의 구상이었다. 이미 driveronline 의 힌트에서 pnp 를 통해서 usb 를 인식시키라는 내용을 보았고 osronline 에서는 vhidmini 의 특정부분을 언급했으며 osronline 의 최초 질문자는 샘플의 포맷과 디스크립터를 언급했다. 다음의 사이트를 보게되면 약 90% 의 감이 오게되는데 임베디드 계통이 역시나 제일 확실하다. 시스템 프로그래머라는 황무지(wild)에서 살아가는 사람들이기 때문이다. 다만, 숫갈로 퍼먹여 주는걸 제일 싫어해서 짜증난다. 다음의 KELP 사이트의 글을 보면(http://kelp.or.kr/korweblog/stories.php?story=07/02/13/3453938)

글쓴이가 usb mouse 구현시 뭔가 이상하다는 식으로 적어놓고 있는 내용을 볼 수 있는데 한번 읽어보자.

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

usb slave 포트를 이용하여 usb mouse를 구현하고 있습니다.
글쓴이 : omayaro (2007년 02월 13일 오후 02:10) 읽은수: 643

<커널 2.6.11에서 gadget api를 이용하여 usb 마우스를 구현해 보고 있습니다.>

처음에 모듈을 등록하기 위하여

static int __init my_module_init(void)
{
int retval;
retval = usb_gadget_register_driver( &g_ugdDriver );
if (retval)
{
printk(KERN_ERR "[ omayaro ] module_init: cannot register gadget driver, ret=%d\n", retval);
return retval;
}
return 0;
}


위에서 처럼 하여 등록을 마쳤습니다.

그리고 pc( window xp 와 fedora core4 를 사용하는 pc 2대를 한번씩 테스트 함 )에

usb cable을 연결하였습니다.

그랬더니 임베디드 보드와 pc에 몇가지 반응이 오더군요..

아래의 내용은 진짜 마우스를 꼽았을때에 windows xp에서 usb descriptor를

분석한 내용입니다.

 

Device Descriptor:
bcdUSB: 0x0110
bDeviceClass: 0x00
bDeviceSubClass: 0x00
bDeviceProtocol: 0x00
bMaxPacketSize0: 0x08 (8)
idVendor: 0x062A
idProduct: 0x0000
bcdDevice: 0x0000
iManufacturer: 0x00
iProduct: 0x00
iSerialNumber: 0x00
bNumConfigurations: 0x01

ConnectionStatus: DeviceConnected
Current Config Value: 0x01
Device Bus Speed: Low
Device Address: 0x02
Open Pipes: 1

Endpoint Descriptor:
bEndpointAddress: 0x81
Transfer Type: Interrupt
wMaxPacketSize: 0x0004 (4)
bInterval: 0x0A

 

그리고 아래의 정보는 제가 짠 프로그램이 동작하여 pc에 등록된 정보입니다.

 

Device Descriptor:
bcdUSB: 0x0110
bDeviceClass: 0x03
bDeviceSubClass: 0x00
bDeviceProtocol: 0x00
bMaxPacketSize0: 0x10 (16)
idVendor: 0x062A
idProduct: 0x0000
bcdDevice: 0x0199
iManufacturer: 0x00
iProduct: 0x00
iSerialNumber: 0x00
bNumConfigurations: 0x01

ConnectionStatus: DeviceConnected
Current Config Value: 0x00
Device Bus Speed: Low
Device Address: 0x00
Open Pipes: 0

 

보시면 ConnectionStatus에 들어 있는 정보가 좀 틀리고 end point의 정보는 아예 없는 것을 보실수 있습니다.. 이 내용을 분석한 제 생각으로는 일단 Open Pipes의 수가 0인 것으로 보아 우선 정상적으로 연결 실패.. 가난 것으로 보이고요 end point가 없는 것으로 보아 어떤 설정또는 ep0를 통하여 세팅중에 에러가 난 것으로 보입니다...

이제 질문...( 서론이 좀 길었죠??ㅡㅜ;;;; ) 제가 아직 usb 에 대해 정확히 이해를 못해서 인지는 몰라도 usb ep0를 통하여 setup이 될때 어떤 순서로 setup이 이루어 지는지 잘 모르겠습니다. 제 생각으로는

1. host가 device descriptor를 요청하여 가져감
2. 나머지 descriptor( configure, interface )를 가져감

으로 생각이 되는데요.. 순서가 저렇게 되는 것이 맞나요?? 그리고 pipe( 제 생각에는 in/out end point )가 open되는 시점이 이 언제인지 궁금합니다.. 조금 정리해서 물어본다면.. usb device가 pc에 꽂힌 후 정상 인식 되기까지 host가 device에게 요청하는 메시지의 순서가 궁금하네요~~ 그리고 언제 pipe가 오픈이 되는 지... 도 궁금합니다~~

고수님들의 답변 기다릴게요~~
하루에 refresh만 5천번하는.. omayaro 였습니다...ㅠ0ㅠ

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

오케이.. 뭔가 삘이오는데.. 바로 앞에서 가슴속에 담아둔 그거네.. -_-; 중요한건 바로 디스크립터(descriptor) 컨피겨(configure) 인터페이스(interface) 라는 내용이 또 나온다. 어쨌거나 저쨌거나 질문자는 실패한 사람이니까 믿을게 못된다. 여기에 달린 댓글이 중요하다. 그런데.. 역시나.. 멋진 시스템 프로그래머들 같으니라구.. ㅎㅎ 직접읽어보라.. 민망하다..

--------------------------------------------------------------------------------------------------
 익명 (2007년 02월 13일 오후 10:08)

    밥은 직접 떠서 드세요.

    device 연결시점에서는 default(첫번째) configuration 으로 동작합니다.
    host 쪽에서 사용자의 요구에 의해 다른 configuration 으로 전환합니다.
    흔한 경우는 아닙니다.
    이런 방식을 사용하는 대표적인 경우는 device 쪽에 end point 가 모자랄 경우입니다.
    간혹, host쪽 사용자에게 디버깅 포트등을 숨기기 위해서 사용하기도 합니다. 
--------------------------------------------------------------------------------------------------


역시나 댓글한번 멋지게 달려있었다. 밥은 직접 떠먹어야 한다는 말. 누가 그걸 모르나. 이쯤되면 검색에 이골이 나기 일보직전이 되고 서서히 자신감도 사라지고 짜증이 섞이기 마련이다. 이때한번 refresh 가 필요한데 검색은 계속되어야 한다.. 쭈~욱.. 점점 검색하다보면 Filter Driver 에 대한 내용이 나오기도 하고 처음부터 검색이 되더라도 알아먹지 못했던 내용이 두번째 검색하다 모르고 똑같은걸 또 보게되면(즉, 본걸 나중에
또 봤을때) 이해가 되기 시작하는 부분이 생겨나기 시작한다. 바로 다음의 부분들이 그러한 부분들이라 하겠다.

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

bodnar
February 11th, 2007, 05:58 AM

I am trying to fix a part of the report descriptor on an existing USB HID device that woked fine but
has problems on Vista. It installs
and everything is OK with it but DirectX refuses to see it due to some inconsistency in the report descriptor.

I understand that I would need to write a filter driver to fix that.

I have downloaded recent WDK and looked at the samples, specifically HID\Firefly sample but I cannot figure out

how to alter

Report Descriptor data when the driver receives IRP_MN_START_DEVICE in DispatchPnP. I can see how PDEVICE_OBJECT

DeviceObject is passed

to it but mmm.. how do I get access to HID device details so I can alter it?

When I look inside HID\Vhidmini virtual HID minidriver I can see exactly what I would want to use in the
filter driver:

deviceInfo->ReportDescriptor = NewReportDescriptor;
deviceInfo->HidDescriptor.DescriptorList[0].wReportLength = ...;

I am a bit lost... Any help is appreciated.

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

미국말로 뭐라 지껄이는지 전혀 관심없다. 오로지 Report Descriptor data when the driver receives IRP_MN_START_DEVICE

in DispatchPnP 라는 문장과 다음의 소스 두부분이다.

deviceInfo->ReportDescriptor = NewReportDescriptor;
deviceInfo->HidDescriptor.DescriptorList[0].wReportLength = ...;

이 글에서 필자가 어느타임에 어디를 수정해야 할지 방향을 구체적으로 잡아나갈 수 있는 단초가 마련되기 시작한다. 즉, DispatchPnP 에서 IRP_MN_START_DEVICE 를 받았을때 Report Descriptor data 가 관계가 있다는 점이고 ReportDescriptor 를 NewReportDescriptor 로 할당하는 조작을 잡아낼 수 있다. 원래는 vhidmini 라는 Microsoft 사의 공식샘플이 어떻게 생겨먹었는지

잠시 소스 일부분을 보자면

        // Store the registry report descriptor in the device extension
        //
        deviceInfo->ReadReportDescFromRegistry = TRUE;
        deviceInfo->ReportDescriptor = RegistryReportDescriptor;
        deviceInfo->HidDescriptor.DescriptorList[0].wReportLength = 
                                   (USHORT)RegistryReportDescriptorLength;

위의 모습처럼 되어있다. 그런데 저 미국아가 한 짓은 deviceInfo->ReportDescriptor = RegistryReportDescriptor 를 NewReportDescriptor 로 바꿨다는 것이다. 그러니 필자도 역시 이 부분을 건드리게 될 것이란 소리가 된다. 그러므로 수정을 가할 부분을 한 부분 구체적으로 알아먹었다. 이 글의 맨 처음 시작부분의 Numega Soft 의 소스라고 되어있는 부분을 보자.

// The HID report descriptor for this device    
// (taken from USB/HID specification)    
   
HID_REPORT_DEscRIPTOR MouseHidReportDesc[] = {   
    0x05, 0x01, // Usage Page (Generic Desktop),     
    0x09, 0x02, // Usage (Mouse),      
    0xA1, 0x01, // Collection (Application),        
    0x09, 0x01, // Usage (Pointer),         
    0xA1, 0x00, // Collection (Physical),           
    0x05, 0x09, // Usage Page (Buttons),            
    0x19, 0x01, // Usage Minimum (01),          
    0x29, 0x03, // Usage Maximun (03),          
    0x15, 0x00, // Logical Minimum (0),
    ... 생략 ...


해당 부분을 보면 이제서야 뭔가 감이 오기 시작하게 되는 것이다.

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

드디어;;
 ·작성일     2007.01.28:15.25 (일)
· 작성자     rechoco
· 조 회     487


hid minidriver 테스트 살짝 성공~

샘플소스를 구해서 레포트 디스크립터랑 익스텐션 조금 손만 본거지만.

디바이스에서 데이터를 hid포멧에 맞춰서 주는게 아니라서..

강제로 제가 바꿔줘야 했거든요ㅋ

마우스로 테스트 해봤더니 쭉쭉 잘옮겨지더군요

물론 목표한 디지타이져는 아직 안됩니다;;
(와컴것 분석했더니 절대좌표모드일때도, 마우스 플래그를 쓰더군요
xp에서는 디지타이져가 지원이 안되니까 절대좌표 "처럼" 마우스좌표로 작업합니다.
저도 그렇게 하긴했는데. 영 개운하지가 않아서;;
디지타이져가 비스타에서는 지원 된다길래 해봤는데 실패했다는;;)

제가 참고한 샘플은 WDK의 vhidmini 소스입니다.

xp용으로 inf파일하고 소스파일 조금 수정하시면 빌드도 잘되고..

헛짓거리중에 잠깐 들러봤습니다.


드라이버 온라인님들 모두 화이팅하세요!!

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


아쉽게도 이 글은 가상 마우스인지 실제 마우스의 필터드라이버를 만든것인지 알길이 없어서 단지 말 그대로 희망만 주는 글인데 되긴 되나부다 정도로만 넘겨야 했다. 중요한 개념가닥을 잡아내는 파편과도 같은 내용들은 모두 끝났고(사실 더 많지만..) 다음의 세가지 정보의 검색이 사실상 전체적인 개념(컨셉)을 모두 얻도록 해주었다.

 

---------------------------------------------------------------------------------------------------
1. http://www.eggheadcafe.com/software/aspnet/32296449/virtual-usb-mouse-device.aspx

<Virtual USB Mouse Device only shows as generic HID device. - tomca>
08-May-08 05:16:00

I wrote a bus driver that generated virtual USB PDO for Printer, Scanner, and
SmartCard.  It worked fine before.  Recently, I was requested to provide a
virtual USB mouse PDO.  What I did was as following steps

1. An usermode application access bus driver to add a new PDO
2. bus driver use IoCreateDeviceSecure to create a new device and invalid
bus relation.
3. PNP manager found this new device, it will query the hardwareid, device
instanceid, and compatible id.
4. I provide USB\Class_03&SubClass_01&Prot_02 as compatible ID
5. System find this is a HID device and start to query Device Descriptor,
Configuration Descriptor, and HID descriptor.
6. Since this is a virtual mouse, bus driver gives HID descriptor without
hardware.  I copy a standard mouse device's HID descriptor (3button usb
mouse) to caller.
7. From Device Manager, I can see a HID device shows up,  but there is not
mouse device shows up.

If I plug in a real usb mouse, I can see system create a HID device first,
then HIDClass driver create a PDO for mouhid driver.  Is anyting wrong I did?

I have carefully checked the USB data sent to caller, everything is ok, but
system doesn't like this device as mouse,  Just consider it as generic USB
HID device.

Could someone give me help?

Thanks!
---------------------------------------------------------------------------------------------------

유저모드


---------------------------------------------------------------------------------------------------
2. KSP(www.ksyspro.org) 라는 곳에서 작성한 "USB강의자료.PDF" 라는 파일이 인터넷에서 검색되었다.
   내용의 제목은 "9차 정기 세미나 강의 자료" USB Device Driver 강의였다. 아쉽지만 원래 이런
   사이트는 문이 닫혀있다. (원래 그런거니까 이해를 해야한다.. -_-; 얼마나 힘들겠는가..? )

 - 내용이 작살이다. 이건 그냥 인터넷에서 받아서 보라.. 전체적인 개념정립이 이루어진다.
   (아마 앞서서 했던 기본적인 검색뻘짓이 없이는 읽을 수 있는 내용이 아니었으리..)

---------------------------------------------------------------------------------------------------
3. MSDN & ReactOS 소스 중의 USB 부분에 있는 Mouse 드라이버
 - 항상 마지막은 MSDN 의 승리이다. 전체적인 모든 내용이 다 들어있다. 빌어먹을 일정수준이상이
   되지 않으면 처음에 백날봐도 못알아 처먹는다는 것이 문제다. 커널이던 응용프로그래밍이던
   이건 차이가 없다. 지금도 응용프로그래밍도 못알아 먹는게 태반이니까. 어쩔수 없이 이 고생을
   치르는건 MSDN 을 보기위해서가 아닐까. (COM 프로그래밍도 MSDN 이 제일 많은 정보가 있다.)
   이 말을 증명해보겠음!!
   다음은 MSDN 의 vhidmini.h 라는 파일에 능구렁이처럼 맨 마지막 부분에 주석으로 처리되어있다.

[vhidmini.h 파일]

... 생략 ...
   
/*
//
// Here is sample descriptor that has two top level collection - mouse 
// collection and  vendor defined collection with a custom feature item. If 
// you want to provide sideband communication with your hidmini 
// driver, you can add a custom collection with the collection provided 
// by the hardware and open the custom collection from an app to 
// communicate with the driver.
// 여기 두개의 탑레벨 모음인 샘플 디스크립터가 있다.
// 커스텀 피처아이템을 가진 마우스 모음과 벤더 정의 모음이다.
// 니가 만약 너의 hidmini 드라이버를 가지고 사이드 밴드 통신을 제공하길
// 원한다면, 너는 하드웨어에서 제공되는 모음과 응용프로그램으로부터 드라이버
// 통신하는 것까지 개인모음을 추가할 수 있다.
// (역주: 즉, 몬소리냐면 이거 앞에서 선언한 DefaultReportDescriptor 대신에
//        이걸 그냥 가져다가 써라. 마우스 예제다. 이 말이나 마찬가지임.
//        여기에 니가 원하는거 추가해서 쓰라는 소리임. 이미 소스에 다 있었음.)
HID_REPORT_DEscRIPTOR           DefaultReportDescriptor[] = {
        0x05, 0x01,     //Usage Page (Generic Desktop),
        0x09, 0x02,     //Usage (Mouse),        
        0xA1, 0x01,     //Collection (Application),
        0x85, 0x01,     //REPORT_ID (1)             
        0x09, 0x01,     //Usage (Pointer),
        0xA1, 0x00,     //Collection (Physical),
        0x05, 0x09,     //Usage Page (Buttons),
        0x19, 0x01,     //Usage Minimum (01),
        0x29, 0x03,     //Usage Maximun (03),
        0x15, 0x00,     //Logical Minimum (0),
        0x25, 0x01,     //Logical Maximum (1),
        0x95, 0x03,     //Report Count (3),
        0x75, 0x01,     //Report Size (1),
        0x81, 0x02,     //Input (Data, Variable, Absolute), ;3 button bits
        0x95, 0x01,     //Report Count (1),
        0x75, 0x05,     //Report Size (5),
        0x81, 0x01,     //Input (Constant), ;5 bit padding
        0x05, 0x01,     //Usage Page (Generic Desktop),
        0x09, 0x30,     //Usage (X),
        0x09, 0x31,     //Usage (Y),
        0x15, 0x81,     //Logical Minimum (-127),
        0x25, 0x7F,     //Logical Maximum (127),
        0x75, 0x08,     //Report Size (8),
        0x95, 0x02,     //Report Count (2),
        0x81, 0x06,     //input (Data, Variable, Relative), ;2 position bytes (X & Y)
        0xC0,             //End Collection,
        0xC0,             //End Collection,

        0x06,0x00, 0xFF,   // USAGE_PAGE (Vender Defined Usage Page)     
        0x09,0x01,           // USAGE (Vendor Usage 0x01)      
        0xA1,0x01,           // COLLECTION (Application)        
        0x85,0x02,           // REPORT_ID (2)                      
        0x09,0x01,           // USAGE (Vendor Usage 0x01)              
        0x15,0x00,           // LOGICAL_MINIMUM(0)                   
        0x26,0xff, 0x00,   // LOGICAL_MAXIMUM(255)               
        0x75,0x08,           // REPORT_SIZE (0x08)                     
        0x95,0x01,           // REPORT_COUNT (0x01)                    
        0xB1,0x00,           // FEATURE (Data,Ary,Abs)             
        0xC0                    // END_COLLECTION                       
};

*/


자.. 이제 끝났다~ 라고?
한숨을 쉬기에는 너무 이르다. 대부분의 혼선과 문제점은 여기서부터 시작되기 때문이다. Microsoft 사의 WinDDK 라는 개발킷에 있는 vhidmini 샘플은 그저 샘플일 뿐이기에 정상작동이 되는지 확인을 해야하기 때문이다. 필자는 위에서 주석처리 되어있는 마우스 예제 DefaultReportDescriptor 의 주석을 풀고 기존에 있던 샘플 DefaultReportDescriptor 와 교체했다.

드라이버를 컴파일하는 방법은 여기서 설명하지 않는다. 그냥 WinDDK 설치후 프로그램 메뉴에서 XP 용 콘솔창을 열고 vhidmini 디렉토리로 이동후 nmake 명령을 내리면 컴파일이 가능한 것을 여기서 구차하게 다 설명을 할순없다. (그러면서도 벌써 설명까지 다 해주는 친절한 금자씨.. ㅎ) 이제 vhidmini 드라이버를 컴파일하고 장치를 인스톨 시키면 오른쪽 화면아래 트레이에 드라이버가 인식되었다고 뜰 것을 기대했다. 우리가 흔히 새 마우스를 USB 포트에 꽂으면 장치가 검색되었다고 뜨는걸 볼 수 있지 않은가? Human Interface Device(휴먼인터페이스장치) 어쩌구라는 메시지와 함께 잠시뒤에 마우스가 발견되었다는 식의 그런 메시지를 기대했다. 그러나 결과는 참담했고 미궁속으로 계속해서 빠져들고 말았다. 왜 그랬을까..? 비단 이 문제는 필자만의 문제가 아니었다. vhidmini 샘플 드라이버를 처음접하는 모든 프로그래머들이 모두 이같은 삽질의 미궁속에 빠져든다는 점을 검색을 통해서 알 수 있었다. 바로, MS 의 함정을 말이다.

여기서 다시 위와 같은 오류를 범해나가는 설명을 할 것이다. 어떤식으로 접근할 것인가와 얼마나 많은 뻘짓이 필요했는가에 대해서 설명할 필요가 있다고 본다. 그로인해서 얻은 것들은 상당히 많이 있다. 바로 단거리 스피드로 달리는 사람들은 놓칠수 있는 정보를 마라토너들은 두루두루 보고 달릴수 있는 것처럼 주변지식들을 충분히 얻을수 있다는 장점이 있다. 이 문서를 쓰는것 자체가 사실 기술적인 것에 너무 치우치는 쪽 보다는 학습방법을 알리는 병행효과를 얻기위한 것이기 때문에 무엇을 보았는지 지금부터 과정을 설명할 것이다.

앞서서 우리는 가상마우스를 만들기 위해서는 Virtual HID Device 를 만들수 있어야 한다는 점만 인식하고 출발했다. 완전히 지식이 전무한 상태에서 기본 골격코드마져 없는 허당상태로 시작할 수 있는 프로그래머는 아무도 없다. 이미 가상마우스 프로그램을 만들어본 경험이 있는 프로그래머라도 기본적인 코드의 골격없이 모든걸 직접 작성하는걸 기대하는건 어려운일이란 얘기이다. 그래서 우리가 앞에서 선행작업을 한 것이 바로 그 뼈대를 찾기위한 작업이었고, 숱한 오류과정을 거치며 우리가 만들 가상장치의 핵심뼈대를 발굴하고 비교 분석하여 선정하는 작업까지 마쳤다. 그리고 우리가 만들 장치에서 가장 중요한 핵심키포인트를 잡아내는 학습방법까지 소개하였다. 결론적으로 앞에서 습득한 사항들을 요약해 보자면..

1. 우리가 만드는 Virtual HID Device 는 mouse 또는 keyboard 와 혼합형태(혹은 단독일수도.. 그건 선택사항)이며 가상 USB 를 통해서 장치가 인식되어야 한다. 이 점은 프로그래밍적으로 정보를 수집하기 전에 머리속으로 구상한 내용에 속한다.(나중에 언급하겠지만 실제 설치/작동은 프로그래머의 상상과 약간 다르다.)

2. 여러 정보들을 수집하여 비교분석 한 뒤 그 중에서 vhidmini 라는 Microsoft 사의 WinDDK 개발킷 공식샘플을 채용하기로 최종결론을 내렸다.

3. vhidmini 라는 샘플을 운용하기위해 요구되는 스킬은 USB 의 HID 라는 인터페이스이며 이 인터페이스의 핵심 키포인트는 바로 Report Descriptor 라는 Descriptor 를 어떻게 기술할 것인가에 달려있다는 점을 알아낼 수 있다. 이 점은 이미 학습방법으로 어떻게 그 특징을 캣치하는지 보여주었다.

4. 우리는 최종적으로 Virtual HID Device 를 마우스로 인식시키기위해 Report Descriptor 라는 기술자(descriptor)를 찾아내야 했으며 적당한 기술자를 vhidmini.h 에서 발견하였다. 이 기술자를 Default 로 맞추고 컴파일 한 뒤 VMware 에 설치된 윈도우에서 설치하면 실제장치로 인식된다는 것까지 모두 정립하였다.
   
다음의 명령어를 이용해서 장치를 설치할 수 있다. 즉, 윈도우가 설치된 VMware 에는 vhidmini.sys 와 vhidmini.inf 그리고 devcon.exe 라는 총 세개의 파일이 복사되어야 한다. devcon 이라는 툴은 윈도우 장치관리자가 할 수 있는 모든 기능+ 를 콘솔에서 명령내릴수 있도록 해주는 커맨드유틸이다.

[설치명령]
devcon install vhidmini.inf "{D49F883C-6486-400a-8C22-1A9EF48577E4}\HID_DEVICE" 위와 같이 VMware 에 컴파일된 vhidmini 드라이버 파일들을 모두 복사한 뒤에 설치명령을 내린다. VMware 의 화면에는 신뢰를 받지못한 장치 드라이버 설치시에 뜨는 경고문구가 뜨게될 것이다. <계속> 이라는 버튼을 클릭하게되면 sys 파일을 찾지못해 디렉토리 지정창이 한번 더 뜰 것이다. 그 이유는 현 설치위치(devcon 명령어 실행디렉토리 위치) 밑에 i386 이라는 디렉토리에 sys 파일이 존재한다는 가정을하기 때문이다. 즉, INF 파일이 존재하는 위치를 기준으로 그 하위 i386 디렉토리에서 드라이버파일을 찾는다. 그래서 드라이버를 못찾는다는 창이 뜨게된다. 이건 그냥 적당히 vhidmini.sys 파일이 있는 디렉토리를 지정하면 알아서 설치가된다. 그런데.. 우리가 예상했던 설치모습이 아니었다. 그건 필자만의 착각이었을런지도 모르겠지만, 일단 이렇게 장치의 설치과정은 밍밍하게 끝나버린다. 이제 장치가 제대로 인식되었는지 확인을 하기위해 "장치관리자" 를 오픈한다. 그러면 휴먼인터페이스 장치쪽에 두가지 장치가 새롭게 추가되어있는 것을 보게될 것이다. 그런데, 뭔가 생각하던것과는 다르게 인식된 듯한 생각을 가지게 될 것이다. 그 장치는 그저 Generic HID 장치일 뿐 마우스가 아니다. 이게 도대체 어찌된 영문인가? 뭔가 잘못된 것이 있는지 확인해보고 수도없이 DefaultReportDescriptor 를 수정 해봐도 역시나 마찬가지로 마우스로 인식되질 않았다. Revert to snapshot 을 수도없이 반복하며 디스크립터 (Report Descriptor) 를 수정해도 역시나 반응은 일반장치(Generic HID) 일 뿐이었다. 정확히 말하면 VMware 기준으로 XP 에서 장치를 설치했을때 설치되는 이름은 두가지였다.

"HID 준수장치"
"Root Enumerated HID Device (sample)"
위의 두가지 장치가 설치된다. 우리가 원하는 것은 "HID 준수장치" 가 "HID 규격 마우스" 로 인식되어야만 한다. 그런데, 이런현상이 계속 지속되어 혼란이 가중될 뿐이었다. 어딘가 필자가 모르는 키포인트가 또다시 존재할 것이리라 생각하고 이 현상을 겪는 어딘가에 있을 동지에게 SOS 를 날려야 했다. 우리의 구글형님이 그러한 고충을 겪는 사람들을 모두 한자리로 집합시켜주었다. 그런데.. 구글이 불러모은 검색정보들은 하나 같이 모두 헛소리들 뿐이었다. 근접은 했어도 정답이 하나도 없는게 아닌가.. 제길.. FireFox 에서 탭을 약 20개 가까이 띄워놓고 검색에 검색을 반복하며 필자의 Report Descriptor 정보중 어디가 잘못되었는지를 찾아내기 위해서 안간힘을 쓰고 있었다. Report Descriptor 라는 것은 무엇인가? USB 라는 장치가 자기의 정보를 상위장치에 넘겨서 인식되도록 하기위한 마치 신분증과도 같은 것이다. 어디서 태어났고 어디서 자랐으며 나이는 몇살이고 남성인지 여성인지 기타등등.. 마치 이런정보처럼 인식정보를 쏘기전에 셋팅하는 값이다. 이 값이 하나라도 잘못될 경우에 장치는 절대로 제대로 인식되지 않는다. 항상 사람이 고생을 하려면 깨닫는 과정에서 착각을 일으키게된다. 필자는 vhidmini.h 파일에 있는 공식적인 마우스(예제) 디스크립터 주석을 풀어서 대체시켰다. 필자는 그 디스크립터를 믿지 못했다. 어딘가 오류가 있거나 한가지를 수정함으로
인해서 다른것까지 수정해야하는 문제점이 걸렸다거나 그런류로 생각할 수 밖에 없었다. 다음은 필자와 같은 문제점을 겪는 사람들에 대한 이야기다. 그다지 위안도 되지 않았고 결국 구글형님을 통해 문제의 정확한 해결점을 찾아낼 수 없었지만.. 그 과정에서 문득 떠오르는 영감을 주었기에 그 과정을 그려보고자 한다.

http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2007-03/msg00258.html
-----------------------------------------------------------------------------------------------------------------
thank for your advice.
i forget to assign REPORT_ID for each report desc.
It works now.
However, i migrated the corrected report to "hidfake". (Walter Oney 's sample)
The system pop up 3 "Found New Device Wizard" window and identfy it as "Unknow Device".
Any difference detween these 2 drivers' enumeration?
Appreciated.
(필자요약: REPORT_ID 를 빼먹었다. 작동된다. 그런데 hidfake 꺼를 배꼈다. 그랬더니 "알려지지않은 장치" 라는 새로운 장치로 "하드웨어 찾기" 가 세개나 뜬다. 나머지는 해석할 필요 없겠다.. 왜 그런가? 라는 질문 이라고 생각하고 넘어간다..)
-----------------------------------------------------------------------------------------------------------------
"Doron Holan [MS]" wrote:
    you only need one HID minidriver. from it, a keyboard and a mouse can
    be
    enumerated. you just have to put each device into its own top level
    collection. If you are having trouble, i would find a USB HID that already
    does this and look at its HID descriptor
(필자요약: 이놈이 다른 게시판에도 있는걸보면 좀 하는거 같다. 대충 번역하면 너는 오직 한개의 HID 미니드라이버만 필요할 뿐이다. 그리고 키보드나 마우스가 열거될수 있는 것으로 부터, 그리고 각각의 그 자신의 탑레벨 모음속에 각장치들을 넣어야만 한다. 만약 문제가 있다면, 니가 만든 USB HID 를 어쩌구 저쩌구.. 뭔가 HID Descriptor 와 연관이 있겠거니하고 그냥 넘어감..)
-----------------------------------------------------------------------------------------------------------------
I'm pretty sure you will need to break up hte device into a Mouse device and Keyboard device. (i.e two drivers,
one with a report descriptor for a keyboard and one for a mouse)
The inf files should not refer to HID\MyVirtualHidDevice - these id's need to be picked up from keyboard.inf or
msmouse.inf - idealy reporting the compatible id of HID_SYSTEM_KEYBOARD or HID_SYSTEM_MOUSE (i think)
(필자요약: 마우스와 키보드장치속에 hte 장치를 깨야할 필요가 있다라고 해석해야 하나..  이놈이 주장하는 내용은 일단, report descriptor 에 키보드와 마우스가 하나로 일치되어있는가를 확인하라는 내용과 HID\MyVirtual HidDevice 라는 장치명으로 되어있는 vhidmini.sys 샘플이 이름이 잘못되어서 그런게 아니냐는 속임수에 빠지기 쉬운 의견을 제시해 놓고 있다. 마치.. 네이버 지식인인가? 하지만 여기서 얻을 수 있는 점이 있는데 HID_SYSTEM_KEYBOARD, HID_SYSTEM_MOUSE 라는 지시어이다. 어설픈건 혼란을 가중시키는데 원래는 HID_DEVICE_SYSTEM_KEYBOARD 이고 HID_DEVICE_SYSTEM_MOUSE 가 맞는거니까 속지말자. 뒤에서 설명하겠지만 이걸 알아 듣기 위해서 새로운 개념을 습득하게 된다.)
-----------------------------------------------------------------------------------------------------------------
Hi,
I write a HID minidriver with standard Mouse and Keyboard report
descriptors.
It is based on vhidmini in Windows Server 2003 DDK.
The driver work fine and I can read/write the report from the
device.
The Device Manager shows it is HID-compliant device in HID class,
but
the
Mouse Class and Keyboard Class have none.
How should I do so that it can be a mouse device and keyboard
device?
Should I modify the INF file? My driver's INF is almost same as the
vhidmini's.
(필자요약: Windows Server 2003 DDK 로 vhidmini 를 만들었다는 식인데 장치명이 HID-compliant(일반 복합HID 장치)로 인식되는데 마우스 클래스와 키보드 클래스가 없다고 말한다. 어떻게 마우스와 키보드 장치로 인식시키는 것이냐고 물어본다. 자기가 INF 파일을 수정해야 하는지 물어본다. 그리고 INF 파일은 vhidmini 와 거의 같다고 말한다. 이 사람이 겪는 증상이 필자가 겪는 증상과 100% 일치한다. 그런데 불행히도 이 글에는 더이상의 답변이 달려있지 않았다. 눈물의 고배를 마시고 돌아서야 하는 이 저린마음.. T.T 어쩔수 없이 또다시 구글형님의 도움을 받아야한다.)
-----------------------------------------------------------------------------------------------------------------
이 질/답들에서 배운 것은 검증해봐야하는 대상들이다. 일단, HID Report Descriptor 가 잘못되었는지 검증해야하며 INF 파일이 잘못되었는지 검증해봐야하고 "한참을 헤메게 만든 요인이었지만" REPORT ID 에 대해서도 검증해봐야 한다는 몇가지 결론을 얻은채 새로운 검색활로를 모색해보게 된다. 이 검색은 첫 발을 내딘수준에 불과하다. 거의 48시간을 오로지 이 문제를 해결하기 위해서 정보들을 모아야 했다.
http://www.techtalkz.com/microsoft-device-drivers/297875-loading-driver-hid-class.html
-----------------------------------------------------------------------------------------------------------------
Loading a driver on HID class
Hi all,
I have a USB device that exposes a HID interface. It is not a mouse or
a keyboard, just a general HID device. Device Manager displays it as a
"HID-compliant device".
Now I would like to install a device driver on it and use the HID
interface to communicate with.
My INF refers the HID\VID_xxxx&PID_xxxx string and my driver gets
loaded.
So I get the PDO from AddDevice and I need the FileObject to
communicate using IOCTL_HID_SET_FEATURE and IOCTL_HID_GET_FEATURE. But
I cannot retrieve it; I use the FireFly sample and the function
FireflyOpenStack to retrieve the FileObject form the PDO but it fails
in my driver with error 0xC000000E (STATUS_NO_SUCH_DEVICE) when
calling ZwOpenFile.
What's wrong? The pdoName of the file open by ZwOpenFile is something
like "\Device\00000096". Is it possible to get the SymbolicLinkName
instead?
If someone could help...
Thanks, Roger
(필자요약: HID 인터페이스를 노출하는 USB 장치를 만들었다. 그런데 그게 마우스나 키보드가 아니네? 단지
           일반 HID 장치인거야. 디바이스 디스플레이에 보면 "HID-compliant device" 라고 표시되네.
       횽님들.. 알려주십쇼.. 뭐 이런 내용식으로 글을 써놨다. 그래도 아는게 많은 사람이라서 그런지
       정보들을 많이 뿌려놨는데 독이되는 요소들이 있지만, 덤으로 알게되는 요소들도 그 못지않게
       많다. IOCTL_HID_SET_FEATURE 과 IOCTL_HID_GET_FEATURE 에대한 얘기는(추후 구현되어야 하는 내용)
           좋은 정보임에 틀림없다. 그런데 우리가 원하는 답을 얻지는 못하고 단지 INF 파일에 VID 와
       PID 스트링이 문제의 시발점이 될수도 있지는 않은가 하는 의심을 해볼수 있다. 물론, 그게 해답은
       아니지만 추가정보를 검색해야할 키워드로써 대상물망에 넣어두자. VID 란 벤더아이디를 의미하고
       제작사의 고유식별번호이며, PID 란 프로덕트 아이디 즉, 제품번호이겠다. 이게 하드웨어는 모두
       고유하다고 하는데 과연 이 때문에 마우스나 키보드로 인식이 안되고 일반장치로 인식되는 것일까?)
-----------------------------------------------------------------------------------------------------------------
when are you trying to open a handle? during AddDevice or
IRP_MN_START_DEVICE? neither will work b/c a file create can only occur
once the start irp has come back to the pnp manager. so to make this work i
would
a) register a custom device interface GUID
b) register for device interface arrivals on your custom guid. when you
get called, open your stack like FireFly does
you will also need to register for handle notifications on the file handle
that you open so that you can gracefully disable the device. If you use the
KMDF firefly sample, the WDFIOTARGET object does this for you
(필자요약: 답변중에 하나인데 이 답변은 질문자의 추측보다 더 가관이다. IRP_NM_START_DEVICE 나 AddDevice 등록시 (필자는 커널을 몰라서 몬소린지 모르지만 이건 아니다정도의 감은 있었다.. -_-;) 하라는 식으로 답변이 달려있는데 KMDF 까지 들먹거리는걸로 봐서는 논점에서 많이 빗나갔다. KMDF 는 새로운 드라이버 개발 프레임워크인데 질문자가 그걸 물어본게 아니다. 기존의 방법으로 설명해줘야하는 것이 옳은데 그렇지도 않았고, 너무 많은 작업을 추가하라고 주문하는거보니 필자의 생각과 달랐다. 필자의 감은 Report Descriptor 만으로도 해결될 문제라고 속삭이고 있었기 때문에 이 답은 해결책이 아니었다. 다른 답변중에는 URB 를 보내라는 말도 있었다. 모두 무시한다.)
-----------------------------------------------------------------------------------------------------------------
지금 거론하는 필자의 문제해결 방법은 링크를 보여주면서 찾아나가는 방법을 설명하고 있다. 그렇기에 링크역시 필자가 검색해서 누른 순서대로 임을 밝힌다. 다음으로 찾은 것은 MSDN 의 설명이다. 그런데 MSDN 의 설명은 항상 깨달음을 얻은뒤에나 값진 보물이 되지 깨달음을 얻기전까지는 그저 잘 만들어진 명세서에 불과하다고 느낄때가 많다. 마치 선생님이 "공부하라"고 그렇게 들볶던 말들이 성인이 된 뒤에 "정답" 이라고 느끼는 것처럼 느낀뒤에만 알 수 있는 것들이 기록되어 있는게 MSDN 과도 같다. 왜 그땐 몰랐지? 왜 그땐 안봤지? 나중에 이런말 자주하게 될거다. ㅎㅎ 그런데.. 역시.. -_-; 이 링크를 보던 시점(현 글을 쓰는 시점기준으로 하루전)만 해도 이 링크는 그저 도움이 안되었다.
http://msdn.microsoft.com/en-us/library/aa487252.aspx
(필자요약: 설명이 잘 되있다. 읽어보라.. 해결책도 들어있다. 그런데 그냥보면 절대 모른다. 개고생하면 그때는 답이 보이지만 그냥보면 모른다.)
-----------------------------------------------------------------------------------------------------------------
http://www.programmer-club.com/pc2020v5/forum/ShowSameTitleN.asp?URL=N&board_pc2020=driver&id=2986
-----------------------------------------------------------------------------------------------------------------
(필자요약: 이 사이트는 중국사이트인데 읽을수가 없다. 몇가지 좋은 키워드와 코드가 있는데 해결책은 아니고 나중에 마우스나 키보드를 구현할때 참고할 만한 코드가 아주 조금 있을 뿐이었다.)
-----------------------------------------------------------------------------------------------------------------
http://www.osronline.com/cf.cfm?PageURL=showThread.CFM?link=144873
-----------------------------------------------------------------------------------------------------------------
(필자요약: 필자가 겪는 문제를 어느정도 일부분은 해결한 것 같기도하고 그렇지 않은거 같기도 한데 희한한
            삽질을 하고 있었다. Descriptor 를 계속해서 바꿔가면서 테스트하는 것을 물어보고 있었다.
        마우스와 키보드를 인식시키기 위해서 vhidmini 를 기본베이스로 디스크립터를 조작하는데 설치가
        안된다는 그런 질문이었다. 질문양이 많아서 짤라붙이기는 못하겠다. 답글을 보자.)

Adrian Schlesinger
xxxxxx@baum.ro
    
Join Date: 24 Sep 2008
Posts To This List: 7
RE: Simulate keystrokes
I have detected what was wrong:
1. When adding the report ID item to the keyboard top-level collection, an additional byte should be returned to
   the system at the beginning of the data, specifying that report ID.
2. Communication from user mode did not work because when cycling through the HID devices,
   in addition to vendor ID, product ID and version, the usage specified for the additional end point should also
   be matched (with Vendor Usage 1), otherwise you can end up trying to call WriteFile for a handle corresponding
   to the keyboard end point.
(필자요약: 질문자의 답글인데 키보드 top-level collection(최상위 모음) 에 REPORT ID 를 추가할때 어쩌구 저쩌구 얘기가 나온다. 그리고 usage 라는 말도 나온다. 필자가 원하는 답이 여기에 있을 것이라고 생각하여 엄청난 검색을 통해 알게되었는데 원하는 답은 아니었다. 단지, top-level 의 개념은 중요했다.
-----------------------------------------------------------------------------------------------------------------
http://www.techreplies.com/drivers-43/hid-minidriver-multiple-report-descriptors-543372/
-----------------------------------------------------------------------------------------------------------------
(필자요약: 앞에서 어떤사람이 한 질문과 똑같은 질문인듯 싶다. 왜 도대체 마우스로 인식이 안되냐.. 이 질문이다.)
-----------------------------------------------------------------------------------------------------------------
다음은 중요한 개념중에 하나인 Top-Level Collection 이다.
http://www.microsoft.com/whdc/archive/HID_HWID.mspx#E1
-----------------------------------------------------------------------------------------------------------------
Special Top-Level Collections (Reserved for OS use)
Certain HID top-level collections generate a special HID device string. In Windows 2000, Windows XP, and Windows
Server 2003, the top-level collections listed in Table 6 are special cased and each has an additional hardware ID.
Table 6 identifies these collections. The last column identifies the additional string that is added to the hardware
ID list.
Table 6: Special-Cased Top-Level Collections
Device Type                Usage Page    Usage ID       Additional Hardware ID
Pointer                    0x01          0x01           HID_DEVICE_SYSTEM_MOUSE         exclusive
Mouse                      0x01          0x02           HID_DEVICE_SYSTEM_MOUSE         exclusive
Joystick                   0x01          0x04           HID_DEVICE_SYSTEM_GAME 
Game pad                   0x01          0x05           HID_DEVICE_SYSTEM_GAME
Keyboard                   0x01          0x06           HID_DEVICE_SYSTEM_KEYBOARD      exclusive
Keypad                     0x01          0x07           HID_DEVICE_SYSTEM_KEYBOARD      exclusive
System Control             0x01          0x80           HID_DEVICE_SYSTEM_CONTROL
Consumer Audio Control     0x0C          0x01           HID_DEVICE_SYSTEM_CONSUMER

(필자요약: 이게 모냐면 Top-Level Collection 이라 불리우는 입력장치유형이다. 위에서 Usage Page 와 Usage ID 라는 것이 있는데 이게 바로 Report Descriptor 에 있는 항목에 적혀있다. 이걸 어떻게 바꾸느냐에 따라서 가상장치가 마우스가 되느냐, 키보드가 되느냐 아니면 조이스틱이 되느냐를 결정한다. 멋지지 않은가? 물론, 원하는 해답은 아니다. 그러나 필수적으로 개념을 갖고가야 한다. 여기서 중요한게 있다면 입력 장치의 형태가 공유(share)모델이냐 아니면 베타적모델(독점)이냐 이다. 마우스와 키보드는 독점모델이다. 즉, 마우스와 키보드는 장치가 열려있으면 다른 프로그램이 장치를 열어서 쓰고읽는 것이 불가능 하도록 secure 모델로 처리되어있단다. 이때, 이걸 피해가려면 새로운 장치를 동일하게 하나더 만들어서 그 장치와 통신하면 이런 독점모델을 피해갈 수 있단다. MSDN 에 다 나와있다.. 전부 다~ 링크가 있었는데 FireFox 가 깨져서 다 날아가 버리는 바람에 찾을수 없지만 베타적오픈과 공유오픈이 가능한 표시가 위의 Top-Level Collection 에 일일이 나열되어 있는 정보도 찾을 수 있었다. 어쨌거나 중요한건 짚고 넘어가자.. 참고로 잊지는 않았겠지? 가상장치가 일반장치로 인식되서 마우스 장치로 인식시키려고 뻘짓하다가 이런곳까지 당도하게 된거란 점.. 이렇게 정보들을 다양한 방법으로 얻어서 공부하는데도 웹서핑한다고 눈치주는 경우도 있다. x같은 경우지.. 이게 단순히 노는걸로 보여? 입에서 욕나오네.. 갑자기 머리에 히터가 작동되서 한번 지껄여봤습니다. 다시 집중모드로 돌아가봅시다.. ㅋㅋ)Table 13-1   HIDCLASS-Compatible ID for Each Supported Usage지원되는 HIDCLASS 호환 아이디.. HIDCLASS 는 각 장치로 분배를 해주는 역할을 한다고 합니다. 더 자세한건 묻지마삼 다칩니다요.. 전 아는것만 얘기할 뿐임..
http://www.microsoft.com/mspress/books/sampchap/6262.aspx

Usage Page         Usage                   Compatible ID
Generic desktop       Pointer or mouse        HID_DEVICE_SYSTEM_MOUSE
                   Keyboard or keypad      HID_DEVICE_SYSTEM_KEYBOARD
                   Joystick or game pad    HID_DEVICE_SYSTEM_GAME
                   System control          HID_DEVICE_SYSTEM_CONTROL
Consumer           (Any)                   HID_DEVICE_SYSTEM_CONSUMER

<Report Descriptor Header>
앞서서 XBCD 라고 XBOX 조이스틱 에뮬레이션 드라이버에 대해서 말한적이 있습니다.
헤더의 USAGE_PAGE 를 잘 봅시다. 그리고 USAGE 를 봅니다.
// XBCD 예
char ReportDescriptor[213] = {
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)     <-- 요건 뭐시냐? Table 13-1 입니다욤..
    0x09, 0x04,                    // USAGE (Joystick)        <-- 위의 Table 6 에 Joystick 의 Usage ID 보입니껑?
    0xa1, 0x01,                    // COLLECTION (Application)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,                    //   PHYSICAL_MAXIMUM (1)
// vhidmini.h 의 맨마지막 주석이 되어있었던 마우스예제 헤더
HID_REPORT_DEscRIPTOR    DefaultReportDescriptor[] = {
        0x05, 0x01,      //Usage Page (Generic Desktop),   <-- Table 13-1 일반 데스크탑
        0x09, 0x02,      //Usage (Mouse),                  <-- Mouse 임
        0xA1, 0x01,      //Collection (Application),
        0x85, 0x01,      //REPORT_ID (1)                   <-- REPORT_ID 꼭 이게 값이 있는지 확인해야함.
        0x09, 0x01,      //Usage (Pointer),                    HID Tool 이라는 놈은 이 값을 빼고 보여줌.(주의!)
        0xA1, 0x00,      //Collection (Physical),
        0x05, 0x09,      //Usage Page (Buttons),
        0x19, 0x01,      //Usage Minimum (01),
        0x29, 0x03,      //Usage Maximun (03),
        0x15, 0x00,      //Logical Minimum (0),
여기서 Top-Level collection 이 지칭하는 의미는 상위장치입니다. 이런식으로 다중 인터페이스를 구현할 수 있는데 예를들면 마우스와 키보드를 가상장치 하나로 일타쌍피도 만들어낼 수 있습니다. 시중에 파는 키보드 중에 마우스도 있고 USB 포트도 달려있는 키보드들은 이런 다중인터페이스를 만들기위해서는 multiple top-level collection 지정을 해줘야 한다는 얘기죠. 어쨌거나.. 이러한 정보들은 얻었고 Report Descriptor 가 잘못된 것인가라고 판단해보니 전혀 아니었습니다. 오히려 첫번째 XBCD 의 헤더모습에서는 REPORT ID 가 보이지 않는데 두번째 vhidmini.h 에서는 REPORT ID 항목도 빼먹지않고 넣었고 완벽합니다. 그런데 왜.. 대체 왜!! 인식이 마우스로 되지않고 일반장치라고 잡히는 거냐 이말이죠.. 심지어는 공식사이트에서 다운로드 받은 마우스와 키보드 Report Descriptor 를 가져다가도 해봤고 직접 하드웨어에서 뽑아낸 값을 통해서도 해봤지만 모두 인식이 안되었답니다.
-----------------------------------------------------------------------------------------------------------------
사실.. 위에서 언급한 내용은 탐색과정에서 추가로 얻어내는 개념들에 대해서 비중이 있었기에 설명을 하였습니다. 아마, 계속해서 같은 방식으로 설명하면 이 문서를 보면서 쌍욕을하게 될지도 모르기에 후다닥 빨리 접겠습니다. 다음은 제가 문제해결(일반장치를 마우스로 인식하게 만드는)을 하기 위해서 찾아다녔던 링크입니다. 더 많지만 추려서 올려봅니다.
http://coding.derkeiler.com/Archive/General/comp.arch.embedded/2008-01/msg00501.html
http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2005-03/0829.html
http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2005-03/0806.html
http://www.techreplies.com/drivers-43/minidriver-hidclass-336914/
http://www.techreplies.com/drivers-43/my-hid-mouse-how-write-data-331146/
http://www.osronline.com/DDKx/intinput/hidfunc_7oky.htm
https://www.usb.org/phpbb/viewtopic.php?t=14027&sid=b40543b8bc019ff50c70025ff1886898

(결정적인 영감을 주게된 링크는 바로 다음의 링크이고 사실, 앞에서 한번 언급했었던 링크입니다.. 정확히 말하자면 해결방법을 직설적으로 말해준게 아니라, 넌 이걸 이해해야된다라고만 코드의 일부분을 언급하고 숫가락으로 떠먹여 주지는 않겠다는 인상을 풍기는 답글이지요.. 처음에는 이걸 보고도 잘 이해를 못합니다. 저만 그런건 아닐겁니다. 어떤 질문자 중에서는 프린터, 스캐너, 스마트카드를 비롯해 각종 디바이스 드라이버를 만들었다는 이력을 밝히며 저와 같은 증상때문에 고민을 하고 있는 사람도 있었으니까요.. 제가 볼때 이건 MS 의 함정입니다. 의도하지 않은 함정말입니다.)
https://www.osronline.com/showthread.cfm?link=138652
-----------------------------------------------------------------------------------------------------------------
바로 이 답글이 눈을 뜬 사람에게만 통하는 핵심인 셈입니다.
allen zhang
xxxxxx@sina.com
    
Join Date: 22 Jul 2008
Posts To This List: 38
RE: VHidMini report descriptor(s)
see the follow source code and the ReadDescriptorFromRegistry function, You should be understand it.
deviceInfo->HidDescriptor = DefaultHidDescriptor;
queryStatus = CheckRegistryForDescriptor(DeviceObject);
if(NT_SUCCESS(queryStatus)) {
    queryStatus = ReadDescriptorFromRegistry(DeviceObject);
    .......
(필자요약: 다음의 소스코드와 ReadDescriptorFromRegistry 함수를 봐라.. 너는 이걸 이해해야할 필요가 있다.
            라고 말하며 일부 소스를 첨부했습니다. 그리고는 아무런 추가의 말도 없습니다. 장난하는것도
        아니고.. -_-; 이때 아차하고 생각을 떠올리면 이 문제는 해결됩니다. 위에서 숱하게 질문하던
        외국 개발자들도 결국에는 알아냈겠지요?)
-----------------------------------------------------------------------------------------------------------------
vhidmini 드라이버를 구동시키고 일반 HID 장치로 인식된 드라이버를 마우스 장치로 둔갑시키기 위해서는
소스를 수정해야 합니다. 바로 vhidmini.c 드라이버 소스를 수정하는 일입니다. 그것도 필자가 생각했었던
Report Descriptor 의 오류를 수정하는 것이 아니라 코드를 수정해야 합니다. 앞에서도 한번 언급했었지만
Microsoft 사의 공식 DDK 샘플소스에 오류가 있을리는 없으니까요. vhidmini.h 에 주석으로 정의되어있던
마우스 Report Descriptor 의 예는 오류가 없었습니다. 오류에 빠지도록 만든것은 바로 ReadDescriptorFromRegistry
함수에 있었습니다. vhidmini 소스를 보면 주석에 써있기를 우리는 하드코딩을 하였다라고 적혀 있습니다.
Report Descriptor 를 하드코딩 하였다는 것이지요. 그런데, 단순히 그냥 하드코딩으로 놔두지.. 더 많은걸
보여주고 싶었던지 if-else 로 두가지 처리루틴으로 나눠놓은것이 문제의 핵심이었던 것입니다. 다음의
소스를 보십시오.
-----------------------------------------------------------------------------------------------------------------
[vhidmini.c 소스에서 수정해야 할 부분]
    
 HID Report Descriptor 를 레지스트리에서 읽어들이는 코드를
 하드코딩쪽으만 처리하도록 수정함.

    deviceInfo->HidDescriptor = DefaultHidDescriptor;
    //
    // Check to see if we need to read the Report Descriptor from
    // registry. If the "ReadFromRegistry" flag in the registry is set
    // then we will read the descriptor from registry using routine 
    // ReadDescriptorFromRegistry(). Otherwise, we will use the 
    // hard-coded default report descriptor.
    //
    queryStatus = CheckRegistryForDescriptor(DeviceObject);  // 함정이 발생하는 지역
    if(NT_SUCCESS(queryStatus)){
    //
    // We need to read read descriptor from registry
    //
    // 장치를 설치할때 INF 파일에 있는 Report Descriptor 가 레지스트리에 기록되고
    // 이 부분에서 레지스트리에 기록된 Report Descriptor 를 읽어들임.
    // 그러므로 백날 헤더의 Report Descriptor 를 바꿔봤자 INF 파일에 있었던 것을
    // 읽어들이는 꼴이 되므로 항상 "일반 HID 장치"(Generic HID Device) 가 드라이버로
    // 등록될 수 밖에 없었던 것이다. 이런 제길.. 이 문제로 이틀을 꼬박 다 날렸다니..
    // Microsoft 는 반성하라~!! Microsoft 는 함정을 제거하라~!!
    // 고로 이 부분으로 빠져들지 않도록 주석처리 하라..
    queryStatus = ReadDescriptorFromRegistry(DeviceObject);
                               
    if(!NT_SUCCESS(queryStatus)){                          
        DebugPrint(("Failed to read descriptor from registry\n"));
        ntStatus = STATUS_UNSUCCESSFUL;
    }
}
else{
    //
    // We will use hard-coded report descriptor. 
    //
    deviceInfo->ReportDescriptor = DefaultReportDescriptor;
    DebugPrint(("Using Hard-coded Report descriptor\n"));
}

... 중략 ...
case IRP_MN_REMOVE_DEVICE:
    //
    // free memory if allocated for report descriptor
    //
    // 이 부분도 주석처리해야 한다. 왜냐면 레지스트리에서부터 읽어들이지 않았기 때문에
    // 메모리 할당이 안되어 있기 때문이다. 그냥 두어도 상관없을거 같지만 메모리 해제부분이니
    // 꺼림칙하므로 되도록이면 제거하길 바란다.
    if(deviceInfo->ReadReportDescFromRegistry)
        ExFreePool(deviceInfo->ReportDescriptor);
    SET_NEW_PNP_STATE(deviceInfo, Deleted);
    ntStatus = STATUS_SUCCESS;           
    break;   
-----------------------------------------------------------------------------------------------------------------
이제 vhidmini 샘플을 컴파일하고 VMware 에 vhidmini.sys 와 vhidmini.inf 파일을 복사하자. 그리고 devcon 명령으로 앞서했던 것처럼 install 을 해보자. 설치를 하고나면 장치관리자의 기존에 있던 "HID 준수장치" 라는 것은 없어지고 마우스항목에 "HID 규격 마우스" 가 추가되는 것을 볼 수 있을 것이다.(ㅎㅎ 이맛을 보려고.. 밤을새고 삽질을..) 이제.. 장치관리자에서 새로 추가된 "HID 규격 마우스" 를 선택한 뒤에 속성을 보자. 속성을 선택한 뒤 "자세히" 라는 것을 클릭한다. 그리고 장치인스턴스 ID 라는 것을 보라. HID\MyVirtualHidDevice&Col01 라고 되어있는 것을 볼 수 있다. 또한, 일치하는 장치 ID 를 선택하면 hid_device_system_mouse 라고 되어있다. 즉, 마우스로 인식이 되었다는 것이다. 가상 HID 디바이스 위에서 마우스 장치가 인식되어 있는 것이다. 이제 가상 HID 디바이스와 어플리케이션 간에 통신루틴을 프로그래밍하고 어플리케이션의 명령에따라 상위 클래스로 IRP/URB 같은 요청을 (이거참.. 이 레이어에서는 어떤 요청을 사용해야하는 건지 또 공부해야하는군.. -_-; USB 강의 문서에 보면 상위 클래스는 URB 통신을 한다고 나와있었다..) 날려주면 키보드나 마우스 같은 장치들을 에뮬레이션 시킬수 있다. 곧, 가상장치를 조종할 수 있다. 하지만? 그리 쉽지는 않을 것이다. vhidmini 샘플에는 testvhid 라는 어플리케이션 소스도 같이 들어있는데 이 testvhid 소스는 어플리케이션단에서 vhid miniport 드라이버와 통신하는 예제이다. 참고로 아무런 수정없이 샘플만 컴파일해도 어플리케이션과 드라이버 사이에 제대로 통신이 이루어지지않는다. 역시나 이 문제는 HID Report Descriptor 의 데이타의 구성문제에 속한다. 한번 고생한 것이 또다시 반복되는 시점이기도 하다. 이 부분을 해결하면 어플리케이션은 2 또는 3 가지의 top-level collection 중에서 사용자정의(User-Defined) 콜렉션을 통해서 miniport 드라이버와 통신을 할 수 있게되고 이 통신에 따라서 마우스 IRP 를 상위 클래스로 때려주면 된다. 더 자세한 내용은 스스로 연구하길 바란다. 이상으로 이번문서를 마무리하려고 한다. 왜냐면 이제 테스트 기반이 마련되었으니 나머지 추가구현은 스스로가 해야할 몫이기 때문이다. 어떠한 목적으로 개발하던간에 그 이상은 이제 필자가 관여할 부분이 아닌것 같다.

어차피 이 문서의 목적은 가상 마우스를 제작하는 것을 중점으로 삶는 것보다도 모르는 분야를 독학하며 개척해 나갈때 자신의 공부스타일의 한 예로써 제시하는 것이었다. 여기서 거론된 공부스타일을 종합해 본다면 이렇게 말할 수 있을것 같다. "관례를 찾아냄으로써 DIFF 를 추출해내는 공부법" 이라고 할 수 있다. 즉, 최대한 많은 자료들을 검색으로 긁어모은 뒤에 분리분석 작업을 통하여 동일한 부분의 반복을 찾아낸다. 찾아낸 반복내용이 있다면 결국 그 반복은 해당 프로그래밍의 관례에 속한다. 즉, 해당 관례는 몸으로 빨아들이고 차이가 나는 지점에서 기술을 흡수한다. 이런식의 반복학습을 통하여 더이상 다른 코드나 정보들을 찾아낼 수 없다고 판단이 들때 그 기술은 자기것이 된다. 필자는 유저레벨을 공부할때 항상 이방식을 택해왔다. 정보가 고갈되고 더이상 찾아낼수 없을때까지 긴시간을 할애해서 리서치를 먼저 한다. 그 뒤에 코딩으로 들어간다. 그리고 관례코드를 따른다. 그렇게되면 생전 처음보는 프로그래밍에서도 어느지점은 건드려도 되고 어느지점은 절대 건드려서는 안되는지 쉽게(? 정확히가 맞겠다) 익힐수 있다.

이제는 커널레벨 공부를시작하면서 이 고통스럽고도 지루한 공부방식을 다시 사용하고자하며 다른 사람에게 조그마한 도움이 되고자 이런 문서를 작성하였다. (같이 게임에 미쳐서 광랩하던 친구가 갑자기 URL 을 려줘서 읽어 보았더니 국가에서 인증한 기술이라는 자랑스런 인증서와 함께 뭔가를 팔고있었다. 보란듯이 대놓고 말이다. 디자인도 쌈빡해서 사고싶게 만드는 그것.. 그게 뭔지는 대충 말안해도 알겠지만.. 이 문서를 빨리 공개해야하겠다는 생각이 들었다. 원래는 문서를 다 작성해놓고도 공개하지않는 방향으로 생각을 굳혔다가 아무래도 생각이 바뀌기 시작하였다. 그 이유는 뒷부분의 부록을 보라..) 아마 이 방식으로 공부하는 사람들이 많겠지만 그렇지 않을수도 있을 것이다. 적어도 이렇게 공부할땐 뼈를 깎듯이 힘들지만 원하고자 하는 지식을 얻으면 그 지식의 깊이가 뼈속으로 스며들 것이다. 필자처럼 어떤 새로운 분야에 공부를 시작하거나 공부하는 방법을 몰라서 물어보려는 사람들이 있다면 이 문서를 읽어보라고 말하고 싶다.
 
<잡설>
필자가 만약에 커널디버깅을 잘 다뤘다면 아마도 쉽게 문제를 해결했을지도 모르겠다. 하지만 필자는 귀차니즘 때문에 커널디버깅을 좋아하지 않았고 결국, 공부도하지 않았다. (요즘들어 먹고 살라니.. 공부중이다.. -_-;) 그런데 필자는 오히려 디버거를 쓰지 않으면 않을수록 프로그램에 대한 이해도는 높아진다고 생각한다. 왜냐면 사람의 머리는 충분히 상황을 시뮬레이션 할 수 있다고 생각하기 때문이다. 에뮬레이션은 불가능하겠지만 시뮬레이션은 가능하다. 그리고 이 작업을 통해서 문제가 발생되는 지점을 캣치할 수 있다고 생각한다. 그렇게 되었을때 남보다 더 느릴지 몰라도 이해도는 훨씬더 깊이있는 굴곡을 생성해낸다고 생각한다. 어쩌면 그렇게 믿고싶은 것일지도 모르겠다. 적어도 자신은 그렇게 소신을 갖고있다. 그렇다고 커널디버깅을 배우는 것을 말리거나 도외시하라는 것은 절대 아니다. 필수적으로 갖고가야할 기술이라는 점에는 변함이 없지만 두가지를 모두 안배하는 것이 스스로에게 좀 더 풍요로운 지식을 가져다 줄 것이라는 점을 인지했으면 좋겠다는 의미이다. "Art of Hooking" 이라는 문서처럼 스스로의 깨달음을 전달하려고 쓴 문서는 아니지만 이 시간에도 같은 문제로 삽질하고있을 그들에게(아직도 정확한 답변을 보지 못한 질문자들이 인터넷에 깔려있음을.. 이미 보여줬다..) 이틀이라는 시간을 좀 더 귀중한 곳에 쓸 수 있도록 해줄 수 있다는 것은 행복한 일이라고 생각한다. 만약 누군가에게 이런 도움을 지속적으로 받을수 있었다면 본인은 솔로여야할 이유가 없었을 것이리라.. (아쉽게도 영어를 못하니 국내만이라도 도움을 받으면 좋을듯 싶다.) 참고로.. 이 문서는 주제를 인지하는 시점부터 해결과정을 도출해내는 모든 전 과정이 거의 실시간으로 쓰여졌다.. 그렇게 해야만이 이 문서의 목적인 "가상마우스" 와 "공부방법론" 두가지를 모두 전달할 수 있다고 판단했기 때문이다. 필자는 누군가 이 문서를 읽고 얻은게 있었다면 그것만으로 행복할 것이다. 하드에 처박혀 쓰레기가 된채 어느날 자신도 모르게 삭제되는 그런 정보가 아니라는 점만으로도 충분히 가치있는 것이니까..
 

[부록1: 필자가 생각하는 에뮬레이션과 시뮬레이션의 차이점]
에뮬레이션: 기계의 톱니바뀌처럼 구성요소들의 기능자체들이 모두 동일하게 작동해야 한다. (기능/작동의 동일화)
시뮬레이션: 기능자체를 동일하게 할 필요없이 입/출력되는 수치/값만 동일하면 된다. (수치/데이타의 동일화)
(필자주: 틀렸을 수도 있다. 정확하지않다. 다만, 여태까지 몸으로 와닿는 느낌자체를 말로 풀어써본 것 뿐이다.)
 
[부록2: 시중에 떠도는 물리형 Auto Mouse 탐지법]
먼저, 가상장치에 대한 것부터 언급해보고 물리형으로 넘어가겠다.

<1. 가상장치 탐지방법>
재밌는 사실이 있는데 아는 사람은 알 것이고 모르는 사람은 모를 것이다.
MSPRESS 에 보면 짜가장치(FakeDevice) 탐색법이 있다.

http://www.microsoft.com/mspress/books/sampchap/6262.aspx
-------------------------------------------------------------------------------------
HANDLE CtestDlg::FindFakeDevice()
{
    GUID hidguid;
    HidD_GetHidGuid(&hidguid);
    CDeviceList devlist(hidguid);
    int ndevices = devlist.Initialize();
    for(int i = 0; i < ndevices; ++i)
    {
         HANDLE h = CreateFile(devlist.m_list[i].m_linkname, 0,
                           FILE_SHARE_READ | FILE_SHARE_WRITE,
                   NULL,
                   OPEN_EXISTING, 0, NULL);
         
     if(h == INVALID_HANDLE_VALUE)
         continue;
     HIDD_ATTRIBUTES attr = {sizeof(HIDD_ATTRIBUTES)};
     BOOLEAN okay = HidD_GetAttributes(h, &attr);
     CloseHandle(h);
     if(!okay)
         continue;
     
     if(attr.VendorID != HIDFAKE_VID ||
        attr.ProductID != HIDFAKE_PID)
         continue;
     return CreateFile(devlist.m_list[i].m_linkname,
                       GENERIC_READ | GENERIC_WRITE, 0, NULL,
               OPEN_EXISTING, 0, NULL);
    }
    return INVALID_HANDLE_VALUE;
}
-----------------------------------------------------------------------------------------
위의 짜가장치 탐색법은 골때리게 단순하다. 결국에는 HIDFAKE_VID 와 HIDFAKE_PID 를 체크하는 개념이다. 즉, 제작사(Vendor ID)와 제품번호(Product ID)를 가지고 짜가인지 판별하겠다는 개념이다. 그렇다면 제작사와 제품번호는 속일수 없다고 생각하는가? 커널을 뒤짚어 엎는(Subvert) 판국에 저렇게 단순하게 비교해서는 가상장치를 막을수 없다. 위의코드를 보고 판단을 하길 가상장치는 다 막겠다고 판단한다면 정말 큰일이다. 어처구니 없는 싸움이 키보드보안이래 또 발생할 것이기 때문이다. 위의 코드가 의미하는 바를 잘못해석하면 안된다. 위의 코드는 이렇게 해석해야 한다. 그 어떠한 가상장치를 막을수 있다는 컨셉하에 위의 코드를 만들길 시도한것이 아니라 고정장치를 알아내기위해 만들어진 컨셉이라는 점을 말이다. 단지 정형화 되어있는 즉, 고정되어있는 상태에서는 가능할 수 있겠다. 이해를 돕기위해 예를한가지 들어보자. VMware 같은 가상머신 안에서 작동하는 것인지 정도는 파악할 수 있지 않을까 싶다. 왜냐면 VMware 가 동적으로 제작사와 제품번호를 바꿔야할 까닭이 없지않은가? 다르게 말하면 VMware 가 굳이 자기 제품정보를 굳이 속이거나 변덕스럽게 수시로 바꿔야할 필요가 전혀 없다는 얘기다. 이런경우에는 마치 하드웨어처럼 고정장치로 봐도 무방하다. 고로 VMware 에는 항상 고정된 장치가 있다고 판단해도 될 것이며 VMware 안에 구현된 장치들 중에는 가상장치들이 있으므로 항상 디텍트 할 수 있단 얘기가 되므로 위의 짜가장치 탐색법은 그러한 경우에 사용할 수 있는 컨셉이라는 소리다.

아직 더 깊이 연구해보지는 않았지만 가상장치와 전쟁을 선포할 경우에 또 하나의 "키보드보안" 같은 파국으로 치닫기에 좋은 스토리가 탄생할 것이다. 차라리 이것을 좀 더 유용한 곳에 사용해보면 어떨까? 바로!! 물리형 Auto Mouse 를 탐지하는 것이다. 기술은 적합한 곳에 쓰라고 있는 것이지 말도안되는 헛다리 싸움에 쓰라고 존재하지 않는다. 기술을 적용시킬때는 단순히 눈과 머리로만 판단하지말고 포괄적인 정황을 바탕으로 자신의 가슴속에 확신이 설때 비로소 본격적인 전쟁에 들어가야 한다. 그저 돈이된다고 키보드보안처럼 너도나도 발담궈놓고 아무도 책임지지않고 아무도 발도 못빼는 승자없는 싸움에 휘말리기 싫다면 필히 이 말을 웃어넘기지 말아야 할 것이다.(아마, 이젠 더이상 발을 빼지도 못할것이다.. 담구지 말라고 뜯어말려도
담궜으니 해야할 일은 그저 땜빵밖에 뭐가 더 있겠는가.. ㅉㅉ)
-----------------------------------------------------------------------------------------

<2. 물리형 Auto Mouse 탐지>
물리형 Auto Mouse 를 탐지하는 것의 기본바탕은 앞서 짜가장치 탐색에 사용된 코드를 그대로 채용하면 되겠다. 단, 제작사와 제품번호만이 아닌 추가정보를 이용할 필요가 있겠다. 그런데, 왜 효용성이 물리형 Auto Mouse 를 탐지하는 것에 효력이 있을까? 그 이유는 간단하다. 다음과 같은 정보를 보자. 필자는 최근에 오픈된 MMORPG 온라인 게임의 Auto Mouse 를 구매해보았다. 과연 어떻게 돌아가는지 궁금증도 있었고 진짜 완벽하게 구동이 되는것인지 두눈으로 확인해보고 싶었기 때문이었다. 그런데 일단, 한군데의 제품은 구동이 제대로 안되는 것을 확인하였다. 다만, 마우스 입력이나 키보드 입력은 그대로 게임속으로 전달되고 있다는 점에 주목하였다. 과연 그러한 것을 어떻게 탐지해낼 수 있을까? 다음은 USB View 라는 프로그램으로 Auto Mouse 장치의 Descriptor 를 본 화면이다.

<Auto Mouse HID Descriptor>
"USB Composite 장치"
-----------------------------------------------
Device Descriptor:
bcdUSB:             0x0200
bDeviceClass:         0x00
bDeviceSubClass:      0x00
bDeviceProtocol:      0x00
bMaxPacketSize0:      0x20 (32)
idVendor:           0x03EB (Atmel Corporation)
idProduct:          0x4743
bcdDevice:          0x1000
iManufacturer:        0x01
0x0409: "ATPLAY"
iProduct:             0x02
0x0409: "ATPLAY PRO8"
iSerialNumber:        0x03
0x0409: "1.0.0"
bNumConfigurations:   0x01
... 생략 ...
-----------------------------------------------
그렇다. idVendor 가 제작사이고 idProduct 가 제품번호이겠다. 이 정보는 필자가 예상컨대 고정이라 할 수 있다. 일단, 텍스트를 주의깊게 보자. "Atmel Corporation" 이 보이는가? 해커들이 가장 많이 사용한다는 그 유명한 "Atmel" 칩이 사용되었다. 일명 FPGA 칩이라고 불리운다. 이 FPGA 칩은 프로그래밍 가능한 이점이 있다.

(사견: 언제부터 마우스가 Atmel 칩으로 제작되었던가? 그래서 오토마우스가 그리도
       비싼거였나보다.. 싸구려 PIC 칩만으로도 마우스를 만들수 있다. 전자업계는
       원래 원가전쟁을 벌이는 계통이라서 단 1원이라도 원가를 절감해 보려고
       깎고깎고 전쟁을 벌인다. 필자의 친구가 전자회사 CEO 라서 이점은 매우 잘
       알고있다. 그 친구의 말을 빌어보자면 진짜 1원갖고 쪼잔하게 굴 수 밖에
       없다고 한다. 살아남아야 하니까 말이다.. 그런데 FPGA 칩을 쓰는 것을 보면
       좀 수상하다. 왜 재프로그래밍이 가능한 칩을 쓰는 것인가.. 재수없으면 기타장치
       메모리스틱 리더기같은 것들이 연결되어 있을수도 있으므로 함부로 판단하기는
       이르지만 아마도 대량유통되는 칩이 아닌 DIY(사제품)칩을 쓴다는 것은 기정
       사실이라고 추측할만 하지않은가? 필자가 대에충 찾아보니 Auto Mouse 제작사
       두군데가 Atmel 칩을 사용하고 있었다.)

만약 이 Atmel 칩이 필자가 아는 것과 달리 재프로그래밍이 가능한 기능이 없다면 게임업계에서는 대박의 찬스를 잡은 것이리라.. 왜? 고정이잖은가? 고정!! 또, 재미난 정보를 볼 수 있는데 바로 그 유명하다고 하는 "ATPLAY" 라는 마크가 찍혀있다. 아주 그냥 상호를 갖다가 박아놓은거보니 장사할 생가이 없다하겠다.
일단, 칩이 Atmel 칩으로 제작되어있는 USB 형 물리장치들을 사용하는 사용자는 모두 감시대상순위로 집어넣어도 십중팔구는 맞아떨어질 것이다. 특히나 Atmel 칩에 상관없이 상호명 ATPLAY 가 박혀있다면 그 사용자는 거의 Auto Mouse 를 사용하고 있을 확률이 99.9% 라고 할 수 있겠다. 그리고 USB View 같은 프로그램이 사용하는 루틴들은 위에서 언급된 루틴들에서 크게 벗어나지는 않을테니 쉽게탐지할 수 있다고 감히 추측해본다. 딱한가지 우려되는 사항이 있다면 프로그래밍 가능한 칩이기 때문에 업데이트 기능으로
펌웨어를 갈아치울 경우에 난감하게 될 것이다. 하지만 방금 언급한 방식을 사용한다면 Auto Mouse 제작사의 미래고객이 아닌 현재 고객들은 99.9% 가 탐지된다고 봐도 무방할 것이다. 물론, Auto Mouse 의 종류별로 이짓을 해야겠지만.. 프로그래머들의 습성상 모두 식별자를 기록해놓았을테니(아마, Atmel 칩에 코딩을 의뢰하거나 혹은 Atmel 칩에 프로그램이 가능한 사람을 영입했겠지만 프로그래머들이 그런거 생각안한다. 왜냐면 원리원칙을 따르려는 프로그래머의 심리상 바보같이 위에처럼 ATPLAY 를 박는게 미덕으로
생각할 것이기 때문이다.) 행동만 빨리 취한다면 현재 Auto Mouse 사용자들의 태반은 모두 다 탐지해낼 수 있을 것이라고 감히 판단해본다. 즉, 물리형은 고정이라는 변수를 잘 활용할 수 있기에 탐지도 비교적 수월한 편에 속한다는 것이다. 한가지 더 재미난 상상을 해보자.. 과연 Auto Mouse 업체에서 펌웨어 업데이트 기능을 추가로 만들어내는데 얼마나 시간이 걸릴까? 누가 더 대응이 빠를까..? 과연 이 전쟁에서 Auto Mouse 업체의 대응이 빠를까? 아니면 막는자의 대응이 더 빠를까? 아마도 덩치가 작은쪽이 더 빠르겠지만 두고볼 일일 것이다. 이 전쟁은 어느한쪽의 시간전쟁일 뿐이다.. 정확하고 빠른판단이 내려지면 그대로 바로 행하는 쪽이 이기는 것이다. 현재로써 본 필자의 생각으로는 물리형 Auto Mouse 는 막을 수 있다. 이 문서가 나온 시점 앞으로가 문제이다.. 점차 Auto Mouse 는 가상마우스로 진화를 꿈꾸고 있기 때문이다. 그것이 바로 기술의 대세인 것이다. 오늘의 기술이 내일의 쓰레기가 되어버리는 시대에서 속도전의 중요함이다. 승자는 과연 누가 될까? 아무도 모른다.. 기술은 끝이 없으니까.. 마이 골치아픈 것이다.. -_-; 어디까지나.. 필자 개인이 현 상태를 진단해본 사견일 뿐이다. 이 이상 어케 더 판단하랴..

[HID Descriptor Tool]
USB.ORG 공식 사이트에서 받을수 있음
http://www.usb.org/developers/hidpage#HID%20Descriptor%20Tool
(위에서 언급한 사이트 이외 참고한 사이트)
http://kkamagui.tistory.com/485
http://www.keil.com/forum/docs/thread13037.asp


"};   
WCHAR DeviceID[]  ={L"ROOT\NUMEGA_VIRTUAL_HID_MOUSE
본 문서는 파워해커에서 제작되었으며 무단배포를 허용함..

<Virtual HID Mouse Driver 연구>

저자: AmesianX
제작: powerhacker.net
제작년도: 2009년 1월 15일

 

[서문]

본 문서의 시작에 앞서 목적에 대해 언급한다. 이 문서는 두가지 목적을 위해서 작성되어졌다.
첫번째는 모르는 부분에대한 새로운 연구나 공부를 시도할때 참고할 수 있는 공부방식(Style)에 대한 설명이고, 두번째는 Virtual HID Mouse Driver 를 제작할때 참고해야할 전초를 다지기위한 목적으로 구성되어 있다. 이렇게 기술문서를 공개하는 이유에는 여러가지가 있지만 무엇보다 이 기술이라는 분야는 언젠가는 자신이 알고있는 오늘의 기술이 내일의 쓰레기가 된다. 일찌감치 알고있는 정보들은 공개하고 더 높은 곳으로 계속 뛰어오를때 진정으로 아무도 가보지못한 고지에 오른 것이다. 그래야 스스로가 발전하는 길이고 바로 모두가 발전하는 길일 것이다. 고지는 점령 당하라고 있는 것이다. 언제까지 정적인 비공개노선으로 점령당하길 기다리고 있을 것인가? 앞으로는 더욱더 가속화될 것이다.


[기술을 습득하는 공부방법]

어떤 새로운 기술을 알고싶다면 최대한 동일기능이 구현된 많은 소스들을 수집하라. 그리고 그 차이점을 소스분석을 통해서 캣치하라. 아마 대부분은 소스분석을 깊게 들어가지 않아도 차이점이 눈에 띄게 될 것이다. 그러나.. 아쉽게도 Virtual HID Mouse 에 대한 소스는 인터넷에서 거의 찾기 힘들 것이다. 물론, 공식적인 샘플들을 찾아낼 수 있지만 필자처럼 커널지식보다 유저레벨 어플리케이션 조작만 파온 사람은 그 유명업체들의 공식샘플을 보고도 감을 잡아내기는 하늘에 별따기처럼 어렵다. 즉, 프로그래밍 = 개념 이라는 공식이 있기 때문에 이 개념만 잡고나면 프로그래밍은 껌씹기나 마찬가지다. 개념을 잡는 요령이 있다면 그것은 바로 앞에서 언급한 동일기능 소스의 차이점을 분석해내는 것이다. 그렇기 때문에 매우 제한된 소스(공식소스들)를 갖고 시작하는 것은 전혀 이해를 이끌어내지 못한다. 최대한 고갈되었다고 생각될 정도로 많은 설명이나 소스들을 검색해서 찾아내야 한다. 이때 사용할 수 있는 방법은 구해낸 소스들의 일부 시그너처(Signature)를 검색키워드로 사용하는 것이다. 이런식으로 최대한 많은 정보들을 뽑다보면 선구자들의 질문들을 찾아낼 수 있다. 바로, 그 질문들에서 핵심개념들을 뽑아낼 수 있다. 자주 언급되는 사항이 바로 그 핵심일 것이다. 어떻게보면 "미네르바" 인지 "미네로하이바" 인지 그 친구처럼 철저한 검색기술로 무장한 채로 짜집기의 달인이 되어야만 할 필요가 있다. 만약 충분히 많이 찾아서 더이상 찾아낼 것 조차 없다고 느끼고 등골이 휘어지는 고통을 여러번 견뎌내었다면 이제 얻어낸 것들을 대상으로 비교분석을 취한다. 그렇게 되면 중요 키포인트가 눈에 보이게 될 것이다. 왜 이렇게 해야 하냐면 답은 간단하다. 스스로 엄청난 고통을 감뇌하면서 충분히 검색을 했는데 다 내용이 거기서 거기인 경우가 99.9% 일 것이다. 왜? 그것은 삽질하는 프로그래머가 택한 프로그래밍 방법론은 달라도 전체적인 흐름은 재밌게도 한가지밖에 없으니까. 이게 답이다.

"어라? 다 똑같은 소리만 짓거리고 있잖아? 뭔가 좀 더 구체적인 것을 달라고!!"

이 소리가 나올때 이미 정답은 구해진 것이나 마찬가지다. 다 똑같은 소리를 짓거린다거나 똑같은 소스에 차이점은 있지만 원하는 것이 아니라고 생각될때 사실상 그것이 원하는 것일 확률이 태반이다. 그 이상의 짜집기(Copy & Paste) 능력은 밥을 숫갈로 퍼서 먹는 것이다. 그런데 필자같은 사람은 퍼서 먹여주는 것을 원한다. 왜? 프로그래밍이 나온 이유가 무엇인가? 로보트를 만들려고 기를 쓰는거보면 모르겠는가? 인간에게 숫갈로 밥을 퍼먹여 주려는게 궁극적인 목적아닌가? 프로그래머는 인간이 아니었나? (하기사 혹자는 로보트
라고도 부릅디다..) 프로그래머는 좀 퍼서 먹여주면 어디가 덧나는가? 짜증나게 약올리는 시스템 프로그래머들이여 퍼먹여주지 않으면 스스로 밥숫갈 놓게되는 날이 온다. 인터넷시대에서 정보라는 것은 물 흐르듯 흐를수 밖에 없기 때문에 빨리 털고 높은 곳으로 뛰지않으면 숫가락 놓을 준비를 해야 할 것이다. 오늘의 신기술이 내일의 쓰레기가 되는 시대에서 서로 돕지않으면 혼자 살아남기 힘들다. 외국애들 보라 오픈소스로 자기의 기술을 다 까발리고 있으면서도 항상 최첨단 기술을 걷고 있는 것을 보면 우리가 얼마나 어리석은지 진정 모르냐 이말이다.

외국애들은 오픈소스를 통해서 시너지라는 것을 이용하고 있다. 물론, 수 많은 개발자들이 다 참가해서 오픈소스가 완성될 것이라고 착각하면 그건 열라 바보이다. 유명 보안 오픈소스인 Nessus 개발자의 고충이 섞인 글을 읽어보았는가? 오픈소스임에도 불구하고 자기혼자만 개발해 왔다고 써있었다. 대부분의 오픈소스들이 마찬가지라고 보면 될 것이다. 다만, 시너지효과로 인해 개발자 1명이 해낼수 있는 능력이 100명 1000명 수준으로 증폭되었기에 프로젝트가 맥을 이어갈 수 있는 것이다. 즉, 게임용어로 말하면 "버프"(버프를 모르진 않겠지..) 를 받은 것이다. 그렇게 되면 소수의 엘리트 파워가 오픈소스에 집중되는 일반유저의 관심만큼 증폭되기 때문이다. 단순히 눈에보이는게 전부라고 생각한다면 큰 것을 놓치게된다. (아니라고? 아님말고.. 허위사실 유포로 감금되어야 하나.. ㅎㅎ)

[현 상황]

현 상황에서는 Virtual HID Mouse 가 Auto Mouse 나 MACRO 라는 시장에서 대안으로 대두된 상태라 x시장에서도 드라이버의 판매가 이루어지고 있는 상황이다. 참고로 이 기술이나 드라이버를 판매자체는 사실 법적인 문제의 소지가 없다. 왜냐면 이 Virtual HID Mouse 기술은 범용기술이기 때문이다. 이 기술이 사용되고있는 쪽은 예를들면 조이스틱을 에뮬레이션하거나(용산에가면 조이스틱 판다..) 블루투스 마우스를 사용하도록 해주거나 혹은 그에 버금가는 마우스 업체들이 주로 보유하고있는 자체기술에서 많이 볼 수 있다. 이건 우리가 늘상 접하는 일반분야에서 말한것 뿐이고 무엇보다 가장 많이 사용되고 있는 곳은 임베디드 산업에서일 것이다. 그러므로 이 기술을 파는 것은 전혀 문제가 될 수 없다. 이 기술자체는 Microsoft 사에서 공식적으로 WinDDK 에 예제와 함께 배포하고 있다는 사실을 알만한 사람들은 이미 다 알고있겠다. 단지 그 이상의 자세한 정보를 찾기가 어렵고 Microsoft 사에서 제공하는 기술정보를 알기위해서 밑받침(선행) 되어야할 정보가 없다는 것이 문제점이다. 그래서 기존에 커널 드라이버를 개발하던 사람들이나 천국이지 필자같은 미천한 어플프로그래머들한테는 짜증만 나게 할 뿐이다. 이 중간에 생략된 정보들이 무엇인지 알아내야 한다. 그것이 유저레벨이라는 미천한 신분에서 커널레벨이라는 귀족신분으로 도약할 수 있는 길이다. 테스트환경 만드는게 짜증나서 공부하지 않았다가 완전 독박 쓴 기분이기에 좀 고약한 말투가 나온다. (기분 상하는 커널레벨의 고급 독자는 당장 이 문서를 접기 바란다. 필자도 커널레벨을 공부해야 윈도우를 진정으로 아는 것이라는 대에 이견이 없다. 다만, 오래전부터 블루스크린과 친구를 맺고싶지 않았을 뿐이다. 이거 참.. 뻘쭘하게 커널과 "절친노트" 라도 찍어야하나..)
===================================================================================================================

현재, 인터넷에는 몇몇의 기술 정보이외에는 관련된 기술적 자료를 찾아볼 수 없다고 해도 과언이 아니다. 진짜 짜증나도록 자료가 없다. 이해를 할 수 있을만한 한글로된 기술자료는 극적으로 한개를 찾을 수 있었다. 먼저, Virtual HID Mouse 를 찾아보면 가장먼저 접하게 되는 사이트가 있다. 까마귀라는 한국사람이 자신이 만들었다고하는 Virtual HID Mouse 가 검색이 된다. 블로그의 글 내용인데 사실 저수준을 다루는 고급개발자가 아니면 볼게없다.. (왜? 필자같은 어플프로그래밍 수준은 못알아 먹으니까.. + 안갈켜주니까
-_-;) 그리고 MSDN 이 검색되고 vhidmini 라는 것이 검색된다. 또한, 짱개 사이트의 vhidmouse 라는 소스와 hidmouse 라는 소스도 검색된다. 근데.. 오래전에 GxxxGuard 라는 소스가 인터넷에 떴다는 그 몹쓸 짱개사이트였다. 구현을 하기 위해서는 vhidmini 라는 소스가 그중에서 제일 유력한 후보가 될 것이고 나머지 vhidmouse 와 hidmouse 는 소스를 구하는데 한참이나 걸릴 것이다. 일단, 대충 둘러서 정보를 캣치해야한다. 다음은 이미 다들 알고있겠지만 SoftICE 라는 걸작을 만들어낸 "Numega Soft" 라는 회사의 Virtual HID Mouse 공식샘플의 일부소스이다. 아쉽게도 이 소스는 Windows 9x 계열에서 작동되는 드라이버이므로 NT 계열에서는 사용할 수 없다. 하지만 캣치할 수 있는 중요한 내용이 포함되어 있다. 위에서 언급한 것중에 vhidmouse 라는 것이다. 다음은 vhidmouse 소스 중의 일부분이다.

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

// vmoudev.cpp -  virtual mouse device for HID example    
//=============================================================================    
//    
// Compuware Corporation    
// NuMega Lab    
// 9 Townsend West    
// Nashua, NH 03060  USA    
//    
// Copyright (c) 1998 Compuware Corporation. All Rights Reserved.    
// Unpublished - rights reserved under the Copyright laws of the    
// United States.    
//    
//=============================================================================    
   
// This module implements the device class of the virtual HID    
// mouse minidriver.    
   
#include <KHID.H>    
#include "vmoudev.h"    
#include "hidmouse.h"    
   
KTrace T("",TRACE_MONITOR, TraceAlways, BreakNever, KUstring(L"HidMouse"));   
   
#define SCALEX 3    
#define SCALEY 3    
   
// The HID report descriptor for this device    
// (taken from USB/HID specification)    
   
HID_REPORT_DEscRIPTOR MouseHidReportDesc[] = {   
    0x05, 0x01, // Usage Page (Generic Desktop),     
    0x09, 0x02, // Usage (Mouse),      
    0xA1, 0x01, // Collection (Application),        
    0x09, 0x01, // Usage (Pointer),         
    0xA1, 0x00, // Collection (Physical),           
    0x05, 0x09, // Usage Page (Buttons),            
    0x19, 0x01, // Usage Minimum (01),          
    0x29, 0x03, // Usage Maximun (03),          
    0x15, 0x00, // Logical Minimum (0),             
    0x25, 0x01, // Logical Maximum (1),             
    0x95, 0x03, // Report Count (3),            
    0x75, 0x01, // Report Size (1),         
    0x81, 0x02, // Input (Data, Variable, Absolute),    ;3 button bits          
    0x95, 0x01, // Report Count (1),            
    0x75, 0x05, // Report Size (5),         
    0x81, 0x01, // Input (Constant),            ;5 bit padding          
    0x05, 0x01, // Usage Page (Generic Desktop),            
    0x09, 0x30, // Usage (X),           
    0x09, 0x31, // Usage (Y),           
    0x15, 0x81, // Logical Minimum (-127),          
    0x25, 0x7F, // Logical Maximum (127),           
    0x75, 0x08, // Report Size (8),             
    0x95, 0x02, // Report Count (2),            
    0x81, 0x06, // Input (Data, Variable, Relative),    ;2 position bytes (X & Y)       
    0xC0,       // End Collection,    
    0xC0        // End Collection    
    };     
   
// HardwareID for the virtual mouse.     
   
WCHAR HardwareID[]={L"ROOT\\NUMEGA_VIRTUAL_HID_MOUSE\0"};   
WCHAR DeviceID[]  ={L"ROOT\\NUMEGA_VIRTUAL_HID_MOUSE\0"};   
   
HID_DEVICE_ATTRIBUTES DeviceAttributes = {   
    sizeof(HID_DEVICE_ATTRIBUTES),     
    MY_VENDOR_ID,   
    MY_PRODUCT_ID,   
    VERSION_NUMBER   
    };

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

위와 같이 HID_REPORT_DEscRIPTOR 라는 것을 볼 수 있는데, 처음에는 이게 뭔지 모른다. 감도 안온다. 그러므로 그 관점을 그대로 두고 다음으로 넘어가서 다른 소스들을 보자. (처음엔 원래 모르겠지.. 나만그런가.. -_-; 제길..)

인터넷에서 검색하면 위의 소스와 MSDN (Microsoft 사의 공식샘플과 설명문서) 을 먼저 보게 될 것이다. 그러면 당연히 vhidmini 라는 것도 접하게 된다. 소스는 인터넷에서 파는 놈들도 있으니 그냥 찾기는 좀 짜증이 날 것이다. Microsoft 사의 홈페이지에서 WinDDK 를 받으라. 그 안에 VHidMini 라는 샘플이 들어있다. 그놈을 보면 다음과 같이 생겨먹은 부분에 주목하자.

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

        if (NT_SUCCESS(ntStatus)) {
            //
            // Use default "HID Descriptor" (hardcoded). We will set the 
            // wReportLength memeber of HID descriptor when we read the 
            // the report descriptor either from registry or the hard-coded 
            // one.
            //

            deviceInfo->HidDescriptor = DefaultHidDescriptor;

            //
            // Check to see if we need to read the Report Descriptor from
            // registry. If the "ReadFromRegistry" flag in the registry is set
            // then we will read the descriptor from registry using routine 
            // ReadDescriptorFromRegistry(). Otherwise, we will use the 
            // hard-coded default report descriptor.
            //

            queryStatus = CheckRegistryForDescriptor(DeviceObject);

            if(NT_SUCCESS(queryStatus)){
                //
                // We need to read read descriptor from registry
                //
                
                queryStatus = ReadDescriptorFromRegistry(DeviceObject);
            
                if(!NT_SUCCESS(queryStatus)){
                    DebugPrint(("Failed to read descriptor from registry\n"));
                    ntStatus = STATUS_UNSUCCESSFUL;
                }

            }

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

Microsoft 에서 MSDN 의 설명을 먼저 읽어본 뒤 위의 소스주석부분을 보자. 다음과 같이 친절하게 설명해주고 있다.

            // Check to see if we need to read the Report Descriptor from
            // registry. If the "ReadFromRegistry" flag in the registry is set
            // then we will read the descriptor from registry using routine 
            // ReadDescriptorFromRegistry(). Otherwise, we will use the 
            // hard-coded default report descriptor.

설명에 써있듯이 자기네는 그냥 하드코딩 했으니까 ReadFromRegistry 를 참고하면 다른 디바이스를 등록할 수 있단다. 처음 접할땐 사전지식이 없기에 "이게 뭔 개소리야?" 라고 생각이 들 것이다. (? 반응이 없으면 나만그런거 같다.. ㅎ)

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

그렇다면 이제 개소리는 집어치우고 다음을 보자.

-->  https://www.osronline.com/showthread.cfm?link=138652

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

Radly
xxxxxx@daryllee.com

This being my first driver project, and an unusual one at that, there's a lot to get my
head wrapped around. My intent is to produce a virtual HID device (mouse emulation) that
uses a complex non-HID physical device as the input medium. I'm using the VHidMini sample
from the WDK hid folder as a starting point, and I'm now at the point where I need to transform
the sample's report format into a mouse format. I notice with confusion that the report descriptor
in vhidmini.inf is different from that in vhidmini.h, with no explanation in vhidmini.htm as
to why they are different. Does anyone here have any insight on that?


어떤 놈이 필자가 생각하는 것과 동일한 구현을 해볼려고 삽질중에 무시무시한 고급개발자들과 해커들이 몰린다는 osronline 에 질문을 던져놓고 있다. 이 소리는 무엇인가? 필자도 결국 저 문제에 봉착하게 될 날이 온다는 시나리오를 미리 발견한 것이다. 그러므로 주의 깊게 읽어볼 필요가 있다. 여기서 얻어낼 수 있는 정보는 sample's report format 이란 것과 report descriptor 라는 두가지 내용이다. 원래부터 찾기힘든 정보들에는 동문서답 내지는 "내가 니 밥처먹는데 밥숫가락으로 퍼먹여주랴?" 정도의 댓글이 달리는데 그래도 이 글의 답글중에 괜찮은 답글이 있다. 근데.. 여전히 찾기힘든 정보만큼이나 짤막하게 달아놓는다. 이런사람이 있다는 것은 희망이고 곧 빛이다. 다음의 답글을 읽어보자.

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

allen zhang
xxxxxx@sina.com
RE: VHidMini report descriptor(s)

see the follow source code and the ReadDescriptorFromRegistry function, You should be understand it.

deviceInfo->HidDescriptor = DefaultHidDescriptor;
queryStatus = CheckRegistryForDescriptor(DeviceObject);
if(NT_SUCCESS(queryStatus)) {
    queryStatus = ReadDescriptorFromRegistry(DeviceObject);
    ...

 

입에서 욕은 나온다. 왜? 말할라면 다 말하던가 아니면 동문서답이나 하고 가던가 감칠맛나게 소스 네줄 뿌리고 튀다니.. 그래도 고맙다. 지식을 갈구하는 자에게는 이것조차 선물이다. 제길.. 현자라면 푸념할때가 아닌거 같다. 여기서 뭔가 개념을 잡을 수 있는 정보를 캣치해야만 한다. 이 글에서 외국아가(짱개류 외국애인지 allen zhang 이구나.. 역시 중국은 AUTO 에 강한가보다..) 말하기를 소스코드를 보란다. 그 안에 ReadDescriptorFromRegistry 를 보라고 권하면서 일부 소스를 긁어서 보여준다. 글은 짧지만 분명 소스를 열어봤기에 긁어서 붙여줬을테니 아쉬워도 고마운 행동이다.

여기서 보라고 한 소스가 바로 위에서 VHidMini 샘플의 일부분이라고 뿌린 부분이다. 즉, 이 부분의 내용은 최초 질문자의 글에서 캣치한 sample's report format 와 report descriptor 라는 부분에대한 응답이다. 즉, 이 함수의 이름으로부터 알 수 있듯이 레지스트리로부터 디스크립터를 읽어들인다는 것에 바로 Virtual HID Mouse 의 핵심구현이 얽혀있다는 것을 시사한다는 점을 알 수 있다. 그런데 필자도 단지 이두개만 가지고 감을 잡지는 못했다. 왜냐면, 커널을 깊이 공부한 적이 없는 사람이 이 두가지의 자료만을 토대로 감을 잡아낼 수 있겠는가? 그렇다면 그건 천재이거나 영어를 모국어처럼 잘하는 사람일게 분명하다. 필자는 남보다 항상 두배로 삽질을 하는데 머리가 남들보다 딸려서 그렇다. 자료도 항상 두배로 찾아야 한다. 결정적으로 힌트가 되었던 것은 역시 국내사이트인데 드라이버 개발정보를 알려주는 곳인 driveronline.org 에서의 힌트와 임베디드 계통의 KELP 사이트에서 였다.

http://driveronline.org/bbs/view.asp?tb=beusb&GotoPage=1&s_bulu=memo&s_key=pnp&no=1491
-------------------------------------------------------------------------------------------------------------

Re] Re] Re] USB 가상 키보드, 마우스 드라이버
·작성일     2007.10.02:10.40 (화)
· 작성자     Woof
· 조 회 605

pnp 를 이용해서든지 해서 가상적인 usb 장치가 인식이 되면 일반적인 usb 장치를 다루듯이 이용하시면 됩니다. 일반적으로 실제 장치들은  Windows에서 제공하는 기본적인 드라이버로도 동작하기 때문에 필요가 없지만 이와 같은 경우에는 간단하게 자기 드라이버를 열어서 인식된 장치 device와 통신하는 드라이버 정도는 필요하겠지요. 뭐, usb라서 따로 드라이버없이 application으로도 충분히 가능한건데 다들 위와 같은 방법을 이용하더군요. 새로나온 umdf 등을 이용하면 더 간단하고 새로나온 것에 대한 공부도 하면서 재미나게 할 수 있을지도 모르겠네요. 위 에서 말한 대부분의 경우 라고 한 것의 예를 간단히 들어보면 자신의 드라이버를 올리고 해당 드라이버에서 application과 통신 device를 생성한 뒤에 pnp를 이용해서 가상적인 usb 장치를 만들고 그것과 통신하는 길?을 적당히 만들어서 이용하시면 됩니다. sample에서는 가상적인 장치 인식이 바로 usb나 그런 부분이 아니였던 것 같은데 적당히 고치면 되겠지요.

위에도 썻지만, 잘 찾으면 다 만들어진 코드 어디 있을 것 같습니다. 저도 한번 찾으려다가 그냥 sample에 있어서 말았는데. :|  해당 usb 드라이버를 이용해서" 라는 부분에 대해서 물어보셔서 이 부분만 따로 답을 달면 해당 usb device를 제어(control)하는 드라이버를 지칭했습니다.  또 처음에 말한 것 처럼 class관련 드라이버에 대해서는 생각할 필요가 없습니다. 역시 위에 쓴 것 처럼 어디에 쓰실지 궁금하네요. 가상 키입력등은 S/W나 그런 자동화 테스트에 이용하기도 하고 꽤 여러군데서 쓰기는 하는데 안좋지는 않지만 뭐 . 그런데도 쓰여서 :|

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


최초 질문자가 어떻게 구현해야 하냐고 질문하자 pnp 를 통해서 가상적인 usb 를 인식시킨 다음에 적당히 device 와 통신시키라고 한다. 자세한 내용은 말해주지 않고 Microsoft 에서 제공하는 샘플로도 구현이 가능할 것이라는 내용과 어딘가에는 이미 다 만들어진 소스가 있을텐데 찾아보라고 한다. 이말 믿고 인터넷에서 찾아헤메다가는 마누라가 집나가도 모를것이다. 답변에서 보듯이 이 사람은 진짜 적당히 답글을 달고 있는 사람이라는 점을 주의해야 한다.

이 사람의 힌트와 통찰력이 Microsoft 사의 샘플에서 존재하는 핵심이라는 점을 알 수 있다. 일단, 정보는 머리속에 꼬깃꼬깃 담아두고 계속 다음 검색으로 넘어가면서 본인의 마음속에 답이 한가지로 수렴되도록 정보들을 계속 얻어 내어보자. 이쯤되면 정상적인 사이트를 뒤지는 것이 힘들어진다. 왜냐면 너무 정보가 부족하기 때문이리라. 고로 컨트롤러를 제어하는 것을 찾아본다. 예를들면 USB HID 조이스틱 드라이버 같은 것을 찾아내는 것이다.

다음과 같은 좋은 예가 있었다.

http://www.redcl0ud.com/files/XBCD_all_src.cab

XBOX 의 6축 조이스틱 패드를 윈도우에서 사용할 수 있도록 해주는 소스였다. 검색을 할때는 기존에 얻었던 소스에서 일부 특이하게 보일만한 함수를 키워드로 검색하면 운좋게 찾을 수 있다. 소스를 보면 너무 길고 난해하고 이해하기 힘들뿐이다. 당연히 커널관련 지식이 깊지않은 이상 어떻게 분석하고싶어도 그럴 도리가 없다. 그러므로 파일구성을 보는 것이 전부이다. 여기서 또한가지 힌트를 얻을 수 있다.

XBCD_control.c
XBCD_driver.c
XBCD_driver.h
XBCD_hid.h
XBCD_report.h

위와 같은 파일구성에서 driver 나 control 소스를 보기전에 report 라는 눈에 띄는 놈이 있다. 이 헤더파일의 내용을 보게되면 다음과 같은 것이 적혀있다.

-------------------------------------------------------------------------------------------------------------
char ReportDescriptor[213] = {
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x04,                    // USAGE (Joystick)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,                    //   PHYSICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x01,                    //   USAGE (Button 1)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x02,                    //   USAGE (Button 2)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x03,                    //   USAGE (Button 3)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x04,                    //   USAGE (Button 4)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x05,                    //   USAGE (Button 5)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x06,                    //   USAGE (Button 6)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x07,                    //   USAGE (Button 7)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x08,                    //   USAGE (Button 8)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x09,                    //   USAGE (Button 9)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0a,                    //   USAGE (Button 10)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0b,                    //   USAGE (Button 11)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0c,                    //   USAGE (Button 12)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x75, 0x04,                    //   REPORT_SIZE (4)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x81, 0x01,                    //   INPUT (Cnst,Ary,Abs)
    0x75, 0x10,                    //   REPORT_SIZE (16)
    0x16, 0x01, 0x80,              //   LOGICAL_MINIMUM (-32767)
    0x26, 0xff, 0x7f,              //   LOGICAL_MAXIMUM (32767)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x7f,              //   PHYSICAL_MAXIMUM (32767)
    0x05, 0x01,                    //   USAGE_PAGE (Generic Desktop)
    0x95, 0x02,                    //   REPORT_COUNT (2)
    0x09, 0x30,                    //   USAGE (X)
    0x09, 0x31,                    //   USAGE (Y)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x02,                    //   USAGE_PAGE (Simulation Controls)
    0x95, 0x02,                    //   REPORT_COUNT (2)
    0x09, 0xba,                    //   USAGE (Rudder)
    0x09, 0xbb,                    //   USAGE (Throttle)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x01,                    //   USAGE_PAGE (Generic Desktop)
    0x09, 0x39,                    //   USAGE (Hat switch)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x07,                    //   LOGICAL_MAXIMUM (7)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0x3b, 0x01,              //   PHYSICAL_MAXIMUM (315)
    0x65, 0x14,                    //   UNIT (Eng Rot:Angular Pos)
    0x75, 0x04,                    //   REPORT_SIZE (4)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,                    //   PHYSICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0d,                    //   USAGE (Button 13)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0e,                    //   USAGE (Button 14)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0f,                    //   USAGE (Button 15)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x10,                    //   USAGE (Button 16)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x00,              //   PHYSICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, 0x03,                    //   REPORT_COUNT (3)
    0x05, 0x00,                    //   USAGE_PAGE (Not Defined)
    0x09, 0x00,                    //   USAGE (Undefined)
    0x09, 0x01,                    //   USAGE (Undefined)
    0x09, 0x02,                    //   USAGE (Undefined)
    0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
    0xc0                           // END_COLLECTION
};
-------------------------------------------------------------------------------------------------------------

그리고 이 홈페이지에서 최대한 얻을 수 있는 것은 다 캣치해야 하는 http://www.redcl0ud.com/xbcd.html 홈페이지의 마지막쯤에 보면 http://www.redcl0ud.com/files/USBView.cab 라는 것이 있다. 그리고 캡춰사진이 있는데 핵심사항으로 체크를 해둔 부분이 있다. idVendor, idProduct 라는 부분에 체크를 해두고 있다. 그리고 USBView 에서 보여주는 내용이 모냐면 바로 Device Descriptor 였다. 오호라.. 내친김에 이 사이트에서는 USB 드라이버를 제작하는 방법까지 설명하는 링크를 걸어두고 있었다.

http://euc.jp/periphs/xbox-controller.en.html

이 링크인데 제목은 "Inside XBox Controller" 라고 되어있다. 대충 무슨내용이 있는지 열거하자면..

-------------------------------------------------------------------------------------------------------------
<Inside Xbox Controller>
...

<Overview>
...

<USB Device Model>
...

<Descriptors>

Here are descriptor dumps of the hub, the gamepad and the memory unit.

    * Descriptors of the integrated hub
    * Descriptors of the gamepad (American)
    * Descriptors of the memory unit

<Vendor/Product IDs>

The vendor ID is 0x045e (Microsoft). Product IDs are as follows:
ID    product
0x001c    integrated hub
0x0202    gamepad (American)
0x0280    memory unit
0x0284    DVD remote receiver
0x0285    gamepad (Japanese)

It is not recommended to distinguish Xbox gamepads by vendor/product IDs because third-party controllers may
have their own vendor/product IDs.

<Device Class>
...

<HID Report Format>
Input Report
The input report is 20-byte.
헤더그림

Output Report
The output report (rumble control) is 6-byte. 
헤더그림

<Example of HID Report Descriptor>
The Xbox gamepad lacks the HID report descriptor that describes the input/output report formats. Based on the
above report formats I have tried writing the report descriptor for your information. This is a mere example;
neither official nor verified. Accuracy is not guaranteed.

    * Text format
    * Binary format
    * HID Descriptor Tool format (to be loaded into HID Descriptor Tool) 
---------------------------------------------------------------------------------------------------------------

위와 같은 내용들이 있었다. 상당히 많은 삘을 주고있다. 누가봐도 HID Descriptor 와 HID Report Format 그리고 Input Report 와 Output Report 를 통해서 통신한다는 아주 기본적인 컨셉(개념)은 머리가 아니라(T.T) 가슴에 와닿을 것이다. (젠쟝.. 가슴에만 담아두마.. -_-;) 일단, 이쯤에서 XBCD 소스는 닫아둔다. 언제 이거 분석하고 앉아있는가.. 최종컨셉이 다르기 때문에 힌트만 뽑아먹고 닫아두는 것이다. 애초에 만들려고 한건 Virtual HID Mouse 인데 이건 그 컨셉이 아니기에 대충 훑어보고 넘겨야 한다. 또 다른 소스들을 보자. 마구잡이로 검색하면서 받아둔 소스중에 앞에서 처음에 말했던 hidmouse 라는 소스를 한번 진단해보자.. -_-;

(PIC 를 이용한 마우스 제작소스)
파일을 열어보니 원하는게 아닌듯 보였는데 알고보니 PIC 용이었다. 운 좋게도 필자는 PIC18x 롬라이터를 갖고 있어서 이 소스가 뭔지 알 수 있었다. 오래전에 친구의 부탁으로 PIC18x 칩에 어셈블리를 롬라이팅 하는 프로그램을 만들어준 적이 있어서 무슨 소스인지 금방 알 수 있었다. 요새는 PIC 프로그래밍에도 C 가 쓰이고 PIC 는 PLC 대체용으로 쓰이기도 한다. 그런데 PIC 로 USB 모듈을 부착하고 마우스로 제작이 가능한거 같았다. 어쨌거나 원하는 내용은 아니었지만 생각해보면 가장 중요한 것이 물리적인 장치 아닌가? 물리적인 장치에서는 기존에 찾은 소스들이나 검색내용들과 어떤 차이가 있는지 알아볼 필요도 있다.
http://www.pudn.com/downloads128/sourcecode/comm/detail543439.html

hidmouse 라는 소스에서 파일구성을 보면 특이한 놈이 있다.
usb_descriptors.c 라는 소스가 있는데 여태까지 눈여겨왔던 descriptor 라는 단어가 보일 수 밖에 없다.

-------------------------------------------------------------------------------------------------------------
/* Device Descriptor */
ROM USB_DEVICE_DEscRIPTOR device_dsc=
{
    0x12,    // Size of this descriptor in bytes
    USB_DEscRIPTOR_DEVICE,                // DEVICE descriptor type
    0x0200,                 // USB Spec Release Number in BCD format
    0x00,                   // Class Code
    0x00,                   // Subclass code
    0x00,                   // Protocol code
    USB_EP0_BUFF_SIZE,          // Max packet size for EP0, see usb_config.h
    MY_VID,                 // Vendor ID
    MY_PID,                 // Product ID: Mouse in a circle fw demo
    0x0003,                 // Device release number in BCD format
    0x01,                   // Manufacturer string index
    0x02,                   // Product string index
    0x00,                   // Device serial number string index
    0x01                    // Number of possible configurations
};

... 중략 ...

//Class specific descriptor - HID mouse
ROM struct{BYTE report[HID_RPT01_SIZE];}hid_rpt01={
    {0x05, 0x01, /* Usage Page (Generic Desktop)             */
    0x09, 0x02, /* Usage (Mouse)                            */
    0xA1, 0x01, /* Collection (Application)                 */
    0x09, 0x01, /*  Usage (Pointer)                         */
    0xA1, 0x00, /*  Collection (Physical)                   */
    0x05, 0x09, /*      Usage Page (Buttons)                */
    0x19, 0x01, /*      Usage Minimum (01)                  */
    0x29, 0x03, /*      Usage Maximum (03)                  */
    0x15, 0x00, /*      Logical Minimum (0)                 */
    0x25, 0x01, /*      Logical Maximum (0)                 */
    0x95, 0x03, /*      Report Count (3)                    */
    0x75, 0x01, /*      Report Size (1)                     */
    0x81, 0x02, /*      Input (Data, Variable, Absolute)    */
    0x95, 0x01, /*      Report Count (1)                    */
    0x75, 0x05, /*      Report Size (5)                     */
    0x81, 0x01, /*      Input (Constant)    ;5 bit padding  */
    0x05, 0x01, /*      Usage Page (Generic Desktop)        */
    0x09, 0x30, /*      Usage (X)                           */
    0x09, 0x31, /*      Usage (Y)                           */
    0x15, 0x81, /*      Logical Minimum (-127)              */
    0x25, 0x7F, /*      Logical Maximum (127)               */
    0x75, 0x08, /*      Report Size (8)                     */
    0x95, 0x02, /*      Report Count (2)                    */
    0x81, 0x06, /*      Input (Data, Variable, Relative)    */
    0xC0, 0xC0}
};/* End Collection,End Collection            */

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

hidmouse 의 소스는 분석하지 않고 특징적인 몇개의 파일만 열어보고 위의 부분에 주목하고 닫아 버린다. 역시 컨셉은 물리 마우스가 아니라 가상 마우스이기 때문이다. 가상 마우스는 연결되면 오른쪽 아래의 트레이에 연결되었다고 풍선글이 떠야 하는 형태로 진행되어야 하는 것이 머리속의 구상이었다. 이미 driveronline 의 힌트에서 pnp 를 통해서 usb 를 인식시키라는 내용을 보았고 osronline 에서는 vhidmini 의 특정부분을 언급했으며 osronline 의 최초 질문자는 샘플의 포맷과 디스크립터를 언급했다. 다음의 사이트를 보게되면 약 90% 의 감이 오게되는데 임베디드 계통이 역시나 제일 확실하다. 시스템 프로그래머라는 황무지(wild)에서 살아가는 사람들이기 때문이다. 다만, 숫갈로 퍼먹여 주는걸 제일 싫어해서 짜증난다. 다음의 KELP 사이트의 글을 보면(http://kelp.or.kr/korweblog/stories.php?story=07/02/13/3453938)

글쓴이가 usb mouse 구현시 뭔가 이상하다는 식으로 적어놓고 있는 내용을 볼 수 있는데 한번 읽어보자.

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

usb slave 포트를 이용하여 usb mouse를 구현하고 있습니다.
글쓴이 : omayaro (2007년 02월 13일 오후 02:10) 읽은수: 643

<커널 2.6.11에서 gadget api를 이용하여 usb 마우스를 구현해 보고 있습니다.>

처음에 모듈을 등록하기 위하여

static int __init my_module_init(void)
{
int retval;
retval = usb_gadget_register_driver( &g_ugdDriver );
if (retval)
{
printk(KERN_ERR "[ omayaro ] module_init: cannot register gadget driver, ret=%d\n", retval);
return retval;
}
return 0;
}


위에서 처럼 하여 등록을 마쳤습니다.

그리고 pc( window xp 와 fedora core4 를 사용하는 pc 2대를 한번씩 테스트 함 )에

usb cable을 연결하였습니다.

그랬더니 임베디드 보드와 pc에 몇가지 반응이 오더군요..

아래의 내용은 진짜 마우스를 꼽았을때에 windows xp에서 usb descriptor를

분석한 내용입니다.

 

Device Descriptor:
bcdUSB: 0x0110
bDeviceClass: 0x00
bDeviceSubClass: 0x00
bDeviceProtocol: 0x00
bMaxPacketSize0: 0x08 (8)
idVendor: 0x062A
idProduct: 0x0000
bcdDevice: 0x0000
iManufacturer: 0x00
iProduct: 0x00
iSerialNumber: 0x00
bNumConfigurations: 0x01

ConnectionStatus: DeviceConnected
Current Config Value: 0x01
Device Bus Speed: Low
Device Address: 0x02
Open Pipes: 1

Endpoint Descriptor:
bEndpointAddress: 0x81
Transfer Type: Interrupt
wMaxPacketSize: 0x0004 (4)
bInterval: 0x0A

 

그리고 아래의 정보는 제가 짠 프로그램이 동작하여 pc에 등록된 정보입니다.

 

Device Descriptor:
bcdUSB: 0x0110
bDeviceClass: 0x03
bDeviceSubClass: 0x00
bDeviceProtocol: 0x00
bMaxPacketSize0: 0x10 (16)
idVendor: 0x062A
idProduct: 0x0000
bcdDevice: 0x0199
iManufacturer: 0x00
iProduct: 0x00
iSerialNumber: 0x00
bNumConfigurations: 0x01

ConnectionStatus: DeviceConnected
Current Config Value: 0x00
Device Bus Speed: Low
Device Address: 0x00
Open Pipes: 0

 

보시면 ConnectionStatus에 들어 있는 정보가 좀 틀리고 end point의 정보는 아예 없는 것을 보실수 있습니다.. 이 내용을 분석한 제 생각으로는 일단 Open Pipes의 수가 0인 것으로 보아 우선 정상적으로 연결 실패.. 가난 것으로 보이고요 end point가 없는 것으로 보아 어떤 설정또는 ep0를 통하여 세팅중에 에러가 난 것으로 보입니다...

이제 질문...( 서론이 좀 길었죠??ㅡㅜ;;;; ) 제가 아직 usb 에 대해 정확히 이해를 못해서 인지는 몰라도 usb ep0를 통하여 setup이 될때 어떤 순서로 setup이 이루어 지는지 잘 모르겠습니다. 제 생각으로는

1. host가 device descriptor를 요청하여 가져감
2. 나머지 descriptor( configure, interface )를 가져감

으로 생각이 되는데요.. 순서가 저렇게 되는 것이 맞나요?? 그리고 pipe( 제 생각에는 in/out end point )가 open되는 시점이 이 언제인지 궁금합니다.. 조금 정리해서 물어본다면.. usb device가 pc에 꽂힌 후 정상 인식 되기까지 host가 device에게 요청하는 메시지의 순서가 궁금하네요~~ 그리고 언제 pipe가 오픈이 되는 지... 도 궁금합니다~~

고수님들의 답변 기다릴게요~~
하루에 refresh만 5천번하는.. omayaro 였습니다...ㅠ0ㅠ

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

오케이.. 뭔가 삘이오는데.. 바로 앞에서 가슴속에 담아둔 그거네.. -_-; 중요한건 바로 디스크립터(descriptor) 컨피겨(configure) 인터페이스(interface) 라는 내용이 또 나온다. 어쨌거나 저쨌거나 질문자는 실패한 사람이니까 믿을게 못된다. 여기에 달린 댓글이 중요하다. 그런데.. 역시나.. 멋진 시스템 프로그래머들 같으니라구.. ㅎㅎ 직접읽어보라.. 민망하다..

--------------------------------------------------------------------------------------------------
 익명 (2007년 02월 13일 오후 10:08)

    밥은 직접 떠서 드세요.

    device 연결시점에서는 default(첫번째) configuration 으로 동작합니다.
    host 쪽에서 사용자의 요구에 의해 다른 configuration 으로 전환합니다.
    흔한 경우는 아닙니다.
    이런 방식을 사용하는 대표적인 경우는 device 쪽에 end point 가 모자랄 경우입니다.
    간혹, host쪽 사용자에게 디버깅 포트등을 숨기기 위해서 사용하기도 합니다. 
--------------------------------------------------------------------------------------------------


역시나 댓글한번 멋지게 달려있었다. 밥은 직접 떠먹어야 한다는 말. 누가 그걸 모르나. 이쯤되면 검색에 이골이 나기 일보직전이 되고 서서히 자신감도 사라지고 짜증이 섞이기 마련이다. 이때한번 refresh 가 필요한데 검색은 계속되어야 한다.. 쭈~욱.. 점점 검색하다보면 Filter Driver 에 대한 내용이 나오기도 하고 처음부터 검색이 되더라도 알아먹지 못했던 내용이 두번째 검색하다 모르고 똑같은걸 또 보게되면(즉, 본걸 나중에
또 봤을때) 이해가 되기 시작하는 부분이 생겨나기 시작한다. 바로 다음의 부분들이 그러한 부분들이라 하겠다.

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

bodnar
February 11th, 2007, 05:58 AM

I am trying to fix a part of the report descriptor on an existing USB HID device that woked fine but
has problems on Vista. It installs
and everything is OK with it but DirectX refuses to see it due to some inconsistency in the report descriptor.

I understand that I would need to write a filter driver to fix that.

I have downloaded recent WDK and looked at the samples, specifically HID\Firefly sample but I cannot figure out

how to alter

Report Descriptor data when the driver receives IRP_MN_START_DEVICE in DispatchPnP. I can see how PDEVICE_OBJECT

DeviceObject is passed

to it but mmm.. how do I get access to HID device details so I can alter it?

When I look inside HID\Vhidmini virtual HID minidriver I can see exactly what I would want to use in the
filter driver:

deviceInfo->ReportDescriptor = NewReportDescriptor;
deviceInfo->HidDescriptor.DescriptorList[0].wReportLength = ...;

I am a bit lost... Any help is appreciated.

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

미국말로 뭐라 지껄이는지 전혀 관심없다. 오로지 Report Descriptor data when the driver receives IRP_MN_START_DEVICE

in DispatchPnP 라는 문장과 다음의 소스 두부분이다.

deviceInfo->ReportDescriptor = NewReportDescriptor;
deviceInfo->HidDescriptor.DescriptorList[0].wReportLength = ...;

이 글에서 필자가 어느타임에 어디를 수정해야 할지 방향을 구체적으로 잡아나갈 수 있는 단초가 마련되기 시작한다. 즉, DispatchPnP 에서 IRP_MN_START_DEVICE 를 받았을때 Report Descriptor data 가 관계가 있다는 점이고 ReportDescriptor 를 NewReportDescriptor 로 할당하는 조작을 잡아낼 수 있다. 원래는 vhidmini 라는 Microsoft 사의 공식샘플이 어떻게 생겨먹었는지

잠시 소스 일부분을 보자면

        // Store the registry report descriptor in the device extension
        //
        deviceInfo->ReadReportDescFromRegistry = TRUE;
        deviceInfo->ReportDescriptor = RegistryReportDescriptor;
        deviceInfo->HidDescriptor.DescriptorList[0].wReportLength = 
                                   (USHORT)RegistryReportDescriptorLength;

위의 모습처럼 되어있다. 그런데 저 미국아가 한 짓은 deviceInfo->ReportDescriptor = RegistryReportDescriptor 를 NewReportDescriptor 로 바꿨다는 것이다. 그러니 필자도 역시 이 부분을 건드리게 될 것이란 소리가 된다. 그러므로 수정을 가할 부분을 한 부분 구체적으로 알아먹었다. 이 글의 맨 처음 시작부분의 Numega Soft 의 소스라고 되어있는 부분을 보자.

// The HID report descriptor for this device    
// (taken from USB/HID specification)    
   
HID_REPORT_DEscRIPTOR MouseHidReportDesc[] = {   
    0x05, 0x01, // Usage Page (Generic Desktop),     
    0x09, 0x02, // Usage (Mouse),      
    0xA1, 0x01, // Collection (Application),        
    0x09, 0x01, // Usage (Pointer),         
    0xA1, 0x00, // Collection (Physical),           
    0x05, 0x09, // Usage Page (Buttons),            
    0x19, 0x01, // Usage Minimum (01),          
    0x29, 0x03, // Usage Maximun (03),          
    0x15, 0x00, // Logical Minimum (0),
    ... 생략 ...


해당 부분을 보면 이제서야 뭔가 감이 오기 시작하게 되는 것이다.

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

드디어;;
 ·작성일     2007.01.28:15.25 (일)
· 작성자     rechoco
· 조 회     487


hid minidriver 테스트 살짝 성공~

샘플소스를 구해서 레포트 디스크립터랑 익스텐션 조금 손만 본거지만.

디바이스에서 데이터를 hid포멧에 맞춰서 주는게 아니라서..

강제로 제가 바꿔줘야 했거든요ㅋ

마우스로 테스트 해봤더니 쭉쭉 잘옮겨지더군요

물론 목표한 디지타이져는 아직 안됩니다;;
(와컴것 분석했더니 절대좌표모드일때도, 마우스 플래그를 쓰더군요
xp에서는 디지타이져가 지원이 안되니까 절대좌표 "처럼" 마우스좌표로 작업합니다.
저도 그렇게 하긴했는데. 영 개운하지가 않아서;;
디지타이져가 비스타에서는 지원 된다길래 해봤는데 실패했다는;;)

제가 참고한 샘플은 WDK의 vhidmini 소스입니다.

xp용으로 inf파일하고 소스파일 조금 수정하시면 빌드도 잘되고..

헛짓거리중에 잠깐 들러봤습니다.


드라이버 온라인님들 모두 화이팅하세요!!

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


아쉽게도 이 글은 가상 마우스인지 실제 마우스의 필터드라이버를 만든것인지 알길이 없어서 단지 말 그대로 희망만 주는 글인데 되긴 되나부다 정도로만 넘겨야 했다. 중요한 개념가닥을 잡아내는 파편과도 같은 내용들은 모두 끝났고(사실 더 많지만..) 다음의 세가지 정보의 검색이 사실상 전체적인 개념(컨셉)을 모두 얻도록 해주었다.

 

---------------------------------------------------------------------------------------------------
1. http://www.eggheadcafe.com/software/aspnet/32296449/virtual-usb-mouse-device.aspx

<Virtual USB Mouse Device only shows as generic HID device. - tomca>
08-May-08 05:16:00

I wrote a bus driver that generated virtual USB PDO for Printer, Scanner, and
SmartCard.  It worked fine before.  Recently, I was requested to provide a
virtual USB mouse PDO.  What I did was as following steps

1. An usermode application access bus driver to add a new PDO
2. bus driver use IoCreateDeviceSecure to create a new device and invalid
bus relation.
3. PNP manager found this new device, it will query the hardwareid, device
instanceid, and compatible id.
4. I provide USB\Class_03&SubClass_01&Prot_02 as compatible ID
5. System find this is a HID device and start to query Device Descriptor,
Configuration Descriptor, and HID descriptor.
6. Since this is a virtual mouse, bus driver gives HID descriptor without
hardware.  I copy a standard mouse device's HID descriptor (3button usb
mouse) to caller.
7. From Device Manager, I can see a HID device shows up,  but there is not
mouse device shows up.

If I plug in a real usb mouse, I can see system create a HID device first,
then HIDClass driver create a PDO for mouhid driver.  Is anyting wrong I did?

I have carefully checked the USB data sent to caller, everything is ok, but
system doesn't like this device as mouse,  Just consider it as generic USB
HID device.

Could someone give me help?

Thanks!
---------------------------------------------------------------------------------------------------

유저모드


---------------------------------------------------------------------------------------------------
2. KSP(www.ksyspro.org) 라는 곳에서 작성한 "USB강의자료.PDF" 라는 파일이 인터넷에서 검색되었다.
   내용의 제목은 "9차 정기 세미나 강의 자료" USB Device Driver 강의였다. 아쉽지만 원래 이런
   사이트는 문이 닫혀있다. (원래 그런거니까 이해를 해야한다.. -_-; 얼마나 힘들겠는가..? )

 - 내용이 작살이다. 이건 그냥 인터넷에서 받아서 보라.. 전체적인 개념정립이 이루어진다.
   (아마 앞서서 했던 기본적인 검색뻘짓이 없이는 읽을 수 있는 내용이 아니었으리..)

---------------------------------------------------------------------------------------------------
3. MSDN & ReactOS 소스 중의 USB 부분에 있는 Mouse 드라이버
 - 항상 마지막은 MSDN 의 승리이다. 전체적인 모든 내용이 다 들어있다. 빌어먹을 일정수준이상이
   되지 않으면 처음에 백날봐도 못알아 처먹는다는 것이 문제다. 커널이던 응용프로그래밍이던
   이건 차이가 없다. 지금도 응용프로그래밍도 못알아 먹는게 태반이니까. 어쩔수 없이 이 고생을
   치르는건 MSDN 을 보기위해서가 아닐까. (COM 프로그래밍도 MSDN 이 제일 많은 정보가 있다.)
   이 말을 증명해보겠음!!
   다음은 MSDN 의 vhidmini.h 라는 파일에 능구렁이처럼 맨 마지막 부분에 주석으로 처리되어있다.

[vhidmini.h 파일]

... 생략 ...
   
/*
//
// Here is sample descriptor that has two top level collection - mouse 
// collection and  vendor defined collection with a custom feature item. If 
// you want to provide sideband communication with your hidmini 
// driver, you can add a custom collection with the collection provided 
// by the hardware and open the custom collection from an app to 
// communicate with the driver.
// 여기 두개의 탑레벨 모음인 샘플 디스크립터가 있다.
// 커스텀 피처아이템을 가진 마우스 모음과 벤더 정의 모음이다.
// 니가 만약 너의 hidmini 드라이버를 가지고 사이드 밴드 통신을 제공하길
// 원한다면, 너는 하드웨어에서 제공되는 모음과 응용프로그램으로부터 드라이버
// 통신하는 것까지 개인모음을 추가할 수 있다.
// (역주: 즉, 몬소리냐면 이거 앞에서 선언한 DefaultReportDescriptor 대신에
//        이걸 그냥 가져다가 써라. 마우스 예제다. 이 말이나 마찬가지임.
//        여기에 니가 원하는거 추가해서 쓰라는 소리임. 이미 소스에 다 있었음.)
HID_REPORT_DEscRIPTOR           DefaultReportDescriptor[] = {
        0x05, 0x01,     //Usage Page (Generic Desktop),
        0x09, 0x02,     //Usage (Mouse),        
        0xA1, 0x01,     //Collection (Application),
        0x85, 0x01,     //REPORT_ID (1)             
        0x09, 0x01,     //Usage (Pointer),
        0xA1, 0x00,     //Collection (Physical),
        0x05, 0x09,     //Usage Page (Buttons),
        0x19, 0x01,     //Usage Minimum (01),
        0x29, 0x03,     //Usage Maximun (03),
        0x15, 0x00,     //Logical Minimum (0),
        0x25, 0x01,     //Logical Maximum (1),
        0x95, 0x03,     //Report Count (3),
        0x75, 0x01,     //Report Size (1),
        0x81, 0x02,     //Input (Data, Variable, Absolute), ;3 button bits
        0x95, 0x01,     //Report Count (1),
        0x75, 0x05,     //Report Size (5),
        0x81, 0x01,     //Input (Constant), ;5 bit padding
        0x05, 0x01,     //Usage Page (Generic Desktop),
        0x09, 0x30,     //Usage (X),
        0x09, 0x31,     //Usage (Y),
        0x15, 0x81,     //Logical Minimum (-127),
        0x25, 0x7F,     //Logical Maximum (127),
        0x75, 0x08,     //Report Size (8),
        0x95, 0x02,     //Report Count (2),
        0x81, 0x06,     //input (Data, Variable, Relative), ;2 position bytes (X & Y)
        0xC0,             //End Collection,
        0xC0,             //End Collection,

        0x06,0x00, 0xFF,   // USAGE_PAGE (Vender Defined Usage Page)     
        0x09,0x01,           // USAGE (Vendor Usage 0x01)      
        0xA1,0x01,           // COLLECTION (Application)        
        0x85,0x02,           // REPORT_ID (2)                      
        0x09,0x01,           // USAGE (Vendor Usage 0x01)              
        0x15,0x00,           // LOGICAL_MINIMUM(0)                   
        0x26,0xff, 0x00,   // LOGICAL_MAXIMUM(255)               
        0x75,0x08,           // REPORT_SIZE (0x08)                     
        0x95,0x01,           // REPORT_COUNT (0x01)                    
        0xB1,0x00,           // FEATURE (Data,Ary,Abs)             
        0xC0                    // END_COLLECTION                       
};

*/


자.. 이제 끝났다~ 라고?
한숨을 쉬기에는 너무 이르다. 대부분의 혼선과 문제점은 여기서부터 시작되기 때문이다. Microsoft 사의 WinDDK 라는 개발킷에 있는 vhidmini 샘플은 그저 샘플일 뿐이기에 정상작동이 되는지 확인을 해야하기 때문이다. 필자는 위에서 주석처리 되어있는 마우스 예제 DefaultReportDescriptor 의 주석을 풀고 기존에 있던 샘플 DefaultReportDescriptor 와 교체했다.

드라이버를 컴파일하는 방법은 여기서 설명하지 않는다. 그냥 WinDDK 설치후 프로그램 메뉴에서 XP 용 콘솔창을 열고 vhidmini 디렉토리로 이동후 nmake 명령을 내리면 컴파일이 가능한 것을 여기서 구차하게 다 설명을 할순없다. (그러면서도 벌써 설명까지 다 해주는 친절한 금자씨.. ㅎ) 이제 vhidmini 드라이버를 컴파일하고 장치를 인스톨 시키면 오른쪽 화면아래 트레이에 드라이버가 인식되었다고 뜰 것을 기대했다. 우리가 흔히 새 마우스를 USB 포트에 꽂으면 장치가 검색되었다고 뜨는걸 볼 수 있지 않은가? Human Interface Device(휴먼인터페이스장치) 어쩌구라는 메시지와 함께 잠시뒤에 마우스가 발견되었다는 식의 그런 메시지를 기대했다. 그러나 결과는 참담했고 미궁속으로 계속해서 빠져들고 말았다. 왜 그랬을까..? 비단 이 문제는 필자만의 문제가 아니었다. vhidmini 샘플 드라이버를 처음접하는 모든 프로그래머들이 모두 이같은 삽질의 미궁속에 빠져든다는 점을 검색을 통해서 알 수 있었다. 바로, MS 의 함정을 말이다.

여기서 다시 위와 같은 오류를 범해나가는 설명을 할 것이다. 어떤식으로 접근할 것인가와 얼마나 많은 뻘짓이 필요했는가에 대해서 설명할 필요가 있다고 본다. 그로인해서 얻은 것들은 상당히 많이 있다. 바로 단거리 스피드로 달리는 사람들은 놓칠수 있는 정보를 마라토너들은 두루두루 보고 달릴수 있는 것처럼 주변지식들을 충분히 얻을수 있다는 장점이 있다. 이 문서를 쓰는것 자체가 사실 기술적인 것에 너무 치우치는 쪽 보다는 학습방법을 알리는 병행효과를 얻기위한 것이기 때문에 무엇을 보았는지 지금부터 과정을 설명할 것이다.

앞서서 우리는 가상마우스를 만들기 위해서는 Virtual HID Device 를 만들수 있어야 한다는 점만 인식하고 출발했다. 완전히 지식이 전무한 상태에서 기본 골격코드마져 없는 허당상태로 시작할 수 있는 프로그래머는 아무도 없다. 이미 가상마우스 프로그램을 만들어본 경험이 있는 프로그래머라도 기본적인 코드의 골격없이 모든걸 직접 작성하는걸 기대하는건 어려운일이란 얘기이다. 그래서 우리가 앞에서 선행작업을 한 것이 바로 그 뼈대를 찾기위한 작업이었고, 숱한 오류과정을 거치며 우리가 만들 가상장치의 핵심뼈대를 발굴하고 비교 분석하여 선정하는 작업까지 마쳤다. 그리고 우리가 만들 장치에서 가장 중요한 핵심키포인트를 잡아내는 학습방법까지 소개하였다. 결론적으로 앞에서 습득한 사항들을 요약해 보자면..

1. 우리가 만드는 Virtual HID Device 는 mouse 또는 keyboard 와 혼합형태(혹은 단독일수도.. 그건 선택사항)이며 가상 USB 를 통해서 장치가 인식되어야 한다. 이 점은 프로그래밍적으로 정보를 수집하기 전에 머리속으로 구상한 내용에 속한다.(나중에 언급하겠지만 실제 설치/작동은 프로그래머의 상상과 약간 다르다.)

2. 여러 정보들을 수집하여 비교분석 한 뒤 그 중에서 vhidmini 라는 Microsoft 사의 WinDDK 개발킷 공식샘플을 채용하기로 최종결론을 내렸다.

3. vhidmini 라는 샘플을 운용하기위해 요구되는 스킬은 USB 의 HID 라는 인터페이스이며 이 인터페이스의 핵심 키포인트는 바로 Report Descriptor 라는 Descriptor 를 어떻게 기술할 것인가에 달려있다는 점을 알아낼 수 있다. 이 점은 이미 학습방법으로 어떻게 그 특징을 캣치하는지 보여주었다.

4. 우리는 최종적으로 Virtual HID Device 를 마우스로 인식시키기위해 Report Descriptor 라는 기술자(descriptor)를 찾아내야 했으며 적당한 기술자를 vhidmini.h 에서 발견하였다. 이 기술자를 Default 로 맞추고 컴파일 한 뒤 VMware 에 설치된 윈도우에서 설치하면 실제장치로 인식된다는 것까지 모두 정립하였다.
   
다음의 명령어를 이용해서 장치를 설치할 수 있다. 즉, 윈도우가 설치된 VMware 에는 vhidmini.sys 와 vhidmini.inf 그리고 devcon.exe 라는 총 세개의 파일이 복사되어야 한다. devcon 이라는 툴은 윈도우 장치관리자가 할 수 있는 모든 기능+ 를 콘솔에서 명령내릴수 있도록 해주는 커맨드유틸이다.

[설치명령]
devcon install vhidmini.inf "{D49F883C-6486-400a-8C22-1A9EF48577E4}\HID_DEVICE" 위와 같이 VMware 에 컴파일된 vhidmini 드라이버 파일들을 모두 복사한 뒤에 설치명령을 내린다. VMware 의 화면에는 신뢰를 받지못한 장치 드라이버 설치시에 뜨는 경고문구가 뜨게될 것이다. <계속> 이라는 버튼을 클릭하게되면 sys 파일을 찾지못해 디렉토리 지정창이 한번 더 뜰 것이다. 그 이유는 현 설치위치(devcon 명령어 실행디렉토리 위치) 밑에 i386 이라는 디렉토리에 sys 파일이 존재한다는 가정을하기 때문이다. 즉, INF 파일이 존재하는 위치를 기준으로 그 하위 i386 디렉토리에서 드라이버파일을 찾는다. 그래서 드라이버를 못찾는다는 창이 뜨게된다. 이건 그냥 적당히 vhidmini.sys 파일이 있는 디렉토리를 지정하면 알아서 설치가된다. 그런데.. 우리가 예상했던 설치모습이 아니었다. 그건 필자만의 착각이었을런지도 모르겠지만, 일단 이렇게 장치의 설치과정은 밍밍하게 끝나버린다. 이제 장치가 제대로 인식되었는지 확인을 하기위해 "장치관리자" 를 오픈한다. 그러면 휴먼인터페이스 장치쪽에 두가지 장치가 새롭게 추가되어있는 것을 보게될 것이다. 그런데, 뭔가 생각하던것과는 다르게 인식된 듯한 생각을 가지게 될 것이다. 그 장치는 그저 Generic HID 장치일 뿐 마우스가 아니다. 이게 도대체 어찌된 영문인가? 뭔가 잘못된 것이 있는지 확인해보고 수도없이 DefaultReportDescriptor 를 수정 해봐도 역시나 마찬가지로 마우스로 인식되질 않았다. Revert to snapshot 을 수도없이 반복하며 디스크립터 (Report Descriptor) 를 수정해도 역시나 반응은 일반장치(Generic HID) 일 뿐이었다. 정확히 말하면 VMware 기준으로 XP 에서 장치를 설치했을때 설치되는 이름은 두가지였다.

"HID 준수장치"
"Root Enumerated HID Device (sample)"
위의 두가지 장치가 설치된다. 우리가 원하는 것은 "HID 준수장치" 가 "HID 규격 마우스" 로 인식되어야만 한다. 그런데, 이런현상이 계속 지속되어 혼란이 가중될 뿐이었다. 어딘가 필자가 모르는 키포인트가 또다시 존재할 것이리라 생각하고 이 현상을 겪는 어딘가에 있을 동지에게 SOS 를 날려야 했다. 우리의 구글형님이 그러한 고충을 겪는 사람들을 모두 한자리로 집합시켜주었다. 그런데.. 구글이 불러모은 검색정보들은 하나 같이 모두 헛소리들 뿐이었다. 근접은 했어도 정답이 하나도 없는게 아닌가.. 제길.. FireFox 에서 탭을 약 20개 가까이 띄워놓고 검색에 검색을 반복하며 필자의 Report Descriptor 정보중 어디가 잘못되었는지를 찾아내기 위해서 안간힘을 쓰고 있었다. Report Descriptor 라는 것은 무엇인가? USB 라는 장치가 자기의 정보를 상위장치에 넘겨서 인식되도록 하기위한 마치 신분증과도 같은 것이다. 어디서 태어났고 어디서 자랐으며 나이는 몇살이고 남성인지 여성인지 기타등등.. 마치 이런정보처럼 인식정보를 쏘기전에 셋팅하는 값이다. 이 값이 하나라도 잘못될 경우에 장치는 절대로 제대로 인식되지 않는다. 항상 사람이 고생을 하려면 깨닫는 과정에서 착각을 일으키게된다. 필자는 vhidmini.h 파일에 있는 공식적인 마우스(예제) 디스크립터 주석을 풀어서 대체시켰다. 필자는 그 디스크립터를 믿지 못했다. 어딘가 오류가 있거나 한가지를 수정함으로
인해서 다른것까지 수정해야하는 문제점이 걸렸다거나 그런류로 생각할 수 밖에 없었다. 다음은 필자와 같은 문제점을 겪는 사람들에 대한 이야기다. 그다지 위안도 되지 않았고 결국 구글형님을 통해 문제의 정확한 해결점을 찾아낼 수 없었지만.. 그 과정에서 문득 떠오르는 영감을 주었기에 그 과정을 그려보고자 한다.

http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2007-03/msg00258.html
-----------------------------------------------------------------------------------------------------------------
thank for your advice.
i forget to assign REPORT_ID for each report desc.
It works now.
However, i migrated the corrected report to "hidfake". (Walter Oney 's sample)
The system pop up 3 "Found New Device Wizard" window and identfy it as "Unknow Device".
Any difference detween these 2 drivers' enumeration?
Appreciated.
(필자요약: REPORT_ID 를 빼먹었다. 작동된다. 그런데 hidfake 꺼를 배꼈다. 그랬더니 "알려지지않은 장치" 라는 새로운 장치로 "하드웨어 찾기" 가 세개나 뜬다. 나머지는 해석할 필요 없겠다.. 왜 그런가? 라는 질문 이라고 생각하고 넘어간다..)
-----------------------------------------------------------------------------------------------------------------
"Doron Holan [MS]" wrote:
    you only need one HID minidriver. from it, a keyboard and a mouse can
    be
    enumerated. you just have to put each device into its own top level
    collection. If you are having trouble, i would find a USB HID that already
    does this and look at its HID descriptor
(필자요약: 이놈이 다른 게시판에도 있는걸보면 좀 하는거 같다. 대충 번역하면 너는 오직 한개의 HID 미니드라이버만 필요할 뿐이다. 그리고 키보드나 마우스가 열거될수 있는 것으로 부터, 그리고 각각의 그 자신의 탑레벨 모음속에 각장치들을 넣어야만 한다. 만약 문제가 있다면, 니가 만든 USB HID 를 어쩌구 저쩌구.. 뭔가 HID Descriptor 와 연관이 있겠거니하고 그냥 넘어감..)
-----------------------------------------------------------------------------------------------------------------
I'm pretty sure you will need to break up hte device into a Mouse device and Keyboard device. (i.e two drivers,
one with a report descriptor for a keyboard and one for a mouse)
The inf files should not refer to HID\MyVirtualHidDevice - these id's need to be picked up from keyboard.inf or
msmouse.inf - idealy reporting the compatible id of HID_SYSTEM_KEYBOARD or HID_SYSTEM_MOUSE (i think)
(필자요약: 마우스와 키보드장치속에 hte 장치를 깨야할 필요가 있다라고 해석해야 하나..  이놈이 주장하는 내용은 일단, report descriptor 에 키보드와 마우스가 하나로 일치되어있는가를 확인하라는 내용과 HID\MyVirtual HidDevice 라는 장치명으로 되어있는 vhidmini.sys 샘플이 이름이 잘못되어서 그런게 아니냐는 속임수에 빠지기 쉬운 의견을 제시해 놓고 있다. 마치.. 네이버 지식인인가? 하지만 여기서 얻을 수 있는 점이 있는데 HID_SYSTEM_KEYBOARD, HID_SYSTEM_MOUSE 라는 지시어이다. 어설픈건 혼란을 가중시키는데 원래는 HID_DEVICE_SYSTEM_KEYBOARD 이고 HID_DEVICE_SYSTEM_MOUSE 가 맞는거니까 속지말자. 뒤에서 설명하겠지만 이걸 알아 듣기 위해서 새로운 개념을 습득하게 된다.)
-----------------------------------------------------------------------------------------------------------------
Hi,
I write a HID minidriver with standard Mouse and Keyboard report
descriptors.
It is based on vhidmini in Windows Server 2003 DDK.
The driver work fine and I can read/write the report from the
device.
The Device Manager shows it is HID-compliant device in HID class,
but
the
Mouse Class and Keyboard Class have none.
How should I do so that it can be a mouse device and keyboard
device?
Should I modify the INF file? My driver's INF is almost same as the
vhidmini's.
(필자요약: Windows Server 2003 DDK 로 vhidmini 를 만들었다는 식인데 장치명이 HID-compliant(일반 복합HID 장치)로 인식되는데 마우스 클래스와 키보드 클래스가 없다고 말한다. 어떻게 마우스와 키보드 장치로 인식시키는 것이냐고 물어본다. 자기가 INF 파일을 수정해야 하는지 물어본다. 그리고 INF 파일은 vhidmini 와 거의 같다고 말한다. 이 사람이 겪는 증상이 필자가 겪는 증상과 100% 일치한다. 그런데 불행히도 이 글에는 더이상의 답변이 달려있지 않았다. 눈물의 고배를 마시고 돌아서야 하는 이 저린마음.. T.T 어쩔수 없이 또다시 구글형님의 도움을 받아야한다.)
-----------------------------------------------------------------------------------------------------------------
이 질/답들에서 배운 것은 검증해봐야하는 대상들이다. 일단, HID Report Descriptor 가 잘못되었는지 검증해야하며 INF 파일이 잘못되었는지 검증해봐야하고 "한참을 헤메게 만든 요인이었지만" REPORT ID 에 대해서도 검증해봐야 한다는 몇가지 결론을 얻은채 새로운 검색활로를 모색해보게 된다. 이 검색은 첫 발을 내딘수준에 불과하다. 거의 48시간을 오로지 이 문제를 해결하기 위해서 정보들을 모아야 했다.
http://www.techtalkz.com/microsoft-device-drivers/297875-loading-driver-hid-class.html
-----------------------------------------------------------------------------------------------------------------
Loading a driver on HID class
Hi all,
I have a USB device that exposes a HID interface. It is not a mouse or
a keyboard, just a general HID device. Device Manager displays it as a
"HID-compliant device".
Now I would like to install a device driver on it and use the HID
interface to communicate with.
My INF refers the HID\VID_xxxx&PID_xxxx string and my driver gets
loaded.
So I get the PDO from AddDevice and I need the FileObject to
communicate using IOCTL_HID_SET_FEATURE and IOCTL_HID_GET_FEATURE. But
I cannot retrieve it; I use the FireFly sample and the function
FireflyOpenStack to retrieve the FileObject form the PDO but it fails
in my driver with error 0xC000000E (STATUS_NO_SUCH_DEVICE) when
calling ZwOpenFile.
What's wrong? The pdoName of the file open by ZwOpenFile is something
like "\Device\00000096". Is it possible to get the SymbolicLinkName
instead?
If someone could help...
Thanks, Roger
(필자요약: HID 인터페이스를 노출하는 USB 장치를 만들었다. 그런데 그게 마우스나 키보드가 아니네? 단지
           일반 HID 장치인거야. 디바이스 디스플레이에 보면 "HID-compliant device" 라고 표시되네.
       횽님들.. 알려주십쇼.. 뭐 이런 내용식으로 글을 써놨다. 그래도 아는게 많은 사람이라서 그런지
       정보들을 많이 뿌려놨는데 독이되는 요소들이 있지만, 덤으로 알게되는 요소들도 그 못지않게
       많다. IOCTL_HID_SET_FEATURE 과 IOCTL_HID_GET_FEATURE 에대한 얘기는(추후 구현되어야 하는 내용)
           좋은 정보임에 틀림없다. 그런데 우리가 원하는 답을 얻지는 못하고 단지 INF 파일에 VID 와
       PID 스트링이 문제의 시발점이 될수도 있지는 않은가 하는 의심을 해볼수 있다. 물론, 그게 해답은
       아니지만 추가정보를 검색해야할 키워드로써 대상물망에 넣어두자. VID 란 벤더아이디를 의미하고
       제작사의 고유식별번호이며, PID 란 프로덕트 아이디 즉, 제품번호이겠다. 이게 하드웨어는 모두
       고유하다고 하는데 과연 이 때문에 마우스나 키보드로 인식이 안되고 일반장치로 인식되는 것일까?)
-----------------------------------------------------------------------------------------------------------------
when are you trying to open a handle? during AddDevice or
IRP_MN_START_DEVICE? neither will work b/c a file create can only occur
once the start irp has come back to the pnp manager. so to make this work i
would
a) register a custom device interface GUID
b) register for device interface arrivals on your custom guid. when you
get called, open your stack like FireFly does
you will also need to register for handle notifications on the file handle
that you open so that you can gracefully disable the device. If you use the
KMDF firefly sample, the WDFIOTARGET object does this for you
(필자요약: 답변중에 하나인데 이 답변은 질문자의 추측보다 더 가관이다. IRP_NM_START_DEVICE 나 AddDevice 등록시 (필자는 커널을 몰라서 몬소린지 모르지만 이건 아니다정도의 감은 있었다.. -_-;) 하라는 식으로 답변이 달려있는데 KMDF 까지 들먹거리는걸로 봐서는 논점에서 많이 빗나갔다. KMDF 는 새로운 드라이버 개발 프레임워크인데 질문자가 그걸 물어본게 아니다. 기존의 방법으로 설명해줘야하는 것이 옳은데 그렇지도 않았고, 너무 많은 작업을 추가하라고 주문하는거보니 필자의 생각과 달랐다. 필자의 감은 Report Descriptor 만으로도 해결될 문제라고 속삭이고 있었기 때문에 이 답은 해결책이 아니었다. 다른 답변중에는 URB 를 보내라는 말도 있었다. 모두 무시한다.)
-----------------------------------------------------------------------------------------------------------------
지금 거론하는 필자의 문제해결 방법은 링크를 보여주면서 찾아나가는 방법을 설명하고 있다. 그렇기에 링크역시 필자가 검색해서 누른 순서대로 임을 밝힌다. 다음으로 찾은 것은 MSDN 의 설명이다. 그런데 MSDN 의 설명은 항상 깨달음을 얻은뒤에나 값진 보물이 되지 깨달음을 얻기전까지는 그저 잘 만들어진 명세서에 불과하다고 느낄때가 많다. 마치 선생님이 "공부하라"고 그렇게 들볶던 말들이 성인이 된 뒤에 "정답" 이라고 느끼는 것처럼 느낀뒤에만 알 수 있는 것들이 기록되어 있는게 MSDN 과도 같다. 왜 그땐 몰랐지? 왜 그땐 안봤지? 나중에 이런말 자주하게 될거다. ㅎㅎ 그런데.. 역시.. -_-; 이 링크를 보던 시점(현 글을 쓰는 시점기준으로 하루전)만 해도 이 링크는 그저 도움이 안되었다.
http://msdn.microsoft.com/en-us/library/aa487252.aspx
(필자요약: 설명이 잘 되있다. 읽어보라.. 해결책도 들어있다. 그런데 그냥보면 절대 모른다. 개고생하면 그때는 답이 보이지만 그냥보면 모른다.)
-----------------------------------------------------------------------------------------------------------------
http://www.programmer-club.com/pc2020v5/forum/ShowSameTitleN.asp?URL=N&board_pc2020=driver&id=2986
-----------------------------------------------------------------------------------------------------------------
(필자요약: 이 사이트는 중국사이트인데 읽을수가 없다. 몇가지 좋은 키워드와 코드가 있는데 해결책은 아니고 나중에 마우스나 키보드를 구현할때 참고할 만한 코드가 아주 조금 있을 뿐이었다.)
-----------------------------------------------------------------------------------------------------------------
http://www.osronline.com/cf.cfm?PageURL=showThread.CFM?link=144873
-----------------------------------------------------------------------------------------------------------------
(필자요약: 필자가 겪는 문제를 어느정도 일부분은 해결한 것 같기도하고 그렇지 않은거 같기도 한데 희한한
            삽질을 하고 있었다. Descriptor 를 계속해서 바꿔가면서 테스트하는 것을 물어보고 있었다.
        마우스와 키보드를 인식시키기 위해서 vhidmini 를 기본베이스로 디스크립터를 조작하는데 설치가
        안된다는 그런 질문이었다. 질문양이 많아서 짤라붙이기는 못하겠다. 답글을 보자.)

Adrian Schlesinger
xxxxxx@baum.ro
    
Join Date: 24 Sep 2008
Posts To This List: 7
RE: Simulate keystrokes
I have detected what was wrong:
1. When adding the report ID item to the keyboard top-level collection, an additional byte should be returned to
   the system at the beginning of the data, specifying that report ID.
2. Communication from user mode did not work because when cycling through the HID devices,
   in addition to vendor ID, product ID and version, the usage specified for the additional end point should also
   be matched (with Vendor Usage 1), otherwise you can end up trying to call WriteFile for a handle corresponding
   to the keyboard end point.
(필자요약: 질문자의 답글인데 키보드 top-level collection(최상위 모음) 에 REPORT ID 를 추가할때 어쩌구 저쩌구 얘기가 나온다. 그리고 usage 라는 말도 나온다. 필자가 원하는 답이 여기에 있을 것이라고 생각하여 엄청난 검색을 통해 알게되었는데 원하는 답은 아니었다. 단지, top-level 의 개념은 중요했다.
-----------------------------------------------------------------------------------------------------------------
http://www.techreplies.com/drivers-43/hid-minidriver-multiple-report-descriptors-543372/
-----------------------------------------------------------------------------------------------------------------
(필자요약: 앞에서 어떤사람이 한 질문과 똑같은 질문인듯 싶다. 왜 도대체 마우스로 인식이 안되냐.. 이 질문이다.)
-----------------------------------------------------------------------------------------------------------------
다음은 중요한 개념중에 하나인 Top-Level Collection 이다.
http://www.microsoft.com/whdc/archive/HID_HWID.mspx#E1
-----------------------------------------------------------------------------------------------------------------
Special Top-Level Collections (Reserved for OS use)
Certain HID top-level collections generate a special HID device string. In Windows 2000, Windows XP, and Windows
Server 2003, the top-level collections listed in Table 6 are special cased and each has an additional hardware ID.
Table 6 identifies these collections. The last column identifies the additional string that is added to the hardware
ID list.
Table 6: Special-Cased Top-Level Collections
Device Type                Usage Page    Usage ID       Additional Hardware ID
Pointer                    0x01          0x01           HID_DEVICE_SYSTEM_MOUSE         exclusive
Mouse                      0x01          0x02           HID_DEVICE_SYSTEM_MOUSE         exclusive
Joystick                   0x01          0x04           HID_DEVICE_SYSTEM_GAME 
Game pad                   0x01          0x05           HID_DEVICE_SYSTEM_GAME
Keyboard                   0x01          0x06           HID_DEVICE_SYSTEM_KEYBOARD      exclusive
Keypad                     0x01          0x07           HID_DEVICE_SYSTEM_KEYBOARD      exclusive
System Control             0x01          0x80           HID_DEVICE_SYSTEM_CONTROL
Consumer Audio Control     0x0C          0x01           HID_DEVICE_SYSTEM_CONSUMER

(필자요약: 이게 모냐면 Top-Level Collection 이라 불리우는 입력장치유형이다. 위에서 Usage Page 와 Usage ID 라는 것이 있는데 이게 바로 Report Descriptor 에 있는 항목에 적혀있다. 이걸 어떻게 바꾸느냐에 따라서 가상장치가 마우스가 되느냐, 키보드가 되느냐 아니면 조이스틱이 되느냐를 결정한다. 멋지지 않은가? 물론, 원하는 해답은 아니다. 그러나 필수적으로 개념을 갖고가야 한다. 여기서 중요한게 있다면 입력 장치의 형태가 공유(share)모델이냐 아니면 베타적모델(독점)이냐 이다. 마우스와 키보드는 독점모델이다. 즉, 마우스와 키보드는 장치가 열려있으면 다른 프로그램이 장치를 열어서 쓰고읽는 것이 불가능 하도록 secure 모델로 처리되어있단다. 이때, 이걸 피해가려면 새로운 장치를 동일하게 하나더 만들어서 그 장치와 통신하면 이런 독점모델을 피해갈 수 있단다. MSDN 에 다 나와있다.. 전부 다~ 링크가 있었는데 FireFox 가 깨져서 다 날아가 버리는 바람에 찾을수 없지만 베타적오픈과 공유오픈이 가능한 표시가 위의 Top-Level Collection 에 일일이 나열되어 있는 정보도 찾을 수 있었다. 어쨌거나 중요한건 짚고 넘어가자.. 참고로 잊지는 않았겠지? 가상장치가 일반장치로 인식되서 마우스 장치로 인식시키려고 뻘짓하다가 이런곳까지 당도하게 된거란 점.. 이렇게 정보들을 다양한 방법으로 얻어서 공부하는데도 웹서핑한다고 눈치주는 경우도 있다. x같은 경우지.. 이게 단순히 노는걸로 보여? 입에서 욕나오네.. 갑자기 머리에 히터가 작동되서 한번 지껄여봤습니다. 다시 집중모드로 돌아가봅시다.. ㅋㅋ)Table 13-1   HIDCLASS-Compatible ID for Each Supported Usage지원되는 HIDCLASS 호환 아이디.. HIDCLASS 는 각 장치로 분배를 해주는 역할을 한다고 합니다. 더 자세한건 묻지마삼 다칩니다요.. 전 아는것만 얘기할 뿐임..
http://www.microsoft.com/mspress/books/sampchap/6262.aspx

Usage Page         Usage                   Compatible ID
Generic desktop       Pointer or mouse        HID_DEVICE_SYSTEM_MOUSE
                   Keyboard or keypad      HID_DEVICE_SYSTEM_KEYBOARD
                   Joystick or game pad    HID_DEVICE_SYSTEM_GAME
                   System control          HID_DEVICE_SYSTEM_CONTROL
Consumer           (Any)                   HID_DEVICE_SYSTEM_CONSUMER

<Report Descriptor Header>
앞서서 XBCD 라고 XBOX 조이스틱 에뮬레이션 드라이버에 대해서 말한적이 있습니다.
헤더의 USAGE_PAGE 를 잘 봅시다. 그리고 USAGE 를 봅니다.
// XBCD 예
char ReportDescriptor[213] = {
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)     <-- 요건 뭐시냐? Table 13-1 입니다욤..
    0x09, 0x04,                    // USAGE (Joystick)        <-- 위의 Table 6 에 Joystick 의 Usage ID 보입니껑?
    0xa1, 0x01,                    // COLLECTION (Application)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,                    //   PHYSICAL_MAXIMUM (1)
// vhidmini.h 의 맨마지막 주석이 되어있었던 마우스예제 헤더
HID_REPORT_DEscRIPTOR    DefaultReportDescriptor[] = {
        0x05, 0x01,      //Usage Page (Generic Desktop),   <-- Table 13-1 일반 데스크탑
        0x09, 0x02,      //Usage (Mouse),                  <-- Mouse 임
        0xA1, 0x01,      //Collection (Application),
        0x85, 0x01,      //REPORT_ID (1)                   <-- REPORT_ID 꼭 이게 값이 있는지 확인해야함.
        0x09, 0x01,      //Usage (Pointer),                    HID Tool 이라는 놈은 이 값을 빼고 보여줌.(주의!)
        0xA1, 0x00,      //Collection (Physical),
        0x05, 0x09,      //Usage Page (Buttons),
        0x19, 0x01,      //Usage Minimum (01),
        0x29, 0x03,      //Usage Maximun (03),
        0x15, 0x00,      //Logical Minimum (0),
여기서 Top-Level collection 이 지칭하는 의미는 상위장치입니다. 이런식으로 다중 인터페이스를 구현할 수 있는데 예를들면 마우스와 키보드를 가상장치 하나로 일타쌍피도 만들어낼 수 있습니다. 시중에 파는 키보드 중에 마우스도 있고 USB 포트도 달려있는 키보드들은 이런 다중인터페이스를 만들기위해서는 multiple top-level collection 지정을 해줘야 한다는 얘기죠. 어쨌거나.. 이러한 정보들은 얻었고 Report Descriptor 가 잘못된 것인가라고 판단해보니 전혀 아니었습니다. 오히려 첫번째 XBCD 의 헤더모습에서는 REPORT ID 가 보이지 않는데 두번째 vhidmini.h 에서는 REPORT ID 항목도 빼먹지않고 넣었고 완벽합니다. 그런데 왜.. 대체 왜!! 인식이 마우스로 되지않고 일반장치라고 잡히는 거냐 이말이죠.. 심지어는 공식사이트에서 다운로드 받은 마우스와 키보드 Report Descriptor 를 가져다가도 해봤고 직접 하드웨어에서 뽑아낸 값을 통해서도 해봤지만 모두 인식이 안되었답니다.
-----------------------------------------------------------------------------------------------------------------
사실.. 위에서 언급한 내용은 탐색과정에서 추가로 얻어내는 개념들에 대해서 비중이 있었기에 설명을 하였습니다. 아마, 계속해서 같은 방식으로 설명하면 이 문서를 보면서 쌍욕을하게 될지도 모르기에 후다닥 빨리 접겠습니다. 다음은 제가 문제해결(일반장치를 마우스로 인식하게 만드는)을 하기 위해서 찾아다녔던 링크입니다. 더 많지만 추려서 올려봅니다.
http://coding.derkeiler.com/Archive/General/comp.arch.embedded/2008-01/msg00501.html
http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2005-03/0829.html
http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2005-03/0806.html
http://www.techreplies.com/drivers-43/minidriver-hidclass-336914/
http://www.techreplies.com/drivers-43/my-hid-mouse-how-write-data-331146/
http://www.osronline.com/DDKx/intinput/hidfunc_7oky.htm
https://www.usb.org/phpbb/viewtopic.php?t=14027&sid=b40543b8bc019ff50c70025ff1886898

(결정적인 영감을 주게된 링크는 바로 다음의 링크이고 사실, 앞에서 한번 언급했었던 링크입니다.. 정확히 말하자면 해결방법을 직설적으로 말해준게 아니라, 넌 이걸 이해해야된다라고만 코드의 일부분을 언급하고 숫가락으로 떠먹여 주지는 않겠다는 인상을 풍기는 답글이지요.. 처음에는 이걸 보고도 잘 이해를 못합니다. 저만 그런건 아닐겁니다. 어떤 질문자 중에서는 프린터, 스캐너, 스마트카드를 비롯해 각종 디바이스 드라이버를 만들었다는 이력을 밝히며 저와 같은 증상때문에 고민을 하고 있는 사람도 있었으니까요.. 제가 볼때 이건 MS 의 함정입니다. 의도하지 않은 함정말입니다.)
https://www.osronline.com/showthread.cfm?link=138652
-----------------------------------------------------------------------------------------------------------------
바로 이 답글이 눈을 뜬 사람에게만 통하는 핵심인 셈입니다.
allen zhang
xxxxxx@sina.com
    
Join Date: 22 Jul 2008
Posts To This List: 38
RE: VHidMini report descriptor(s)
see the follow source code and the ReadDescriptorFromRegistry function, You should be understand it.
deviceInfo->HidDescriptor = DefaultHidDescriptor;
queryStatus = CheckRegistryForDescriptor(DeviceObject);
if(NT_SUCCESS(queryStatus)) {
    queryStatus = ReadDescriptorFromRegistry(DeviceObject);
    .......
(필자요약: 다음의 소스코드와 ReadDescriptorFromRegistry 함수를 봐라.. 너는 이걸 이해해야할 필요가 있다.
            라고 말하며 일부 소스를 첨부했습니다. 그리고는 아무런 추가의 말도 없습니다. 장난하는것도
        아니고.. -_-; 이때 아차하고 생각을 떠올리면 이 문제는 해결됩니다. 위에서 숱하게 질문하던
        외국 개발자들도 결국에는 알아냈겠지요?)
-----------------------------------------------------------------------------------------------------------------
vhidmini 드라이버를 구동시키고 일반 HID 장치로 인식된 드라이버를 마우스 장치로 둔갑시키기 위해서는
소스를 수정해야 합니다. 바로 vhidmini.c 드라이버 소스를 수정하는 일입니다. 그것도 필자가 생각했었던
Report Descriptor 의 오류를 수정하는 것이 아니라 코드를 수정해야 합니다. 앞에서도 한번 언급했었지만
Microsoft 사의 공식 DDK 샘플소스에 오류가 있을리는 없으니까요. vhidmini.h 에 주석으로 정의되어있던
마우스 Report Descriptor 의 예는 오류가 없었습니다. 오류에 빠지도록 만든것은 바로 ReadDescriptorFromRegistry
함수에 있었습니다. vhidmini 소스를 보면 주석에 써있기를 우리는 하드코딩을 하였다라고 적혀 있습니다.
Report Descriptor 를 하드코딩 하였다는 것이지요. 그런데, 단순히 그냥 하드코딩으로 놔두지.. 더 많은걸
보여주고 싶었던지 if-else 로 두가지 처리루틴으로 나눠놓은것이 문제의 핵심이었던 것입니다. 다음의
소스를 보십시오.
-----------------------------------------------------------------------------------------------------------------
[vhidmini.c 소스에서 수정해야 할 부분]
    
 HID Report Descriptor 를 레지스트리에서 읽어들이는 코드를
 하드코딩쪽으만 처리하도록 수정함.

    deviceInfo->HidDescriptor = DefaultHidDescriptor;
    //
    // Check to see if we need to read the Report Descriptor from
    // registry. If the "ReadFromRegistry" flag in the registry is set
    // then we will read the descriptor from registry using routine 
    // ReadDescriptorFromRegistry(). Otherwise, we will use the 
    // hard-coded default report descriptor.
    //
    queryStatus = CheckRegistryForDescriptor(DeviceObject);  // 함정이 발생하는 지역
    if(NT_SUCCESS(queryStatus)){
    //
    // We need to read read descriptor from registry
    //
    // 장치를 설치할때 INF 파일에 있는 Report Descriptor 가 레지스트리에 기록되고
    // 이 부분에서 레지스트리에 기록된 Report Descriptor 를 읽어들임.
    // 그러므로 백날 헤더의 Report Descriptor 를 바꿔봤자 INF 파일에 있었던 것을
    // 읽어들이는 꼴이 되므로 항상 "일반 HID 장치"(Generic HID Device) 가 드라이버로
    // 등록될 수 밖에 없었던 것이다. 이런 제길.. 이 문제로 이틀을 꼬박 다 날렸다니..
    // Microsoft 는 반성하라~!! Microsoft 는 함정을 제거하라~!!
    // 고로 이 부분으로 빠져들지 않도록 주석처리 하라..
    queryStatus = ReadDescriptorFromRegistry(DeviceObject);
                               
    if(!NT_SUCCESS(queryStatus)){                          
        DebugPrint(("Failed to read descriptor from registry\n"));
        ntStatus = STATUS_UNSUCCESSFUL;
    }
}
else{
    //
    // We will use hard-coded report descriptor. 
    //
    deviceInfo->ReportDescriptor = DefaultReportDescriptor;
    DebugPrint(("Using Hard-coded Report descriptor\n"));
}

... 중략 ...
case IRP_MN_REMOVE_DEVICE:
    //
    // free memory if allocated for report descriptor
    //
    // 이 부분도 주석처리해야 한다. 왜냐면 레지스트리에서부터 읽어들이지 않았기 때문에
    // 메모리 할당이 안되어 있기 때문이다. 그냥 두어도 상관없을거 같지만 메모리 해제부분이니
    // 꺼림칙하므로 되도록이면 제거하길 바란다.
    if(deviceInfo->ReadReportDescFromRegistry)
        ExFreePool(deviceInfo->ReportDescriptor);
    SET_NEW_PNP_STATE(deviceInfo, Deleted);
    ntStatus = STATUS_SUCCESS;           
    break;   
-----------------------------------------------------------------------------------------------------------------
이제 vhidmini 샘플을 컴파일하고 VMware 에 vhidmini.sys 와 vhidmini.inf 파일을 복사하자. 그리고 devcon 명령으로 앞서했던 것처럼 install 을 해보자. 설치를 하고나면 장치관리자의 기존에 있던 "HID 준수장치" 라는 것은 없어지고 마우스항목에 "HID 규격 마우스" 가 추가되는 것을 볼 수 있을 것이다.(ㅎㅎ 이맛을 보려고.. 밤을새고 삽질을..) 이제.. 장치관리자에서 새로 추가된 "HID 규격 마우스" 를 선택한 뒤에 속성을 보자. 속성을 선택한 뒤 "자세히" 라는 것을 클릭한다. 그리고 장치인스턴스 ID 라는 것을 보라. HID\MyVirtualHidDevice&Col01 라고 되어있는 것을 볼 수 있다. 또한, 일치하는 장치 ID 를 선택하면 hid_device_system_mouse 라고 되어있다. 즉, 마우스로 인식이 되었다는 것이다. 가상 HID 디바이스 위에서 마우스 장치가 인식되어 있는 것이다. 이제 가상 HID 디바이스와 어플리케이션 간에 통신루틴을 프로그래밍하고 어플리케이션의 명령에따라 상위 클래스로 IRP/URB 같은 요청을 (이거참.. 이 레이어에서는 어떤 요청을 사용해야하는 건지 또 공부해야하는군.. -_-; USB 강의 문서에 보면 상위 클래스는 URB 통신을 한다고 나와있었다..) 날려주면 키보드나 마우스 같은 장치들을 에뮬레이션 시킬수 있다. 곧, 가상장치를 조종할 수 있다. 하지만? 그리 쉽지는 않을 것이다. vhidmini 샘플에는 testvhid 라는 어플리케이션 소스도 같이 들어있는데 이 testvhid 소스는 어플리케이션단에서 vhid miniport 드라이버와 통신하는 예제이다. 참고로 아무런 수정없이 샘플만 컴파일해도 어플리케이션과 드라이버 사이에 제대로 통신이 이루어지지않는다. 역시나 이 문제는 HID Report Descriptor 의 데이타의 구성문제에 속한다. 한번 고생한 것이 또다시 반복되는 시점이기도 하다. 이 부분을 해결하면 어플리케이션은 2 또는 3 가지의 top-level collection 중에서 사용자정의(User-Defined) 콜렉션을 통해서 miniport 드라이버와 통신을 할 수 있게되고 이 통신에 따라서 마우스 IRP 를 상위 클래스로 때려주면 된다. 더 자세한 내용은 스스로 연구하길 바란다. 이상으로 이번문서를 마무리하려고 한다. 왜냐면 이제 테스트 기반이 마련되었으니 나머지 추가구현은 스스로가 해야할 몫이기 때문이다. 어떠한 목적으로 개발하던간에 그 이상은 이제 필자가 관여할 부분이 아닌것 같다.

어차피 이 문서의 목적은 가상 마우스를 제작하는 것을 중점으로 삶는 것보다도 모르는 분야를 독학하며 개척해 나갈때 자신의 공부스타일의 한 예로써 제시하는 것이었다. 여기서 거론된 공부스타일을 종합해 본다면 이렇게 말할 수 있을것 같다. "관례를 찾아냄으로써 DIFF 를 추출해내는 공부법" 이라고 할 수 있다. 즉, 최대한 많은 자료들을 검색으로 긁어모은 뒤에 분리분석 작업을 통하여 동일한 부분의 반복을 찾아낸다. 찾아낸 반복내용이 있다면 결국 그 반복은 해당 프로그래밍의 관례에 속한다. 즉, 해당 관례는 몸으로 빨아들이고 차이가 나는 지점에서 기술을 흡수한다. 이런식의 반복학습을 통하여 더이상 다른 코드나 정보들을 찾아낼 수 없다고 판단이 들때 그 기술은 자기것이 된다. 필자는 유저레벨을 공부할때 항상 이방식을 택해왔다. 정보가 고갈되고 더이상 찾아낼수 없을때까지 긴시간을 할애해서 리서치를 먼저 한다. 그 뒤에 코딩으로 들어간다. 그리고 관례코드를 따른다. 그렇게되면 생전 처음보는 프로그래밍에서도 어느지점은 건드려도 되고 어느지점은 절대 건드려서는 안되는지 쉽게(? 정확히가 맞겠다) 익힐수 있다.

이제는 커널레벨 공부를시작하면서 이 고통스럽고도 지루한 공부방식을 다시 사용하고자하며 다른 사람에게 조그마한 도움이 되고자 이런 문서를 작성하였다. (같이 게임에 미쳐서 광랩하던 친구가 갑자기 URL 을 려줘서 읽어 보았더니 국가에서 인증한 기술이라는 자랑스런 인증서와 함께 뭔가를 팔고있었다. 보란듯이 대놓고 말이다. 디자인도 쌈빡해서 사고싶게 만드는 그것.. 그게 뭔지는 대충 말안해도 알겠지만.. 이 문서를 빨리 공개해야하겠다는 생각이 들었다. 원래는 문서를 다 작성해놓고도 공개하지않는 방향으로 생각을 굳혔다가 아무래도 생각이 바뀌기 시작하였다. 그 이유는 뒷부분의 부록을 보라..) 아마 이 방식으로 공부하는 사람들이 많겠지만 그렇지 않을수도 있을 것이다. 적어도 이렇게 공부할땐 뼈를 깎듯이 힘들지만 원하고자 하는 지식을 얻으면 그 지식의 깊이가 뼈속으로 스며들 것이다. 필자처럼 어떤 새로운 분야에 공부를 시작하거나 공부하는 방법을 몰라서 물어보려는 사람들이 있다면 이 문서를 읽어보라고 말하고 싶다.
 
<잡설>
필자가 만약에 커널디버깅을 잘 다뤘다면 아마도 쉽게 문제를 해결했을지도 모르겠다. 하지만 필자는 귀차니즘 때문에 커널디버깅을 좋아하지 않았고 결국, 공부도하지 않았다. (요즘들어 먹고 살라니.. 공부중이다.. -_-;) 그런데 필자는 오히려 디버거를 쓰지 않으면 않을수록 프로그램에 대한 이해도는 높아진다고 생각한다. 왜냐면 사람의 머리는 충분히 상황을 시뮬레이션 할 수 있다고 생각하기 때문이다. 에뮬레이션은 불가능하겠지만 시뮬레이션은 가능하다. 그리고 이 작업을 통해서 문제가 발생되는 지점을 캣치할 수 있다고 생각한다. 그렇게 되었을때 남보다 더 느릴지 몰라도 이해도는 훨씬더 깊이있는 굴곡을 생성해낸다고 생각한다. 어쩌면 그렇게 믿고싶은 것일지도 모르겠다. 적어도 자신은 그렇게 소신을 갖고있다. 그렇다고 커널디버깅을 배우는 것을 말리거나 도외시하라는 것은 절대 아니다. 필수적으로 갖고가야할 기술이라는 점에는 변함이 없지만 두가지를 모두 안배하는 것이 스스로에게 좀 더 풍요로운 지식을 가져다 줄 것이라는 점을 인지했으면 좋겠다는 의미이다. "Art of Hooking" 이라는 문서처럼 스스로의 깨달음을 전달하려고 쓴 문서는 아니지만 이 시간에도 같은 문제로 삽질하고있을 그들에게(아직도 정확한 답변을 보지 못한 질문자들이 인터넷에 깔려있음을.. 이미 보여줬다..) 이틀이라는 시간을 좀 더 귀중한 곳에 쓸 수 있도록 해줄 수 있다는 것은 행복한 일이라고 생각한다. 만약 누군가에게 이런 도움을 지속적으로 받을수 있었다면 본인은 솔로여야할 이유가 없었을 것이리라.. (아쉽게도 영어를 못하니 국내만이라도 도움을 받으면 좋을듯 싶다.) 참고로.. 이 문서는 주제를 인지하는 시점부터 해결과정을 도출해내는 모든 전 과정이 거의 실시간으로 쓰여졌다.. 그렇게 해야만이 이 문서의 목적인 "가상마우스" 와 "공부방법론" 두가지를 모두 전달할 수 있다고 판단했기 때문이다. 필자는 누군가 이 문서를 읽고 얻은게 있었다면 그것만으로 행복할 것이다. 하드에 처박혀 쓰레기가 된채 어느날 자신도 모르게 삭제되는 그런 정보가 아니라는 점만으로도 충분히 가치있는 것이니까..
 

[부록1: 필자가 생각하는 에뮬레이션과 시뮬레이션의 차이점]
에뮬레이션: 기계의 톱니바뀌처럼 구성요소들의 기능자체들이 모두 동일하게 작동해야 한다. (기능/작동의 동일화)
시뮬레이션: 기능자체를 동일하게 할 필요없이 입/출력되는 수치/값만 동일하면 된다. (수치/데이타의 동일화)
(필자주: 틀렸을 수도 있다. 정확하지않다. 다만, 여태까지 몸으로 와닿는 느낌자체를 말로 풀어써본 것 뿐이다.)
 
[부록2: 시중에 떠도는 물리형 Auto Mouse 탐지법]
먼저, 가상장치에 대한 것부터 언급해보고 물리형으로 넘어가겠다.

<1. 가상장치 탐지방법>
재밌는 사실이 있는데 아는 사람은 알 것이고 모르는 사람은 모를 것이다.
MSPRESS 에 보면 짜가장치(FakeDevice) 탐색법이 있다.

http://www.microsoft.com/mspress/books/sampchap/6262.aspx
-------------------------------------------------------------------------------------
HANDLE CtestDlg::FindFakeDevice()
{
    GUID hidguid;
    HidD_GetHidGuid(&hidguid);
    CDeviceList devlist(hidguid);
    int ndevices = devlist.Initialize();
    for(int i = 0; i < ndevices; ++i)
    {
         HANDLE h = CreateFile(devlist.m_list[i].m_linkname, 0,
                           FILE_SHARE_READ | FILE_SHARE_WRITE,
                   NULL,
                   OPEN_EXISTING, 0, NULL);
         
     if(h == INVALID_HANDLE_VALUE)
         continue;
     HIDD_ATTRIBUTES attr = {sizeof(HIDD_ATTRIBUTES)};
     BOOLEAN okay = HidD_GetAttributes(h, &attr);
     CloseHandle(h);
     if(!okay)
         continue;
     
     if(attr.VendorID != HIDFAKE_VID ||
        attr.ProductID != HIDFAKE_PID)
         continue;
     return CreateFile(devlist.m_list[i].m_linkname,
                       GENERIC_READ | GENERIC_WRITE, 0, NULL,
               OPEN_EXISTING, 0, NULL);
    }
    return INVALID_HANDLE_VALUE;
}
-----------------------------------------------------------------------------------------
위의 짜가장치 탐색법은 골때리게 단순하다. 결국에는 HIDFAKE_VID 와 HIDFAKE_PID 를 체크하는 개념이다. 즉, 제작사(Vendor ID)와 제품번호(Product ID)를 가지고 짜가인지 판별하겠다는 개념이다. 그렇다면 제작사와 제품번호는 속일수 없다고 생각하는가? 커널을 뒤짚어 엎는(Subvert) 판국에 저렇게 단순하게 비교해서는 가상장치를 막을수 없다. 위의코드를 보고 판단을 하길 가상장치는 다 막겠다고 판단한다면 정말 큰일이다. 어처구니 없는 싸움이 키보드보안이래 또 발생할 것이기 때문이다. 위의 코드가 의미하는 바를 잘못해석하면 안된다. 위의 코드는 이렇게 해석해야 한다. 그 어떠한 가상장치를 막을수 있다는 컨셉하에 위의 코드를 만들길 시도한것이 아니라 고정장치를 알아내기위해 만들어진 컨셉이라는 점을 말이다. 단지 정형화 되어있는 즉, 고정되어있는 상태에서는 가능할 수 있겠다. 이해를 돕기위해 예를한가지 들어보자. VMware 같은 가상머신 안에서 작동하는 것인지 정도는 파악할 수 있지 않을까 싶다. 왜냐면 VMware 가 동적으로 제작사와 제품번호를 바꿔야할 까닭이 없지않은가? 다르게 말하면 VMware 가 굳이 자기 제품정보를 굳이 속이거나 변덕스럽게 수시로 바꿔야할 필요가 전혀 없다는 얘기다. 이런경우에는 마치 하드웨어처럼 고정장치로 봐도 무방하다. 고로 VMware 에는 항상 고정된 장치가 있다고 판단해도 될 것이며 VMware 안에 구현된 장치들 중에는 가상장치들이 있으므로 항상 디텍트 할 수 있단 얘기가 되므로 위의 짜가장치 탐색법은 그러한 경우에 사용할 수 있는 컨셉이라는 소리다.

아직 더 깊이 연구해보지는 않았지만 가상장치와 전쟁을 선포할 경우에 또 하나의 "키보드보안" 같은 파국으로 치닫기에 좋은 스토리가 탄생할 것이다. 차라리 이것을 좀 더 유용한 곳에 사용해보면 어떨까? 바로!! 물리형 Auto Mouse 를 탐지하는 것이다. 기술은 적합한 곳에 쓰라고 있는 것이지 말도안되는 헛다리 싸움에 쓰라고 존재하지 않는다. 기술을 적용시킬때는 단순히 눈과 머리로만 판단하지말고 포괄적인 정황을 바탕으로 자신의 가슴속에 확신이 설때 비로소 본격적인 전쟁에 들어가야 한다. 그저 돈이된다고 키보드보안처럼 너도나도 발담궈놓고 아무도 책임지지않고 아무도 발도 못빼는 승자없는 싸움에 휘말리기 싫다면 필히 이 말을 웃어넘기지 말아야 할 것이다.(아마, 이젠 더이상 발을 빼지도 못할것이다.. 담구지 말라고 뜯어말려도
담궜으니 해야할 일은 그저 땜빵밖에 뭐가 더 있겠는가.. ㅉㅉ)
-----------------------------------------------------------------------------------------

<2. 물리형 Auto Mouse 탐지>
물리형 Auto Mouse 를 탐지하는 것의 기본바탕은 앞서 짜가장치 탐색에 사용된 코드를 그대로 채용하면 되겠다. 단, 제작사와 제품번호만이 아닌 추가정보를 이용할 필요가 있겠다. 그런데, 왜 효용성이 물리형 Auto Mouse 를 탐지하는 것에 효력이 있을까? 그 이유는 간단하다. 다음과 같은 정보를 보자. 필자는 최근에 오픈된 MMORPG 온라인 게임의 Auto Mouse 를 구매해보았다. 과연 어떻게 돌아가는지 궁금증도 있었고 진짜 완벽하게 구동이 되는것인지 두눈으로 확인해보고 싶었기 때문이었다. 그런데 일단, 한군데의 제품은 구동이 제대로 안되는 것을 확인하였다. 다만, 마우스 입력이나 키보드 입력은 그대로 게임속으로 전달되고 있다는 점에 주목하였다. 과연 그러한 것을 어떻게 탐지해낼 수 있을까? 다음은 USB View 라는 프로그램으로 Auto Mouse 장치의 Descriptor 를 본 화면이다.

<Auto Mouse HID Descriptor>
"USB Composite 장치"
-----------------------------------------------
Device Descriptor:
bcdUSB:             0x0200
bDeviceClass:         0x00
bDeviceSubClass:      0x00
bDeviceProtocol:      0x00
bMaxPacketSize0:      0x20 (32)
idVendor:           0x03EB (Atmel Corporation)
idProduct:          0x4743
bcdDevice:          0x1000
iManufacturer:        0x01
0x0409: "ATPLAY"
iProduct:             0x02
0x0409: "ATPLAY PRO8"
iSerialNumber:        0x03
0x0409: "1.0.0"
bNumConfigurations:   0x01
... 생략 ...
-----------------------------------------------
그렇다. idVendor 가 제작사이고 idProduct 가 제품번호이겠다. 이 정보는 필자가 예상컨대 고정이라 할 수 있다. 일단, 텍스트를 주의깊게 보자. "Atmel Corporation" 이 보이는가? 해커들이 가장 많이 사용한다는 그 유명한 "Atmel" 칩이 사용되었다. 일명 FPGA 칩이라고 불리운다. 이 FPGA 칩은 프로그래밍 가능한 이점이 있다.

(사견: 언제부터 마우스가 Atmel 칩으로 제작되었던가? 그래서 오토마우스가 그리도
       비싼거였나보다.. 싸구려 PIC 칩만으로도 마우스를 만들수 있다. 전자업계는
       원래 원가전쟁을 벌이는 계통이라서 단 1원이라도 원가를 절감해 보려고
       깎고깎고 전쟁을 벌인다. 필자의 친구가 전자회사 CEO 라서 이점은 매우 잘
       알고있다. 그 친구의 말을 빌어보자면 진짜 1원갖고 쪼잔하게 굴 수 밖에
       없다고 한다. 살아남아야 하니까 말이다.. 그런데 FPGA 칩을 쓰는 것을 보면
       좀 수상하다. 왜 재프로그래밍이 가능한 칩을 쓰는 것인가.. 재수없으면 기타장치
       메모리스틱 리더기같은 것들이 연결되어 있을수도 있으므로 함부로 판단하기는
       이르지만 아마도 대량유통되는 칩이 아닌 DIY(사제품)칩을 쓴다는 것은 기정
       사실이라고 추측할만 하지않은가? 필자가 대에충 찾아보니 Auto Mouse 제작사
       두군데가 Atmel 칩을 사용하고 있었다.)

만약 이 Atmel 칩이 필자가 아는 것과 달리 재프로그래밍이 가능한 기능이 없다면 게임업계에서는 대박의 찬스를 잡은 것이리라.. 왜? 고정이잖은가? 고정!! 또, 재미난 정보를 볼 수 있는데 바로 그 유명하다고 하는 "ATPLAY" 라는 마크가 찍혀있다. 아주 그냥 상호를 갖다가 박아놓은거보니 장사할 생가이 없다하겠다.
일단, 칩이 Atmel 칩으로 제작되어있는 USB 형 물리장치들을 사용하는 사용자는 모두 감시대상순위로 집어넣어도 십중팔구는 맞아떨어질 것이다. 특히나 Atmel 칩에 상관없이 상호명 ATPLAY 가 박혀있다면 그 사용자는 거의 Auto Mouse 를 사용하고 있을 확률이 99.9% 라고 할 수 있겠다. 그리고 USB View 같은 프로그램이 사용하는 루틴들은 위에서 언급된 루틴들에서 크게 벗어나지는 않을테니 쉽게탐지할 수 있다고 감히 추측해본다. 딱한가지 우려되는 사항이 있다면 프로그래밍 가능한 칩이기 때문에 업데이트 기능으로
펌웨어를 갈아치울 경우에 난감하게 될 것이다. 하지만 방금 언급한 방식을 사용한다면 Auto Mouse 제작사의 미래고객이 아닌 현재 고객들은 99.9% 가 탐지된다고 봐도 무방할 것이다. 물론, Auto Mouse 의 종류별로 이짓을 해야겠지만.. 프로그래머들의 습성상 모두 식별자를 기록해놓았을테니(아마, Atmel 칩에 코딩을 의뢰하거나 혹은 Atmel 칩에 프로그램이 가능한 사람을 영입했겠지만 프로그래머들이 그런거 생각안한다. 왜냐면 원리원칙을 따르려는 프로그래머의 심리상 바보같이 위에처럼 ATPLAY 를 박는게 미덕으로
생각할 것이기 때문이다.) 행동만 빨리 취한다면 현재 Auto Mouse 사용자들의 태반은 모두 다 탐지해낼 수 있을 것이라고 감히 판단해본다. 즉, 물리형은 고정이라는 변수를 잘 활용할 수 있기에 탐지도 비교적 수월한 편에 속한다는 것이다. 한가지 더 재미난 상상을 해보자.. 과연 Auto Mouse 업체에서 펌웨어 업데이트 기능을 추가로 만들어내는데 얼마나 시간이 걸릴까? 누가 더 대응이 빠를까..? 과연 이 전쟁에서 Auto Mouse 업체의 대응이 빠를까? 아니면 막는자의 대응이 더 빠를까? 아마도 덩치가 작은쪽이 더 빠르겠지만 두고볼 일일 것이다. 이 전쟁은 어느한쪽의 시간전쟁일 뿐이다.. 정확하고 빠른판단이 내려지면 그대로 바로 행하는 쪽이 이기는 것이다. 현재로써 본 필자의 생각으로는 물리형 Auto Mouse 는 막을 수 있다. 이 문서가 나온 시점 앞으로가 문제이다.. 점차 Auto Mouse 는 가상마우스로 진화를 꿈꾸고 있기 때문이다. 그것이 바로 기술의 대세인 것이다. 오늘의 기술이 내일의 쓰레기가 되어버리는 시대에서 속도전의 중요함이다. 승자는 과연 누가 될까? 아무도 모른다.. 기술은 끝이 없으니까.. 마이 골치아픈 것이다.. -_-; 어디까지나.. 필자 개인이 현 상태를 진단해본 사견일 뿐이다. 이 이상 어케 더 판단하랴..

[HID Descriptor Tool]
USB.ORG 공식 사이트에서 받을수 있음
http://www.usb.org/developers/hidpage#HID%20Descriptor%20Tool
(위에서 언급한 사이트 이외 참고한 사이트)
http://kkamagui.tistory.com/485
http://www.keil.com/forum/docs/thread13037.asp


"};   
   
HID_DEVICE_ATTRIBUTES DeviceAttributes = {   
    sizeof(HID_DEVICE_ATTRIBUTES),     
    MY_VENDOR_ID,   
    MY_PRODUCT_ID,   
    VERSION_NUMBER   
    };

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

위와 같이 HID_REPORT_DEscRIPTOR 라는 것을 볼 수 있는데, 처음에는 이게 뭔지 모른다. 감도 안온다. 그러므로 그 관점을 그대로 두고 다음으로 넘어가서 다른 소스들을 보자. (처음엔 원래 모르겠지.. 나만그런가.. -_-; 제길..)

인터넷에서 검색하면 위의 소스와 MSDN (Microsoft 사의 공식샘플과 설명문서) 을 먼저 보게 될 것이다. 그러면 당연히 vhidmini 라는 것도 접하게 된다. 소스는 인터넷에서 파는 놈들도 있으니 그냥 찾기는 좀 짜증이 날 것이다. Microsoft 사의 홈페이지에서 WinDDK 를 받으라. 그 안에 VHidMini 라는 샘플이 들어있다. 그놈을 보면 다음과 같이 생겨먹은 부분에 주목하자.

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

        if (NT_SUCCESS(ntStatus)) {
            //
            // Use default "HID Descriptor" (hardcoded). We will set the 
            // wReportLength memeber of HID descriptor when we read the 
            // the report descriptor either from registry or the hard-coded 
            // one.
            //

            deviceInfo->HidDescriptor = DefaultHidDescriptor;

            //
            // Check to see if we need to read the Report Descriptor from
            // registry. If the "ReadFromRegistry" flag in the registry is set
            // then we will read the descriptor from registry using routine 
            // ReadDescriptorFromRegistry(). Otherwise, we will use the 
            // hard-coded default report descriptor.
            //

            queryStatus = CheckRegistryForDescriptor(DeviceObject);

            if(NT_SUCCESS(queryStatus)){
                //
                // We need to read read descriptor from registry
                //
                
                queryStatus = ReadDescriptorFromRegistry(DeviceObject);
            
                if(!NT_SUCCESS(queryStatus)){
                    DebugPrint(("Failed to read descriptor from registry\n"));
                    ntStatus = STATUS_UNSUCCESSFUL;
                }

            }

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

Microsoft 에서 MSDN 의 설명을 먼저 읽어본 뒤 위의 소스주석부분을 보자. 다음과 같이 친절하게 설명해주고 있다.

            // Check to see if we need to read the Report Descriptor from
            // registry. If the "ReadFromRegistry" flag in the registry is set
            // then we will read the descriptor from registry using routine 
            // ReadDescriptorFromRegistry(). Otherwise, we will use the 
            // hard-coded default report descriptor.

설명에 써있듯이 자기네는 그냥 하드코딩 했으니까 ReadFromRegistry 를 참고하면 다른 디바이스를 등록할 수 있단다. 처음 접할땐 사전지식이 없기에 "이게 뭔 개소리야?" 라고 생각이 들 것이다. (? 반응이 없으면 나만그런거 같다.. ㅎ)

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

그렇다면 이제 개소리는 집어치우고 다음을 보자.

-->  https://www.osronline.com/showthread.cfm?link=138652

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

Radly
xxxxxx@daryllee.com

This being my first driver project, and an unusual one at that, there's a lot to get my
head wrapped around. My intent is to produce a virtual HID device (mouse emulation) that
uses a complex non-HID physical device as the input medium. I'm using the VHidMini sample
from the WDK hid folder as a starting point, and I'm now at the point where I need to transform
the sample's report format into a mouse format. I notice with confusion that the report descriptor
in vhidmini.inf is different from that in vhidmini.h, with no explanation in vhidmini.htm as
to why they are different. Does anyone here have any insight on that?


어떤 놈이 필자가 생각하는 것과 동일한 구현을 해볼려고 삽질중에 무시무시한 고급개발자들과 해커들이 몰린다는 osronline 에 질문을 던져놓고 있다. 이 소리는 무엇인가? 필자도 결국 저 문제에 봉착하게 될 날이 온다는 시나리오를 미리 발견한 것이다. 그러므로 주의 깊게 읽어볼 필요가 있다. 여기서 얻어낼 수 있는 정보는 sample's report format 이란 것과 report descriptor 라는 두가지 내용이다. 원래부터 찾기힘든 정보들에는 동문서답 내지는 "내가 니 밥처먹는데 밥숫가락으로 퍼먹여주랴?" 정도의 댓글이 달리는데 그래도 이 글의 답글중에 괜찮은 답글이 있다. 근데.. 여전히 찾기힘든 정보만큼이나 짤막하게 달아놓는다. 이런사람이 있다는 것은 희망이고 곧 빛이다. 다음의 답글을 읽어보자.

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

allen zhang
xxxxxx@sina.com
RE: VHidMini report descriptor(s)

see the follow source code and the ReadDescriptorFromRegistry function, You should be understand it.

deviceInfo->HidDescriptor = DefaultHidDescriptor;
queryStatus = CheckRegistryForDescriptor(DeviceObject);
if(NT_SUCCESS(queryStatus)) {
    queryStatus = ReadDescriptorFromRegistry(DeviceObject);
    ...

 

입에서 욕은 나온다. 왜? 말할라면 다 말하던가 아니면 동문서답이나 하고 가던가 감칠맛나게 소스 네줄 뿌리고 튀다니.. 그래도 고맙다. 지식을 갈구하는 자에게는 이것조차 선물이다. 제길.. 현자라면 푸념할때가 아닌거 같다. 여기서 뭔가 개념을 잡을 수 있는 정보를 캣치해야만 한다. 이 글에서 외국아가(짱개류 외국애인지 allen zhang 이구나.. 역시 중국은 AUTO 에 강한가보다..) 말하기를 소스코드를 보란다. 그 안에 ReadDescriptorFromRegistry 를 보라고 권하면서 일부 소스를 긁어서 보여준다. 글은 짧지만 분명 소스를 열어봤기에 긁어서 붙여줬을테니 아쉬워도 고마운 행동이다.

여기서 보라고 한 소스가 바로 위에서 VHidMini 샘플의 일부분이라고 뿌린 부분이다. 즉, 이 부분의 내용은 최초 질문자의 글에서 캣치한 sample's report format 와 report descriptor 라는 부분에대한 응답이다. 즉, 이 함수의 이름으로부터 알 수 있듯이 레지스트리로부터 디스크립터를 읽어들인다는 것에 바로 Virtual HID Mouse 의 핵심구현이 얽혀있다는 것을 시사한다는 점을 알 수 있다. 그런데 필자도 단지 이두개만 가지고 감을 잡지는 못했다. 왜냐면, 커널을 깊이 공부한 적이 없는 사람이 이 두가지의 자료만을 토대로 감을 잡아낼 수 있겠는가? 그렇다면 그건 천재이거나 영어를 모국어처럼 잘하는 사람일게 분명하다. 필자는 남보다 항상 두배로 삽질을 하는데 머리가 남들보다 딸려서 그렇다. 자료도 항상 두배로 찾아야 한다. 결정적으로 힌트가 되었던 것은 역시 국내사이트인데 드라이버 개발정보를 알려주는 곳인 driveronline.org 에서의 힌트와 임베디드 계통의 KELP 사이트에서 였다.

http://driveronline.org/bbs/view.asp?tb=beusb&GotoPage=1&s_bulu=memo&s_key=pnp&no=1491
-------------------------------------------------------------------------------------------------------------

Re] Re] Re] USB 가상 키보드, 마우스 드라이버
·작성일     2007.10.02:10.40 (화)
· 작성자     Woof
· 조 회 605

pnp 를 이용해서든지 해서 가상적인 usb 장치가 인식이 되면 일반적인 usb 장치를 다루듯이 이용하시면 됩니다. 일반적으로 실제 장치들은  Windows에서 제공하는 기본적인 드라이버로도 동작하기 때문에 필요가 없지만 이와 같은 경우에는 간단하게 자기 드라이버를 열어서 인식된 장치 device와 통신하는 드라이버 정도는 필요하겠지요. 뭐, usb라서 따로 드라이버없이 application으로도 충분히 가능한건데 다들 위와 같은 방법을 이용하더군요. 새로나온 umdf 등을 이용하면 더 간단하고 새로나온 것에 대한 공부도 하면서 재미나게 할 수 있을지도 모르겠네요. 위 에서 말한 대부분의 경우 라고 한 것의 예를 간단히 들어보면 자신의 드라이버를 올리고 해당 드라이버에서 application과 통신 device를 생성한 뒤에 pnp를 이용해서 가상적인 usb 장치를 만들고 그것과 통신하는 길?을 적당히 만들어서 이용하시면 됩니다. sample에서는 가상적인 장치 인식이 바로 usb나 그런 부분이 아니였던 것 같은데 적당히 고치면 되겠지요.

위에도 썻지만, 잘 찾으면 다 만들어진 코드 어디 있을 것 같습니다. 저도 한번 찾으려다가 그냥 sample에 있어서 말았는데. :|  해당 usb 드라이버를 이용해서" 라는 부분에 대해서 물어보셔서 이 부분만 따로 답을 달면 해당 usb device를 제어(control)하는 드라이버를 지칭했습니다.  또 처음에 말한 것 처럼 class관련 드라이버에 대해서는 생각할 필요가 없습니다. 역시 위에 쓴 것 처럼 어디에 쓰실지 궁금하네요. 가상 키입력등은 S/W나 그런 자동화 테스트에 이용하기도 하고 꽤 여러군데서 쓰기는 하는데 안좋지는 않지만 뭐 . 그런데도 쓰여서 :|

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


최초 질문자가 어떻게 구현해야 하냐고 질문하자 pnp 를 통해서 가상적인 usb 를 인식시킨 다음에 적당히 device 와 통신시키라고 한다. 자세한 내용은 말해주지 않고 Microsoft 에서 제공하는 샘플로도 구현이 가능할 것이라는 내용과 어딘가에는 이미 다 만들어진 소스가 있을텐데 찾아보라고 한다. 이말 믿고 인터넷에서 찾아헤메다가는 마누라가 집나가도 모를것이다. 답변에서 보듯이 이 사람은 진짜 적당히 답글을 달고 있는 사람이라는 점을 주의해야 한다.

이 사람의 힌트와 통찰력이 Microsoft 사의 샘플에서 존재하는 핵심이라는 점을 알 수 있다. 일단, 정보는 머리속에 꼬깃꼬깃 담아두고 계속 다음 검색으로 넘어가면서 본인의 마음속에 답이 한가지로 수렴되도록 정보들을 계속 얻어 내어보자. 이쯤되면 정상적인 사이트를 뒤지는 것이 힘들어진다. 왜냐면 너무 정보가 부족하기 때문이리라. 고로 컨트롤러를 제어하는 것을 찾아본다. 예를들면 USB HID 조이스틱 드라이버 같은 것을 찾아내는 것이다.

다음과 같은 좋은 예가 있었다.

http://www.redcl0ud.com/files/XBCD_all_src.cab

XBOX 의 6축 조이스틱 패드를 윈도우에서 사용할 수 있도록 해주는 소스였다. 검색을 할때는 기존에 얻었던 소스에서 일부 특이하게 보일만한 함수를 키워드로 검색하면 운좋게 찾을 수 있다. 소스를 보면 너무 길고 난해하고 이해하기 힘들뿐이다. 당연히 커널관련 지식이 깊지않은 이상 어떻게 분석하고싶어도 그럴 도리가 없다. 그러므로 파일구성을 보는 것이 전부이다. 여기서 또한가지 힌트를 얻을 수 있다.

XBCD_control.c
XBCD_driver.c
XBCD_driver.h
XBCD_hid.h
XBCD_report.h

위와 같은 파일구성에서 driver 나 control 소스를 보기전에 report 라는 눈에 띄는 놈이 있다. 이 헤더파일의 내용을 보게되면 다음과 같은 것이 적혀있다.

-------------------------------------------------------------------------------------------------------------
char ReportDescriptor[213] = {
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x04,                    // USAGE (Joystick)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,                    //   PHYSICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x01,                    //   USAGE (Button 1)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x02,                    //   USAGE (Button 2)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x03,                    //   USAGE (Button 3)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x04,                    //   USAGE (Button 4)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x05,                    //   USAGE (Button 5)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x06,                    //   USAGE (Button 6)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x07,                    //   USAGE (Button 7)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x08,                    //   USAGE (Button 8)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x09,                    //   USAGE (Button 9)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0a,                    //   USAGE (Button 10)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0b,                    //   USAGE (Button 11)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0c,                    //   USAGE (Button 12)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x75, 0x04,                    //   REPORT_SIZE (4)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x81, 0x01,                    //   INPUT (Cnst,Ary,Abs)
    0x75, 0x10,                    //   REPORT_SIZE (16)
    0x16, 0x01, 0x80,              //   LOGICAL_MINIMUM (-32767)
    0x26, 0xff, 0x7f,              //   LOGICAL_MAXIMUM (32767)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x7f,              //   PHYSICAL_MAXIMUM (32767)
    0x05, 0x01,                    //   USAGE_PAGE (Generic Desktop)
    0x95, 0x02,                    //   REPORT_COUNT (2)
    0x09, 0x30,                    //   USAGE (X)
    0x09, 0x31,                    //   USAGE (Y)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x02,                    //   USAGE_PAGE (Simulation Controls)
    0x95, 0x02,                    //   REPORT_COUNT (2)
    0x09, 0xba,                    //   USAGE (Rudder)
    0x09, 0xbb,                    //   USAGE (Throttle)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x01,                    //   USAGE_PAGE (Generic Desktop)
    0x09, 0x39,                    //   USAGE (Hat switch)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x07,                    //   LOGICAL_MAXIMUM (7)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0x3b, 0x01,              //   PHYSICAL_MAXIMUM (315)
    0x65, 0x14,                    //   UNIT (Eng Rot:Angular Pos)
    0x75, 0x04,                    //   REPORT_SIZE (4)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,                    //   PHYSICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0d,                    //   USAGE (Button 13)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0e,                    //   USAGE (Button 14)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0f,                    //   USAGE (Button 15)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x10,                    //   USAGE (Button 16)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x00,              //   PHYSICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, 0x03,                    //   REPORT_COUNT (3)
    0x05, 0x00,                    //   USAGE_PAGE (Not Defined)
    0x09, 0x00,                    //   USAGE (Undefined)
    0x09, 0x01,                    //   USAGE (Undefined)
    0x09, 0x02,                    //   USAGE (Undefined)
    0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
    0xc0                           // END_COLLECTION
};
-------------------------------------------------------------------------------------------------------------

그리고 이 홈페이지에서 최대한 얻을 수 있는 것은 다 캣치해야 하는 http://www.redcl0ud.com/xbcd.html 홈페이지의 마지막쯤에 보면 http://www.redcl0ud.com/files/USBView.cab 라는 것이 있다. 그리고 캡춰사진이 있는데 핵심사항으로 체크를 해둔 부분이 있다. idVendor, idProduct 라는 부분에 체크를 해두고 있다. 그리고 USBView 에서 보여주는 내용이 모냐면 바로 Device Descriptor 였다. 오호라.. 내친김에 이 사이트에서는 USB 드라이버를 제작하는 방법까지 설명하는 링크를 걸어두고 있었다.

http://euc.jp/periphs/xbox-controller.en.html

이 링크인데 제목은 "Inside XBox Controller" 라고 되어있다. 대충 무슨내용이 있는지 열거하자면..

-------------------------------------------------------------------------------------------------------------
<Inside Xbox Controller>
...

<Overview>
...

<USB Device Model>
...

<Descriptors>

Here are descriptor dumps of the hub, the gamepad and the memory unit.

    * Descriptors of the integrated hub
    * Descriptors of the gamepad (American)
    * Descriptors of the memory unit

<Vendor/Product IDs>

The vendor ID is 0x045e (Microsoft). Product IDs are as follows:
ID    product
0x001c    integrated hub
0x0202    gamepad (American)
0x0280    memory unit
0x0284    DVD remote receiver
0x0285    gamepad (Japanese)

It is not recommended to distinguish Xbox gamepads by vendor/product IDs because third-party controllers may
have their own vendor/product IDs.

<Device Class>
...

<HID Report Format>
Input Report
The input report is 20-byte.
헤더그림

Output Report
The output report (rumble control) is 6-byte. 
헤더그림

<Example of HID Report Descriptor>
The Xbox gamepad lacks the HID report descriptor that describes the input/output report formats. Based on the
above report formats I have tried writing the report descriptor for your information. This is a mere example;
neither official nor verified. Accuracy is not guaranteed.

    * Text format
    * Binary format
    * HID Descriptor Tool format (to be loaded into HID Descriptor Tool) 
---------------------------------------------------------------------------------------------------------------

위와 같은 내용들이 있었다. 상당히 많은 삘을 주고있다. 누가봐도 HID Descriptor 와 HID Report Format 그리고 Input Report 와 Output Report 를 통해서 통신한다는 아주 기본적인 컨셉(개념)은 머리가 아니라(T.T) 가슴에 와닿을 것이다. (젠쟝.. 가슴에만 담아두마.. -_-;) 일단, 이쯤에서 XBCD 소스는 닫아둔다. 언제 이거 분석하고 앉아있는가.. 최종컨셉이 다르기 때문에 힌트만 뽑아먹고 닫아두는 것이다. 애초에 만들려고 한건 Virtual HID Mouse 인데 이건 그 컨셉이 아니기에 대충 훑어보고 넘겨야 한다. 또 다른 소스들을 보자. 마구잡이로 검색하면서 받아둔 소스중에 앞에서 처음에 말했던 hidmouse 라는 소스를 한번 진단해보자.. -_-;

(PIC 를 이용한 마우스 제작소스)
파일을 열어보니 원하는게 아닌듯 보였는데 알고보니 PIC 용이었다. 운 좋게도 필자는 PIC18x 롬라이터를 갖고 있어서 이 소스가 뭔지 알 수 있었다. 오래전에 친구의 부탁으로 PIC18x 칩에 어셈블리를 롬라이팅 하는 프로그램을 만들어준 적이 있어서 무슨 소스인지 금방 알 수 있었다. 요새는 PIC 프로그래밍에도 C 가 쓰이고 PIC 는 PLC 대체용으로 쓰이기도 한다. 그런데 PIC 로 USB 모듈을 부착하고 마우스로 제작이 가능한거 같았다. 어쨌거나 원하는 내용은 아니었지만 생각해보면 가장 중요한 것이 물리적인 장치 아닌가? 물리적인 장치에서는 기존에 찾은 소스들이나 검색내용들과 어떤 차이가 있는지 알아볼 필요도 있다.
http://www.pudn.com/downloads128/sourcecode/comm/detail543439.html

hidmouse 라는 소스에서 파일구성을 보면 특이한 놈이 있다.
usb_descriptors.c 라는 소스가 있는데 여태까지 눈여겨왔던 descriptor 라는 단어가 보일 수 밖에 없다.

-------------------------------------------------------------------------------------------------------------
/* Device Descriptor */
ROM USB_DEVICE_DEscRIPTOR device_dsc=
{
    0x12,    // Size of this descriptor in bytes
    USB_DEscRIPTOR_DEVICE,                // DEVICE descriptor type
    0x0200,                 // USB Spec Release Number in BCD format
    0x00,                   // Class Code
    0x00,                   // Subclass code
    0x00,                   // Protocol code
    USB_EP0_BUFF_SIZE,          // Max packet size for EP0, see usb_config.h
    MY_VID,                 // Vendor ID
    MY_PID,                 // Product ID: Mouse in a circle fw demo
    0x0003,                 // Device release number in BCD format
    0x01,                   // Manufacturer string index
    0x02,                   // Product string index
    0x00,                   // Device serial number string index
    0x01                    // Number of possible configurations
};

... 중략 ...

//Class specific descriptor - HID mouse
ROM struct{BYTE report[HID_RPT01_SIZE];}hid_rpt01={
    {0x05, 0x01, /* Usage Page (Generic Desktop)             */
    0x09, 0x02, /* Usage (Mouse)                            */
    0xA1, 0x01, /* Collection (Application)                 */
    0x09, 0x01, /*  Usage (Pointer)                         */
    0xA1, 0x00, /*  Collection (Physical)                   */
    0x05, 0x09, /*      Usage Page (Buttons)                */
    0x19, 0x01, /*      Usage Minimum (01)                  */
    0x29, 0x03, /*      Usage Maximum (03)                  */
    0x15, 0x00, /*      Logical Minimum (0)                 */
    0x25, 0x01, /*      Logical Maximum (0)                 */
    0x95, 0x03, /*      Report Count (3)                    */
    0x75, 0x01, /*      Report Size (1)                     */
    0x81, 0x02, /*      Input (Data, Variable, Absolute)    */
    0x95, 0x01, /*      Report Count (1)                    */
    0x75, 0x05, /*      Report Size (5)                     */
    0x81, 0x01, /*      Input (Constant)    ;5 bit padding  */
    0x05, 0x01, /*      Usage Page (Generic Desktop)        */
    0x09, 0x30, /*      Usage (X)                           */
    0x09, 0x31, /*      Usage (Y)                           */
    0x15, 0x81, /*      Logical Minimum (-127)              */
    0x25, 0x7F, /*      Logical Maximum (127)               */
    0x75, 0x08, /*      Report Size (8)                     */
    0x95, 0x02, /*      Report Count (2)                    */
    0x81, 0x06, /*      Input (Data, Variable, Relative)    */
    0xC0, 0xC0}
};/* End Collection,End Collection            */

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

hidmouse 의 소스는 분석하지 않고 특징적인 몇개의 파일만 열어보고 위의 부분에 주목하고 닫아 버린다. 역시 컨셉은 물리 마우스가 아니라 가상 마우스이기 때문이다. 가상 마우스는 연결되면 오른쪽 아래의 트레이에 연결되었다고 풍선글이 떠야 하는 형태로 진행되어야 하는 것이 머리속의 구상이었다. 이미 driveronline 의 힌트에서 pnp 를 통해서 usb 를 인식시키라는 내용을 보았고 osronline 에서는 vhidmini 의 특정부분을 언급했으며 osronline 의 최초 질문자는 샘플의 포맷과 디스크립터를 언급했다. 다음의 사이트를 보게되면 약 90% 의 감이 오게되는데 임베디드 계통이 역시나 제일 확실하다. 시스템 프로그래머라는 황무지(wild)에서 살아가는 사람들이기 때문이다. 다만, 숫갈로 퍼먹여 주는걸 제일 싫어해서 짜증난다. 다음의 KELP 사이트의 글을 보면(http://kelp.or.kr/korweblog/stories.php?story=07/02/13/3453938)

글쓴이가 usb mouse 구현시 뭔가 이상하다는 식으로 적어놓고 있는 내용을 볼 수 있는데 한번 읽어보자.

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

usb slave 포트를 이용하여 usb mouse를 구현하고 있습니다.
글쓴이 : omayaro (2007년 02월 13일 오후 02:10) 읽은수: 643

<커널 2.6.11에서 gadget api를 이용하여 usb 마우스를 구현해 보고 있습니다.>

처음에 모듈을 등록하기 위하여

static int __init my_module_init(void)
{
int retval;
retval = usb_gadget_register_driver( &g_ugdDriver );
if (retval)
{
printk(KERN_ERR "[ omayaro ] module_init: cannot register gadget driver, ret=%d\n", retval);
return retval;
}
return 0;
}


위에서 처럼 하여 등록을 마쳤습니다.

그리고 pc( window xp 와 fedora core4 를 사용하는 pc 2대를 한번씩 테스트 함 )에

usb cable을 연결하였습니다.

그랬더니 임베디드 보드와 pc에 몇가지 반응이 오더군요..

아래의 내용은 진짜 마우스를 꼽았을때에 windows xp에서 usb descriptor를

분석한 내용입니다.

 

Device Descriptor:
bcdUSB: 0x0110
bDeviceClass: 0x00
bDeviceSubClass: 0x00
bDeviceProtocol: 0x00
bMaxPacketSize0: 0x08 (8)
idVendor: 0x062A
idProduct: 0x0000
bcdDevice: 0x0000
iManufacturer: 0x00
iProduct: 0x00
iSerialNumber: 0x00
bNumConfigurations: 0x01

ConnectionStatus: DeviceConnected
Current Config Value: 0x01
Device Bus Speed: Low
Device Address: 0x02
Open Pipes: 1

Endpoint Descriptor:
bEndpointAddress: 0x81
Transfer Type: Interrupt
wMaxPacketSize: 0x0004 (4)
bInterval: 0x0A

 

그리고 아래의 정보는 제가 짠 프로그램이 동작하여 pc에 등록된 정보입니다.

 

Device Descriptor:
bcdUSB: 0x0110
bDeviceClass: 0x03
bDeviceSubClass: 0x00
bDeviceProtocol: 0x00
bMaxPacketSize0: 0x10 (16)
idVendor: 0x062A
idProduct: 0x0000
bcdDevice: 0x0199
iManufacturer: 0x00
iProduct: 0x00
iSerialNumber: 0x00
bNumConfigurations: 0x01

ConnectionStatus: DeviceConnected
Current Config Value: 0x00
Device Bus Speed: Low
Device Address: 0x00
Open Pipes: 0

 

보시면 ConnectionStatus에 들어 있는 정보가 좀 틀리고 end point의 정보는 아예 없는 것을 보실수 있습니다.. 이 내용을 분석한 제 생각으로는 일단 Open Pipes의 수가 0인 것으로 보아 우선 정상적으로 연결 실패.. 가난 것으로 보이고요 end point가 없는 것으로 보아 어떤 설정또는 ep0를 통하여 세팅중에 에러가 난 것으로 보입니다...

이제 질문...( 서론이 좀 길었죠??ㅡㅜ;;;; ) 제가 아직 usb 에 대해 정확히 이해를 못해서 인지는 몰라도 usb ep0를 통하여 setup이 될때 어떤 순서로 setup이 이루어 지는지 잘 모르겠습니다. 제 생각으로는

1. host가 device descriptor를 요청하여 가져감
2. 나머지 descriptor( configure, interface )를 가져감

으로 생각이 되는데요.. 순서가 저렇게 되는 것이 맞나요?? 그리고 pipe( 제 생각에는 in/out end point )가 open되는 시점이 이 언제인지 궁금합니다.. 조금 정리해서 물어본다면.. usb device가 pc에 꽂힌 후 정상 인식 되기까지 host가 device에게 요청하는 메시지의 순서가 궁금하네요~~ 그리고 언제 pipe가 오픈이 되는 지... 도 궁금합니다~~

고수님들의 답변 기다릴게요~~
하루에 refresh만 5천번하는.. omayaro 였습니다...ㅠ0ㅠ

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

오케이.. 뭔가 삘이오는데.. 바로 앞에서 가슴속에 담아둔 그거네.. -_-; 중요한건 바로 디스크립터(descriptor) 컨피겨(configure) 인터페이스(interface) 라는 내용이 또 나온다. 어쨌거나 저쨌거나 질문자는 실패한 사람이니까 믿을게 못된다. 여기에 달린 댓글이 중요하다. 그런데.. 역시나.. 멋진 시스템 프로그래머들 같으니라구.. ㅎㅎ 직접읽어보라.. 민망하다..

--------------------------------------------------------------------------------------------------
 익명 (2007년 02월 13일 오후 10:08)

    밥은 직접 떠서 드세요.

    device 연결시점에서는 default(첫번째) configuration 으로 동작합니다.
    host 쪽에서 사용자의 요구에 의해 다른 configuration 으로 전환합니다.
    흔한 경우는 아닙니다.
    이런 방식을 사용하는 대표적인 경우는 device 쪽에 end point 가 모자랄 경우입니다.
    간혹, host쪽 사용자에게 디버깅 포트등을 숨기기 위해서 사용하기도 합니다. 
--------------------------------------------------------------------------------------------------


역시나 댓글한번 멋지게 달려있었다. 밥은 직접 떠먹어야 한다는 말. 누가 그걸 모르나. 이쯤되면 검색에 이골이 나기 일보직전이 되고 서서히 자신감도 사라지고 짜증이 섞이기 마련이다. 이때한번 refresh 가 필요한데 검색은 계속되어야 한다.. 쭈~욱.. 점점 검색하다보면 Filter Driver 에 대한 내용이 나오기도 하고 처음부터 검색이 되더라도 알아먹지 못했던 내용이 두번째 검색하다 모르고 똑같은걸 또 보게되면(즉, 본걸 나중에
또 봤을때) 이해가 되기 시작하는 부분이 생겨나기 시작한다. 바로 다음의 부분들이 그러한 부분들이라 하겠다.

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

bodnar
February 11th, 2007, 05:58 AM

I am trying to fix a part of the report descriptor on an existing USB HID device that woked fine but
has problems on Vista. It installs
and everything is OK with it but DirectX refuses to see it due to some inconsistency in the report descriptor.

I understand that I would need to write a filter driver to fix that.

I have downloaded recent WDK and looked at the samples, specifically HID\Firefly sample but I cannot figure out

how to alter

Report Descriptor data when the driver receives IRP_MN_START_DEVICE in DispatchPnP. I can see how PDEVICE_OBJECT

DeviceObject is passed

to it but mmm.. how do I get access to HID device details so I can alter it?

When I look inside HID\Vhidmini virtual HID minidriver I can see exactly what I would want to use in the
filter driver:

deviceInfo->ReportDescriptor = NewReportDescriptor;
deviceInfo->HidDescriptor.DescriptorList[0].wReportLength = ...;

I am a bit lost... Any help is appreciated.

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

미국말로 뭐라 지껄이는지 전혀 관심없다. 오로지 Report Descriptor data when the driver receives IRP_MN_START_DEVICE

in DispatchPnP 라는 문장과 다음의 소스 두부분이다.

deviceInfo->ReportDescriptor = NewReportDescriptor;
deviceInfo->HidDescriptor.DescriptorList[0].wReportLength = ...;

이 글에서 필자가 어느타임에 어디를 수정해야 할지 방향을 구체적으로 잡아나갈 수 있는 단초가 마련되기 시작한다. 즉, DispatchPnP 에서 IRP_MN_START_DEVICE 를 받았을때 Report Descriptor data 가 관계가 있다는 점이고 ReportDescriptor 를 NewReportDescriptor 로 할당하는 조작을 잡아낼 수 있다. 원래는 vhidmini 라는 Microsoft 사의 공식샘플이 어떻게 생겨먹었는지

잠시 소스 일부분을 보자면

        // Store the registry report descriptor in the device extension
        //
        deviceInfo->ReadReportDescFromRegistry = TRUE;
        deviceInfo->ReportDescriptor = RegistryReportDescriptor;
        deviceInfo->HidDescriptor.DescriptorList[0].wReportLength = 
                                   (USHORT)RegistryReportDescriptorLength;

위의 모습처럼 되어있다. 그런데 저 미국아가 한 짓은 deviceInfo->ReportDescriptor = RegistryReportDescriptor 를 NewReportDescriptor 로 바꿨다는 것이다. 그러니 필자도 역시 이 부분을 건드리게 될 것이란 소리가 된다. 그러므로 수정을 가할 부분을 한 부분 구체적으로 알아먹었다. 이 글의 맨 처음 시작부분의 Numega Soft 의 소스라고 되어있는 부분을 보자.

// The HID report descriptor for this device    
// (taken from USB/HID specification)    
   
HID_REPORT_DEscRIPTOR MouseHidReportDesc[] = {   
    0x05, 0x01, // Usage Page (Generic Desktop),     
    0x09, 0x02, // Usage (Mouse),      
    0xA1, 0x01, // Collection (Application),        
    0x09, 0x01, // Usage (Pointer),         
    0xA1, 0x00, // Collection (Physical),           
    0x05, 0x09, // Usage Page (Buttons),            
    0x19, 0x01, // Usage Minimum (01),          
    0x29, 0x03, // Usage Maximun (03),          
    0x15, 0x00, // Logical Minimum (0),
    ... 생략 ...


해당 부분을 보면 이제서야 뭔가 감이 오기 시작하게 되는 것이다.

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

드디어;;
 ·작성일     2007.01.28:15.25 (일)
· 작성자     rechoco
· 조 회     487


hid minidriver 테스트 살짝 성공~

샘플소스를 구해서 레포트 디스크립터랑 익스텐션 조금 손만 본거지만.

디바이스에서 데이터를 hid포멧에 맞춰서 주는게 아니라서..

강제로 제가 바꿔줘야 했거든요ㅋ

마우스로 테스트 해봤더니 쭉쭉 잘옮겨지더군요

물론 목표한 디지타이져는 아직 안됩니다;;
(와컴것 분석했더니 절대좌표모드일때도, 마우스 플래그를 쓰더군요
xp에서는 디지타이져가 지원이 안되니까 절대좌표 "처럼" 마우스좌표로 작업합니다.
저도 그렇게 하긴했는데. 영 개운하지가 않아서;;
디지타이져가 비스타에서는 지원 된다길래 해봤는데 실패했다는;;)

제가 참고한 샘플은 WDK의 vhidmini 소스입니다.

xp용으로 inf파일하고 소스파일 조금 수정하시면 빌드도 잘되고..

헛짓거리중에 잠깐 들러봤습니다.


드라이버 온라인님들 모두 화이팅하세요!!

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


아쉽게도 이 글은 가상 마우스인지 실제 마우스의 필터드라이버를 만든것인지 알길이 없어서 단지 말 그대로 희망만 주는 글인데 되긴 되나부다 정도로만 넘겨야 했다. 중요한 개념가닥을 잡아내는 파편과도 같은 내용들은 모두 끝났고(사실 더 많지만..) 다음의 세가지 정보의 검색이 사실상 전체적인 개념(컨셉)을 모두 얻도록 해주었다.

 

---------------------------------------------------------------------------------------------------
1. http://www.eggheadcafe.com/software/aspnet/32296449/virtual-usb-mouse-device.aspx

<Virtual USB Mouse Device only shows as generic HID device. - tomca>
08-May-08 05:16:00

I wrote a bus driver that generated virtual USB PDO for Printer, Scanner, and
SmartCard.  It worked fine before.  Recently, I was requested to provide a
virtual USB mouse PDO.  What I did was as following steps

1. An usermode application access bus driver to add a new PDO
2. bus driver use IoCreateDeviceSecure to create a new device and invalid
bus relation.
3. PNP manager found this new device, it will query the hardwareid, device
instanceid, and compatible id.
4. I provide USB\Class_03&SubClass_01&Prot_02 as compatible ID
5. System find this is a HID device and start to query Device Descriptor,
Configuration Descriptor, and HID descriptor.
6. Since this is a virtual mouse, bus driver gives HID descriptor without
hardware.  I copy a standard mouse device's HID descriptor (3button usb
mouse) to caller.
7. From Device Manager, I can see a HID device shows up,  but there is not
mouse device shows up.

If I plug in a real usb mouse, I can see system create a HID device first,
then HIDClass driver create a PDO for mouhid driver.  Is anyting wrong I did?

I have carefully checked the USB data sent to caller, everything is ok, but
system doesn't like this device as mouse,  Just consider it as generic USB
HID device.

Could someone give me help?

Thanks!
---------------------------------------------------------------------------------------------------

유저모드


---------------------------------------------------------------------------------------------------
2. KSP(www.ksyspro.org) 라는 곳에서 작성한 "USB강의자료.PDF" 라는 파일이 인터넷에서 검색되었다.
   내용의 제목은 "9차 정기 세미나 강의 자료" USB Device Driver 강의였다. 아쉽지만 원래 이런
   사이트는 문이 닫혀있다. (원래 그런거니까 이해를 해야한다.. -_-; 얼마나 힘들겠는가..? )

 - 내용이 작살이다. 이건 그냥 인터넷에서 받아서 보라.. 전체적인 개념정립이 이루어진다.
   (아마 앞서서 했던 기본적인 검색뻘짓이 없이는 읽을 수 있는 내용이 아니었으리..)

---------------------------------------------------------------------------------------------------
3. MSDN & ReactOS 소스 중의 USB 부분에 있는 Mouse 드라이버
 - 항상 마지막은 MSDN 의 승리이다. 전체적인 모든 내용이 다 들어있다. 빌어먹을 일정수준이상이
   되지 않으면 처음에 백날봐도 못알아 처먹는다는 것이 문제다. 커널이던 응용프로그래밍이던
   이건 차이가 없다. 지금도 응용프로그래밍도 못알아 먹는게 태반이니까. 어쩔수 없이 이 고생을
   치르는건 MSDN 을 보기위해서가 아닐까. (COM 프로그래밍도 MSDN 이 제일 많은 정보가 있다.)
   이 말을 증명해보겠음!!
   다음은 MSDN 의 vhidmini.h 라는 파일에 능구렁이처럼 맨 마지막 부분에 주석으로 처리되어있다.

[vhidmini.h 파일]

... 생략 ...
   
/*
//
// Here is sample descriptor that has two top level collection - mouse 
// collection and  vendor defined collection with a custom feature item. If 
// you want to provide sideband communication with your hidmini 
// driver, you can add a custom collection with the collection provided 
// by the hardware and open the custom collection from an app to 
// communicate with the driver.
// 여기 두개의 탑레벨 모음인 샘플 디스크립터가 있다.
// 커스텀 피처아이템을 가진 마우스 모음과 벤더 정의 모음이다.
// 니가 만약 너의 hidmini 드라이버를 가지고 사이드 밴드 통신을 제공하길
// 원한다면, 너는 하드웨어에서 제공되는 모음과 응용프로그램으로부터 드라이버
// 통신하는 것까지 개인모음을 추가할 수 있다.
// (역주: 즉, 몬소리냐면 이거 앞에서 선언한 DefaultReportDescriptor 대신에
//        이걸 그냥 가져다가 써라. 마우스 예제다. 이 말이나 마찬가지임.
//        여기에 니가 원하는거 추가해서 쓰라는 소리임. 이미 소스에 다 있었음.)
HID_REPORT_DEscRIPTOR           DefaultReportDescriptor[] = {
        0x05, 0x01,     //Usage Page (Generic Desktop),
        0x09, 0x02,     //Usage (Mouse),        
        0xA1, 0x01,     //Collection (Application),
        0x85, 0x01,     //REPORT_ID (1)             
        0x09, 0x01,     //Usage (Pointer),
        0xA1, 0x00,     //Collection (Physical),
        0x05, 0x09,     //Usage Page (Buttons),
        0x19, 0x01,     //Usage Minimum (01),
        0x29, 0x03,     //Usage Maximun (03),
        0x15, 0x00,     //Logical Minimum (0),
        0x25, 0x01,     //Logical Maximum (1),
        0x95, 0x03,     //Report Count (3),
        0x75, 0x01,     //Report Size (1),
        0x81, 0x02,     //Input (Data, Variable, Absolute), ;3 button bits
        0x95, 0x01,     //Report Count (1),
        0x75, 0x05,     //Report Size (5),
        0x81, 0x01,     //Input (Constant), ;5 bit padding
        0x05, 0x01,     //Usage Page (Generic Desktop),
        0x09, 0x30,     //Usage (X),
        0x09, 0x31,     //Usage (Y),
        0x15, 0x81,     //Logical Minimum (-127),
        0x25, 0x7F,     //Logical Maximum (127),
        0x75, 0x08,     //Report Size (8),
        0x95, 0x02,     //Report Count (2),
        0x81, 0x06,     //input (Data, Variable, Relative), ;2 position bytes (X & Y)
        0xC0,             //End Collection,
        0xC0,             //End Collection,

        0x06,0x00, 0xFF,   // USAGE_PAGE (Vender Defined Usage Page)     
        0x09,0x01,           // USAGE (Vendor Usage 0x01)      
        0xA1,0x01,           // COLLECTION (Application)        
        0x85,0x02,           // REPORT_ID (2)                      
        0x09,0x01,           // USAGE (Vendor Usage 0x01)              
        0x15,0x00,           // LOGICAL_MINIMUM(0)                   
        0x26,0xff, 0x00,   // LOGICAL_MAXIMUM(255)               
        0x75,0x08,           // REPORT_SIZE (0x08)                     
        0x95,0x01,           // REPORT_COUNT (0x01)                    
        0xB1,0x00,           // FEATURE (Data,Ary,Abs)             
        0xC0                    // END_COLLECTION                       
};

*/


자.. 이제 끝났다~ 라고?
한숨을 쉬기에는 너무 이르다. 대부분의 혼선과 문제점은 여기서부터 시작되기 때문이다. Microsoft 사의 WinDDK 라는 개발킷에 있는 vhidmini 샘플은 그저 샘플일 뿐이기에 정상작동이 되는지 확인을 해야하기 때문이다. 필자는 위에서 주석처리 되어있는 마우스 예제 DefaultReportDescriptor 의 주석을 풀고 기존에 있던 샘플 DefaultReportDescriptor 와 교체했다.

드라이버를 컴파일하는 방법은 여기서 설명하지 않는다. 그냥 WinDDK 설치후 프로그램 메뉴에서 XP 용 콘솔창을 열고 vhidmini 디렉토리로 이동후 nmake 명령을 내리면 컴파일이 가능한 것을 여기서 구차하게 다 설명을 할순없다. (그러면서도 벌써 설명까지 다 해주는 친절한 금자씨.. ㅎ) 이제 vhidmini 드라이버를 컴파일하고 장치를 인스톨 시키면 오른쪽 화면아래 트레이에 드라이버가 인식되었다고 뜰 것을 기대했다. 우리가 흔히 새 마우스를 USB 포트에 꽂으면 장치가 검색되었다고 뜨는걸 볼 수 있지 않은가? Human Interface Device(휴먼인터페이스장치) 어쩌구라는 메시지와 함께 잠시뒤에 마우스가 발견되었다는 식의 그런 메시지를 기대했다. 그러나 결과는 참담했고 미궁속으로 계속해서 빠져들고 말았다. 왜 그랬을까..? 비단 이 문제는 필자만의 문제가 아니었다. vhidmini 샘플 드라이버를 처음접하는 모든 프로그래머들이 모두 이같은 삽질의 미궁속에 빠져든다는 점을 검색을 통해서 알 수 있었다. 바로, MS 의 함정을 말이다.

여기서 다시 위와 같은 오류를 범해나가는 설명을 할 것이다. 어떤식으로 접근할 것인가와 얼마나 많은 뻘짓이 필요했는가에 대해서 설명할 필요가 있다고 본다. 그로인해서 얻은 것들은 상당히 많이 있다. 바로 단거리 스피드로 달리는 사람들은 놓칠수 있는 정보를 마라토너들은 두루두루 보고 달릴수 있는 것처럼 주변지식들을 충분히 얻을수 있다는 장점이 있다. 이 문서를 쓰는것 자체가 사실 기술적인 것에 너무 치우치는 쪽 보다는 학습방법을 알리는 병행효과를 얻기위한 것이기 때문에 무엇을 보았는지 지금부터 과정을 설명할 것이다.

앞서서 우리는 가상마우스를 만들기 위해서는 Virtual HID Device 를 만들수 있어야 한다는 점만 인식하고 출발했다. 완전히 지식이 전무한 상태에서 기본 골격코드마져 없는 허당상태로 시작할 수 있는 프로그래머는 아무도 없다. 이미 가상마우스 프로그램을 만들어본 경험이 있는 프로그래머라도 기본적인 코드의 골격없이 모든걸 직접 작성하는걸 기대하는건 어려운일이란 얘기이다. 그래서 우리가 앞에서 선행작업을 한 것이 바로 그 뼈대를 찾기위한 작업이었고, 숱한 오류과정을 거치며 우리가 만들 가상장치의 핵심뼈대를 발굴하고 비교 분석하여 선정하는 작업까지 마쳤다. 그리고 우리가 만들 장치에서 가장 중요한 핵심키포인트를 잡아내는 학습방법까지 소개하였다. 결론적으로 앞에서 습득한 사항들을 요약해 보자면..

1. 우리가 만드는 Virtual HID Device 는 mouse 또는 keyboard 와 혼합형태(혹은 단독일수도.. 그건 선택사항)이며 가상 USB 를 통해서 장치가 인식되어야 한다. 이 점은 프로그래밍적으로 정보를 수집하기 전에 머리속으로 구상한 내용에 속한다.(나중에 언급하겠지만 실제 설치/작동은 프로그래머의 상상과 약간 다르다.)

2. 여러 정보들을 수집하여 비교분석 한 뒤 그 중에서 vhidmini 라는 Microsoft 사의 WinDDK 개발킷 공식샘플을 채용하기로 최종결론을 내렸다.

3. vhidmini 라는 샘플을 운용하기위해 요구되는 스킬은 USB 의 HID 라는 인터페이스이며 이 인터페이스의 핵심 키포인트는 바로 Report Descriptor 라는 Descriptor 를 어떻게 기술할 것인가에 달려있다는 점을 알아낼 수 있다. 이 점은 이미 학습방법으로 어떻게 그 특징을 캣치하는지 보여주었다.

4. 우리는 최종적으로 Virtual HID Device 를 마우스로 인식시키기위해 Report Descriptor 라는 기술자(descriptor)를 찾아내야 했으며 적당한 기술자를 vhidmini.h 에서 발견하였다. 이 기술자를 Default 로 맞추고 컴파일 한 뒤 VMware 에 설치된 윈도우에서 설치하면 실제장치로 인식된다는 것까지 모두 정립하였다.
   
다음의 명령어를 이용해서 장치를 설치할 수 있다. 즉, 윈도우가 설치된 VMware 에는 vhidmini.sys 와 vhidmini.inf 그리고 devcon.exe 라는 총 세개의 파일이 복사되어야 한다. devcon 이라는 툴은 윈도우 장치관리자가 할 수 있는 모든 기능+ 를 콘솔에서 명령내릴수 있도록 해주는 커맨드유틸이다.

[설치명령]
devcon install vhidmini.inf "{D49F883C-6486-400a-8C22-1A9EF48577E4}\HID_DEVICE" 위와 같이 VMware 에 컴파일된 vhidmini 드라이버 파일들을 모두 복사한 뒤에 설치명령을 내린다. VMware 의 화면에는 신뢰를 받지못한 장치 드라이버 설치시에 뜨는 경고문구가 뜨게될 것이다. <계속> 이라는 버튼을 클릭하게되면 sys 파일을 찾지못해 디렉토리 지정창이 한번 더 뜰 것이다. 그 이유는 현 설치위치(devcon 명령어 실행디렉토리 위치) 밑에 i386 이라는 디렉토리에 sys 파일이 존재한다는 가정을하기 때문이다. 즉, INF 파일이 존재하는 위치를 기준으로 그 하위 i386 디렉토리에서 드라이버파일을 찾는다. 그래서 드라이버를 못찾는다는 창이 뜨게된다. 이건 그냥 적당히 vhidmini.sys 파일이 있는 디렉토리를 지정하면 알아서 설치가된다. 그런데.. 우리가 예상했던 설치모습이 아니었다. 그건 필자만의 착각이었을런지도 모르겠지만, 일단 이렇게 장치의 설치과정은 밍밍하게 끝나버린다. 이제 장치가 제대로 인식되었는지 확인을 하기위해 "장치관리자" 를 오픈한다. 그러면 휴먼인터페이스 장치쪽에 두가지 장치가 새롭게 추가되어있는 것을 보게될 것이다. 그런데, 뭔가 생각하던것과는 다르게 인식된 듯한 생각을 가지게 될 것이다. 그 장치는 그저 Generic HID 장치일 뿐 마우스가 아니다. 이게 도대체 어찌된 영문인가? 뭔가 잘못된 것이 있는지 확인해보고 수도없이 DefaultReportDescriptor 를 수정 해봐도 역시나 마찬가지로 마우스로 인식되질 않았다. Revert to snapshot 을 수도없이 반복하며 디스크립터 (Report Descriptor) 를 수정해도 역시나 반응은 일반장치(Generic HID) 일 뿐이었다. 정확히 말하면 VMware 기준으로 XP 에서 장치를 설치했을때 설치되는 이름은 두가지였다.

"HID 준수장치"
"Root Enumerated HID Device (sample)"
위의 두가지 장치가 설치된다. 우리가 원하는 것은 "HID 준수장치" 가 "HID 규격 마우스" 로 인식되어야만 한다. 그런데, 이런현상이 계속 지속되어 혼란이 가중될 뿐이었다. 어딘가 필자가 모르는 키포인트가 또다시 존재할 것이리라 생각하고 이 현상을 겪는 어딘가에 있을 동지에게 SOS 를 날려야 했다. 우리의 구글형님이 그러한 고충을 겪는 사람들을 모두 한자리로 집합시켜주었다. 그런데.. 구글이 불러모은 검색정보들은 하나 같이 모두 헛소리들 뿐이었다. 근접은 했어도 정답이 하나도 없는게 아닌가.. 제길.. FireFox 에서 탭을 약 20개 가까이 띄워놓고 검색에 검색을 반복하며 필자의 Report Descriptor 정보중 어디가 잘못되었는지를 찾아내기 위해서 안간힘을 쓰고 있었다. Report Descriptor 라는 것은 무엇인가? USB 라는 장치가 자기의 정보를 상위장치에 넘겨서 인식되도록 하기위한 마치 신분증과도 같은 것이다. 어디서 태어났고 어디서 자랐으며 나이는 몇살이고 남성인지 여성인지 기타등등.. 마치 이런정보처럼 인식정보를 쏘기전에 셋팅하는 값이다. 이 값이 하나라도 잘못될 경우에 장치는 절대로 제대로 인식되지 않는다. 항상 사람이 고생을 하려면 깨닫는 과정에서 착각을 일으키게된다. 필자는 vhidmini.h 파일에 있는 공식적인 마우스(예제) 디스크립터 주석을 풀어서 대체시켰다. 필자는 그 디스크립터를 믿지 못했다. 어딘가 오류가 있거나 한가지를 수정함으로
인해서 다른것까지 수정해야하는 문제점이 걸렸다거나 그런류로 생각할 수 밖에 없었다. 다음은 필자와 같은 문제점을 겪는 사람들에 대한 이야기다. 그다지 위안도 되지 않았고 결국 구글형님을 통해 문제의 정확한 해결점을 찾아낼 수 없었지만.. 그 과정에서 문득 떠오르는 영감을 주었기에 그 과정을 그려보고자 한다.

http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2007-03/msg00258.html
-----------------------------------------------------------------------------------------------------------------
thank for your advice.
i forget to assign REPORT_ID for each report desc.
It works now.
However, i migrated the corrected report to "hidfake". (Walter Oney 's sample)
The system pop up 3 "Found New Device Wizard" window and identfy it as "Unknow Device".
Any difference detween these 2 drivers' enumeration?
Appreciated.
(필자요약: REPORT_ID 를 빼먹었다. 작동된다. 그런데 hidfake 꺼를 배꼈다. 그랬더니 "알려지지않은 장치" 라는 새로운 장치로 "하드웨어 찾기" 가 세개나 뜬다. 나머지는 해석할 필요 없겠다.. 왜 그런가? 라는 질문 이라고 생각하고 넘어간다..)
-----------------------------------------------------------------------------------------------------------------
"Doron Holan [MS]" wrote:
    you only need one HID minidriver. from it, a keyboard and a mouse can
    be
    enumerated. you just have to put each device into its own top level
    collection. If you are having trouble, i would find a USB HID that already
    does this and look at its HID descriptor
(필자요약: 이놈이 다른 게시판에도 있는걸보면 좀 하는거 같다. 대충 번역하면 너는 오직 한개의 HID 미니드라이버만 필요할 뿐이다. 그리고 키보드나 마우스가 열거될수 있는 것으로 부터, 그리고 각각의 그 자신의 탑레벨 모음속에 각장치들을 넣어야만 한다. 만약 문제가 있다면, 니가 만든 USB HID 를 어쩌구 저쩌구.. 뭔가 HID Descriptor 와 연관이 있겠거니하고 그냥 넘어감..)
-----------------------------------------------------------------------------------------------------------------
I'm pretty sure you will need to break up hte device into a Mouse device and Keyboard device. (i.e two drivers,
one with a report descriptor for a keyboard and one for a mouse)
The inf files should not refer to HID\MyVirtualHidDevice - these id's need to be picked up from keyboard.inf or
msmouse.inf - idealy reporting the compatible id of HID_SYSTEM_KEYBOARD or HID_SYSTEM_MOUSE (i think)
(필자요약: 마우스와 키보드장치속에 hte 장치를 깨야할 필요가 있다라고 해석해야 하나..  이놈이 주장하는 내용은 일단, report descriptor 에 키보드와 마우스가 하나로 일치되어있는가를 확인하라는 내용과 HID\MyVirtual HidDevice 라는 장치명으로 되어있는 vhidmini.sys 샘플이 이름이 잘못되어서 그런게 아니냐는 속임수에 빠지기 쉬운 의견을 제시해 놓고 있다. 마치.. 네이버 지식인인가? 하지만 여기서 얻을 수 있는 점이 있는데 HID_SYSTEM_KEYBOARD, HID_SYSTEM_MOUSE 라는 지시어이다. 어설픈건 혼란을 가중시키는데 원래는 HID_DEVICE_SYSTEM_KEYBOARD 이고 HID_DEVICE_SYSTEM_MOUSE 가 맞는거니까 속지말자. 뒤에서 설명하겠지만 이걸 알아 듣기 위해서 새로운 개념을 습득하게 된다.)
-----------------------------------------------------------------------------------------------------------------
Hi,
I write a HID minidriver with standard Mouse and Keyboard report
descriptors.
It is based on vhidmini in Windows Server 2003 DDK.
The driver work fine and I can read/write the report from the
device.
The Device Manager shows it is HID-compliant device in HID class,
but
the
Mouse Class and Keyboard Class have none.
How should I do so that it can be a mouse device and keyboard
device?
Should I modify the INF file? My driver's INF is almost same as the
vhidmini's.
(필자요약: Windows Server 2003 DDK 로 vhidmini 를 만들었다는 식인데 장치명이 HID-compliant(일반 복합HID 장치)로 인식되는데 마우스 클래스와 키보드 클래스가 없다고 말한다. 어떻게 마우스와 키보드 장치로 인식시키는 것이냐고 물어본다. 자기가 INF 파일을 수정해야 하는지 물어본다. 그리고 INF 파일은 vhidmini 와 거의 같다고 말한다. 이 사람이 겪는 증상이 필자가 겪는 증상과 100% 일치한다. 그런데 불행히도 이 글에는 더이상의 답변이 달려있지 않았다. 눈물의 고배를 마시고 돌아서야 하는 이 저린마음.. T.T 어쩔수 없이 또다시 구글형님의 도움을 받아야한다.)
-----------------------------------------------------------------------------------------------------------------
이 질/답들에서 배운 것은 검증해봐야하는 대상들이다. 일단, HID Report Descriptor 가 잘못되었는지 검증해야하며 INF 파일이 잘못되었는지 검증해봐야하고 "한참을 헤메게 만든 요인이었지만" REPORT ID 에 대해서도 검증해봐야 한다는 몇가지 결론을 얻은채 새로운 검색활로를 모색해보게 된다. 이 검색은 첫 발을 내딘수준에 불과하다. 거의 48시간을 오로지 이 문제를 해결하기 위해서 정보들을 모아야 했다.
http://www.techtalkz.com/microsoft-device-drivers/297875-loading-driver-hid-class.html
-----------------------------------------------------------------------------------------------------------------
Loading a driver on HID class
Hi all,
I have a USB device that exposes a HID interface. It is not a mouse or
a keyboard, just a general HID device. Device Manager displays it as a
"HID-compliant device".
Now I would like to install a device driver on it and use the HID
interface to communicate with.
My INF refers the HID\VID_xxxx&PID_xxxx string and my driver gets
loaded.
So I get the PDO from AddDevice and I need the FileObject to
communicate using IOCTL_HID_SET_FEATURE and IOCTL_HID_GET_FEATURE. But
I cannot retrieve it; I use the FireFly sample and the function
FireflyOpenStack to retrieve the FileObject form the PDO but it fails
in my driver with error 0xC000000E (STATUS_NO_SUCH_DEVICE) when
calling ZwOpenFile.
What's wrong? The pdoName of the file open by ZwOpenFile is something
like "\Device
본 문서는 파워해커에서 제작되었으며 무단배포를 허용함..

<Virtual HID Mouse Driver 연구>

저자: AmesianX
제작: powerhacker.net
제작년도: 2009년 1월 15일

 

[서문]

본 문서의 시작에 앞서 목적에 대해 언급한다. 이 문서는 두가지 목적을 위해서 작성되어졌다.
첫번째는 모르는 부분에대한 새로운 연구나 공부를 시도할때 참고할 수 있는 공부방식(Style)에 대한 설명이고, 두번째는 Virtual HID Mouse Driver 를 제작할때 참고해야할 전초를 다지기위한 목적으로 구성되어 있다. 이렇게 기술문서를 공개하는 이유에는 여러가지가 있지만 무엇보다 이 기술이라는 분야는 언젠가는 자신이 알고있는 오늘의 기술이 내일의 쓰레기가 된다. 일찌감치 알고있는 정보들은 공개하고 더 높은 곳으로 계속 뛰어오를때 진정으로 아무도 가보지못한 고지에 오른 것이다. 그래야 스스로가 발전하는 길이고 바로 모두가 발전하는 길일 것이다. 고지는 점령 당하라고 있는 것이다. 언제까지 정적인 비공개노선으로 점령당하길 기다리고 있을 것인가? 앞으로는 더욱더 가속화될 것이다.


[기술을 습득하는 공부방법]

어떤 새로운 기술을 알고싶다면 최대한 동일기능이 구현된 많은 소스들을 수집하라. 그리고 그 차이점을 소스분석을 통해서 캣치하라. 아마 대부분은 소스분석을 깊게 들어가지 않아도 차이점이 눈에 띄게 될 것이다. 그러나.. 아쉽게도 Virtual HID Mouse 에 대한 소스는 인터넷에서 거의 찾기 힘들 것이다. 물론, 공식적인 샘플들을 찾아낼 수 있지만 필자처럼 커널지식보다 유저레벨 어플리케이션 조작만 파온 사람은 그 유명업체들의 공식샘플을 보고도 감을 잡아내기는 하늘에 별따기처럼 어렵다. 즉, 프로그래밍 = 개념 이라는 공식이 있기 때문에 이 개념만 잡고나면 프로그래밍은 껌씹기나 마찬가지다. 개념을 잡는 요령이 있다면 그것은 바로 앞에서 언급한 동일기능 소스의 차이점을 분석해내는 것이다. 그렇기 때문에 매우 제한된 소스(공식소스들)를 갖고 시작하는 것은 전혀 이해를 이끌어내지 못한다. 최대한 고갈되었다고 생각될 정도로 많은 설명이나 소스들을 검색해서 찾아내야 한다. 이때 사용할 수 있는 방법은 구해낸 소스들의 일부 시그너처(Signature)를 검색키워드로 사용하는 것이다. 이런식으로 최대한 많은 정보들을 뽑다보면 선구자들의 질문들을 찾아낼 수 있다. 바로, 그 질문들에서 핵심개념들을 뽑아낼 수 있다. 자주 언급되는 사항이 바로 그 핵심일 것이다. 어떻게보면 "미네르바" 인지 "미네로하이바" 인지 그 친구처럼 철저한 검색기술로 무장한 채로 짜집기의 달인이 되어야만 할 필요가 있다. 만약 충분히 많이 찾아서 더이상 찾아낼 것 조차 없다고 느끼고 등골이 휘어지는 고통을 여러번 견뎌내었다면 이제 얻어낸 것들을 대상으로 비교분석을 취한다. 그렇게 되면 중요 키포인트가 눈에 보이게 될 것이다. 왜 이렇게 해야 하냐면 답은 간단하다. 스스로 엄청난 고통을 감뇌하면서 충분히 검색을 했는데 다 내용이 거기서 거기인 경우가 99.9% 일 것이다. 왜? 그것은 삽질하는 프로그래머가 택한 프로그래밍 방법론은 달라도 전체적인 흐름은 재밌게도 한가지밖에 없으니까. 이게 답이다.

"어라? 다 똑같은 소리만 짓거리고 있잖아? 뭔가 좀 더 구체적인 것을 달라고!!"

이 소리가 나올때 이미 정답은 구해진 것이나 마찬가지다. 다 똑같은 소리를 짓거린다거나 똑같은 소스에 차이점은 있지만 원하는 것이 아니라고 생각될때 사실상 그것이 원하는 것일 확률이 태반이다. 그 이상의 짜집기(Copy & Paste) 능력은 밥을 숫갈로 퍼서 먹는 것이다. 그런데 필자같은 사람은 퍼서 먹여주는 것을 원한다. 왜? 프로그래밍이 나온 이유가 무엇인가? 로보트를 만들려고 기를 쓰는거보면 모르겠는가? 인간에게 숫갈로 밥을 퍼먹여 주려는게 궁극적인 목적아닌가? 프로그래머는 인간이 아니었나? (하기사 혹자는 로보트
라고도 부릅디다..) 프로그래머는 좀 퍼서 먹여주면 어디가 덧나는가? 짜증나게 약올리는 시스템 프로그래머들이여 퍼먹여주지 않으면 스스로 밥숫갈 놓게되는 날이 온다. 인터넷시대에서 정보라는 것은 물 흐르듯 흐를수 밖에 없기 때문에 빨리 털고 높은 곳으로 뛰지않으면 숫가락 놓을 준비를 해야 할 것이다. 오늘의 신기술이 내일의 쓰레기가 되는 시대에서 서로 돕지않으면 혼자 살아남기 힘들다. 외국애들 보라 오픈소스로 자기의 기술을 다 까발리고 있으면서도 항상 최첨단 기술을 걷고 있는 것을 보면 우리가 얼마나 어리석은지 진정 모르냐 이말이다.

외국애들은 오픈소스를 통해서 시너지라는 것을 이용하고 있다. 물론, 수 많은 개발자들이 다 참가해서 오픈소스가 완성될 것이라고 착각하면 그건 열라 바보이다. 유명 보안 오픈소스인 Nessus 개발자의 고충이 섞인 글을 읽어보았는가? 오픈소스임에도 불구하고 자기혼자만 개발해 왔다고 써있었다. 대부분의 오픈소스들이 마찬가지라고 보면 될 것이다. 다만, 시너지효과로 인해 개발자 1명이 해낼수 있는 능력이 100명 1000명 수준으로 증폭되었기에 프로젝트가 맥을 이어갈 수 있는 것이다. 즉, 게임용어로 말하면 "버프"(버프를 모르진 않겠지..) 를 받은 것이다. 그렇게 되면 소수의 엘리트 파워가 오픈소스에 집중되는 일반유저의 관심만큼 증폭되기 때문이다. 단순히 눈에보이는게 전부라고 생각한다면 큰 것을 놓치게된다. (아니라고? 아님말고.. 허위사실 유포로 감금되어야 하나.. ㅎㅎ)

[현 상황]

현 상황에서는 Virtual HID Mouse 가 Auto Mouse 나 MACRO 라는 시장에서 대안으로 대두된 상태라 x시장에서도 드라이버의 판매가 이루어지고 있는 상황이다. 참고로 이 기술이나 드라이버를 판매자체는 사실 법적인 문제의 소지가 없다. 왜냐면 이 Virtual HID Mouse 기술은 범용기술이기 때문이다. 이 기술이 사용되고있는 쪽은 예를들면 조이스틱을 에뮬레이션하거나(용산에가면 조이스틱 판다..) 블루투스 마우스를 사용하도록 해주거나 혹은 그에 버금가는 마우스 업체들이 주로 보유하고있는 자체기술에서 많이 볼 수 있다. 이건 우리가 늘상 접하는 일반분야에서 말한것 뿐이고 무엇보다 가장 많이 사용되고 있는 곳은 임베디드 산업에서일 것이다. 그러므로 이 기술을 파는 것은 전혀 문제가 될 수 없다. 이 기술자체는 Microsoft 사에서 공식적으로 WinDDK 에 예제와 함께 배포하고 있다는 사실을 알만한 사람들은 이미 다 알고있겠다. 단지 그 이상의 자세한 정보를 찾기가 어렵고 Microsoft 사에서 제공하는 기술정보를 알기위해서 밑받침(선행) 되어야할 정보가 없다는 것이 문제점이다. 그래서 기존에 커널 드라이버를 개발하던 사람들이나 천국이지 필자같은 미천한 어플프로그래머들한테는 짜증만 나게 할 뿐이다. 이 중간에 생략된 정보들이 무엇인지 알아내야 한다. 그것이 유저레벨이라는 미천한 신분에서 커널레벨이라는 귀족신분으로 도약할 수 있는 길이다. 테스트환경 만드는게 짜증나서 공부하지 않았다가 완전 독박 쓴 기분이기에 좀 고약한 말투가 나온다. (기분 상하는 커널레벨의 고급 독자는 당장 이 문서를 접기 바란다. 필자도 커널레벨을 공부해야 윈도우를 진정으로 아는 것이라는 대에 이견이 없다. 다만, 오래전부터 블루스크린과 친구를 맺고싶지 않았을 뿐이다. 이거 참.. 뻘쭘하게 커널과 "절친노트" 라도 찍어야하나..)
===================================================================================================================

현재, 인터넷에는 몇몇의 기술 정보이외에는 관련된 기술적 자료를 찾아볼 수 없다고 해도 과언이 아니다. 진짜 짜증나도록 자료가 없다. 이해를 할 수 있을만한 한글로된 기술자료는 극적으로 한개를 찾을 수 있었다. 먼저, Virtual HID Mouse 를 찾아보면 가장먼저 접하게 되는 사이트가 있다. 까마귀라는 한국사람이 자신이 만들었다고하는 Virtual HID Mouse 가 검색이 된다. 블로그의 글 내용인데 사실 저수준을 다루는 고급개발자가 아니면 볼게없다.. (왜? 필자같은 어플프로그래밍 수준은 못알아 먹으니까.. + 안갈켜주니까
-_-;) 그리고 MSDN 이 검색되고 vhidmini 라는 것이 검색된다. 또한, 짱개 사이트의 vhidmouse 라는 소스와 hidmouse 라는 소스도 검색된다. 근데.. 오래전에 GxxxGuard 라는 소스가 인터넷에 떴다는 그 몹쓸 짱개사이트였다. 구현을 하기 위해서는 vhidmini 라는 소스가 그중에서 제일 유력한 후보가 될 것이고 나머지 vhidmouse 와 hidmouse 는 소스를 구하는데 한참이나 걸릴 것이다. 일단, 대충 둘러서 정보를 캣치해야한다. 다음은 이미 다들 알고있겠지만 SoftICE 라는 걸작을 만들어낸 "Numega Soft" 라는 회사의 Virtual HID Mouse 공식샘플의 일부소스이다. 아쉽게도 이 소스는 Windows 9x 계열에서 작동되는 드라이버이므로 NT 계열에서는 사용할 수 없다. 하지만 캣치할 수 있는 중요한 내용이 포함되어 있다. 위에서 언급한 것중에 vhidmouse 라는 것이다. 다음은 vhidmouse 소스 중의 일부분이다.

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

// vmoudev.cpp -  virtual mouse device for HID example    
//=============================================================================    
//    
// Compuware Corporation    
// NuMega Lab    
// 9 Townsend West    
// Nashua, NH 03060  USA    
//    
// Copyright (c) 1998 Compuware Corporation. All Rights Reserved.    
// Unpublished - rights reserved under the Copyright laws of the    
// United States.    
//    
//=============================================================================    
   
// This module implements the device class of the virtual HID    
// mouse minidriver.    
   
#include <KHID.H>    
#include "vmoudev.h"    
#include "hidmouse.h"    
   
KTrace T("",TRACE_MONITOR, TraceAlways, BreakNever, KUstring(L"HidMouse"));   
   
#define SCALEX 3    
#define SCALEY 3    
   
// The HID report descriptor for this device    
// (taken from USB/HID specification)    
   
HID_REPORT_DEscRIPTOR MouseHidReportDesc[] = {   
    0x05, 0x01, // Usage Page (Generic Desktop),     
    0x09, 0x02, // Usage (Mouse),      
    0xA1, 0x01, // Collection (Application),        
    0x09, 0x01, // Usage (Pointer),         
    0xA1, 0x00, // Collection (Physical),           
    0x05, 0x09, // Usage Page (Buttons),            
    0x19, 0x01, // Usage Minimum (01),          
    0x29, 0x03, // Usage Maximun (03),          
    0x15, 0x00, // Logical Minimum (0),             
    0x25, 0x01, // Logical Maximum (1),             
    0x95, 0x03, // Report Count (3),            
    0x75, 0x01, // Report Size (1),         
    0x81, 0x02, // Input (Data, Variable, Absolute),    ;3 button bits          
    0x95, 0x01, // Report Count (1),            
    0x75, 0x05, // Report Size (5),         
    0x81, 0x01, // Input (Constant),            ;5 bit padding          
    0x05, 0x01, // Usage Page (Generic Desktop),            
    0x09, 0x30, // Usage (X),           
    0x09, 0x31, // Usage (Y),           
    0x15, 0x81, // Logical Minimum (-127),          
    0x25, 0x7F, // Logical Maximum (127),           
    0x75, 0x08, // Report Size (8),             
    0x95, 0x02, // Report Count (2),            
    0x81, 0x06, // Input (Data, Variable, Relative),    ;2 position bytes (X & Y)       
    0xC0,       // End Collection,    
    0xC0        // End Collection    
    };     
   
// HardwareID for the virtual mouse.     
   
WCHAR HardwareID[]={L"ROOT\\NUMEGA_VIRTUAL_HID_MOUSE\0"};   
WCHAR DeviceID[]  ={L"ROOT\\NUMEGA_VIRTUAL_HID_MOUSE\0"};   
   
HID_DEVICE_ATTRIBUTES DeviceAttributes = {   
    sizeof(HID_DEVICE_ATTRIBUTES),     
    MY_VENDOR_ID,   
    MY_PRODUCT_ID,   
    VERSION_NUMBER   
    };

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

위와 같이 HID_REPORT_DEscRIPTOR 라는 것을 볼 수 있는데, 처음에는 이게 뭔지 모른다. 감도 안온다. 그러므로 그 관점을 그대로 두고 다음으로 넘어가서 다른 소스들을 보자. (처음엔 원래 모르겠지.. 나만그런가.. -_-; 제길..)

인터넷에서 검색하면 위의 소스와 MSDN (Microsoft 사의 공식샘플과 설명문서) 을 먼저 보게 될 것이다. 그러면 당연히 vhidmini 라는 것도 접하게 된다. 소스는 인터넷에서 파는 놈들도 있으니 그냥 찾기는 좀 짜증이 날 것이다. Microsoft 사의 홈페이지에서 WinDDK 를 받으라. 그 안에 VHidMini 라는 샘플이 들어있다. 그놈을 보면 다음과 같이 생겨먹은 부분에 주목하자.

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

        if (NT_SUCCESS(ntStatus)) {
            //
            // Use default "HID Descriptor" (hardcoded). We will set the 
            // wReportLength memeber of HID descriptor when we read the 
            // the report descriptor either from registry or the hard-coded 
            // one.
            //

            deviceInfo->HidDescriptor = DefaultHidDescriptor;

            //
            // Check to see if we need to read the Report Descriptor from
            // registry. If the "ReadFromRegistry" flag in the registry is set
            // then we will read the descriptor from registry using routine 
            // ReadDescriptorFromRegistry(). Otherwise, we will use the 
            // hard-coded default report descriptor.
            //

            queryStatus = CheckRegistryForDescriptor(DeviceObject);

            if(NT_SUCCESS(queryStatus)){
                //
                // We need to read read descriptor from registry
                //
                
                queryStatus = ReadDescriptorFromRegistry(DeviceObject);
            
                if(!NT_SUCCESS(queryStatus)){
                    DebugPrint(("Failed to read descriptor from registry\n"));
                    ntStatus = STATUS_UNSUCCESSFUL;
                }

            }

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

Microsoft 에서 MSDN 의 설명을 먼저 읽어본 뒤 위의 소스주석부분을 보자. 다음과 같이 친절하게 설명해주고 있다.

            // Check to see if we need to read the Report Descriptor from
            // registry. If the "ReadFromRegistry" flag in the registry is set
            // then we will read the descriptor from registry using routine 
            // ReadDescriptorFromRegistry(). Otherwise, we will use the 
            // hard-coded default report descriptor.

설명에 써있듯이 자기네는 그냥 하드코딩 했으니까 ReadFromRegistry 를 참고하면 다른 디바이스를 등록할 수 있단다. 처음 접할땐 사전지식이 없기에 "이게 뭔 개소리야?" 라고 생각이 들 것이다. (? 반응이 없으면 나만그런거 같다.. ㅎ)

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

그렇다면 이제 개소리는 집어치우고 다음을 보자.

-->  https://www.osronline.com/showthread.cfm?link=138652

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

Radly
xxxxxx@daryllee.com

This being my first driver project, and an unusual one at that, there's a lot to get my
head wrapped around. My intent is to produce a virtual HID device (mouse emulation) that
uses a complex non-HID physical device as the input medium. I'm using the VHidMini sample
from the WDK hid folder as a starting point, and I'm now at the point where I need to transform
the sample's report format into a mouse format. I notice with confusion that the report descriptor
in vhidmini.inf is different from that in vhidmini.h, with no explanation in vhidmini.htm as
to why they are different. Does anyone here have any insight on that?


어떤 놈이 필자가 생각하는 것과 동일한 구현을 해볼려고 삽질중에 무시무시한 고급개발자들과 해커들이 몰린다는 osronline 에 질문을 던져놓고 있다. 이 소리는 무엇인가? 필자도 결국 저 문제에 봉착하게 될 날이 온다는 시나리오를 미리 발견한 것이다. 그러므로 주의 깊게 읽어볼 필요가 있다. 여기서 얻어낼 수 있는 정보는 sample's report format 이란 것과 report descriptor 라는 두가지 내용이다. 원래부터 찾기힘든 정보들에는 동문서답 내지는 "내가 니 밥처먹는데 밥숫가락으로 퍼먹여주랴?" 정도의 댓글이 달리는데 그래도 이 글의 답글중에 괜찮은 답글이 있다. 근데.. 여전히 찾기힘든 정보만큼이나 짤막하게 달아놓는다. 이런사람이 있다는 것은 희망이고 곧 빛이다. 다음의 답글을 읽어보자.

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

allen zhang
xxxxxx@sina.com
RE: VHidMini report descriptor(s)

see the follow source code and the ReadDescriptorFromRegistry function, You should be understand it.

deviceInfo->HidDescriptor = DefaultHidDescriptor;
queryStatus = CheckRegistryForDescriptor(DeviceObject);
if(NT_SUCCESS(queryStatus)) {
    queryStatus = ReadDescriptorFromRegistry(DeviceObject);
    ...

 

입에서 욕은 나온다. 왜? 말할라면 다 말하던가 아니면 동문서답이나 하고 가던가 감칠맛나게 소스 네줄 뿌리고 튀다니.. 그래도 고맙다. 지식을 갈구하는 자에게는 이것조차 선물이다. 제길.. 현자라면 푸념할때가 아닌거 같다. 여기서 뭔가 개념을 잡을 수 있는 정보를 캣치해야만 한다. 이 글에서 외국아가(짱개류 외국애인지 allen zhang 이구나.. 역시 중국은 AUTO 에 강한가보다..) 말하기를 소스코드를 보란다. 그 안에 ReadDescriptorFromRegistry 를 보라고 권하면서 일부 소스를 긁어서 보여준다. 글은 짧지만 분명 소스를 열어봤기에 긁어서 붙여줬을테니 아쉬워도 고마운 행동이다.

여기서 보라고 한 소스가 바로 위에서 VHidMini 샘플의 일부분이라고 뿌린 부분이다. 즉, 이 부분의 내용은 최초 질문자의 글에서 캣치한 sample's report format 와 report descriptor 라는 부분에대한 응답이다. 즉, 이 함수의 이름으로부터 알 수 있듯이 레지스트리로부터 디스크립터를 읽어들인다는 것에 바로 Virtual HID Mouse 의 핵심구현이 얽혀있다는 것을 시사한다는 점을 알 수 있다. 그런데 필자도 단지 이두개만 가지고 감을 잡지는 못했다. 왜냐면, 커널을 깊이 공부한 적이 없는 사람이 이 두가지의 자료만을 토대로 감을 잡아낼 수 있겠는가? 그렇다면 그건 천재이거나 영어를 모국어처럼 잘하는 사람일게 분명하다. 필자는 남보다 항상 두배로 삽질을 하는데 머리가 남들보다 딸려서 그렇다. 자료도 항상 두배로 찾아야 한다. 결정적으로 힌트가 되었던 것은 역시 국내사이트인데 드라이버 개발정보를 알려주는 곳인 driveronline.org 에서의 힌트와 임베디드 계통의 KELP 사이트에서 였다.

http://driveronline.org/bbs/view.asp?tb=beusb&GotoPage=1&s_bulu=memo&s_key=pnp&no=1491
-------------------------------------------------------------------------------------------------------------

Re] Re] Re] USB 가상 키보드, 마우스 드라이버
·작성일     2007.10.02:10.40 (화)
· 작성자     Woof
· 조 회 605

pnp 를 이용해서든지 해서 가상적인 usb 장치가 인식이 되면 일반적인 usb 장치를 다루듯이 이용하시면 됩니다. 일반적으로 실제 장치들은  Windows에서 제공하는 기본적인 드라이버로도 동작하기 때문에 필요가 없지만 이와 같은 경우에는 간단하게 자기 드라이버를 열어서 인식된 장치 device와 통신하는 드라이버 정도는 필요하겠지요. 뭐, usb라서 따로 드라이버없이 application으로도 충분히 가능한건데 다들 위와 같은 방법을 이용하더군요. 새로나온 umdf 등을 이용하면 더 간단하고 새로나온 것에 대한 공부도 하면서 재미나게 할 수 있을지도 모르겠네요. 위 에서 말한 대부분의 경우 라고 한 것의 예를 간단히 들어보면 자신의 드라이버를 올리고 해당 드라이버에서 application과 통신 device를 생성한 뒤에 pnp를 이용해서 가상적인 usb 장치를 만들고 그것과 통신하는 길?을 적당히 만들어서 이용하시면 됩니다. sample에서는 가상적인 장치 인식이 바로 usb나 그런 부분이 아니였던 것 같은데 적당히 고치면 되겠지요.

위에도 썻지만, 잘 찾으면 다 만들어진 코드 어디 있을 것 같습니다. 저도 한번 찾으려다가 그냥 sample에 있어서 말았는데. :|  해당 usb 드라이버를 이용해서" 라는 부분에 대해서 물어보셔서 이 부분만 따로 답을 달면 해당 usb device를 제어(control)하는 드라이버를 지칭했습니다.  또 처음에 말한 것 처럼 class관련 드라이버에 대해서는 생각할 필요가 없습니다. 역시 위에 쓴 것 처럼 어디에 쓰실지 궁금하네요. 가상 키입력등은 S/W나 그런 자동화 테스트에 이용하기도 하고 꽤 여러군데서 쓰기는 하는데 안좋지는 않지만 뭐 . 그런데도 쓰여서 :|

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


최초 질문자가 어떻게 구현해야 하냐고 질문하자 pnp 를 통해서 가상적인 usb 를 인식시킨 다음에 적당히 device 와 통신시키라고 한다. 자세한 내용은 말해주지 않고 Microsoft 에서 제공하는 샘플로도 구현이 가능할 것이라는 내용과 어딘가에는 이미 다 만들어진 소스가 있을텐데 찾아보라고 한다. 이말 믿고 인터넷에서 찾아헤메다가는 마누라가 집나가도 모를것이다. 답변에서 보듯이 이 사람은 진짜 적당히 답글을 달고 있는 사람이라는 점을 주의해야 한다.

이 사람의 힌트와 통찰력이 Microsoft 사의 샘플에서 존재하는 핵심이라는 점을 알 수 있다. 일단, 정보는 머리속에 꼬깃꼬깃 담아두고 계속 다음 검색으로 넘어가면서 본인의 마음속에 답이 한가지로 수렴되도록 정보들을 계속 얻어 내어보자. 이쯤되면 정상적인 사이트를 뒤지는 것이 힘들어진다. 왜냐면 너무 정보가 부족하기 때문이리라. 고로 컨트롤러를 제어하는 것을 찾아본다. 예를들면 USB HID 조이스틱 드라이버 같은 것을 찾아내는 것이다.

다음과 같은 좋은 예가 있었다.

http://www.redcl0ud.com/files/XBCD_all_src.cab

XBOX 의 6축 조이스틱 패드를 윈도우에서 사용할 수 있도록 해주는 소스였다. 검색을 할때는 기존에 얻었던 소스에서 일부 특이하게 보일만한 함수를 키워드로 검색하면 운좋게 찾을 수 있다. 소스를 보면 너무 길고 난해하고 이해하기 힘들뿐이다. 당연히 커널관련 지식이 깊지않은 이상 어떻게 분석하고싶어도 그럴 도리가 없다. 그러므로 파일구성을 보는 것이 전부이다. 여기서 또한가지 힌트를 얻을 수 있다.

XBCD_control.c
XBCD_driver.c
XBCD_driver.h
XBCD_hid.h
XBCD_report.h

위와 같은 파일구성에서 driver 나 control 소스를 보기전에 report 라는 눈에 띄는 놈이 있다. 이 헤더파일의 내용을 보게되면 다음과 같은 것이 적혀있다.

-------------------------------------------------------------------------------------------------------------
char ReportDescriptor[213] = {
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x04,                    // USAGE (Joystick)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,                    //   PHYSICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x01,                    //   USAGE (Button 1)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x02,                    //   USAGE (Button 2)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x03,                    //   USAGE (Button 3)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x04,                    //   USAGE (Button 4)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x05,                    //   USAGE (Button 5)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x06,                    //   USAGE (Button 6)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x07,                    //   USAGE (Button 7)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x08,                    //   USAGE (Button 8)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x09,                    //   USAGE (Button 9)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0a,                    //   USAGE (Button 10)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0b,                    //   USAGE (Button 11)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0c,                    //   USAGE (Button 12)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x75, 0x04,                    //   REPORT_SIZE (4)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x81, 0x01,                    //   INPUT (Cnst,Ary,Abs)
    0x75, 0x10,                    //   REPORT_SIZE (16)
    0x16, 0x01, 0x80,              //   LOGICAL_MINIMUM (-32767)
    0x26, 0xff, 0x7f,              //   LOGICAL_MAXIMUM (32767)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x7f,              //   PHYSICAL_MAXIMUM (32767)
    0x05, 0x01,                    //   USAGE_PAGE (Generic Desktop)
    0x95, 0x02,                    //   REPORT_COUNT (2)
    0x09, 0x30,                    //   USAGE (X)
    0x09, 0x31,                    //   USAGE (Y)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x02,                    //   USAGE_PAGE (Simulation Controls)
    0x95, 0x02,                    //   REPORT_COUNT (2)
    0x09, 0xba,                    //   USAGE (Rudder)
    0x09, 0xbb,                    //   USAGE (Throttle)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x01,                    //   USAGE_PAGE (Generic Desktop)
    0x09, 0x39,                    //   USAGE (Hat switch)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x07,                    //   LOGICAL_MAXIMUM (7)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0x3b, 0x01,              //   PHYSICAL_MAXIMUM (315)
    0x65, 0x14,                    //   UNIT (Eng Rot:Angular Pos)
    0x75, 0x04,                    //   REPORT_SIZE (4)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,                    //   PHYSICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0d,                    //   USAGE (Button 13)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0e,                    //   USAGE (Button 14)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x0f,                    //   USAGE (Button 15)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x09, 0x10,                    //   USAGE (Button 16)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x00,              //   PHYSICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x95, 0x03,                    //   REPORT_COUNT (3)
    0x05, 0x00,                    //   USAGE_PAGE (Not Defined)
    0x09, 0x00,                    //   USAGE (Undefined)
    0x09, 0x01,                    //   USAGE (Undefined)
    0x09, 0x02,                    //   USAGE (Undefined)
    0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
    0xc0                           // END_COLLECTION
};
-------------------------------------------------------------------------------------------------------------

그리고 이 홈페이지에서 최대한 얻을 수 있는 것은 다 캣치해야 하는 http://www.redcl0ud.com/xbcd.html 홈페이지의 마지막쯤에 보면 http://www.redcl0ud.com/files/USBView.cab 라는 것이 있다. 그리고 캡춰사진이 있는데 핵심사항으로 체크를 해둔 부분이 있다. idVendor, idProduct 라는 부분에 체크를 해두고 있다. 그리고 USBView 에서 보여주는 내용이 모냐면 바로 Device Descriptor 였다. 오호라.. 내친김에 이 사이트에서는 USB 드라이버를 제작하는 방법까지 설명하는 링크를 걸어두고 있었다.

http://euc.jp/periphs/xbox-controller.en.html

이 링크인데 제목은 "Inside XBox Controller" 라고 되어있다. 대충 무슨내용이 있는지 열거하자면..

-------------------------------------------------------------------------------------------------------------
<Inside Xbox Controller>
...

<Overview>
...

<USB Device Model>
...

<Descriptors>

Here are descriptor dumps of the hub, the gamepad and the memory unit.

    * Descriptors of the integrated hub
    * Descriptors of the gamepad (American)
    * Descriptors of the memory unit

<Vendor/Product IDs>

The vendor ID is 0x045e (Microsoft). Product IDs are as follows:
ID    product
0x001c    integrated hub
0x0202    gamepad (American)
0x0280    memory unit
0x0284    DVD remote receiver
0x0285    gamepad (Japanese)

It is not recommended to distinguish Xbox gamepads by vendor/product IDs because third-party controllers may
have their own vendor/product IDs.

<Device Class>
...

<HID Report Format>
Input Report
The input report is 20-byte.
헤더그림

Output Report
The output report (rumble control) is 6-byte. 
헤더그림

<Example of HID Report Descriptor>
The Xbox gamepad lacks the HID report descriptor that describes the input/output report formats. Based on the
above report formats I have tried writing the report descriptor for your information. This is a mere example;
neither official nor verified. Accuracy is not guaranteed.

    * Text format
    * Binary format
    * HID Descriptor Tool format (to be loaded into HID Descriptor Tool) 
---------------------------------------------------------------------------------------------------------------

위와 같은 내용들이 있었다. 상당히 많은 삘을 주고있다. 누가봐도 HID Descriptor 와 HID Report Format 그리고 Input Report 와 Output Report 를 통해서 통신한다는 아주 기본적인 컨셉(개념)은 머리가 아니라(T.T) 가슴에 와닿을 것이다. (젠쟝.. 가슴에만 담아두마.. -_-;) 일단, 이쯤에서 XBCD 소스는 닫아둔다. 언제 이거 분석하고 앉아있는가.. 최종컨셉이 다르기 때문에 힌트만 뽑아먹고 닫아두는 것이다. 애초에 만들려고 한건 Virtual HID Mouse 인데 이건 그 컨셉이 아니기에 대충 훑어보고 넘겨야 한다. 또 다른 소스들을 보자. 마구잡이로 검색하면서 받아둔 소스중에 앞에서 처음에 말했던 hidmouse 라는 소스를 한번 진단해보자.. -_-;

(PIC 를 이용한 마우스 제작소스)
파일을 열어보니 원하는게 아닌듯 보였는데 알고보니 PIC 용이었다. 운 좋게도 필자는 PIC18x 롬라이터를 갖고 있어서 이 소스가 뭔지 알 수 있었다. 오래전에 친구의 부탁으로 PIC18x 칩에 어셈블리를 롬라이팅 하는 프로그램을 만들어준 적이 있어서 무슨 소스인지 금방 알 수 있었다. 요새는 PIC 프로그래밍에도 C 가 쓰이고 PIC 는 PLC 대체용으로 쓰이기도 한다. 그런데 PIC 로 USB 모듈을 부착하고 마우스로 제작이 가능한거 같았다. 어쨌거나 원하는 내용은 아니었지만 생각해보면 가장 중요한 것이 물리적인 장치 아닌가? 물리적인 장치에서는 기존에 찾은 소스들이나 검색내용들과 어떤 차이가 있는지 알아볼 필요도 있다.
http://www.pudn.com/downloads128/sourcecode/comm/detail543439.html

hidmouse 라는 소스에서 파일구성을 보면 특이한 놈이 있다.
usb_descriptors.c 라는 소스가 있는데 여태까지 눈여겨왔던 descriptor 라는 단어가 보일 수 밖에 없다.

-------------------------------------------------------------------------------------------------------------
/* Device Descriptor */
ROM USB_DEVICE_DEscRIPTOR device_dsc=
{
    0x12,    // Size of this descriptor in bytes
    USB_DEscRIPTOR_DEVICE,                // DEVICE descriptor type
    0x0200,                 // USB Spec Release Number in BCD format
    0x00,                   // Class Code
    0x00,                   // Subclass code
    0x00,                   // Protocol code
    USB_EP0_BUFF_SIZE,          // Max packet size for EP0, see usb_config.h
    MY_VID,                 // Vendor ID
    MY_PID,                 // Product ID: Mouse in a circle fw demo
    0x0003,                 // Device release number in BCD format
    0x01,                   // Manufacturer string index
    0x02,                   // Product string index
    0x00,                   // Device serial number string index
    0x01                    // Number of possible configurations
};

... 중략 ...

//Class specific descriptor - HID mouse
ROM struct{BYTE report[HID_RPT01_SIZE];}hid_rpt01={
    {0x05, 0x01, /* Usage Page (Generic Desktop)             */
    0x09, 0x02, /* Usage (Mouse)                            */
    0xA1, 0x01, /* Collection (Application)                 */
    0x09, 0x01, /*  Usage (Pointer)                         */
    0xA1, 0x00, /*  Collection (Physical)                   */
    0x05, 0x09, /*      Usage Page (Buttons)                */
    0x19, 0x01, /*      Usage Minimum (01)                  */
    0x29, 0x03, /*      Usage Maximum (03)                  */
    0x15, 0x00, /*      Logical Minimum (0)                 */
    0x25, 0x01, /*      Logical Maximum (0)                 */
    0x95, 0x03, /*      Report Count (3)                    */
    0x75, 0x01, /*      Report Size (1)                     */
    0x81, 0x02, /*      Input (Data, Variable, Absolute)    */
    0x95, 0x01, /*      Report Count (1)                    */
    0x75, 0x05, /*      Report Size (5)                     */
    0x81, 0x01, /*      Input (Constant)    ;5 bit padding  */
    0x05, 0x01, /*      Usage Page (Generic Desktop)        */
    0x09, 0x30, /*      Usage (X)                           */
    0x09, 0x31, /*      Usage (Y)                           */
    0x15, 0x81, /*      Logical Minimum (-127)              */
    0x25, 0x7F, /*      Logical Maximum (127)               */
    0x75, 0x08, /*      Report Size (8)                     */
    0x95, 0x02, /*      Report Count (2)                    */
    0x81, 0x06, /*      Input (Data, Variable, Relative)    */
    0xC0, 0xC0}
};/* End Collection,End Collection            */

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

hidmouse 의 소스는 분석하지 않고 특징적인 몇개의 파일만 열어보고 위의 부분에 주목하고 닫아 버린다. 역시 컨셉은 물리 마우스가 아니라 가상 마우스이기 때문이다. 가상 마우스는 연결되면 오른쪽 아래의 트레이에 연결되었다고 풍선글이 떠야 하는 형태로 진행되어야 하는 것이 머리속의 구상이었다. 이미 driveronline 의 힌트에서 pnp 를 통해서 usb 를 인식시키라는 내용을 보았고 osronline 에서는 vhidmini 의 특정부분을 언급했으며 osronline 의 최초 질문자는 샘플의 포맷과 디스크립터를 언급했다. 다음의 사이트를 보게되면 약 90% 의 감이 오게되는데 임베디드 계통이 역시나 제일 확실하다. 시스템 프로그래머라는 황무지(wild)에서 살아가는 사람들이기 때문이다. 다만, 숫갈로 퍼먹여 주는걸 제일 싫어해서 짜증난다. 다음의 KELP 사이트의 글을 보면(http://kelp.or.kr/korweblog/stories.php?story=07/02/13/3453938)

글쓴이가 usb mouse 구현시 뭔가 이상하다는 식으로 적어놓고 있는 내용을 볼 수 있는데 한번 읽어보자.

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

usb slave 포트를 이용하여 usb mouse를 구현하고 있습니다.
글쓴이 : omayaro (2007년 02월 13일 오후 02:10) 읽은수: 643

<커널 2.6.11에서 gadget api를 이용하여 usb 마우스를 구현해 보고 있습니다.>

처음에 모듈을 등록하기 위하여

static int __init my_module_init(void)
{
int retval;
retval = usb_gadget_register_driver( &g_ugdDriver );
if (retval)
{
printk(KERN_ERR "[ omayaro ] module_init: cannot register gadget driver, ret=%d\n", retval);
return retval;
}
return 0;
}


위에서 처럼 하여 등록을 마쳤습니다.

그리고 pc( window xp 와 fedora core4 를 사용하는 pc 2대를 한번씩 테스트 함 )에

usb cable을 연결하였습니다.

그랬더니 임베디드 보드와 pc에 몇가지 반응이 오더군요..

아래의 내용은 진짜 마우스를 꼽았을때에 windows xp에서 usb descriptor를

분석한 내용입니다.

 

Device Descriptor:
bcdUSB: 0x0110
bDeviceClass: 0x00
bDeviceSubClass: 0x00
bDeviceProtocol: 0x00
bMaxPacketSize0: 0x08 (8)
idVendor: 0x062A
idProduct: 0x0000
bcdDevice: 0x0000
iManufacturer: 0x00
iProduct: 0x00
iSerialNumber: 0x00
bNumConfigurations: 0x01

ConnectionStatus: DeviceConnected
Current Config Value: 0x01
Device Bus Speed: Low
Device Address: 0x02
Open Pipes: 1

Endpoint Descriptor:
bEndpointAddress: 0x81
Transfer Type: Interrupt
wMaxPacketSize: 0x0004 (4)
bInterval: 0x0A

 

그리고 아래의 정보는 제가 짠 프로그램이 동작하여 pc에 등록된 정보입니다.

 

Device Descriptor:
bcdUSB: 0x0110
bDeviceClass: 0x03
bDeviceSubClass: 0x00
bDeviceProtocol: 0x00
bMaxPacketSize0: 0x10 (16)
idVendor: 0x062A
idProduct: 0x0000
bcdDevice: 0x0199
iManufacturer: 0x00
iProduct: 0x00
iSerialNumber: 0x00
bNumConfigurations: 0x01

ConnectionStatus: DeviceConnected
Current Config Value: 0x00
Device Bus Speed: Low
Device Address: 0x00
Open Pipes: 0

 

보시면 ConnectionStatus에 들어 있는 정보가 좀 틀리고 end point의 정보는 아예 없는 것을 보실수 있습니다.. 이 내용을 분석한 제 생각으로는 일단 Open Pipes의 수가 0인 것으로 보아 우선 정상적으로 연결 실패.. 가난 것으로 보이고요 end point가 없는 것으로 보아 어떤 설정또는 ep0를 통하여 세팅중에 에러가 난 것으로 보입니다...

이제 질문...( 서론이 좀 길었죠??ㅡㅜ;;;; ) 제가 아직 usb 에 대해 정확히 이해를 못해서 인지는 몰라도 usb ep0를 통하여 setup이 될때 어떤 순서로 setup이 이루어 지는지 잘 모르겠습니다. 제 생각으로는

1. host가 device descriptor를 요청하여 가져감
2. 나머지 descriptor( configure, interface )를 가져감

으로 생각이 되는데요.. 순서가 저렇게 되는 것이 맞나요?? 그리고 pipe( 제 생각에는 in/out end point )가 open되는 시점이 이 언제인지 궁금합니다.. 조금 정리해서 물어본다면.. usb device가 pc에 꽂힌 후 정상 인식 되기까지 host가 device에게 요청하는 메시지의 순서가 궁금하네요~~ 그리고 언제 pipe가 오픈이 되는 지... 도 궁금합니다~~

고수님들의 답변 기다릴게요~~
하루에 refresh만 5천번하는.. omayaro 였습니다...ㅠ0ㅠ

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

오케이.. 뭔가 삘이오는데.. 바로 앞에서 가슴속에 담아둔 그거네.. -_-; 중요한건 바로 디스크립터(descriptor) 컨피겨(configure) 인터페이스(interface) 라는 내용이 또 나온다. 어쨌거나 저쨌거나 질문자는 실패한 사람이니까 믿을게 못된다. 여기에 달린 댓글이 중요하다. 그런데.. 역시나.. 멋진 시스템 프로그래머들 같으니라구.. ㅎㅎ 직접읽어보라.. 민망하다..

--------------------------------------------------------------------------------------------------
 익명 (2007년 02월 13일 오후 10:08)

    밥은 직접 떠서 드세요.

    device 연결시점에서는 default(첫번째) configuration 으로 동작합니다.
    host 쪽에서 사용자의 요구에 의해 다른 configuration 으로 전환합니다.
    흔한 경우는 아닙니다.
    이런 방식을 사용하는 대표적인 경우는 device 쪽에 end point 가 모자랄 경우입니다.
    간혹, host쪽 사용자에게 디버깅 포트등을 숨기기 위해서 사용하기도 합니다. 
--------------------------------------------------------------------------------------------------


역시나 댓글한번 멋지게 달려있었다. 밥은 직접 떠먹어야 한다는 말. 누가 그걸 모르나. 이쯤되면 검색에 이골이 나기 일보직전이 되고 서서히 자신감도 사라지고 짜증이 섞이기 마련이다. 이때한번 refresh 가 필요한데 검색은 계속되어야 한다.. 쭈~욱.. 점점 검색하다보면 Filter Driver 에 대한 내용이 나오기도 하고 처음부터 검색이 되더라도 알아먹지 못했던 내용이 두번째 검색하다 모르고 똑같은걸 또 보게되면(즉, 본걸 나중에
또 봤을때) 이해가 되기 시작하는 부분이 생겨나기 시작한다. 바로 다음의 부분들이 그러한 부분들이라 하겠다.

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

bodnar
February 11th, 2007, 05:58 AM

I am trying to fix a part of the report descriptor on an existing USB HID device that woked fine but
has problems on Vista. It installs
and everything is OK with it but DirectX refuses to see it due to some inconsistency in the report descriptor.

I understand that I would need to write a filter driver to fix that.

I have downloaded recent WDK and looked at the samples, specifically HID\Firefly sample but I cannot figure out

how to alter

Report Descriptor data when the driver receives IRP_MN_START_DEVICE in DispatchPnP. I can see how PDEVICE_OBJECT

DeviceObject is passed

to it but mmm.. how do I get access to HID device details so I can alter it?

When I look inside HID\Vhidmini virtual HID minidriver I can see exactly what I would want to use in the
filter driver:

deviceInfo->ReportDescriptor = NewReportDescriptor;
deviceInfo->HidDescriptor.DescriptorList[0].wReportLength = ...;

I am a bit lost... Any help is appreciated.

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

미국말로 뭐라 지껄이는지 전혀 관심없다. 오로지 Report Descriptor data when the driver receives IRP_MN_START_DEVICE

in DispatchPnP 라는 문장과 다음의 소스 두부분이다.

deviceInfo->ReportDescriptor = NewReportDescriptor;
deviceInfo->HidDescriptor.DescriptorList[0].wReportLength = ...;

이 글에서 필자가 어느타임에 어디를 수정해야 할지 방향을 구체적으로 잡아나갈 수 있는 단초가 마련되기 시작한다. 즉, DispatchPnP 에서 IRP_MN_START_DEVICE 를 받았을때 Report Descriptor data 가 관계가 있다는 점이고 ReportDescriptor 를 NewReportDescriptor 로 할당하는 조작을 잡아낼 수 있다. 원래는 vhidmini 라는 Microsoft 사의 공식샘플이 어떻게 생겨먹었는지

잠시 소스 일부분을 보자면

        // Store the registry report descriptor in the device extension
        //
        deviceInfo->ReadReportDescFromRegistry = TRUE;
        deviceInfo->ReportDescriptor = RegistryReportDescriptor;
        deviceInfo->HidDescriptor.DescriptorList[0].wReportLength = 
                                   (USHORT)RegistryReportDescriptorLength;

위의 모습처럼 되어있다. 그런데 저 미국아가 한 짓은 deviceInfo->ReportDescriptor = RegistryReportDescriptor 를 NewReportDescriptor 로 바꿨다는 것이다. 그러니 필자도 역시 이 부분을 건드리게 될 것이란 소리가 된다. 그러므로 수정을 가할 부분을 한 부분 구체적으로 알아먹었다. 이 글의 맨 처음 시작부분의 Numega Soft 의 소스라고 되어있는 부분을 보자.

// The HID report descriptor for this device    
// (taken from USB/HID specification)    
   
HID_REPORT_DEscRIPTOR MouseHidReportDesc[] = {   
    0x05, 0x01, // Usage Page (Generic Desktop),     
    0x09, 0x02, // Usage (Mouse),      
    0xA1, 0x01, // Collection (Application),        
    0x09, 0x01, // Usage (Pointer),         
    0xA1, 0x00, // Collection (Physical),           
    0x05, 0x09, // Usage Page (Buttons),            
    0x19, 0x01, // Usage Minimum (01),          
    0x29, 0x03, // Usage Maximun (03),          
    0x15, 0x00, // Logical Minimum (0),
    ... 생략 ...


해당 부분을 보면 이제서야 뭔가 감이 오기 시작하게 되는 것이다.

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

드디어;;
 ·작성일     2007.01.28:15.25 (일)
· 작성자     rechoco
· 조 회     487


hid minidriver 테스트 살짝 성공~

샘플소스를 구해서 레포트 디스크립터랑 익스텐션 조금 손만 본거지만.

디바이스에서 데이터를 hid포멧에 맞춰서 주는게 아니라서..

강제로 제가 바꿔줘야 했거든요ㅋ

마우스로 테스트 해봤더니 쭉쭉 잘옮겨지더군요

물론 목표한 디지타이져는 아직 안됩니다;;
(와컴것 분석했더니 절대좌표모드일때도, 마우스 플래그를 쓰더군요
xp에서는 디지타이져가 지원이 안되니까 절대좌표 "처럼" 마우스좌표로 작업합니다.
저도 그렇게 하긴했는데. 영 개운하지가 않아서;;
디지타이져가 비스타에서는 지원 된다길래 해봤는데 실패했다는;;)

제가 참고한 샘플은 WDK의 vhidmini 소스입니다.

xp용으로 inf파일하고 소스파일 조금 수정하시면 빌드도 잘되고..

헛짓거리중에 잠깐 들러봤습니다.


드라이버 온라인님들 모두 화이팅하세요!!

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


아쉽게도 이 글은 가상 마우스인지 실제 마우스의 필터드라이버를 만든것인지 알길이 없어서 단지 말 그대로 희망만 주는 글인데 되긴 되나부다 정도로만 넘겨야 했다. 중요한 개념가닥을 잡아내는 파편과도 같은 내용들은 모두 끝났고(사실 더 많지만..) 다음의 세가지 정보의 검색이 사실상 전체적인 개념(컨셉)을 모두 얻도록 해주었다.

 

---------------------------------------------------------------------------------------------------
1. http://www.eggheadcafe.com/software/aspnet/32296449/virtual-usb-mouse-device.aspx

<Virtual USB Mouse Device only shows as generic HID device. - tomca>
08-May-08 05:16:00

I wrote a bus driver that generated virtual USB PDO for Printer, Scanner, and
SmartCard.  It worked fine before.  Recently, I was requested to provide a
virtual USB mouse PDO.  What I did was as following steps

1. An usermode application access bus driver to add a new PDO
2. bus driver use IoCreateDeviceSecure to create a new device and invalid
bus relation.
3. PNP manager found this new device, it will query the hardwareid, device
instanceid, and compatible id.
4. I provide USB\Class_03&SubClass_01&Prot_02 as compatible ID
5. System find this is a HID device and start to query Device Descriptor,
Configuration Descriptor, and HID descriptor.
6. Since this is a virtual mouse, bus driver gives HID descriptor without
hardware.  I copy a standard mouse device's HID descriptor (3button usb
mouse) to caller.
7. From Device Manager, I can see a HID device shows up,  but there is not
mouse device shows up.

If I plug in a real usb mouse, I can see system create a HID device first,
then HIDClass driver create a PDO for mouhid driver.  Is anyting wrong I did?

I have carefully checked the USB data sent to caller, everything is ok, but
system doesn't like this device as mouse,  Just consider it as generic USB
HID device.

Could someone give me help?

Thanks!
---------------------------------------------------------------------------------------------------

유저모드


---------------------------------------------------------------------------------------------------
2. KSP(www.ksyspro.org) 라는 곳에서 작성한 "USB강의자료.PDF" 라는 파일이 인터넷에서 검색되었다.
   내용의 제목은 "9차 정기 세미나 강의 자료" USB Device Driver 강의였다. 아쉽지만 원래 이런
   사이트는 문이 닫혀있다. (원래 그런거니까 이해를 해야한다.. -_-; 얼마나 힘들겠는가..? )

 - 내용이 작살이다. 이건 그냥 인터넷에서 받아서 보라.. 전체적인 개념정립이 이루어진다.
   (아마 앞서서 했던 기본적인 검색뻘짓이 없이는 읽을 수 있는 내용이 아니었으리..)

---------------------------------------------------------------------------------------------------
3. MSDN & ReactOS 소스 중의 USB 부분에 있는 Mouse 드라이버
 - 항상 마지막은 MSDN 의 승리이다. 전체적인 모든 내용이 다 들어있다. 빌어먹을 일정수준이상이
   되지 않으면 처음에 백날봐도 못알아 처먹는다는 것이 문제다. 커널이던 응용프로그래밍이던
   이건 차이가 없다. 지금도 응용프로그래밍도 못알아 먹는게 태반이니까. 어쩔수 없이 이 고생을
   치르는건 MSDN 을 보기위해서가 아닐까. (COM 프로그래밍도 MSDN 이 제일 많은 정보가 있다.)
   이 말을 증명해보겠음!!
   다음은 MSDN 의 vhidmini.h 라는 파일에 능구렁이처럼 맨 마지막 부분에 주석으로 처리되어있다.

[vhidmini.h 파일]

... 생략 ...
   
/*
//
// Here is sample descriptor that has two top level collection - mouse 
// collection and  vendor defined collection with a custom feature item. If 
// you want to provide sideband communication with your hidmini 
// driver, you can add a custom collection with the collection provided 
// by the hardware and open the custom collection from an app to 
// communicate with the driver.
// 여기 두개의 탑레벨 모음인 샘플 디스크립터가 있다.
// 커스텀 피처아이템을 가진 마우스 모음과 벤더 정의 모음이다.
// 니가 만약 너의 hidmini 드라이버를 가지고 사이드 밴드 통신을 제공하길
// 원한다면, 너는 하드웨어에서 제공되는 모음과 응용프로그램으로부터 드라이버
// 통신하는 것까지 개인모음을 추가할 수 있다.
// (역주: 즉, 몬소리냐면 이거 앞에서 선언한 DefaultReportDescriptor 대신에
//        이걸 그냥 가져다가 써라. 마우스 예제다. 이 말이나 마찬가지임.
//        여기에 니가 원하는거 추가해서 쓰라는 소리임. 이미 소스에 다 있었음.)
HID_REPORT_DEscRIPTOR           DefaultReportDescriptor[] = {
        0x05, 0x01,     //Usage Page (Generic Desktop),
        0x09, 0x02,     //Usage (Mouse),        
        0xA1, 0x01,     //Collection (Application),
        0x85, 0x01,     //REPORT_ID (1)             
        0x09, 0x01,     //Usage (Pointer),
        0xA1, 0x00,     //Collection (Physical),
        0x05, 0x09,     //Usage Page (Buttons),
        0x19, 0x01,     //Usage Minimum (01),
        0x29, 0x03,     //Usage Maximun (03),
        0x15, 0x00,     //Logical Minimum (0),
        0x25, 0x01,     //Logical Maximum (1),
        0x95, 0x03,     //Report Count (3),
        0x75, 0x01,     //Report Size (1),
        0x81, 0x02,     //Input (Data, Variable, Absolute), ;3 button bits
        0x95, 0x01,     //Report Count (1),
        0x75, 0x05,     //Report Size (5),
        0x81, 0x01,     //Input (Constant), ;5 bit padding
        0x05, 0x01,     //Usage Page (Generic Desktop),
        0x09, 0x30,     //Usage (X),
        0x09, 0x31,     //Usage (Y),
        0x15, 0x81,     //Logical Minimum (-127),
        0x25, 0x7F,     //Logical Maximum (127),
        0x75, 0x08,     //Report Size (8),
        0x95, 0x02,     //Report Count (2),
        0x81, 0x06,     //input (Data, Variable, Relative), ;2 position bytes (X & Y)
        0xC0,             //End Collection,
        0xC0,             //End Collection,

        0x06,0x00, 0xFF,   // USAGE_PAGE (Vender Defined Usage Page)     
        0x09,0x01,           // USAGE (Vendor Usage 0x01)      
        0xA1,0x01,           // COLLECTION (Application)        
        0x85,0x02,           // REPORT_ID (2)                      
        0x09,0x01,           // USAGE (Vendor Usage 0x01)              
        0x15,0x00,           // LOGICAL_MINIMUM(0)                   
        0x26,0xff, 0x00,   // LOGICAL_MAXIMUM(255)               
        0x75,0x08,           // REPORT_SIZE (0x08)                     
        0x95,0x01,           // REPORT_COUNT (0x01)                    
        0xB1,0x00,           // FEATURE (Data,Ary,Abs)             
        0xC0                    // END_COLLECTION                       
};

*/


자.. 이제 끝났다~ 라고?
한숨을 쉬기에는 너무 이르다. 대부분의 혼선과 문제점은 여기서부터 시작되기 때문이다. Microsoft 사의 WinDDK 라는 개발킷에 있는 vhidmini 샘플은 그저 샘플일 뿐이기에 정상작동이 되는지 확인을 해야하기 때문이다. 필자는 위에서 주석처리 되어있는 마우스 예제 DefaultReportDescriptor 의 주석을 풀고 기존에 있던 샘플 DefaultReportDescriptor 와 교체했다.

드라이버를 컴파일하는 방법은 여기서 설명하지 않는다. 그냥 WinDDK 설치후 프로그램 메뉴에서 XP 용 콘솔창을 열고 vhidmini 디렉토리로 이동후 nmake 명령을 내리면 컴파일이 가능한 것을 여기서 구차하게 다 설명을 할순없다. (그러면서도 벌써 설명까지 다 해주는 친절한 금자씨.. ㅎ) 이제 vhidmini 드라이버를 컴파일하고 장치를 인스톨 시키면 오른쪽 화면아래 트레이에 드라이버가 인식되었다고 뜰 것을 기대했다. 우리가 흔히 새 마우스를 USB 포트에 꽂으면 장치가 검색되었다고 뜨는걸 볼 수 있지 않은가? Human Interface Device(휴먼인터페이스장치) 어쩌구라는 메시지와 함께 잠시뒤에 마우스가 발견되었다는 식의 그런 메시지를 기대했다. 그러나 결과는 참담했고 미궁속으로 계속해서 빠져들고 말았다. 왜 그랬을까..? 비단 이 문제는 필자만의 문제가 아니었다. vhidmini 샘플 드라이버를 처음접하는 모든 프로그래머들이 모두 이같은 삽질의 미궁속에 빠져든다는 점을 검색을 통해서 알 수 있었다. 바로, MS 의 함정을 말이다.

여기서 다시 위와 같은 오류를 범해나가는 설명을 할 것이다. 어떤식으로 접근할 것인가와 얼마나 많은 뻘짓이 필요했는가에 대해서 설명할 필요가 있다고 본다. 그로인해서 얻은 것들은 상당히 많이 있다. 바로 단거리 스피드로 달리는 사람들은 놓칠수 있는 정보를 마라토너들은 두루두루 보고 달릴수 있는 것처럼 주변지식들을 충분히 얻을수 있다는 장점이 있다. 이 문서를 쓰는것 자체가 사실 기술적인 것에 너무 치우치는 쪽 보다는 학습방법을 알리는 병행효과를 얻기위한 것이기 때문에 무엇을 보았는지 지금부터 과정을 설명할 것이다.

앞서서 우리는 가상마우스를 만들기 위해서는 Virtual HID Device 를 만들수 있어야 한다는 점만 인식하고 출발했다. 완전히 지식이 전무한 상태에서 기본 골격코드마져 없는 허당상태로 시작할 수 있는 프로그래머는 아무도 없다. 이미 가상마우스 프로그램을 만들어본 경험이 있는 프로그래머라도 기본적인 코드의 골격없이 모든걸 직접 작성하는걸 기대하는건 어려운일이란 얘기이다. 그래서 우리가 앞에서 선행작업을 한 것이 바로 그 뼈대를 찾기위한 작업이었고, 숱한 오류과정을 거치며 우리가 만들 가상장치의 핵심뼈대를 발굴하고 비교 분석하여 선정하는 작업까지 마쳤다. 그리고 우리가 만들 장치에서 가장 중요한 핵심키포인트를 잡아내는 학습방법까지 소개하였다. 결론적으로 앞에서 습득한 사항들을 요약해 보자면..

1. 우리가 만드는 Virtual HID Device 는 mouse 또는 keyboard 와 혼합형태(혹은 단독일수도.. 그건 선택사항)이며 가상 USB 를 통해서 장치가 인식되어야 한다. 이 점은 프로그래밍적으로 정보를 수집하기 전에 머리속으로 구상한 내용에 속한다.(나중에 언급하겠지만 실제 설치/작동은 프로그래머의 상상과 약간 다르다.)

2. 여러 정보들을 수집하여 비교분석 한 뒤 그 중에서 vhidmini 라는 Microsoft 사의 WinDDK 개발킷 공식샘플을 채용하기로 최종결론을 내렸다.

3. vhidmini 라는 샘플을 운용하기위해 요구되는 스킬은 USB 의 HID 라는 인터페이스이며 이 인터페이스의 핵심 키포인트는 바로 Report Descriptor 라는 Descriptor 를 어떻게 기술할 것인가에 달려있다는 점을 알아낼 수 있다. 이 점은 이미 학습방법으로 어떻게 그 특징을 캣치하는지 보여주었다.

4. 우리는 최종적으로 Virtual HID Device 를 마우스로 인식시키기위해 Report Descriptor 라는 기술자(descriptor)를 찾아내야 했으며 적당한 기술자를 vhidmini.h 에서 발견하였다. 이 기술자를 Default 로 맞추고 컴파일 한 뒤 VMware 에 설치된 윈도우에서 설치하면 실제장치로 인식된다는 것까지 모두 정립하였다.
   
다음의 명령어를 이용해서 장치를 설치할 수 있다. 즉, 윈도우가 설치된 VMware 에는 vhidmini.sys 와 vhidmini.inf 그리고 devcon.exe 라는 총 세개의 파일이 복사되어야 한다. devcon 이라는 툴은 윈도우 장치관리자가 할 수 있는 모든 기능+ 를 콘솔에서 명령내릴수 있도록 해주는 커맨드유틸이다.

[설치명령]
devcon install vhidmini.inf "{D49F883C-6486-400a-8C22-1A9EF48577E4}\HID_DEVICE" 위와 같이 VMware 에 컴파일된 vhidmini 드라이버 파일들을 모두 복사한 뒤에 설치명령을 내린다. VMware 의 화면에는 신뢰를 받지못한 장치 드라이버 설치시에 뜨는 경고문구가 뜨게될 것이다. <계속> 이라는 버튼을 클릭하게되면 sys 파일을 찾지못해 디렉토리 지정창이 한번 더 뜰 것이다. 그 이유는 현 설치위치(devcon 명령어 실행디렉토리 위치) 밑에 i386 이라는 디렉토리에 sys 파일이 존재한다는 가정을하기 때문이다. 즉, INF 파일이 존재하는 위치를 기준으로 그 하위 i386 디렉토리에서 드라이버파일을 찾는다. 그래서 드라이버를 못찾는다는 창이 뜨게된다. 이건 그냥 적당히 vhidmini.sys 파일이 있는 디렉토리를 지정하면 알아서 설치가된다. 그런데.. 우리가 예상했던 설치모습이 아니었다. 그건 필자만의 착각이었을런지도 모르겠지만, 일단 이렇게 장치의 설치과정은 밍밍하게 끝나버린다. 이제 장치가 제대로 인식되었는지 확인을 하기위해 "장치관리자" 를 오픈한다. 그러면 휴먼인터페이스 장치쪽에 두가지 장치가 새롭게 추가되어있는 것을 보게될 것이다. 그런데, 뭔가 생각하던것과는 다르게 인식된 듯한 생각을 가지게 될 것이다. 그 장치는 그저 Generic HID 장치일 뿐 마우스가 아니다. 이게 도대체 어찌된 영문인가? 뭔가 잘못된 것이 있는지 확인해보고 수도없이 DefaultReportDescriptor 를 수정 해봐도 역시나 마찬가지로 마우스로 인식되질 않았다. Revert to snapshot 을 수도없이 반복하며 디스크립터 (Report Descriptor) 를 수정해도 역시나 반응은 일반장치(Generic HID) 일 뿐이었다. 정확히 말하면 VMware 기준으로 XP 에서 장치를 설치했을때 설치되는 이름은 두가지였다.

"HID 준수장치"
"Root Enumerated HID Device (sample)"
위의 두가지 장치가 설치된다. 우리가 원하는 것은 "HID 준수장치" 가 "HID 규격 마우스" 로 인식되어야만 한다. 그런데, 이런현상이 계속 지속되어 혼란이 가중될 뿐이었다. 어딘가 필자가 모르는 키포인트가 또다시 존재할 것이리라 생각하고 이 현상을 겪는 어딘가에 있을 동지에게 SOS 를 날려야 했다. 우리의 구글형님이 그러한 고충을 겪는 사람들을 모두 한자리로 집합시켜주었다. 그런데.. 구글이 불러모은 검색정보들은 하나 같이 모두 헛소리들 뿐이었다. 근접은 했어도 정답이 하나도 없는게 아닌가.. 제길.. FireFox 에서 탭을 약 20개 가까이 띄워놓고 검색에 검색을 반복하며 필자의 Report Descriptor 정보중 어디가 잘못되었는지를 찾아내기 위해서 안간힘을 쓰고 있었다. Report Descriptor 라는 것은 무엇인가? USB 라는 장치가 자기의 정보를 상위장치에 넘겨서 인식되도록 하기위한 마치 신분증과도 같은 것이다. 어디서 태어났고 어디서 자랐으며 나이는 몇살이고 남성인지 여성인지 기타등등.. 마치 이런정보처럼 인식정보를 쏘기전에 셋팅하는 값이다. 이 값이 하나라도 잘못될 경우에 장치는 절대로 제대로 인식되지 않는다. 항상 사람이 고생을 하려면 깨닫는 과정에서 착각을 일으키게된다. 필자는 vhidmini.h 파일에 있는 공식적인 마우스(예제) 디스크립터 주석을 풀어서 대체시켰다. 필자는 그 디스크립터를 믿지 못했다. 어딘가 오류가 있거나 한가지를 수정함으로
인해서 다른것까지 수정해야하는 문제점이 걸렸다거나 그런류로 생각할 수 밖에 없었다. 다음은 필자와 같은 문제점을 겪는 사람들에 대한 이야기다. 그다지 위안도 되지 않았고 결국 구글형님을 통해 문제의 정확한 해결점을 찾아낼 수 없었지만.. 그 과정에서 문득 떠오르는 영감을 주었기에 그 과정을 그려보고자 한다.

http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2007-03/msg00258.html
-----------------------------------------------------------------------------------------------------------------
thank for your advice.
i forget to assign REPORT_ID for each report desc.
It works now.
However, i migrated the corrected report to "hidfake". (Walter Oney 's sample)
The system pop up 3 "Found New Device Wizard" window and identfy it as "Unknow Device".
Any difference detween these 2 drivers' enumeration?
Appreciated.
(필자요약: REPORT_ID 를 빼먹었다. 작동된다. 그런데 hidfake 꺼를 배꼈다. 그랬더니 "알려지지않은 장치" 라는 새로운 장치로 "하드웨어 찾기" 가 세개나 뜬다. 나머지는 해석할 필요 없겠다.. 왜 그런가? 라는 질문 이라고 생각하고 넘어간다..)
-----------------------------------------------------------------------------------------------------------------
"Doron Holan [MS]" wrote:
    you only need one HID minidriver. from it, a keyboard and a mouse can
    be
    enumerated. you just have to put each device into its own top level
    collection. If you are having trouble, i would find a USB HID that already
    does this and look at its HID descriptor
(필자요약: 이놈이 다른 게시판에도 있는걸보면 좀 하는거 같다. 대충 번역하면 너는 오직 한개의 HID 미니드라이버만 필요할 뿐이다. 그리고 키보드나 마우스가 열거될수 있는 것으로 부터, 그리고 각각의 그 자신의 탑레벨 모음속에 각장치들을 넣어야만 한다. 만약 문제가 있다면, 니가 만든 USB HID 를 어쩌구 저쩌구.. 뭔가 HID Descriptor 와 연관이 있겠거니하고 그냥 넘어감..)
-----------------------------------------------------------------------------------------------------------------
I'm pretty sure you will need to break up hte device into a Mouse device and Keyboard device. (i.e two drivers,
one with a report descriptor for a keyboard and one for a mouse)
The inf files should not refer to HID\MyVirtualHidDevice - these id's need to be picked up from keyboard.inf or
msmouse.inf - idealy reporting the compatible id of HID_SYSTEM_KEYBOARD or HID_SYSTEM_MOUSE (i think)
(필자요약: 마우스와 키보드장치속에 hte 장치를 깨야할 필요가 있다라고 해석해야 하나..  이놈이 주장하는 내용은 일단, report descriptor 에 키보드와 마우스가 하나로 일치되어있는가를 확인하라는 내용과 HID\MyVirtual HidDevice 라는 장치명으로 되어있는 vhidmini.sys 샘플이 이름이 잘못되어서 그런게 아니냐는 속임수에 빠지기 쉬운 의견을 제시해 놓고 있다. 마치.. 네이버 지식인인가? 하지만 여기서 얻을 수 있는 점이 있는데 HID_SYSTEM_KEYBOARD, HID_SYSTEM_MOUSE 라는 지시어이다. 어설픈건 혼란을 가중시키는데 원래는 HID_DEVICE_SYSTEM_KEYBOARD 이고 HID_DEVICE_SYSTEM_MOUSE 가 맞는거니까 속지말자. 뒤에서 설명하겠지만 이걸 알아 듣기 위해서 새로운 개념을 습득하게 된다.)
-----------------------------------------------------------------------------------------------------------------
Hi,
I write a HID minidriver with standard Mouse and Keyboard report
descriptors.
It is based on vhidmini in Windows Server 2003 DDK.
The driver work fine and I can read/write the report from the
device.
The Device Manager shows it is HID-compliant device in HID class,
but
the
Mouse Class and Keyboard Class have none.
How should I do so that it can be a mouse device and keyboard
device?
Should I modify the INF file? My driver's INF is almost same as the
vhidmini's.
(필자요약: Windows Server 2003 DDK 로 vhidmini 를 만들었다는 식인데 장치명이 HID-compliant(일반 복합HID 장치)로 인식되는데 마우스 클래스와 키보드 클래스가 없다고 말한다. 어떻게 마우스와 키보드 장치로 인식시키는 것이냐고 물어본다. 자기가 INF 파일을 수정해야 하는지 물어본다. 그리고 INF 파일은 vhidmini 와 거의 같다고 말한다. 이 사람이 겪는 증상이 필자가 겪는 증상과 100% 일치한다. 그런데 불행히도 이 글에는 더이상의 답변이 달려있지 않았다. 눈물의 고배를 마시고 돌아서야 하는 이 저린마음.. T.T 어쩔수 없이 또다시 구글형님의 도움을 받아야한다.)
-----------------------------------------------------------------------------------------------------------------
이 질/답들에서 배운 것은 검증해봐야하는 대상들이다. 일단, HID Report Descriptor 가 잘못되었는지 검증해야하며 INF 파일이 잘못되었는지 검증해봐야하고 "한참을 헤메게 만든 요인이었지만" REPORT ID 에 대해서도 검증해봐야 한다는 몇가지 결론을 얻은채 새로운 검색활로를 모색해보게 된다. 이 검색은 첫 발을 내딘수준에 불과하다. 거의 48시간을 오로지 이 문제를 해결하기 위해서 정보들을 모아야 했다.
http://www.techtalkz.com/microsoft-device-drivers/297875-loading-driver-hid-class.html
-----------------------------------------------------------------------------------------------------------------
Loading a driver on HID class
Hi all,
I have a USB device that exposes a HID interface. It is not a mouse or
a keyboard, just a general HID device. Device Manager displays it as a
"HID-compliant device".
Now I would like to install a device driver on it and use the HID
interface to communicate with.
My INF refers the HID\VID_xxxx&PID_xxxx string and my driver gets
loaded.
So I get the PDO from AddDevice and I need the FileObject to
communicate using IOCTL_HID_SET_FEATURE and IOCTL_HID_GET_FEATURE. But
I cannot retrieve it; I use the FireFly sample and the function
FireflyOpenStack to retrieve the FileObject form the PDO but it fails
in my driver with error 0xC000000E (STATUS_NO_SUCH_DEVICE) when
calling ZwOpenFile.
What's wrong? The pdoName of the file open by ZwOpenFile is something
like "\Device\00000096". Is it possible to get the SymbolicLinkName
instead?
If someone could help...
Thanks, Roger
(필자요약: HID 인터페이스를 노출하는 USB 장치를 만들었다. 그런데 그게 마우스나 키보드가 아니네? 단지
           일반 HID 장치인거야. 디바이스 디스플레이에 보면 "HID-compliant device" 라고 표시되네.
       횽님들.. 알려주십쇼.. 뭐 이런 내용식으로 글을 써놨다. 그래도 아는게 많은 사람이라서 그런지
       정보들을 많이 뿌려놨는데 독이되는 요소들이 있지만, 덤으로 알게되는 요소들도 그 못지않게
       많다. IOCTL_HID_SET_FEATURE 과 IOCTL_HID_GET_FEATURE 에대한 얘기는(추후 구현되어야 하는 내용)
           좋은 정보임에 틀림없다. 그런데 우리가 원하는 답을 얻지는 못하고 단지 INF 파일에 VID 와
       PID 스트링이 문제의 시발점이 될수도 있지는 않은가 하는 의심을 해볼수 있다. 물론, 그게 해답은
       아니지만 추가정보를 검색해야할 키워드로써 대상물망에 넣어두자. VID 란 벤더아이디를 의미하고
       제작사의 고유식별번호이며, PID 란 프로덕트 아이디 즉, 제품번호이겠다. 이게 하드웨어는 모두
       고유하다고 하는데 과연 이 때문에 마우스나 키보드로 인식이 안되고 일반장치로 인식되는 것일까?)
-----------------------------------------------------------------------------------------------------------------
when are you trying to open a handle? during AddDevice or
IRP_MN_START_DEVICE? neither will work b/c a file create can only occur
once the start irp has come back to the pnp manager. so to make this work i
would
a) register a custom device interface GUID
b) register for device interface arrivals on your custom guid. when you
get called, open your stack like FireFly does
you will also need to register for handle notifications on the file handle
that you open so that you can gracefully disable the device. If you use the
KMDF firefly sample, the WDFIOTARGET object does this for you
(필자요약: 답변중에 하나인데 이 답변은 질문자의 추측보다 더 가관이다. IRP_NM_START_DEVICE 나 AddDevice 등록시 (필자는 커널을 몰라서 몬소린지 모르지만 이건 아니다정도의 감은 있었다.. -_-;) 하라는 식으로 답변이 달려있는데 KMDF 까지 들먹거리는걸로 봐서는 논점에서 많이 빗나갔다. KMDF 는 새로운 드라이버 개발 프레임워크인데 질문자가 그걸 물어본게 아니다. 기존의 방법으로 설명해줘야하는 것이 옳은데 그렇지도 않았고, 너무 많은 작업을 추가하라고 주문하는거보니 필자의 생각과 달랐다. 필자의 감은 Report Descriptor 만으로도 해결될 문제라고 속삭이고 있었기 때문에 이 답은 해결책이 아니었다. 다른 답변중에는 URB 를 보내라는 말도 있었다. 모두 무시한다.)
-----------------------------------------------------------------------------------------------------------------
지금 거론하는 필자의 문제해결 방법은 링크를 보여주면서 찾아나가는 방법을 설명하고 있다. 그렇기에 링크역시 필자가 검색해서 누른 순서대로 임을 밝힌다. 다음으로 찾은 것은 MSDN 의 설명이다. 그런데 MSDN 의 설명은 항상 깨달음을 얻은뒤에나 값진 보물이 되지 깨달음을 얻기전까지는 그저 잘 만들어진 명세서에 불과하다고 느낄때가 많다. 마치 선생님이 "공부하라"고 그렇게 들볶던 말들이 성인이 된 뒤에 "정답" 이라고 느끼는 것처럼 느낀뒤에만 알 수 있는 것들이 기록되어 있는게 MSDN 과도 같다. 왜 그땐 몰랐지? 왜 그땐 안봤지? 나중에 이런말 자주하게 될거다. ㅎㅎ 그런데.. 역시.. -_-; 이 링크를 보던 시점(현 글을 쓰는 시점기준으로 하루전)만 해도 이 링크는 그저 도움이 안되었다.
http://msdn.microsoft.com/en-us/library/aa487252.aspx
(필자요약: 설명이 잘 되있다. 읽어보라.. 해결책도 들어있다. 그런데 그냥보면 절대 모른다. 개고생하면 그때는 답이 보이지만 그냥보면 모른다.)
-----------------------------------------------------------------------------------------------------------------
http://www.programmer-club.com/pc2020v5/forum/ShowSameTitleN.asp?URL=N&board_pc2020=driver&id=2986
-----------------------------------------------------------------------------------------------------------------
(필자요약: 이 사이트는 중국사이트인데 읽을수가 없다. 몇가지 좋은 키워드와 코드가 있는데 해결책은 아니고 나중에 마우스나 키보드를 구현할때 참고할 만한 코드가 아주 조금 있을 뿐이었다.)
-----------------------------------------------------------------------------------------------------------------
http://www.osronline.com/cf.cfm?PageURL=showThread.CFM?link=144873
-----------------------------------------------------------------------------------------------------------------
(필자요약: 필자가 겪는 문제를 어느정도 일부분은 해결한 것 같기도하고 그렇지 않은거 같기도 한데 희한한
            삽질을 하고 있었다. Descriptor 를 계속해서 바꿔가면서 테스트하는 것을 물어보고 있었다.
        마우스와 키보드를 인식시키기 위해서 vhidmini 를 기본베이스로 디스크립터를 조작하는데 설치가
        안된다는 그런 질문이었다. 질문양이 많아서 짤라붙이기는 못하겠다. 답글을 보자.)

Adrian Schlesinger
xxxxxx@baum.ro
    
Join Date: 24 Sep 2008
Posts To This List: 7
RE: Simulate keystrokes
I have detected what was wrong:
1. When adding the report ID item to the keyboard top-level collection, an additional byte should be returned to
   the system at the beginning of the data, specifying that report ID.
2. Communication from user mode did not work because when cycling through the HID devices,
   in addition to vendor ID, product ID and version, the usage specified for the additional end point should also
   be matched (with Vendor Usage 1), otherwise you can end up trying to call WriteFile for a handle corresponding
   to the keyboard end point.
(필자요약: 질문자의 답글인데 키보드 top-level collection(최상위 모음) 에 REPORT ID 를 추가할때 어쩌구 저쩌구 얘기가 나온다. 그리고 usage 라는 말도 나온다. 필자가 원하는 답이 여기에 있을 것이라고 생각하여 엄청난 검색을 통해 알게되었는데 원하는 답은 아니었다. 단지, top-level 의 개념은 중요했다.
-----------------------------------------------------------------------------------------------------------------
http://www.techreplies.com/drivers-43/hid-minidriver-multiple-report-descriptors-543372/
-----------------------------------------------------------------------------------------------------------------
(필자요약: 앞에서 어떤사람이 한 질문과 똑같은 질문인듯 싶다. 왜 도대체 마우스로 인식이 안되냐.. 이 질문이다.)
-----------------------------------------------------------------------------------------------------------------
다음은 중요한 개념중에 하나인 Top-Level Collection 이다.
http://www.microsoft.com/whdc/archive/HID_HWID.mspx#E1
-----------------------------------------------------------------------------------------------------------------
Special Top-Level Collections (Reserved for OS use)
Certain HID top-level collections generate a special HID device string. In Windows 2000, Windows XP, and Windows
Server 2003, the top-level collections listed in Table 6 are special cased and each has an additional hardware ID.
Table 6 identifies these collections. The last column identifies the additional string that is added to the hardware
ID list.
Table 6: Special-Cased Top-Level Collections
Device Type                Usage Page    Usage ID       Additional Hardware ID
Pointer                    0x01          0x01           HID_DEVICE_SYSTEM_MOUSE         exclusive
Mouse                      0x01          0x02           HID_DEVICE_SYSTEM_MOUSE         exclusive
Joystick                   0x01          0x04           HID_DEVICE_SYSTEM_GAME 
Game pad                   0x01          0x05           HID_DEVICE_SYSTEM_GAME
Keyboard                   0x01          0x06           HID_DEVICE_SYSTEM_KEYBOARD      exclusive
Keypad                     0x01          0x07           HID_DEVICE_SYSTEM_KEYBOARD      exclusive
System Control             0x01          0x80           HID_DEVICE_SYSTEM_CONTROL
Consumer Audio Control     0x0C          0x01           HID_DEVICE_SYSTEM_CONSUMER

(필자요약: 이게 모냐면 Top-Level Collection 이라 불리우는 입력장치유형이다. 위에서 Usage Page 와 Usage ID 라는 것이 있는데 이게 바로 Report Descriptor 에 있는 항목에 적혀있다. 이걸 어떻게 바꾸느냐에 따라서 가상장치가 마우스가 되느냐, 키보드가 되느냐 아니면 조이스틱이 되느냐를 결정한다. 멋지지 않은가? 물론, 원하는 해답은 아니다. 그러나 필수적으로 개념을 갖고가야 한다. 여기서 중요한게 있다면 입력 장치의 형태가 공유(share)모델이냐 아니면 베타적모델(독점)이냐 이다. 마우스와 키보드는 독점모델이다. 즉, 마우스와 키보드는 장치가 열려있으면 다른 프로그램이 장치를 열어서 쓰고읽는 것이 불가능 하도록 secure 모델로 처리되어있단다. 이때, 이걸 피해가려면 새로운 장치를 동일하게 하나더 만들어서 그 장치와 통신하면 이런 독점모델을 피해갈 수 있단다. MSDN 에 다 나와있다.. 전부 다~ 링크가 있었는데 FireFox 가 깨져서 다 날아가 버리는 바람에 찾을수 없지만 베타적오픈과 공유오픈이 가능한 표시가 위의 Top-Level Collection 에 일일이 나열되어 있는 정보도 찾을 수 있었다. 어쨌거나 중요한건 짚고 넘어가자.. 참고로 잊지는 않았겠지? 가상장치가 일반장치로 인식되서 마우스 장치로 인식시키려고 뻘짓하다가 이런곳까지 당도하게 된거란 점.. 이렇게 정보들을 다양한 방법으로 얻어서 공부하는데도 웹서핑한다고 눈치주는 경우도 있다. x같은 경우지.. 이게 단순히 노는걸로 보여? 입에서 욕나오네.. 갑자기 머리에 히터가 작동되서 한번 지껄여봤습니다. 다시 집중모드로 돌아가봅시다.. ㅋㅋ)Table 13-1   HIDCLASS-Compatible ID for Each Supported Usage지원되는 HIDCLASS 호환 아이디.. HIDCLASS 는 각 장치로 분배를 해주는 역할을 한다고 합니다. 더 자세한건 묻지마삼 다칩니다요.. 전 아는것만 얘기할 뿐임..
http://www.microsoft.com/mspress/books/sampchap/6262.aspx

Usage Page         Usage                   Compatible ID
Generic desktop       Pointer or mouse        HID_DEVICE_SYSTEM_MOUSE
                   Keyboard or keypad      HID_DEVICE_SYSTEM_KEYBOARD
                   Joystick or game pad    HID_DEVICE_SYSTEM_GAME
                   System control          HID_DEVICE_SYSTEM_CONTROL
Consumer           (Any)                   HID_DEVICE_SYSTEM_CONSUMER

<Report Descriptor Header>
앞서서 XBCD 라고 XBOX 조이스틱 에뮬레이션 드라이버에 대해서 말한적이 있습니다.
헤더의 USAGE_PAGE 를 잘 봅시다. 그리고 USAGE 를 봅니다.
// XBCD 예
char ReportDescriptor[213] = {
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)     <-- 요건 뭐시냐? Table 13-1 입니다욤..
    0x09, 0x04,                    // USAGE (Joystick)        <-- 위의 Table 6 에 Joystick 의 Usage ID 보입니껑?
    0xa1, 0x01,                    // COLLECTION (Application)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,                    //   PHYSICAL_MAXIMUM (1)
// vhidmini.h 의 맨마지막 주석이 되어있었던 마우스예제 헤더
HID_REPORT_DEscRIPTOR    DefaultReportDescriptor[] = {
        0x05, 0x01,      //Usage Page (Generic Desktop),   <-- Table 13-1 일반 데스크탑
        0x09, 0x02,      //Usage (Mouse),                  <-- Mouse 임
        0xA1, 0x01,      //Collection (Application),
        0x85, 0x01,      //REPORT_ID (1)                   <-- REPORT_ID 꼭 이게 값이 있는지 확인해야함.
        0x09, 0x01,      //Usage (Pointer),                    HID Tool 이라는 놈은 이 값을 빼고 보여줌.(주의!)
        0xA1, 0x00,      //Collection (Physical),
        0x05, 0x09,      //Usage Page (Buttons),
        0x19, 0x01,      //Usage Minimum (01),
        0x29, 0x03,      //Usage Maximun (03),
        0x15, 0x00,      //Logical Minimum (0),
여기서 Top-Level collection 이 지칭하는 의미는 상위장치입니다. 이런식으로 다중 인터페이스를 구현할 수 있는데 예를들면 마우스와 키보드를 가상장치 하나로 일타쌍피도 만들어낼 수 있습니다. 시중에 파는 키보드 중에 마우스도 있고 USB 포트도 달려있는 키보드들은 이런 다중인터페이스를 만들기위해서는 multiple top-level collection 지정을 해줘야 한다는 얘기죠. 어쨌거나.. 이러한 정보들은 얻었고 Report Descriptor 가 잘못된 것인가라고 판단해보니 전혀 아니었습니다. 오히려 첫번째 XBCD 의 헤더모습에서는 REPORT ID 가 보이지 않는데 두번째 vhidmini.h 에서는 REPORT ID 항목도 빼먹지않고 넣었고 완벽합니다. 그런데 왜.. 대체 왜!! 인식이 마우스로 되지않고 일반장치라고 잡히는 거냐 이말이죠.. 심지어는 공식사이트에서 다운로드 받은 마우스와 키보드 Report Descriptor 를 가져다가도 해봤고 직접 하드웨어에서 뽑아낸 값을 통해서도 해봤지만 모두 인식이 안되었답니다.
-----------------------------------------------------------------------------------------------------------------
사실.. 위에서 언급한 내용은 탐색과정에서 추가로 얻어내는 개념들에 대해서 비중이 있었기에 설명을 하였습니다. 아마, 계속해서 같은 방식으로 설명하면 이 문서를 보면서 쌍욕을하게 될지도 모르기에 후다닥 빨리 접겠습니다. 다음은 제가 문제해결(일반장치를 마우스로 인식하게 만드는)을 하기 위해서 찾아다녔던 링크입니다. 더 많지만 추려서 올려봅니다.
http://coding.derkeiler.com/Archive/General/comp.arch.embedded/2008-01/msg00501.html
http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2005-03/0829.html
http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2005-03/0806.html
http://www.techreplies.com/drivers-43/minidriver-hidclass-336914/
http://www.techreplies.com/drivers-43/my-hid-mouse-how-write-data-331146/
http://www.osronline.com/DDKx/intinput/hidfunc_7oky.htm
https://www.usb.org/phpbb/viewtopic.php?t=14027&sid=b40543b8bc019ff50c70025ff1886898

(결정적인 영감을 주게된 링크는 바로 다음의 링크이고 사실, 앞에서 한번 언급했었던 링크입니다.. 정확히 말하자면 해결방법을 직설적으로 말해준게 아니라, 넌 이걸 이해해야된다라고만 코드의 일부분을 언급하고 숫가락으로 떠먹여 주지는 않겠다는 인상을 풍기는 답글이지요.. 처음에는 이걸 보고도 잘 이해를 못합니다. 저만 그런건 아닐겁니다. 어떤 질문자 중에서는 프린터, 스캐너, 스마트카드를 비롯해 각종 디바이스 드라이버를 만들었다는 이력을 밝히며 저와 같은 증상때문에 고민을 하고 있는 사람도 있었으니까요.. 제가 볼때 이건 MS 의 함정입니다. 의도하지 않은 함정말입니다.)
https://www.osronline.com/showthread.cfm?link=138652
-----------------------------------------------------------------------------------------------------------------
바로 이 답글이 눈을 뜬 사람에게만 통하는 핵심인 셈입니다.
allen zhang
xxxxxx@sina.com
    
Join Date: 22 Jul 2008
Posts To This List: 38
RE: VHidMini report descriptor(s)
see the follow source code and the ReadDescriptorFromRegistry function, You should be understand it.
deviceInfo->HidDescriptor = DefaultHidDescriptor;
queryStatus = CheckRegistryForDescriptor(DeviceObject);
if(NT_SUCCESS(queryStatus)) {
    queryStatus = ReadDescriptorFromRegistry(DeviceObject);
    .......
(필자요약: 다음의 소스코드와 ReadDescriptorFromRegistry 함수를 봐라.. 너는 이걸 이해해야할 필요가 있다.
            라고 말하며 일부 소스를 첨부했습니다. 그리고는 아무런 추가의 말도 없습니다. 장난하는것도
        아니고.. -_-; 이때 아차하고 생각을 떠올리면 이 문제는 해결됩니다. 위에서 숱하게 질문하던
        외국 개발자들도 결국에는 알아냈겠지요?)
-----------------------------------------------------------------------------------------------------------------
vhidmini 드라이버를 구동시키고 일반 HID 장치로 인식된 드라이버를 마우스 장치로 둔갑시키기 위해서는
소스를 수정해야 합니다. 바로 vhidmini.c 드라이버 소스를 수정하는 일입니다. 그것도 필자가 생각했었던
Report Descriptor 의 오류를 수정하는 것이 아니라 코드를 수정해야 합니다. 앞에서도 한번 언급했었지만
Microsoft 사의 공식 DDK 샘플소스에 오류가 있을리는 없으니까요. vhidmini.h 에 주석으로 정의되어있던
마우스 Report Descriptor 의 예는 오류가 없었습니다. 오류에 빠지도록 만든것은 바로 ReadDescriptorFromRegistry
함수에 있었습니다. vhidmini 소스를 보면 주석에 써있기를 우리는 하드코딩을 하였다라고 적혀 있습니다.
Report Descriptor 를 하드코딩 하였다는 것이지요. 그런데, 단순히 그냥 하드코딩으로 놔두지.. 더 많은걸
보여주고 싶었던지 if-else 로 두가지 처리루틴으로 나눠놓은것이 문제의 핵심이었던 것입니다. 다음의
소스를 보십시오.
-----------------------------------------------------------------------------------------------------------------
[vhidmini.c 소스에서 수정해야 할 부분]
    
 HID Report Descriptor 를 레지스트리에서 읽어들이는 코드를
 하드코딩쪽으만 처리하도록 수정함.

    deviceInfo->HidDescriptor = DefaultHidDescriptor;
    //
    // Check to see if we need to read the Report Descriptor from
    // registry. If the "ReadFromRegistry" flag in the registry is set
    // then we will read the descriptor from registry using routine 
    // ReadDescriptorFromRegistry(). Otherwise, we will use the 
    // hard-coded default report descriptor.
    //
    queryStatus = CheckRegistryForDescriptor(DeviceObject);  // 함정이 발생하는 지역
    if(NT_SUCCESS(queryStatus)){
    //
    // We need to read read descriptor from registry
    //
    // 장치를 설치할때 INF 파일에 있는 Report Descriptor 가 레지스트리에 기록되고
    // 이 부분에서 레지스트리에 기록된 Report Descriptor 를 읽어들임.
    // 그러므로 백날 헤더의 Report Descriptor 를 바꿔봤자 INF 파일에 있었던 것을
    // 읽어들이는 꼴이 되므로 항상 "일반 HID 장치"(Generic HID Device) 가 드라이버로
    // 등록될 수 밖에 없었던 것이다. 이런 제길.. 이 문제로 이틀을 꼬박 다 날렸다니..
    // Microsoft 는 반성하라~!! Microsoft 는 함정을 제거하라~!!
    // 고로 이 부분으로 빠져들지 않도록 주석처리 하라..
    queryStatus = ReadDescriptorFromRegistry(DeviceObject);
                               
    if(!NT_SUCCESS(queryStatus)){                          
        DebugPrint(("Failed to read descriptor from registry\n"));
        ntStatus = STATUS_UNSUCCESSFUL;
    }
}
else{
    //
    // We will use hard-coded report descriptor. 
    //
    deviceInfo->ReportDescriptor = DefaultReportDescriptor;
    DebugPrint(("Using Hard-coded Report descriptor\n"));
}

... 중략 ...
case IRP_MN_REMOVE_DEVICE:
    //
    // free memory if allocated for report descriptor
    //
    // 이 부분도 주석처리해야 한다. 왜냐면 레지스트리에서부터 읽어들이지 않았기 때문에
    // 메모리 할당이 안되어 있기 때문이다. 그냥 두어도 상관없을거 같지만 메모리 해제부분이니
    // 꺼림칙하므로 되도록이면 제거하길 바란다.
    if(deviceInfo->ReadReportDescFromRegistry)
        ExFreePool(deviceInfo->ReportDescriptor);
    SET_NEW_PNP_STATE(deviceInfo, Deleted);
    ntStatus = STATUS_SUCCESS;           
    break;   
-----------------------------------------------------------------------------------------------------------------
이제 vhidmini 샘플을 컴파일하고 VMware 에 vhidmini.sys 와 vhidmini.inf 파일을 복사하자. 그리고 devcon 명령으로 앞서했던 것처럼 install 을 해보자. 설치를 하고나면 장치관리자의 기존에 있던 "HID 준수장치" 라는 것은 없어지고 마우스항목에 "HID 규격 마우스" 가 추가되는 것을 볼 수 있을 것이다.(ㅎㅎ 이맛을 보려고.. 밤을새고 삽질을..) 이제.. 장치관리자에서 새로 추가된 "HID 규격 마우스" 를 선택한 뒤에 속성을 보자. 속성을 선택한 뒤 "자세히" 라는 것을 클릭한다. 그리고 장치인스턴스 ID 라는 것을 보라. HID\MyVirtualHidDevice&Col01 라고 되어있는 것을 볼 수 있다. 또한, 일치하는 장치 ID 를 선택하면 hid_device_system_mouse 라고 되어있다. 즉, 마우스로 인식이 되었다는 것이다. 가상 HID 디바이스 위에서 마우스 장치가 인식되어 있는 것이다. 이제 가상 HID 디바이스와 어플리케이션 간에 통신루틴을 프로그래밍하고 어플리케이션의 명령에따라 상위 클래스로 IRP/URB 같은 요청을 (이거참.. 이 레이어에서는 어떤 요청을 사용해야하는 건지 또 공부해야하는군.. -_-; USB 강의 문서에 보면 상위 클래스는 URB 통신을 한다고 나와있었다..) 날려주면 키보드나 마우스 같은 장치들을 에뮬레이션 시킬수 있다. 곧, 가상장치를 조종할 수 있다. 하지만? 그리 쉽지는 않을 것이다. vhidmini 샘플에는 testvhid 라는 어플리케이션 소스도 같이 들어있는데 이 testvhid 소스는 어플리케이션단에서 vhid miniport 드라이버와 통신하는 예제이다. 참고로 아무런 수정없이 샘플만 컴파일해도 어플리케이션과 드라이버 사이에 제대로 통신이 이루어지지않는다. 역시나 이 문제는 HID Report Descriptor 의 데이타의 구성문제에 속한다. 한번 고생한 것이 또다시 반복되는 시점이기도 하다. 이 부분을 해결하면 어플리케이션은 2 또는 3 가지의 top-level collection 중에서 사용자정의(User-Defined) 콜렉션을 통해서 miniport 드라이버와 통신을 할 수 있게되고 이 통신에 따라서 마우스 IRP 를 상위 클래스로 때려주면 된다. 더 자세한 내용은 스스로 연구하길 바란다. 이상으로 이번문서를 마무리하려고 한다. 왜냐면 이제 테스트 기반이 마련되었으니 나머지 추가구현은 스스로가 해야할 몫이기 때문이다. 어떠한 목적으로 개발하던간에 그 이상은 이제 필자가 관여할 부분이 아닌것 같다.

어차피 이 문서의 목적은 가상 마우스를 제작하는 것을 중점으로 삶는 것보다도 모르는 분야를 독학하며 개척해 나갈때 자신의 공부스타일의 한 예로써 제시하는 것이었다. 여기서 거론된 공부스타일을 종합해 본다면 이렇게 말할 수 있을것 같다. "관례를 찾아냄으로써 DIFF 를 추출해내는 공부법" 이라고 할 수 있다. 즉, 최대한 많은 자료들을 검색으로 긁어모은 뒤에 분리분석 작업을 통하여 동일한 부분의 반복을 찾아낸다. 찾아낸 반복내용이 있다면 결국 그 반복은 해당 프로그래밍의 관례에 속한다. 즉, 해당 관례는 몸으로 빨아들이고 차이가 나는 지점에서 기술을 흡수한다. 이런식의 반복학습을 통하여 더이상 다른 코드나 정보들을 찾아낼 수 없다고 판단이 들때 그 기술은 자기것이 된다. 필자는 유저레벨을 공부할때 항상 이방식을 택해왔다. 정보가 고갈되고 더이상 찾아낼수 없을때까지 긴시간을 할애해서 리서치를 먼저 한다. 그 뒤에 코딩으로 들어간다. 그리고 관례코드를 따른다. 그렇게되면 생전 처음보는 프로그래밍에서도 어느지점은 건드려도 되고 어느지점은 절대 건드려서는 안되는지 쉽게(? 정확히가 맞겠다) 익힐수 있다.

이제는 커널레벨 공부를시작하면서 이 고통스럽고도 지루한 공부방식을 다시 사용하고자하며 다른 사람에게 조그마한 도움이 되고자 이런 문서를 작성하였다. (같이 게임에 미쳐서 광랩하던 친구가 갑자기 URL 을 려줘서 읽어 보았더니 국가에서 인증한 기술이라는 자랑스런 인증서와 함께 뭔가를 팔고있었다. 보란듯이 대놓고 말이다. 디자인도 쌈빡해서 사고싶게 만드는 그것.. 그게 뭔지는 대충 말안해도 알겠지만.. 이 문서를 빨리 공개해야하겠다는 생각이 들었다. 원래는 문서를 다 작성해놓고도 공개하지않는 방향으로 생각을 굳혔다가 아무래도 생각이 바뀌기 시작하였다. 그 이유는 뒷부분의 부록을 보라..) 아마 이 방식으로 공부하는 사람들이 많겠지만 그렇지 않을수도 있을 것이다. 적어도 이렇게 공부할땐 뼈를 깎듯이 힘들지만 원하고자 하는 지식을 얻으면 그 지식의 깊이가 뼈속으로 스며들 것이다. 필자처럼 어떤 새로운 분야에 공부를 시작하거나 공부하는 방법을 몰라서 물어보려는 사람들이 있다면 이 문서를 읽어보라고 말하고 싶다.
 
<잡설>
필자가 만약에 커널디버깅을 잘 다뤘다면 아마도 쉽게 문제를 해결했을지도 모르겠다. 하지만 필자는 귀차니즘 때문에 커널디버깅을 좋아하지 않았고 결국, 공부도하지 않았다. (요즘들어 먹고 살라니.. 공부중이다.. -_-;) 그런데 필자는 오히려 디버거를 쓰지 않으면 않을수록 프로그램에 대한 이해도는 높아진다고 생각한다. 왜냐면 사람의 머리는 충분히 상황을 시뮬레이션 할 수 있다고 생각하기 때문이다. 에뮬레이션은 불가능하겠지만 시뮬레이션은 가능하다. 그리고 이 작업을 통해서 문제가 발생되는 지점을 캣치할 수 있다고 생각한다. 그렇게 되었을때 남보다 더 느릴지 몰라도 이해도는 훨씬더 깊이있는 굴곡을 생성해낸다고 생각한다. 어쩌면 그렇게 믿고싶은 것일지도 모르겠다. 적어도 자신은 그렇게 소신을 갖고있다. 그렇다고 커널디버깅을 배우는 것을 말리거나 도외시하라는 것은 절대 아니다. 필수적으로 갖고가야할 기술이라는 점에는 변함이 없지만 두가지를 모두 안배하는 것이 스스로에게 좀 더 풍요로운 지식을 가져다 줄 것이라는 점을 인지했으면 좋겠다는 의미이다. "Art of Hooking" 이라는 문서처럼 스스로의 깨달음을 전달하려고 쓴 문서는 아니지만 이 시간에도 같은 문제로 삽질하고있을 그들에게(아직도 정확한 답변을 보지 못한 질문자들이 인터넷에 깔려있음을.. 이미 보여줬다..) 이틀이라는 시간을 좀 더 귀중한 곳에 쓸 수 있도록 해줄 수 있다는 것은 행복한 일이라고 생각한다. 만약 누군가에게 이런 도움을 지속적으로 받을수 있었다면 본인은 솔로여야할 이유가 없었을 것이리라.. (아쉽게도 영어를 못하니 국내만이라도 도움을 받으면 좋을듯 싶다.) 참고로.. 이 문서는 주제를 인지하는 시점부터 해결과정을 도출해내는 모든 전 과정이 거의 실시간으로 쓰여졌다.. 그렇게 해야만이 이 문서의 목적인 "가상마우스" 와 "공부방법론" 두가지를 모두 전달할 수 있다고 판단했기 때문이다. 필자는 누군가 이 문서를 읽고 얻은게 있었다면 그것만으로 행복할 것이다. 하드에 처박혀 쓰레기가 된채 어느날 자신도 모르게 삭제되는 그런 정보가 아니라는 점만으로도 충분히 가치있는 것이니까..
 

[부록1: 필자가 생각하는 에뮬레이션과 시뮬레이션의 차이점]
에뮬레이션: 기계의 톱니바뀌처럼 구성요소들의 기능자체들이 모두 동일하게 작동해야 한다. (기능/작동의 동일화)
시뮬레이션: 기능자체를 동일하게 할 필요없이 입/출력되는 수치/값만 동일하면 된다. (수치/데이타의 동일화)
(필자주: 틀렸을 수도 있다. 정확하지않다. 다만, 여태까지 몸으로 와닿는 느낌자체를 말로 풀어써본 것 뿐이다.)
 
[부록2: 시중에 떠도는 물리형 Auto Mouse 탐지법]
먼저, 가상장치에 대한 것부터 언급해보고 물리형으로 넘어가겠다.

<1. 가상장치 탐지방법>
재밌는 사실이 있는데 아는 사람은 알 것이고 모르는 사람은 모를 것이다.
MSPRESS 에 보면 짜가장치(FakeDevice) 탐색법이 있다.

http://www.microsoft.com/mspress/books/sampchap/6262.aspx
-------------------------------------------------------------------------------------
HANDLE CtestDlg::FindFakeDevice()
{
    GUID hidguid;
    HidD_GetHidGuid(&hidguid);
    CDeviceList devlist(hidguid);
    int ndevices = devlist.Initialize();
    for(int i = 0; i < ndevices; ++i)
    {
         HANDLE h = CreateFile(devlist.m_list[i].m_linkname, 0,
                           FILE_SHARE_READ | FILE_SHARE_WRITE,
                   NULL,
                   OPEN_EXISTING, 0, NULL);
         
     if(h == INVALID_HANDLE_VALUE)
         continue;
     HIDD_ATTRIBUTES attr = {sizeof(HIDD_ATTRIBUTES)};
     BOOLEAN okay = HidD_GetAttributes(h, &attr);
     CloseHandle(h);
     if(!okay)
         continue;
     
     if(attr.VendorID != HIDFAKE_VID ||
        attr.ProductID != HIDFAKE_PID)
         continue;
     return CreateFile(devlist.m_list[i].m_linkname,
                       GENERIC_READ | GENERIC_WRITE, 0, NULL,
               OPEN_EXISTING, 0, NULL);
    }
    return INVALID_HANDLE_VALUE;
}
-----------------------------------------------------------------------------------------
위의 짜가장치 탐색법은 골때리게 단순하다. 결국에는 HIDFAKE_VID 와 HIDFAKE_PID 를 체크하는 개념이다. 즉, 제작사(Vendor ID)와 제품번호(Product ID)를 가지고 짜가인지 판별하겠다는 개념이다. 그렇다면 제작사와 제품번호는 속일수 없다고 생각하는가? 커널을 뒤짚어 엎는(Subvert) 판국에 저렇게 단순하게 비교해서는 가상장치를 막을수 없다. 위의코드를 보고 판단을 하길 가상장치는 다 막겠다고 판단한다면 정말 큰일이다. 어처구니 없는 싸움이 키보드보안이래 또 발생할 것이기 때문이다. 위의 코드가 의미하는 바를 잘못해석하면 안된다. 위의 코드는 이렇게 해석해야 한다. 그 어떠한 가상장치를 막을수 있다는 컨셉하에 위의 코드를 만들길 시도한것이 아니라 고정장치를 알아내기위해 만들어진 컨셉이라는 점을 말이다. 단지 정형화 되어있는 즉, 고정되어있는 상태에서는 가능할 수 있겠다. 이해를 돕기위해 예를한가지 들어보자. VMware 같은 가상머신 안에서 작동하는 것인지 정도는 파악할 수 있지 않을까 싶다. 왜냐면 VMware 가 동적으로 제작사와 제품번호를 바꿔야할 까닭이 없지않은가? 다르게 말하면 VMware 가 굳이 자기 제품정보를 굳이 속이거나 변덕스럽게 수시로 바꿔야할 필요가 전혀 없다는 얘기다. 이런경우에는 마치 하드웨어처럼 고정장치로 봐도 무방하다. 고로 VMware 에는 항상 고정된 장치가 있다고 판단해도 될 것이며 VMware 안에 구현된 장치들 중에는 가상장치들이 있으므로 항상 디텍트 할 수 있단 얘기가 되므로 위의 짜가장치 탐색법은 그러한 경우에 사용할 수 있는 컨셉이라는 소리다.

아직 더 깊이 연구해보지는 않았지만 가상장치와 전쟁을 선포할 경우에 또 하나의 "키보드보안" 같은 파국으로 치닫기에 좋은 스토리가 탄생할 것이다. 차라리 이것을 좀 더 유용한 곳에 사용해보면 어떨까? 바로!! 물리형 Auto Mouse 를 탐지하는 것이다. 기술은 적합한 곳에 쓰라고 있는 것이지 말도안되는 헛다리 싸움에 쓰라고 존재하지 않는다. 기술을 적용시킬때는 단순히 눈과 머리로만 판단하지말고 포괄적인 정황을 바탕으로 자신의 가슴속에 확신이 설때 비로소 본격적인 전쟁에 들어가야 한다. 그저 돈이된다고 키보드보안처럼 너도나도 발담궈놓고 아무도 책임지지않고 아무도 발도 못빼는 승자없는 싸움에 휘말리기 싫다면 필히 이 말을 웃어넘기지 말아야 할 것이다.(아마, 이젠 더이상 발을 빼지도 못할것이다.. 담구지 말라고 뜯어말려도
담궜으니 해야할 일은 그저 땜빵밖에 뭐가 더 있겠는가.. ㅉㅉ)
-----------------------------------------------------------------------------------------

<2. 물리형 Auto Mouse 탐지>
물리형 Auto Mouse 를 탐지하는 것의 기본바탕은 앞서 짜가장치 탐색에 사용된 코드를 그대로 채용하면 되겠다. 단, 제작사와 제품번호만이 아닌 추가정보를 이용할 필요가 있겠다. 그런데, 왜 효용성이 물리형 Auto Mouse 를 탐지하는 것에 효력이 있을까? 그 이유는 간단하다. 다음과 같은 정보를 보자. 필자는 최근에 오픈된 MMORPG 온라인 게임의 Auto Mouse 를 구매해보았다. 과연 어떻게 돌아가는지 궁금증도 있었고 진짜 완벽하게 구동이 되는것인지 두눈으로 확인해보고 싶었기 때문이었다. 그런데 일단, 한군데의 제품은 구동이 제대로 안되는 것을 확인하였다. 다만, 마우스 입력이나 키보드 입력은 그대로 게임속으로 전달되고 있다는 점에 주목하였다. 과연 그러한 것을 어떻게 탐지해낼 수 있을까? 다음은 USB View 라는 프로그램으로 Auto Mouse 장치의 Descriptor 를 본 화면이다.

<Auto Mouse HID Descriptor>
"USB Composite 장치"
-----------------------------------------------
Device Descriptor:
bcdUSB:             0x0200
bDeviceClass:         0x00
bDeviceSubClass:      0x00
bDeviceProtocol:      0x00
bMaxPacketSize0:      0x20 (32)
idVendor:           0x03EB (Atmel Corporation)
idProduct:          0x4743
bcdDevice:          0x1000
iManufacturer:        0x01
0x0409: "ATPLAY"
iProduct:             0x02
0x0409: "ATPLAY PRO8"
iSerialNumber:        0x03
0x0409: "1.0.0"
bNumConfigurations:   0x01
... 생략 ...
-----------------------------------------------
그렇다. idVendor 가 제작사이고 idProduct 가 제품번호이겠다. 이 정보는 필자가 예상컨대 고정이라 할 수 있다. 일단, 텍스트를 주의깊게 보자. "Atmel Corporation" 이 보이는가? 해커들이 가장 많이 사용한다는 그 유명한 "Atmel" 칩이 사용되었다. 일명 FPGA 칩이라고 불리운다. 이 FPGA 칩은 프로그래밍 가능한 이점이 있다.

(사견: 언제부터 마우스가 Atmel 칩으로 제작되었던가? 그래서 오토마우스가 그리도
       비싼거였나보다.. 싸구려 PIC 칩만으로도 마우스를 만들수 있다. 전자업계는
       원래 원가전쟁을 벌이는 계통이라서 단 1원이라도 원가를 절감해 보려고
       깎고깎고 전쟁을 벌인다. 필자의 친구가 전자회사 CEO 라서 이점은 매우 잘
       알고있다. 그 친구의 말을 빌어보자면 진짜 1원갖고 쪼잔하게 굴 수 밖에
       없다고 한다. 살아남아야 하니까 말이다.. 그런데 FPGA 칩을 쓰는 것을 보면
       좀 수상하다. 왜 재프로그래밍이 가능한 칩을 쓰는 것인가.. 재수없으면 기타장치
       메모리스틱 리더기같은 것들이 연결되어 있을수도 있으므로 함부로 판단하기는
       이르지만 아마도 대량유통되는 칩이 아닌 DIY(사제품)칩을 쓴다는 것은 기정
       사실이라고 추측할만 하지않은가? 필자가 대에충 찾아보니 Auto Mouse 제작사
       두군데가 Atmel 칩을 사용하고 있었다.)

만약 이 Atmel 칩이 필자가 아는 것과 달리 재프로그래밍이 가능한 기능이 없다면 게임업계에서는 대박의 찬스를 잡은 것이리라.. 왜? 고정이잖은가? 고정!! 또, 재미난 정보를 볼 수 있는데 바로 그 유명하다고 하는 "ATPLAY" 라는 마크가 찍혀있다. 아주 그냥 상호를 갖다가 박아놓은거보니 장사할 생가이 없다하겠다.
일단, 칩이 Atmel 칩으로 제작되어있는 USB 형 물리장치들을 사용하는 사용자는 모두 감시대상순위로 집어넣어도 십중팔구는 맞아떨어질 것이다. 특히나 Atmel 칩에 상관없이 상호명 ATPLAY 가 박혀있다면 그 사용자는 거의 Auto Mouse 를 사용하고 있을 확률이 99.9% 라고 할 수 있겠다. 그리고 USB View 같은 프로그램이 사용하는 루틴들은 위에서 언급된 루틴들에서 크게 벗어나지는 않을테니 쉽게탐지할 수 있다고 감히 추측해본다. 딱한가지 우려되는 사항이 있다면 프로그래밍 가능한 칩이기 때문에 업데이트 기능으로
펌웨어를 갈아치울 경우에 난감하게 될 것이다. 하지만 방금 언급한 방식을 사용한다면 Auto Mouse 제작사의 미래고객이 아닌 현재 고객들은 99.9% 가 탐지된다고 봐도 무방할 것이다. 물론, Auto Mouse 의 종류별로 이짓을 해야겠지만.. 프로그래머들의 습성상 모두 식별자를 기록해놓았을테니(아마, Atmel 칩에 코딩을 의뢰하거나 혹은 Atmel 칩에 프로그램이 가능한 사람을 영입했겠지만 프로그래머들이 그런거 생각안한다. 왜냐면 원리원칙을 따르려는 프로그래머의 심리상 바보같이 위에처럼 ATPLAY 를 박는게 미덕으로
생각할 것이기 때문이다.) 행동만 빨리 취한다면 현재 Auto Mouse 사용자들의 태반은 모두 다 탐지해낼 수 있을 것이라고 감히 판단해본다. 즉, 물리형은 고정이라는 변수를 잘 활용할 수 있기에 탐지도 비교적 수월한 편에 속한다는 것이다. 한가지 더 재미난 상상을 해보자.. 과연 Auto Mouse 업체에서 펌웨어 업데이트 기능을 추가로 만들어내는데 얼마나 시간이 걸릴까? 누가 더 대응이 빠를까..? 과연 이 전쟁에서 Auto Mouse 업체의 대응이 빠를까? 아니면 막는자의 대응이 더 빠를까? 아마도 덩치가 작은쪽이 더 빠르겠지만 두고볼 일일 것이다. 이 전쟁은 어느한쪽의 시간전쟁일 뿐이다.. 정확하고 빠른판단이 내려지면 그대로 바로 행하는 쪽이 이기는 것이다. 현재로써 본 필자의 생각으로는 물리형 Auto Mouse 는 막을 수 있다. 이 문서가 나온 시점 앞으로가 문제이다.. 점차 Auto Mouse 는 가상마우스로 진화를 꿈꾸고 있기 때문이다. 그것이 바로 기술의 대세인 것이다. 오늘의 기술이 내일의 쓰레기가 되어버리는 시대에서 속도전의 중요함이다. 승자는 과연 누가 될까? 아무도 모른다.. 기술은 끝이 없으니까.. 마이 골치아픈 것이다.. -_-; 어디까지나.. 필자 개인이 현 상태를 진단해본 사견일 뿐이다. 이 이상 어케 더 판단하랴..

[HID Descriptor Tool]
USB.ORG 공식 사이트에서 받을수 있음
http://www.usb.org/developers/hidpage#HID%20Descriptor%20Tool
(위에서 언급한 사이트 이외 참고한 사이트)
http://kkamagui.tistory.com/485
http://www.keil.com/forum/docs/thread13037.asp


000096". Is it possible to get the SymbolicLinkName
instead?
If someone could help...
Thanks, Roger
(필자요약: HID 인터페이스를 노출하는 USB 장치를 만들었다. 그런데 그게 마우스나 키보드가 아니네? 단지
           일반 HID 장치인거야. 디바이스 디스플레이에 보면 "HID-compliant device" 라고 표시되네.
       횽님들.. 알려주십쇼.. 뭐 이런 내용식으로 글을 써놨다. 그래도 아는게 많은 사람이라서 그런지
       정보들을 많이 뿌려놨는데 독이되는 요소들이 있지만, 덤으로 알게되는 요소들도 그 못지않게
       많다. IOCTL_HID_SET_FEATURE 과 IOCTL_HID_GET_FEATURE 에대한 얘기는(추후 구현되어야 하는 내용)
           좋은 정보임에 틀림없다. 그런데 우리가 원하는 답을 얻지는 못하고 단지 INF 파일에 VID 와
       PID 스트링이 문제의 시발점이 될수도 있지는 않은가 하는 의심을 해볼수 있다. 물론, 그게 해답은
       아니지만 추가정보를 검색해야할 키워드로써 대상물망에 넣어두자. VID 란 벤더아이디를 의미하고
       제작사의 고유식별번호이며, PID 란 프로덕트 아이디 즉, 제품번호이겠다. 이게 하드웨어는 모두
       고유하다고 하는데 과연 이 때문에 마우스나 키보드로 인식이 안되고 일반장치로 인식되는 것일까?)
-----------------------------------------------------------------------------------------------------------------
when are you trying to open a handle? during AddDevice or
IRP_MN_START_DEVICE? neither will work b/c a file create can only occur
once the start irp has come back to the pnp manager. so to make this work i
would
a) register a custom device interface GUID
b) register for device interface arrivals on your custom guid. when you
get called, open your stack like FireFly does
you will also need to register for handle notifications on the file handle
that you open so that you can gracefully disable the device. If you use the
KMDF firefly sample, the WDFIOTARGET object does this for you
(필자요약: 답변중에 하나인데 이 답변은 질문자의 추측보다 더 가관이다. IRP_NM_START_DEVICE 나 AddDevice 등록시 (필자는 커널을 몰라서 몬소린지 모르지만 이건 아니다정도의 감은 있었다.. -_-;) 하라는 식으로 답변이 달려있는데 KMDF 까지 들먹거리는걸로 봐서는 논점에서 많이 빗나갔다. KMDF 는 새로운 드라이버 개발 프레임워크인데 질문자가 그걸 물어본게 아니다. 기존의 방법으로 설명해줘야하는 것이 옳은데 그렇지도 않았고, 너무 많은 작업을 추가하라고 주문하는거보니 필자의 생각과 달랐다. 필자의 감은 Report Descriptor 만으로도 해결될 문제라고 속삭이고 있었기 때문에 이 답은 해결책이 아니었다. 다른 답변중에는 URB 를 보내라는 말도 있었다. 모두 무시한다.)
-----------------------------------------------------------------------------------------------------------------
지금 거론하는 필자의 문제해결 방법은 링크를 보여주면서 찾아나가는 방법을 설명하고 있다. 그렇기에 링크역시 필자가 검색해서 누른 순서대로 임을 밝힌다. 다음으로 찾은 것은 MSDN 의 설명이다. 그런데 MSDN 의 설명은 항상 깨달음을 얻은뒤에나 값진 보물이 되지 깨달음을 얻기전까지는 그저 잘 만들어진 명세서에 불과하다고 느낄때가 많다. 마치 선생님이 "공부하라"고 그렇게 들볶던 말들이 성인이 된 뒤에 "정답" 이라고 느끼는 것처럼 느낀뒤에만 알 수 있는 것들이 기록되어 있는게 MSDN 과도 같다. 왜 그땐 몰랐지? 왜 그땐 안봤지? 나중에 이런말 자주하게 될거다. ㅎㅎ 그런데.. 역시.. -_-; 이 링크를 보던 시점(현 글을 쓰는 시점기준으로 하루전)만 해도 이 링크는 그저 도움이 안되었다.
http://msdn.microsoft.com/en-us/library/aa487252.aspx
(필자요약: 설명이 잘 되있다. 읽어보라.. 해결책도 들어있다. 그런데 그냥보면 절대 모른다. 개고생하면 그때는 답이 보이지만 그냥보면 모른다.)
-----------------------------------------------------------------------------------------------------------------
http://www.programmer-club.com/pc2020v5/forum/ShowSameTitleN.asp?URL=N&board_pc2020=driver&id=2986
-----------------------------------------------------------------------------------------------------------------
(필자요약: 이 사이트는 중국사이트인데 읽을수가 없다. 몇가지 좋은 키워드와 코드가 있는데 해결책은 아니고 나중에 마우스나 키보드를 구현할때 참고할 만한 코드가 아주 조금 있을 뿐이었다.)
-----------------------------------------------------------------------------------------------------------------
http://www.osronline.com/cf.cfm?PageURL=showThread.CFM?link=144873
-----------------------------------------------------------------------------------------------------------------
(필자요약: 필자가 겪는 문제를 어느정도 일부분은 해결한 것 같기도하고 그렇지 않은거 같기도 한데 희한한
            삽질을 하고 있었다. Descriptor 를 계속해서 바꿔가면서 테스트하는 것을 물어보고 있었다.
        마우스와 키보드를 인식시키기 위해서 vhidmini 를 기본베이스로 디스크립터를 조작하는데 설치가
        안된다는 그런 질문이었다. 질문양이 많아서 짤라붙이기는 못하겠다. 답글을 보자.)

Adrian Schlesinger
xxxxxx@baum.ro
    
Join Date: 24 Sep 2008
Posts To This List: 7
RE: Simulate keystrokes
I have detected what was wrong:
1. When adding the report ID item to the keyboard top-level collection, an additional byte should be returned to
   the system at the beginning of the data, specifying that report ID.
2. Communication from user mode did not work because when cycling through the HID devices,
   in addition to vendor ID, product ID and version, the usage specified for the additional end point should also
   be matched (with Vendor Usage 1), otherwise you can end up trying to call WriteFile for a handle corresponding
   to the keyboard end point.
(필자요약: 질문자의 답글인데 키보드 top-level collection(최상위 모음) 에 REPORT ID 를 추가할때 어쩌구 저쩌구 얘기가 나온다. 그리고 usage 라는 말도 나온다. 필자가 원하는 답이 여기에 있을 것이라고 생각하여 엄청난 검색을 통해 알게되었는데 원하는 답은 아니었다. 단지, top-level 의 개념은 중요했다.
-----------------------------------------------------------------------------------------------------------------
http://www.techreplies.com/drivers-43/hid-minidriver-multiple-report-descriptors-543372/
-----------------------------------------------------------------------------------------------------------------
(필자요약: 앞에서 어떤사람이 한 질문과 똑같은 질문인듯 싶다. 왜 도대체 마우스로 인식이 안되냐.. 이 질문이다.)
-----------------------------------------------------------------------------------------------------------------
다음은 중요한 개념중에 하나인 Top-Level Collection 이다.
http://www.microsoft.com/whdc/archive/HID_HWID.mspx#E1
-----------------------------------------------------------------------------------------------------------------
Special Top-Level Collections (Reserved for OS use)
Certain HID top-level collections generate a special HID device string. In Windows 2000, Windows XP, and Windows
Server 2003, the top-level collections listed in Table 6 are special cased and each has an additional hardware ID.
Table 6 identifies these collections. The last column identifies the additional string that is added to the hardware
ID list.
Table 6: Special-Cased Top-Level Collections
Device Type                Usage Page    Usage ID       Additional Hardware ID
Pointer                    0x01          0x01           HID_DEVICE_SYSTEM_MOUSE         exclusive
Mouse                      0x01          0x02           HID_DEVICE_SYSTEM_MOUSE         exclusive
Joystick                   0x01          0x04           HID_DEVICE_SYSTEM_GAME 
Game pad                   0x01          0x05           HID_DEVICE_SYSTEM_GAME
Keyboard                   0x01          0x06           HID_DEVICE_SYSTEM_KEYBOARD      exclusive
Keypad                     0x01          0x07           HID_DEVICE_SYSTEM_KEYBOARD      exclusive
System Control             0x01          0x80           HID_DEVICE_SYSTEM_CONTROL
Consumer Audio Control     0x0C          0x01           HID_DEVICE_SYSTEM_CONSUMER

(필자요약: 이게 모냐면 Top-Level Collection 이라 불리우는 입력장치유형이다. 위에서 Usage Page 와 Usage ID 라는 것이 있는데 이게 바로 Report Descriptor 에 있는 항목에 적혀있다. 이걸 어떻게 바꾸느냐에 따라서 가상장치가 마우스가 되느냐, 키보드가 되느냐 아니면 조이스틱이 되느냐를 결정한다. 멋지지 않은가? 물론, 원하는 해답은 아니다. 그러나 필수적으로 개념을 갖고가야 한다. 여기서 중요한게 있다면 입력 장치의 형태가 공유(share)모델이냐 아니면 베타적모델(독점)이냐 이다. 마우스와 키보드는 독점모델이다. 즉, 마우스와 키보드는 장치가 열려있으면 다른 프로그램이 장치를 열어서 쓰고읽는 것이 불가능 하도록 secure 모델로 처리되어있단다. 이때, 이걸 피해가려면 새로운 장치를 동일하게 하나더 만들어서 그 장치와 통신하면 이런 독점모델을 피해갈 수 있단다. MSDN 에 다 나와있다.. 전부 다~ 링크가 있었는데 FireFox 가 깨져서 다 날아가 버리는 바람에 찾을수 없지만 베타적오픈과 공유오픈이 가능한 표시가 위의 Top-Level Collection 에 일일이 나열되어 있는 정보도 찾을 수 있었다. 어쨌거나 중요한건 짚고 넘어가자.. 참고로 잊지는 않았겠지? 가상장치가 일반장치로 인식되서 마우스 장치로 인식시키려고 뻘짓하다가 이런곳까지 당도하게 된거란 점.. 이렇게 정보들을 다양한 방법으로 얻어서 공부하는데도 웹서핑한다고 눈치주는 경우도 있다. x같은 경우지.. 이게 단순히 노는걸로 보여? 입에서 욕나오네.. 갑자기 머리에 히터가 작동되서 한번 지껄여봤습니다. 다시 집중모드로 돌아가봅시다.. ㅋㅋ)Table 13-1   HIDCLASS-Compatible ID for Each Supported Usage지원되는 HIDCLASS 호환 아이디.. HIDCLASS 는 각 장치로 분배를 해주는 역할을 한다고 합니다. 더 자세한건 묻지마삼 다칩니다요.. 전 아는것만 얘기할 뿐임..
http://www.microsoft.com/mspress/books/sampchap/6262.aspx

Usage Page         Usage                   Compatible ID
Generic desktop       Pointer or mouse        HID_DEVICE_SYSTEM_MOUSE
                   Keyboard or keypad      HID_DEVICE_SYSTEM_KEYBOARD
                   Joystick or game pad    HID_DEVICE_SYSTEM_GAME
                   System control          HID_DEVICE_SYSTEM_CONTROL
Consumer           (Any)                   HID_DEVICE_SYSTEM_CONSUMER

<Report Descriptor Header>
앞서서 XBCD 라고 XBOX 조이스틱 에뮬레이션 드라이버에 대해서 말한적이 있습니다.
헤더의 USAGE_PAGE 를 잘 봅시다. 그리고 USAGE 를 봅니다.
// XBCD 예
char ReportDescriptor[213] = {
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)     <-- 요건 뭐시냐? Table 13-1 입니다욤..
    0x09, 0x04,                    // USAGE (Joystick)        <-- 위의 Table 6 에 Joystick 의 Usage ID 보입니껑?
    0xa1, 0x01,                    // COLLECTION (Application)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,                    //   PHYSICAL_MAXIMUM (1)
// vhidmini.h 의 맨마지막 주석이 되어있었던 마우스예제 헤더
HID_REPORT_DEscRIPTOR    DefaultReportDescriptor[] = {
        0x05, 0x01,      //Usage Page (Generic Desktop),   <-- Table 13-1 일반 데스크탑
        0x09, 0x02,      //Usage (Mouse),                  <-- Mouse 임
        0xA1, 0x01,      //Collection (Application),
        0x85, 0x01,      //REPORT_ID (1)                   <-- REPORT_ID 꼭 이게 값이 있는지 확인해야함.
        0x09, 0x01,      //Usage (Pointer),                    HID Tool 이라는 놈은 이 값을 빼고 보여줌.(주의!)
        0xA1, 0x00,      //Collection (Physical),
        0x05, 0x09,      //Usage Page (Buttons),
        0x19, 0x01,      //Usage Minimum (01),
        0x29, 0x03,      //Usage Maximun (03),
        0x15, 0x00,      //Logical Minimum (0),
여기서 Top-Level collection 이 지칭하는 의미는 상위장치입니다. 이런식으로 다중 인터페이스를 구현할 수 있는데 예를들면 마우스와 키보드를 가상장치 하나로 일타쌍피도 만들어낼 수 있습니다. 시중에 파는 키보드 중에 마우스도 있고 USB 포트도 달려있는 키보드들은 이런 다중인터페이스를 만들기위해서는 multiple top-level collection 지정을 해줘야 한다는 얘기죠. 어쨌거나.. 이러한 정보들은 얻었고 Report Descriptor 가 잘못된 것인가라고 판단해보니 전혀 아니었습니다. 오히려 첫번째 XBCD 의 헤더모습에서는 REPORT ID 가 보이지 않는데 두번째 vhidmini.h 에서는 REPORT ID 항목도 빼먹지않고 넣었고 완벽합니다. 그런데 왜.. 대체 왜!! 인식이 마우스로 되지않고 일반장치라고 잡히는 거냐 이말이죠.. 심지어는 공식사이트에서 다운로드 받은 마우스와 키보드 Report Descriptor 를 가져다가도 해봤고 직접 하드웨어에서 뽑아낸 값을 통해서도 해봤지만 모두 인식이 안되었답니다.
-----------------------------------------------------------------------------------------------------------------
사실.. 위에서 언급한 내용은 탐색과정에서 추가로 얻어내는 개념들에 대해서 비중이 있었기에 설명을 하였습니다. 아마, 계속해서 같은 방식으로 설명하면 이 문서를 보면서 쌍욕을하게 될지도 모르기에 후다닥 빨리 접겠습니다. 다음은 제가 문제해결(일반장치를 마우스로 인식하게 만드는)을 하기 위해서 찾아다녔던 링크입니다. 더 많지만 추려서 올려봅니다.
http://coding.derkeiler.com/Archive/General/comp.arch.embedded/2008-01/msg00501.html
http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2005-03/0829.html
http://www.tech-archive.net/Archive/Development/microsoft.public.development.device.drivers/2005-03/0806.html
http://www.techreplies.com/drivers-43/minidriver-hidclass-336914/
http://www.techreplies.com/drivers-43/my-hid-mouse-how-write-data-331146/
http://www.osronline.com/DDKx/intinput/hidfunc_7oky.htm
https://www.usb.org/phpbb/viewtopic.php?t=14027&sid=b40543b8bc019ff50c70025ff1886898

(결정적인 영감을 주게된 링크는 바로 다음의 링크이고 사실, 앞에서 한번 언급했었던 링크입니다.. 정확히 말하자면 해결방법을 직설적으로 말해준게 아니라, 넌 이걸 이해해야된다라고만 코드의 일부분을 언급하고 숫가락으로 떠먹여 주지는 않겠다는 인상을 풍기는 답글이지요.. 처음에는 이걸 보고도 잘 이해를 못합니다. 저만 그런건 아닐겁니다. 어떤 질문자 중에서는 프린터, 스캐너, 스마트카드를 비롯해 각종 디바이스 드라이버를 만들었다는 이력을 밝히며 저와 같은 증상때문에 고민을 하고 있는 사람도 있었으니까요.. 제가 볼때 이건 MS 의 함정입니다. 의도하지 않은 함정말입니다.)
https://www.osronline.com/showthread.cfm?link=138652
-----------------------------------------------------------------------------------------------------------------
바로 이 답글이 눈을 뜬 사람에게만 통하는 핵심인 셈입니다.
allen zhang
xxxxxx@sina.com
    
Join Date: 22 Jul 2008
Posts To This List: 38
RE: VHidMini report descriptor(s)
see the follow source code and the ReadDescriptorFromRegistry function, You should be understand it.
deviceInfo->HidDescriptor = DefaultHidDescriptor;
queryStatus = CheckRegistryForDescriptor(DeviceObject);
if(NT_SUCCESS(queryStatus)) {
    queryStatus = ReadDescriptorFromRegistry(DeviceObject);
    .......
(필자요약: 다음의 소스코드와 ReadDescriptorFromRegistry 함수를 봐라.. 너는 이걸 이해해야할 필요가 있다.
            라고 말하며 일부 소스를 첨부했습니다. 그리고는 아무런 추가의 말도 없습니다. 장난하는것도
        아니고.. -_-; 이때 아차하고 생각을 떠올리면 이 문제는 해결됩니다. 위에서 숱하게 질문하던
        외국 개발자들도 결국에는 알아냈겠지요?)
-----------------------------------------------------------------------------------------------------------------
vhidmini 드라이버를 구동시키고 일반 HID 장치로 인식된 드라이버를 마우스 장치로 둔갑시키기 위해서는
소스를 수정해야 합니다. 바로 vhidmini.c 드라이버 소스를 수정하는 일입니다. 그것도 필자가 생각했었던
Report Descriptor 의 오류를 수정하는 것이 아니라 코드를 수정해야 합니다. 앞에서도 한번 언급했었지만
Microsoft 사의 공식 DDK 샘플소스에 오류가 있을리는 없으니까요. vhidmini.h 에 주석으로 정의되어있던
마우스 Report Descriptor 의 예는 오류가 없었습니다. 오류에 빠지도록 만든것은 바로 ReadDescriptorFromRegistry
함수에 있었습니다. vhidmini 소스를 보면 주석에 써있기를 우리는 하드코딩을 하였다라고 적혀 있습니다.
Report Descriptor 를 하드코딩 하였다는 것이지요. 그런데, 단순히 그냥 하드코딩으로 놔두지.. 더 많은걸
보여주고 싶었던지 if-else 로 두가지 처리루틴으로 나눠놓은것이 문제의 핵심이었던 것입니다. 다음의
소스를 보십시오.
-----------------------------------------------------------------------------------------------------------------
[vhidmini.c 소스에서 수정해야 할 부분]
    
 HID Report Descriptor 를 레지스트리에서 읽어들이는 코드를
 하드코딩쪽으만 처리하도록 수정함.

    deviceInfo->HidDescriptor = DefaultHidDescriptor;
    //
    // Check to see if we need to read the Report Descriptor from
    // registry. If the "ReadFromRegistry" flag in the registry is set
    // then we will read the descriptor from registry using routine 
    // ReadDescriptorFromRegistry(). Otherwise, we will use the 
    // hard-coded default report descriptor.
    //
    queryStatus = CheckRegistryForDescriptor(DeviceObject);  // 함정이 발생하는 지역
    if(NT_SUCCESS(queryStatus)){
    //
    // We need to read read descriptor from registry
    //
    // 장치를 설치할때 INF 파일에 있는 Report Descriptor 가 레지스트리에 기록되고
    // 이 부분에서 레지스트리에 기록된 Report Descriptor 를 읽어들임.
    // 그러므로 백날 헤더의 Report Descriptor 를 바꿔봤자 INF 파일에 있었던 것을
    // 읽어들이는 꼴이 되므로 항상 "일반 HID 장치"(Generic HID Device) 가 드라이버로
    // 등록될 수 밖에 없었던 것이다. 이런 제길.. 이 문제로 이틀을 꼬박 다 날렸다니..
    // Microsoft 는 반성하라~!! Microsoft 는 함정을 제거하라~!!
    // 고로 이 부분으로 빠져들지 않도록 주석처리 하라..
    queryStatus = ReadDescriptorFromRegistry(DeviceObject);
                               
    if(!NT_SUCCESS(queryStatus)){                          
        DebugPrint(("Failed to read descriptor from registry\n"));
        ntStatus = STATUS_UNSUCCESSFUL;
    }
}
else{
    //
    // We will use hard-coded report descriptor. 
    //
    deviceInfo->ReportDescriptor = DefaultReportDescriptor;
    DebugPrint(("Using Hard-coded Report descriptor\n"));
}

... 중략 ...
case IRP_MN_REMOVE_DEVICE:
    //
    // free memory if allocated for report descriptor
    //
    // 이 부분도 주석처리해야 한다. 왜냐면 레지스트리에서부터 읽어들이지 않았기 때문에
    // 메모리 할당이 안되어 있기 때문이다. 그냥 두어도 상관없을거 같지만 메모리 해제부분이니
    // 꺼림칙하므로 되도록이면 제거하길 바란다.
    if(deviceInfo->ReadReportDescFromRegistry)
        ExFreePool(deviceInfo->ReportDescriptor);
    SET_NEW_PNP_STATE(deviceInfo, Deleted);
    ntStatus = STATUS_SUCCESS;           
    break;   
-----------------------------------------------------------------------------------------------------------------
이제 vhidmini 샘플을 컴파일하고 VMware 에 vhidmini.sys 와 vhidmini.inf 파일을 복사하자. 그리고 devcon 명령으로 앞서했던 것처럼 install 을 해보자. 설치를 하고나면 장치관리자의 기존에 있던 "HID 준수장치" 라는 것은 없어지고 마우스항목에 "HID 규격 마우스" 가 추가되는 것을 볼 수 있을 것이다.(ㅎㅎ 이맛을 보려고.. 밤을새고 삽질을..) 이제.. 장치관리자에서 새로 추가된 "HID 규격 마우스" 를 선택한 뒤에 속성을 보자. 속성을 선택한 뒤 "자세히" 라는 것을 클릭한다. 그리고 장치인스턴스 ID 라는 것을 보라. HID\MyVirtualHidDevice&Col01 라고 되어있는 것을 볼 수 있다. 또한, 일치하는 장치 ID 를 선택하면 hid_device_system_mouse 라고 되어있다. 즉, 마우스로 인식이 되었다는 것이다. 가상 HID 디바이스 위에서 마우스 장치가 인식되어 있는 것이다. 이제 가상 HID 디바이스와 어플리케이션 간에 통신루틴을 프로그래밍하고 어플리케이션의 명령에따라 상위 클래스로 IRP/URB 같은 요청을 (이거참.. 이 레이어에서는 어떤 요청을 사용해야하는 건지 또 공부해야하는군.. -_-; USB 강의 문서에 보면 상위 클래스는 URB 통신을 한다고 나와있었다..) 날려주면 키보드나 마우스 같은 장치들을 에뮬레이션 시킬수 있다. 곧, 가상장치를 조종할 수 있다. 하지만? 그리 쉽지는 않을 것이다. vhidmini 샘플에는 testvhid 라는 어플리케이션 소스도 같이 들어있는데 이 testvhid 소스는 어플리케이션단에서 vhid miniport 드라이버와 통신하는 예제이다. 참고로 아무런 수정없이 샘플만 컴파일해도 어플리케이션과 드라이버 사이에 제대로 통신이 이루어지지않는다. 역시나 이 문제는 HID Report Descriptor 의 데이타의 구성문제에 속한다. 한번 고생한 것이 또다시 반복되는 시점이기도 하다. 이 부분을 해결하면 어플리케이션은 2 또는 3 가지의 top-level collection 중에서 사용자정의(User-Defined) 콜렉션을 통해서 miniport 드라이버와 통신을 할 수 있게되고 이 통신에 따라서 마우스 IRP 를 상위 클래스로 때려주면 된다. 더 자세한 내용은 스스로 연구하길 바란다. 이상으로 이번문서를 마무리하려고 한다. 왜냐면 이제 테스트 기반이 마련되었으니 나머지 추가구현은 스스로가 해야할 몫이기 때문이다. 어떠한 목적으로 개발하던간에 그 이상은 이제 필자가 관여할 부분이 아닌것 같다.

어차피 이 문서의 목적은 가상 마우스를 제작하는 것을 중점으로 삶는 것보다도 모르는 분야를 독학하며 개척해 나갈때 자신의 공부스타일의 한 예로써 제시하는 것이었다. 여기서 거론된 공부스타일을 종합해 본다면 이렇게 말할 수 있을것 같다. "관례를 찾아냄으로써 DIFF 를 추출해내는 공부법" 이라고 할 수 있다. 즉, 최대한 많은 자료들을 검색으로 긁어모은 뒤에 분리분석 작업을 통하여 동일한 부분의 반복을 찾아낸다. 찾아낸 반복내용이 있다면 결국 그 반복은 해당 프로그래밍의 관례에 속한다. 즉, 해당 관례는 몸으로 빨아들이고 차이가 나는 지점에서 기술을 흡수한다. 이런식의 반복학습을 통하여 더이상 다른 코드나 정보들을 찾아낼 수 없다고 판단이 들때 그 기술은 자기것이 된다. 필자는 유저레벨을 공부할때 항상 이방식을 택해왔다. 정보가 고갈되고 더이상 찾아낼수 없을때까지 긴시간을 할애해서 리서치를 먼저 한다. 그 뒤에 코딩으로 들어간다. 그리고 관례코드를 따른다. 그렇게되면 생전 처음보는 프로그래밍에서도 어느지점은 건드려도 되고 어느지점은 절대 건드려서는 안되는지 쉽게(? 정확히가 맞겠다) 익힐수 있다.

이제는 커널레벨 공부를시작하면서 이 고통스럽고도 지루한 공부방식을 다시 사용하고자하며 다른 사람에게 조그마한 도움이 되고자 이런 문서를 작성하였다. (같이 게임에 미쳐서 광랩하던 친구가 갑자기 URL 을 려줘서 읽어 보았더니 국가에서 인증한 기술이라는 자랑스런 인증서와 함께 뭔가를 팔고있었다. 보란듯이 대놓고 말이다. 디자인도 쌈빡해서 사고싶게 만드는 그것.. 그게 뭔지는 대충 말안해도 알겠지만.. 이 문서를 빨리 공개해야하겠다는 생각이 들었다. 원래는 문서를 다 작성해놓고도 공개하지않는 방향으로 생각을 굳혔다가 아무래도 생각이 바뀌기 시작하였다. 그 이유는 뒷부분의 부록을 보라..) 아마 이 방식으로 공부하는 사람들이 많겠지만 그렇지 않을수도 있을 것이다. 적어도 이렇게 공부할땐 뼈를 깎듯이 힘들지만 원하고자 하는 지식을 얻으면 그 지식의 깊이가 뼈속으로 스며들 것이다. 필자처럼 어떤 새로운 분야에 공부를 시작하거나 공부하는 방법을 몰라서 물어보려는 사람들이 있다면 이 문서를 읽어보라고 말하고 싶다.
 
<잡설>
필자가 만약에 커널디버깅을 잘 다뤘다면 아마도 쉽게 문제를 해결했을지도 모르겠다. 하지만 필자는 귀차니즘 때문에 커널디버깅을 좋아하지 않았고 결국, 공부도하지 않았다. (요즘들어 먹고 살라니.. 공부중이다.. -_-;) 그런데 필자는 오히려 디버거를 쓰지 않으면 않을수록 프로그램에 대한 이해도는 높아진다고 생각한다. 왜냐면 사람의 머리는 충분히 상황을 시뮬레이션 할 수 있다고 생각하기 때문이다. 에뮬레이션은 불가능하겠지만 시뮬레이션은 가능하다. 그리고 이 작업을 통해서 문제가 발생되는 지점을 캣치할 수 있다고 생각한다. 그렇게 되었을때 남보다 더 느릴지 몰라도 이해도는 훨씬더 깊이있는 굴곡을 생성해낸다고 생각한다. 어쩌면 그렇게 믿고싶은 것일지도 모르겠다. 적어도 자신은 그렇게 소신을 갖고있다. 그렇다고 커널디버깅을 배우는 것을 말리거나 도외시하라는 것은 절대 아니다. 필수적으로 갖고가야할 기술이라는 점에는 변함이 없지만 두가지를 모두 안배하는 것이 스스로에게 좀 더 풍요로운 지식을 가져다 줄 것이라는 점을 인지했으면 좋겠다는 의미이다. "Art of Hooking" 이라는 문서처럼 스스로의 깨달음을 전달하려고 쓴 문서는 아니지만 이 시간에도 같은 문제로 삽질하고있을 그들에게(아직도 정확한 답변을 보지 못한 질문자들이 인터넷에 깔려있음을.. 이미 보여줬다..) 이틀이라는 시간을 좀 더 귀중한 곳에 쓸 수 있도록 해줄 수 있다는 것은 행복한 일이라고 생각한다. 만약 누군가에게 이런 도움을 지속적으로 받을수 있었다면 본인은 솔로여야할 이유가 없었을 것이리라.. (아쉽게도 영어를 못하니 국내만이라도 도움을 받으면 좋을듯 싶다.) 참고로.. 이 문서는 주제를 인지하는 시점부터 해결과정을 도출해내는 모든 전 과정이 거의 실시간으로 쓰여졌다.. 그렇게 해야만이 이 문서의 목적인 "가상마우스" 와 "공부방법론" 두가지를 모두 전달할 수 있다고 판단했기 때문이다. 필자는 누군가 이 문서를 읽고 얻은게 있었다면 그것만으로 행복할 것이다. 하드에 처박혀 쓰레기가 된채 어느날 자신도 모르게 삭제되는 그런 정보가 아니라는 점만으로도 충분히 가치있는 것이니까..
 

[부록1: 필자가 생각하는 에뮬레이션과 시뮬레이션의 차이점]
에뮬레이션: 기계의 톱니바뀌처럼 구성요소들의 기능자체들이 모두 동일하게 작동해야 한다. (기능/작동의 동일화)
시뮬레이션: 기능자체를 동일하게 할 필요없이 입/출력되는 수치/값만 동일하면 된다. (수치/데이타의 동일화)
(필자주: 틀렸을 수도 있다. 정확하지않다. 다만, 여태까지 몸으로 와닿는 느낌자체를 말로 풀어써본 것 뿐이다.)
 
[부록2: 시중에 떠도는 물리형 Auto Mouse 탐지법]
먼저, 가상장치에 대한 것부터 언급해보고 물리형으로 넘어가겠다.

<1. 가상장치 탐지방법>
재밌는 사실이 있는데 아는 사람은 알 것이고 모르는 사람은 모를 것이다.
MSPRESS 에 보면 짜가장치(FakeDevice) 탐색법이 있다.

http://www.microsoft.com/mspress/books/sampchap/6262.aspx
-------------------------------------------------------------------------------------
HANDLE CtestDlg::FindFakeDevice()
{
    GUID hidguid;
    HidD_GetHidGuid(&hidguid);
    CDeviceList devlist(hidguid);
    int ndevices = devlist.Initialize();
    for(int i = 0; i < ndevices; ++i)
    {
         HANDLE h = CreateFile(devlist.m_list[i].m_linkname, 0,
                           FILE_SHARE_READ | FILE_SHARE_WRITE,
                   NULL,
                   OPEN_EXISTING, 0, NULL);
         
     if(h == INVALID_HANDLE_VALUE)
         continue;
     HIDD_ATTRIBUTES attr = {sizeof(HIDD_ATTRIBUTES)};
     BOOLEAN okay = HidD_GetAttributes(h, &attr);
     CloseHandle(h);
     if(!okay)
         continue;
     
     if(attr.VendorID != HIDFAKE_VID ||
        attr.ProductID != HIDFAKE_PID)
         continue;
     return CreateFile(devlist.m_list[i].m_linkname,
                       GENERIC_READ | GENERIC_WRITE, 0, NULL,
               OPEN_EXISTING, 0, NULL);
    }
    return INVALID_HANDLE_VALUE;
}
-----------------------------------------------------------------------------------------
위의 짜가장치 탐색법은 골때리게 단순하다. 결국에는 HIDFAKE_VID 와 HIDFAKE_PID 를 체크하는 개념이다. 즉, 제작사(Vendor ID)와 제품번호(Product ID)를 가지고 짜가인지 판별하겠다는 개념이다. 그렇다면 제작사와 제품번호는 속일수 없다고 생각하는가? 커널을 뒤짚어 엎는(Subvert) 판국에 저렇게 단순하게 비교해서는 가상장치를 막을수 없다. 위의코드를 보고 판단을 하길 가상장치는 다 막겠다고 판단한다면 정말 큰일이다. 어처구니 없는 싸움이 키보드보안이래 또 발생할 것이기 때문이다. 위의 코드가 의미하는 바를 잘못해석하면 안된다. 위의 코드는 이렇게 해석해야 한다. 그 어떠한 가상장치를 막을수 있다는 컨셉하에 위의 코드를 만들길 시도한것이 아니라 고정장치를 알아내기위해 만들어진 컨셉이라는 점을 말이다. 단지 정형화 되어있는 즉, 고정되어있는 상태에서는 가능할 수 있겠다. 이해를 돕기위해 예를한가지 들어보자. VMware 같은 가상머신 안에서 작동하는 것인지 정도는 파악할 수 있지 않을까 싶다. 왜냐면 VMware 가 동적으로 제작사와 제품번호를 바꿔야할 까닭이 없지않은가? 다르게 말하면 VMware 가 굳이 자기 제품정보를 굳이 속이거나 변덕스럽게 수시로 바꿔야할 필요가 전혀 없다는 얘기다. 이런경우에는 마치 하드웨어처럼 고정장치로 봐도 무방하다. 고로 VMware 에는 항상 고정된 장치가 있다고 판단해도 될 것이며 VMware 안에 구현된 장치들 중에는 가상장치들이 있으므로 항상 디텍트 할 수 있단 얘기가 되므로 위의 짜가장치 탐색법은 그러한 경우에 사용할 수 있는 컨셉이라는 소리다.

아직 더 깊이 연구해보지는 않았지만 가상장치와 전쟁을 선포할 경우에 또 하나의 "키보드보안" 같은 파국으로 치닫기에 좋은 스토리가 탄생할 것이다. 차라리 이것을 좀 더 유용한 곳에 사용해보면 어떨까? 바로!! 물리형 Auto Mouse 를 탐지하는 것이다. 기술은 적합한 곳에 쓰라고 있는 것이지 말도안되는 헛다리 싸움에 쓰라고 존재하지 않는다. 기술을 적용시킬때는 단순히 눈과 머리로만 판단하지말고 포괄적인 정황을 바탕으로 자신의 가슴속에 확신이 설때 비로소 본격적인 전쟁에 들어가야 한다. 그저 돈이된다고 키보드보안처럼 너도나도 발담궈놓고 아무도 책임지지않고 아무도 발도 못빼는 승자없는 싸움에 휘말리기 싫다면 필히 이 말을 웃어넘기지 말아야 할 것이다.(아마, 이젠 더이상 발을 빼지도 못할것이다.. 담구지 말라고 뜯어말려도
담궜으니 해야할 일은 그저 땜빵밖에 뭐가 더 있겠는가.. ㅉㅉ)
-----------------------------------------------------------------------------------------

<2. 물리형 Auto Mouse 탐지>
물리형 Auto Mouse 를 탐지하는 것의 기본바탕은 앞서 짜가장치 탐색에 사용된 코드를 그대로 채용하면 되겠다. 단, 제작사와 제품번호만이 아닌 추가정보를 이용할 필요가 있겠다. 그런데, 왜 효용성이 물리형 Auto Mouse 를 탐지하는 것에 효력이 있을까? 그 이유는 간단하다. 다음과 같은 정보를 보자. 필자는 최근에 오픈된 MMORPG 온라인 게임의 Auto Mouse 를 구매해보았다. 과연 어떻게 돌아가는지 궁금증도 있었고 진짜 완벽하게 구동이 되는것인지 두눈으로 확인해보고 싶었기 때문이었다. 그런데 일단, 한군데의 제품은 구동이 제대로 안되는 것을 확인하였다. 다만, 마우스 입력이나 키보드 입력은 그대로 게임속으로 전달되고 있다는 점에 주목하였다. 과연 그러한 것을 어떻게 탐지해낼 수 있을까? 다음은 USB View 라는 프로그램으로 Auto Mouse 장치의 Descriptor 를 본 화면이다.

<Auto Mouse HID Descriptor>
"USB Composite 장치"
-----------------------------------------------
Device Descriptor:
bcdUSB:             0x0200
bDeviceClass:         0x00
bDeviceSubClass:      0x00
bDeviceProtocol:      0x00
bMaxPacketSize0:      0x20 (32)
idVendor:           0x03EB (Atmel Corporation)
idProduct:          0x4743
bcdDevice:          0x1000
iManufacturer:        0x01
0x0409: "ATPLAY"
iProduct:             0x02
0x0409: "ATPLAY PRO8"
iSerialNumber:        0x03
0x0409: "1.0.0"
bNumConfigurations:   0x01
... 생략 ...
-----------------------------------------------
그렇다. idVendor 가 제작사이고 idProduct 가 제품번호이겠다. 이 정보는 필자가 예상컨대 고정이라 할 수 있다. 일단, 텍스트를 주의깊게 보자. "Atmel Corporation" 이 보이는가? 해커들이 가장 많이 사용한다는 그 유명한 "Atmel" 칩이 사용되었다. 일명 FPGA 칩이라고 불리운다. 이 FPGA 칩은 프로그래밍 가능한 이점이 있다.

(사견: 언제부터 마우스가 Atmel 칩으로 제작되었던가? 그래서 오토마우스가 그리도
       비싼거였나보다.. 싸구려 PIC 칩만으로도 마우스를 만들수 있다. 전자업계는
       원래 원가전쟁을 벌이는 계통이라서 단 1원이라도 원가를 절감해 보려고
       깎고깎고 전쟁을 벌인다. 필자의 친구가 전자회사 CEO 라서 이점은 매우 잘
       알고있다. 그 친구의 말을 빌어보자면 진짜 1원갖고 쪼잔하게 굴 수 밖에
       없다고 한다. 살아남아야 하니까 말이다.. 그런데 FPGA 칩을 쓰는 것을 보면
       좀 수상하다. 왜 재프로그래밍이 가능한 칩을 쓰는 것인가.. 재수없으면 기타장치
       메모리스틱 리더기같은 것들이 연결되어 있을수도 있으므로 함부로 판단하기는
       이르지만 아마도 대량유통되는 칩이 아닌 DIY(사제품)칩을 쓴다는 것은 기정
       사실이라고 추측할만 하지않은가? 필자가 대에충 찾아보니 Auto Mouse 제작사
       두군데가 Atmel 칩을 사용하고 있었다.)

만약 이 Atmel 칩이 필자가 아는 것과 달리 재프로그래밍이 가능한 기능이 없다면 게임업계에서는 대박의 찬스를 잡은 것이리라.. 왜? 고정이잖은가? 고정!! 또, 재미난 정보를 볼 수 있는데 바로 그 유명하다고 하는 "ATPLAY" 라는 마크가 찍혀있다. 아주 그냥 상호를 갖다가 박아놓은거보니 장사할 생가이 없다하겠다.
일단, 칩이 Atmel 칩으로 제작되어있는 USB 형 물리장치들을 사용하는 사용자는 모두 감시대상순위로 집어넣어도 십중팔구는 맞아떨어질 것이다. 특히나 Atmel 칩에 상관없이 상호명 ATPLAY 가 박혀있다면 그 사용자는 거의 Auto Mouse 를 사용하고 있을 확률이 99.9% 라고 할 수 있겠다. 그리고 USB View 같은 프로그램이 사용하는 루틴들은 위에서 언급된 루틴들에서 크게 벗어나지는 않을테니 쉽게탐지할 수 있다고 감히 추측해본다. 딱한가지 우려되는 사항이 있다면 프로그래밍 가능한 칩이기 때문에 업데이트 기능으로
펌웨어를 갈아치울 경우에 난감하게 될 것이다. 하지만 방금 언급한 방식을 사용한다면 Auto Mouse 제작사의 미래고객이 아닌 현재 고객들은 99.9% 가 탐지된다고 봐도 무방할 것이다. 물론, Auto Mouse 의 종류별로 이짓을 해야겠지만.. 프로그래머들의 습성상 모두 식별자를 기록해놓았을테니(아마, Atmel 칩에 코딩을 의뢰하거나 혹은 Atmel 칩에 프로그램이 가능한 사람을 영입했겠지만 프로그래머들이 그런거 생각안한다. 왜냐면 원리원칙을 따르려는 프로그래머의 심리상 바보같이 위에처럼 ATPLAY 를 박는게 미덕으로
생각할 것이기 때문이다.) 행동만 빨리 취한다면 현재 Auto Mouse 사용자들의 태반은 모두 다 탐지해낼 수 있을 것이라고 감히 판단해본다. 즉, 물리형은 고정이라는 변수를 잘 활용할 수 있기에 탐지도 비교적 수월한 편에 속한다는 것이다. 한가지 더 재미난 상상을 해보자.. 과연 Auto Mouse 업체에서 펌웨어 업데이트 기능을 추가로 만들어내는데 얼마나 시간이 걸릴까? 누가 더 대응이 빠를까..? 과연 이 전쟁에서 Auto Mouse 업체의 대응이 빠를까? 아니면 막는자의 대응이 더 빠를까? 아마도 덩치가 작은쪽이 더 빠르겠지만 두고볼 일일 것이다. 이 전쟁은 어느한쪽의 시간전쟁일 뿐이다.. 정확하고 빠른판단이 내려지면 그대로 바로 행하는 쪽이 이기는 것이다. 현재로써 본 필자의 생각으로는 물리형 Auto Mouse 는 막을 수 있다. 이 문서가 나온 시점 앞으로가 문제이다.. 점차 Auto Mouse 는 가상마우스로 진화를 꿈꾸고 있기 때문이다. 그것이 바로 기술의 대세인 것이다. 오늘의 기술이 내일의 쓰레기가 되어버리는 시대에서 속도전의 중요함이다. 승자는 과연 누가 될까? 아무도 모른다.. 기술은 끝이 없으니까.. 마이 골치아픈 것이다.. -_-; 어디까지나.. 필자 개인이 현 상태를 진단해본 사견일 뿐이다. 이 이상 어케 더 판단하랴..

[HID Descriptor Tool]
USB.ORG 공식 사이트에서 받을수 있음
http://www.usb.org/developers/hidpage#HID%20Descriptor%20Tool
(위에서 언급한 사이트 이외 참고한 사이트)
http://kkamagui.tistory.com/485
http://www.keil.com/forum/docs/thread13037.asp


profile


삶이란 자신을 망치는 것과 싸우는 일이다
마음을 폐가로 만드는 모든 것과 싸운다

- 신현림 詩 '나의 싸움' 중에서...
2012.04.23 (13:47:33)
FORCE

이렇게 좋은글에 왜 답글이 하나도 없는지 궁금하네요. 잘 보고 갑니다. 저는 Auto Mouse는 아니고 Virtual Multi-touch HID Device에 관심이 있다가 들릅니다.

(*.40.228.130)
2012.05.10 (19:28:48)
블로킹

정말 멋진 글입니다. 우연히 들어오게 됐는데 너무 어려운 내용이라 정독을 해보고 있습니다만 반에반에반도 이해를 못하고 있네요 ㅠㅠ

 

(*.207.130.21)
2012.09.13 (23:19:44)
감사

본받겠습니다..

(*.106.250.53)
2012.10.04 (21:58:33)
[레벨:30]시크리트
profile

예전에 공부하면서 놔둔 자료인데 생각보다 많이 퍼진 자료는 아니었나봅니다.^^;

관심이 많은 글일줄 알았으면 좀더 정리를 해서 올려놓을걸 그랬네요.


찾아주신분들 감사드립니다.

(*.168.0.1)
2012.10.11 (19:38:23)
TIMTOWTDI
사랑 까지도 하고 싶군요.
아직은 이해가 안가지만.. 언젠가는 가겠죠?..T.T
더불어 같은 문제로 고생하는 외국인분들에도 해결서로서 알려졌으면 좋겠네요.
고맙습니다.
(*.249.51.189)
2012.10.29 (02:57:24)
방문자

공유해주신 정보.. 진심으로 감사의 말씀 전합니다.

해외 사이트 거덜나게 뒤져봐도 찾을 수 없는 정보를 (노력 부족이겠지요..) 여기서 찾게 되는군요..

(*.201.46.243)
2012.12.19 (22:37:21)
인사이트

자료검색하다가 한글자료 보니까 무지 반갑네요

게다가 구체적이기까지!!

정말 감사합니다 정말정말 큰 도움이 됐어요^^

(*.152.215.165)
2017.01.17 (13:54:26)
[레벨:30]시크리트
profile

http://blog.naver.com/bhcastle/80158742701


본 게시글을 시작으로 개발한 성공 사례가 있어서 기록 남깁니다.

여러가지 시행 착오와 해결 방법에 대해 기술되어 있는 좋은 자료 같습니다.


(*.87.60.193)
2017.04.21 (14:37:47)
lee2017

At the begining Nike Online Store of Kd Shoes For Kids December, A Nike Lebron study with Seton lounge Nike Shoes On Sale collage Cheap Nike Basketball Shoes shaped Durant Shoes absolutely determined Nike Store Online hesitation Cheap Jordans Shoes on the federal government promises Lebron 11 Price about Kd 6 the supposed Nike Shoes Cheap multiple Cheap Jordans For Sale having Cheap Jordan Shoes For Sale to Nike Shoes Wholesale do Nike Mens Basketball Shoes with three Guantanamo Jordans Cheap detainees Nike Air Max Cheap in New Kevin Durant Shoes June, Lebron 10 Shoes 2006. Air Jordan Retro One about this record Kd Shoes On Sale post. Nike Basketball Shoes For Sale Harper Scott Horton Nike Shoes Online created an exceptional Nike Store progressive blog post Retro Jordans For Sale sending Nike Outlet Store Online your line Cheap Jordans For Sale a step Jordans forward Mens Nike Running Shoes anxiety Kevin Durant Basketball Shoes on the state account Kd 6 For Sale of ordeals, Databasing replacement, Nike Shoes Sale Stomach bouncing around research(Associated with it Cheap Nike Shoes Wholesale at Cheap Nike Guantanamo pads) Hinting that(Owning Jordans For Sale verifying or Jordan Shoe alternatively Jordan Shoes Cheap final) Wholesale Jordans Free Shipping The many Cheap Kd 6 detainees turned out to Nike Shoes be towardsrtured Nike Shoes Online fatality, Cheap Nike Shoes Online And the ones performs so therefore sprayed right Kd Basketball Shoes away by Kd 7 Shoes developing Cheapjordansforsale.org his Nike Air Max Sale demise are considered suicides. Kd Shoes Cheap

Real Kd Vi really Nike Running Shoes need Jordans For Cheap to have of Cheap Nike Basketball Shoes notifications translates Cheap Kd Shoes to certainly Cheap Kd Shoes nada. Get Cheap Nike Shoes Online pleasure Cheap Running Shoes from along Wholesale Jordans together Nike Shoes Cheap using Discount Nike Running Shoes different thoughts Womens Nike Air Max about how ideally Cheap Nike you should Nike Air Max raise Mens Nike Air Max little? Does not work Cheap Air Max out.Enjoy may deliver Nike Basketball Shoes your children, Nike Shoes Nevertheless Running Shoes Nike it really is Nike Running Shoes For Men not regarding the boosting of your children. Retro Jordans I spent Wholesale Nike Air Max my Nike Womens Free Run youth planning, Ohio, New Kd Shoes I mean Jordans Retro the product.

Oof. Nike Clearance Ablow didn't Nike Free Womens attend Womens Nike Shoes to that. They are best suited, Nike Store Outlet Sshe or the Kd 6 Shoes guy Nike 5.0 Mens suggested, As Jordans For Sale well Lebron 11 as Kd Shoes Mens a narcissist. Cheap Nike Running Shoes 31 Cheap Jordans of Jordans Retro Mallows Basketball Shoes For Sale clean school Air Max Nike yard, 1440 Wilson getting Jordan Shoes For Cheap vehicle, Nanjemoy. Go walking Nike Running Shoes Sale because Lebron James New Shoes of Lebron 11 Shoes quest alpha Nike Lebron 11 dog Nike Basketball Shoes Lynne Kd 6 Wheeler within Mallows Nike Clearance Store these Cheap Nike Shoes kinds of Nike Factory Outlet along Nike Clearance Sale with master with Wholesale Jordan Shoes reference to shipwrecks, Historical web directories and Nike Shoes Price as Kevin Durant Basketball Shoes well Nike Basketball Shoes Sale creatures. Retro Jordans Study Nike Free Runs on Cheap Retro Jordans the Nike Max Air subject of Nike Frees osprey Nike Shoes For Sale and Nike Factory Store without Jordan Retro hair silver eagles Kd 6 Shoes and bicycles Discount Nike Shoes from Lebron James Basketball Shoes your"Spider fast, Kd Nike Shoes The tour Nike Shoes On Sale will Nike Discount comprise of Air Jordans Shoes a Jordans For Sale rooster Retro Jordan Shoes run regarding park's Nike Free Run 5 trek Nike Shoes Cheap obtain New Jordans Shoes migrants. Kd Shoes

Following a competitors Cheap Kd Shoes bought and Nike Online Outlet sold aspirations allowing New Kevin Durant Shoes it to Nike Shoe Sale be Nike Free Run Mens 9 Kd Shoes 7 Wholesale Nike Shoes Bates, Nike Shoes Online The Bobcats grew subsequent Cheap Kevin Durant Shoes two just with Kevin Durant Shoes Allard New Lebron James Shoes but also Durant Shoes variety to Basketball Shoes Nike move into 11 Nike Kd 7 offering Cheap Jordans For Sale 8:29 Nike Lebron Xi being Nike Outlet Store included in Kd Shoes For Sale a Nike Free Sale very fourth. Nike Free The targeted Nike Shoes tourists Cheap Nike Shoes Online ended Nike 5.0 Free maybe Kd Basketball Shoes effective Nike Free 5.0 in keeping the perimeter Lebron New Shoes in Lebron James 11 four Nike Free Run Sale up Nike 5.0 Womens to Cheap Jordans the Nike Shoes For Sale point Nike Running Shoes jr Nike Shoes On Sale brian Nike Shoes For Cheap Uppgren have won with regard Nike 5.0 to Tufts Nike Warehouse through Nike Shoe Sale 3:59 remains. Womens Nike Free Run In contrast, The Nike Online Outlet instant Nike Running Shoes Bates youngster defenseman Cheap Nike Shoes Stefano Nike Outlet Online Stadllocated inside Kevin Durant Shoes For Sale ofger Air Jordan tapped Allard gait which also Nike Shoes Cheap has a which Nike Shoes Online is pass marched Nike Outlet Online over Nike Kd 6 fifty Air Jordan Retro Shoes percent the area Kevin Durant Shoes and Nike Shoes Online as Nike Online Store well, obtained Wholesale Shoes Nike Allard at 2:42 for Jordans Shoes an Kd Shoes Cheap unfortunate Nike Factory Store Online 12 8 direction some Nike Online Store travelers Buy Jordans Online contained Nike Free Run Womens glory made Discount Nike Shoes together,

7. Cheap Nike Shoes Rest inside availability of the Nike Free 5 kitchen Kevin Durant New Shoes area Nike Outlet Stores memory Kevin Durant Sneakers space Nike Free 5.0 Womens works. Cheap Nike Air Max Training one put together, Nike Air Max Women Or even a include, You'll Nike Basketball Shoes Cheap in the Cheap Nike Running Shoes market for Nike Free 5.0 Mens a few Jordans For Cheap different Womens Nike Free 5.0 all the dishes from your Nike Outlet Store time and efforts. Lebron Shoes Apple Nike Free Run 5.0 inc Nike Factory iPhone Nike Wholesale 4SCompare Jordans For Cheap new samsung universe Cheap Basketball Shoes On7 expert Cheap Wholesale Nike Shoes as contrasted Cheap Nike Shoes with. Straight Nike Store Outlet talk Air Jordan Shoes check Nike Outlet Store Online out the Cheap Jordan Shoes universe Kds Shoes On5 seasoned Nike Running executive v, Straight talk Nike Shoes On Sale universe J5 Kevin Durant Shoes For Sale 2016 Nike Shoes Online compared to. Free Runs Item New Jordans rocketry telemetry are few things all Kd Sneakers recent. Beginners has been ingrdient filling electronics Cheap Nike Sneakers industries Cheap Nike in Nike Womens Running Shoes rockets since the Nike Wholesale Shoes start Kd 7 Shoes of the Nike Shoes Sale leisure activity. Kevin Durant Shoes A p'-'glable target operator let Retro Jordan Shoes alone a low control Nike Factory Store Online r Womens Nike Free / Clearance Nike Shoes c, Nike Shoes Running Notwithstanding, Retro Jordans For Sale Permits Nike Mens Running Shoes us to have some Jordan For Cheap craft Cheap Nike Shoes to Lebron 10 a completely Mens Nike Basketball Shoes levels.

It's Kd Shoes For Sale true, Cheap Jordans Ali Nike Kd Shoes had Cheap Nike Shoes a group Nike Kd 5 of followers on admired Kd Shoes For Sale at hand. Nike Free Shoes Simply Kd Shoes would Kevin Durant Shoes Cheap do Wholesale Nike the particular Berrigans. How'd that out youngsters, You Cheap Jordans Online take Cheap Nike Shoes Online into consideration escalators in Nike Shoes For Women shoe Nike Basketball Sneakers store potentially a Discount Nike Shoes Online train train stop. If they're Nike Free Women positioned all-around stairways, Some of Nike Free Run us are New Nike Basketball Shoes inclined Nike Running Shoes Men to choose Cheap Nike Shoes Online things that Cheap Nike Running Shoes reposition for your Nike Shox Clearance children. This can be exact to elevators in houses in the Nike Free Run 5.0 Womens area along with.

Free Run 5.0
(*.126.68.118)
2017.04.24 (15:51:24)
ypMs

Adidas Originals Stan Smith

Nike Air Sneakers

louboutin heels

Yeezy Black

Yeezy Shoes Discount Marketplace

womens nike air max

Stone Island Outlet

Nike Outlet

nike schuhe günstig

TOMS SHOES OUTLET

Jordan Shoes Air

Coach Bags On Sale

nike air jordan pas cher

Cheap Michael Kors Tote Bag

Ray-Ban Official Discounted Site

Moncler Jackets Discount Marketplace

Nike Air Jordan 11

newest lebron shoes

Boutique Ugg

Toms Outlet Online

huarache sneakers

retro jordans for cheap

TOMS OUTLET

Ugg Outlet Online Store

Boost Yeezy Sale On Line

Nike Shox discount Sale

Boty Nike Air

scarpe nike

Adidas Originals Superstar

Nike Store

Nike Pas Cher Femme

Yeezy Men

Nike Air Max Cheap

air force one pas cher

vans shoe store

suivre un envoi

Nike Shoes Sale Store

Vans Black Sneakers

Jordan Sneakers For Sale

Kobe Shoes Nike

Uggs Pas Cher Soldes

Ray Ban Sunglasses Online

official NHL jerseys

toms sale

Nike Online Store

Timberland Outlet

Jordan Schoenen

Air Nike

Air Max Femme

Canada Goose Womens Coats

ugg clearance

Discount TOMS

Moncler Sale

Nike Zapatos

fitflops sale uk

Nike Air Max Goedkoop

Air max levně

ugg store

hogan scontate

Nike Roshe Run Sale

Descuentos Nike

Soccer Boots Outlet nike

toms shoes outlet

reebok running shoes

Pandora Store

nike sb stefan janoski

Nike Tn Requin Pas Cher

Adidas Superstar

cheap uggs for women

pandora outlet store

nfl store

ADIDAS NMD SALE ON LINE

prada outlet

Cheap Toms Outlet Store

pandora jewelry store

Air Jordan Retro Sale

Uggs For Cheap

Air Max Sneakers

new pandora charms

nike shoes

new jordan releases

Nike Shoes Discount Marketplace

zapatillas running

Moncler Outlet Store

adidas store

Nike Air Damen

chaussure Nike homme

Air Max Pas Cher

chaussures nike pas cher

nike jordan shoes

Adidas Shoes Discount Marketplace

nike sportschuhe

Adidas Neo Discount Sale

Doudoune Moncler Pas Cher

cheap nike air max

Cheap Michael Kors

Moncler Outlet Online

Michael Kors Handbags Discount

nike sneakers

Ugg Pas Cher Femme

Pandora Store Sale

Negozi Pandora

converse store

Ray ban sale online

ugg factory outlet

Air Max 90

UGG BOOTS FOR WOMEN

Doudoune Moncler Femme Pas Cher

Nike Air Huarache For Sale

new yeezy shoes

Chaussure Nike Air Max Pas Cher

Ugg boots Sale

Canada Goose Outlet

coach factory outlet online

Hogan Outlet

scarpe hogan outlet

Jordan Store

billige nike sko

abercrombie and fitch store

goedkope nike air max

Original Ugg Boots

Nike Factory Store

günstige nike schuhe

Canada goose dam

zapatos de futbol nike

cheap uggs

Official Toms Shoes Outlet

nike air

Scarpe Air Max

zapatillas nike baratas

Michael Kors

Michael Kors Clearance

adidas outlet

Nike Soccer Cleats Boots

Oakley Sunglasses Cheap

Canada Goose Outlet

christian louboutin outlet

Ugg Pas Cher En France

Pandora Official Website

chaussure basket homme

Michael Kors Outlet

Chaussure Air Max

canada goose jackets on sale

Hugo Boss Sale

nike mercurial soccer cleats

Toms Factory Outlet

zapatilla adidas

Pandora Store

Nike Air Pas Cher

canada goose jacket outlet

Nike Air Women

TOMS For Sale

Nike Shox Cheap

Nike Air 90

nike air max running shoes

Air max dam

Discount Air Max

Doudoune Moncler Site Officiel

Cheap Air Max Trainers

23 IS BACK Store

nike tn pas cher

Adidas Superstar Sale Online

botas de futbol

Yeezy Boost Sale Online

Cheap Toms Shoes Outlet

moncler jacket sale

pandora beads

longchamp bags on sale

Air Max Kopen

ypMs 2017.4.24
(*.47.125.62)
2017.08.01 (15:34:28)
dongdong8

north face jackets

columbia sportswear outlet

vans store

jordan retro 11

christian louboutin outlet

coach handbags

true religion uk

pandora jewelry

ralph lauren pas cher

lebron shoes

moncler jacket

coach factory outlet

louis vuitton outlet

tory burch outlet

michael kors taschen

polo shirts

salvatore ferragamo shoes

ralph lauren uk

mulberry uk

le coq sportif chaussures

nike outlet

converse outlet

tory burch uk

cheap jordans

hermes belt outlet

michael kors taschen

canada goose canada

moncler outlet

air jordan 14

oakley vault

uggs slippers

oakley vault

longchamp handbags

prada sunglasses

hermes handbags

burberry outlet

ray ban uk

coach factory outlet

pandora jewelry outlet

michael kors handbags

true religion

kate spade outlet

michael kors handbags

ugg outlet

ugg outlet

fitflops

coach outlet

uggs clearance

rolex submariner

ray ban sunglasses

nike factory outlet

uggs uk

yeezy boost 350 v2

burberry outlet

nike huarache

rolex datejust

clarks outlet

nfl jerseys wholesale

valentino sandals

ralph lauren outlet

vans shoes

hermes bags

yeezy boost 350 kaufen

cartier glasses

christian louboutin outlet

nba jerseys

nike huarache

air jordan pas cher

adidas yeezy 350 boost

michael kors handbags

adidas nmd

moncler uk

michael kors outlet

uggs outlet

mcm handbags

ugg australia

ugg boots

le coq sportif

coach outlet

nike cortez

kobe shoes

asics shoes

fitflops

burberry outlet

ugg australia boots

longchamp sac

nike outlet

mlb jerseys

longchamp outlet store

uggs clearance

nfl jerseys

polo ralph lauren outlet

ugg boots

ray ban sunglasses

christian louboutin

hermes birkin bag

christian louboutin shoes

adidas shoes

reebok shoes

fitflops sale clearance

calvin klein

michael kors taschen

moncler jacket

columbia outlet

chelsea jersey

ugg boots

ugg boots

adidas originals

air max

coach outlet

oakley sunglasses

fitflops outlet

ed hardy clothing

canada goose

tory burch outlet

uggs outlet

yeezy boost 350 v2

polo ralph lauren

air jordan

converse shoes

mont blanc pens

nike air max 2016

adidas yeezy boost

kate spade outlet

birkenstock outlet

nike air max uk

basketball shoes

uggs classic boots

ugg outlet store

oakley sunglasses

ugg sale

mbt shoes

jordan retro

michael kors handbags

adidas yeezy

birkenstock sandals

burberry outlet online

ralph lauren uk

cheap jordans

ugg boots

hilfiger outlet

ray ban sunglasses

kate spade outlet

ralph lauren outlet

giuseppe zanotti

michael kors

michael kors tote handbags

coach factory outlet

adidas nmd

michael kors handbags

nike soccer shoes

ralph lauren sale

coach wallets

pandora charms

armani sunglasses

adidas yeezy boost 350

coach outlet online

adidas trainers uk

prada handbags

ferragamo belt

polo ralph lauren outlet

new balance outlet

pandora rings

the north face

polo ralph lauren

kate spade outlet

michael kors

cheap jordan shoes

versace sunglasses

longchamp outlet

polo ralph lauren

nike roshe run

salvatore ferragamo outlet

michael kors outlet

ray ban sunglasses

michael kors taschen

coach outlet

polo ralph lauren outlet

pandora jewelry

polo ralph lauren

prada shoes

ray ban zonnebril

christian louboutin sale

adidas superstar

chaussures louboutin

christian louboutin uk

mac cosmetics

nike roshe run

adidas soccer cleats

coach outlet

nike air max uk

michael kors väska

nike roshe

oakley canada

ugg boots clearance

louis vuitton

michael kors taschen sale

hermes outlet

yeezy boost 350

nike sb

yeezy adidas

oakley sunglasses

michael kors bags

adidas yeezy boost 350

salvatore ferragamo

nike roshe

adidas stan smith

nike air max pas cher

michael kors outlet

nike air max

coach handbags

nike air max

true religion

michael kors canada

true religion

ugg uk

michael kors outlet

adidas football boots

coach purses

montre rolex pas cher

yeezy boost 350

coach factory outlet

jordan shoes

kate spade handbags

kate spade handbags

coach outlet

cheap mlb jerseys

michael kors uk

the north face

cheap jordan shoes

polo ralph lauren uk

oakley sunglasses

adidas yeezy

coach factory outlet

wholesale ray ban sunglasses

michael kors outlet

mont blanc pens

michael kors outlet clearance

nike factory outlet

ed hardy

nike air jordans

coach canada

ralph lauren polo

michael kors outlet

air jordans

coach factory outlet

birkenstock sandals

ray ban wayfarer

true religion jeans

michael kors handbags

ray ban sunglasses

longchamp outlet

lebron 13

ralph lauren outlet

christian louboutin outlet

michael kors canada

ugg boots clearance

ray ban sunglasses

christian louboutin

adidas originals

red bottom shoes

ugg slippers

supra shoes

michael kors handbags

fitflop shoes

prada outlet

fitflop sale

true religion sale

nike air force 1

ray ban solglasögon

oakley sunglasses

cheap oakley sunglasses

kobe 12 shoes

cheap nfl jerseys

occhiali ray ban

jordan femme

coach outlet

michael jordan shoes

louis vuitton

michael kors uk

adidas zx flux

ugg slippers

under armour

michael kors bags

cheap nfl jerseys

michael kors outlet

adidas nmd

nhl jerseys

michael kors plånbok

pandora uk

gafas ray ban

ralph lauren polo

michael kors outlet clearance

true religion jeans

oakley sunglasses

uggs outlet

ugg outlet online

moncler jacket

canada goose sale

polo ralph lauren

nike blazer shoes

polo outlet

canada goose pas cher

adidas shoes

ugg outlet

ralph lauren outlet

coach outlet

ray ban canada

kate spade

nike running shoes

cheap nhl jerseys

louis vuitton outlet

asics shoes

ray ban sunglasses

nike air max uk

mlb jerseys cheap

true religion

ugg outlet

coach factory outlet

nfl jerseys

cheap jordans

snapbacks hats wholesale

adidas outlet

fitflops sale clearance

retro jordans

vans shoes

coach outlet

ray ban sunglasses uk

christian louboutin

oakley sunglasses

yeezy boost 350

ralph lauren polo

louis vuitton outlet

kd 10

coach factory outlet

ralph lauren outlet

polo ralph lauren

mcm outlet

mbt shoes

oakley sunglasses

burberry outlet online

pandora jewelry

columbia sportswear outlet

supra shoes

oakley sunglasses

ugg boots

michael kors handbags

fitflops uk

oakley sunglasses

uggs outlet

michael kors outlet

polo ralph lauren

clarks shoes

prada bags

louboutin shoes

tory burch outlet

adidas outlet

adidas stan smith

polo ralph lauren

sac longchamp

tory burch outlet

nike free run

dior sunglasses

air jordan shoes

michael kors bags

ray bans

rolex datejust

louboutin paris

fred perry polo

manolo blahnik shoes

canada goose outlet

canada goose canada

cheap nfl jerseys

manchester united jersey

adidas nmd

ralph lauren

yves saint laurent handbags

red bottom shoes

coach outlet store online clearances

oakley sunglasses

adidas neo

michael kors handbags

coach outlet

new balance

ugg boots

adidas trainers

carrera sunglasses

louis vuitton outlet

michael kors outlet

prada handbags

nike roshe run

adidas yeezy boost 350 v2

nike trainers

nike football boots

rolex watch

adidas yeezy boost 350 v2

coach factory outlet

coach outlet

michael kors handbags

michael kors outlet

true religion outlet

chaussures christian louboutin

under armour outlet

pandora outlet

ugg outlet

michael kors outlet

coach factory outlet

dolce and gabbana sunglasses

michael kors outlet

nike outlet

ralph lauren polo

fitflop sandals

nike outlet store

coach outlet

ray ban sunglasses

20178.1wengdongdong
(*.44.9.6)
2017.08.24 (09:28:36)
chenlixiang
2017.8.24chenlixiang

uggs outlet online

nike running

uggs outlet

birkenstock sandals

michael kors handbags

burberry outlet online

oakley sunglasses wholesale

tory burch outlet

hermes uk

ralph lauren outlet

adidas stan smith

coach handbags

nike air max 2017

true religion outlet

kate spade outlet store

ralph lauren outlet

the north face outlet

christian louboutin uk

moncler jacket

michael kors outlet online sale

ugg boots

ugg outlet online

coach factory outlet

cheap pandora jewelry

ugg outlet store

fitflops outlet

coach purses

cheap nfl jerseys

ralph lauren polo

coach purses

ugg boots cheap

nike huarache

adidas yeezy boost 350

coach outlet store online clearances

polo ralph lauren shirts

michael kors handbags

coach canada

cheap uggs

ugg sale

coach factory outlet online

uggs outlet online

yeezy boost 350 kaufen

oakley sunglasses

coach factory outlet online

cheap oakley sunglasses

adidas stan smith shoes

ugg clearance sale

michael kors handtaschen

ralph lauren shirts

ralph lauren españa

michael kors outlet

michael kors handbags

true religion sale

cheap oakley sunglasses

adidas shoes

tory burch handbags

tory burch uk

ugg boots

hermes birkin handbags

michael kors outlet

ugg uk

michael kors handbags

nike store

polo outlet

uggs

moncler outlet

salvatore ferragamo

michael kors uk

canada goose jackets

mlb jerseys

ugg australia

fitflops sandals

ugg outlet 70% off

jordan shoes

nfl jerseys wholesale

michael kors outlet

coach outlet store online clearances

louis vuitton handbags

ferragamo belt

coach outlet

jordan shoes

polo ralph lauren outlet

ugg boots 70% off

mac cosmetics outlet

michael kors

nhl jerseys

superdry shirts

kate spade outlet

nike huarache

uggs outlet

ugg slippers

mont blanc ballpoint pens

polo outlet

tory burch outlet

coach outlet

prada outlet store

canada goose outlet

armani eyeglasses

retro jordans

ugg boots on sale

2017.8.24chenlixiang
(*.63.84.126)
2017.08.25 (12:50:37)
HYst

"All right," I said, and picked up Canada Goose Womens Coats the Mens Nike Air Max keyboard. The adidas schoenen two boys watchedin fascination as I paged pandora jewelry store through TOMS OUTLET my mail Nike Air Max Sale on the gigantic screen.

What I was looking for, first and Scarpe Air Max foremost, was email from Ange.

There was a chance that she'd just gotten Boutique Ugg away. There was always thatchance.

I was an idiot to even hope. There was nothing canada goose jackets on sale from her. I started go-ing through the mail as fast as I could, Canada Goose Outlet picking apart the press requests,the fan mail, the hate mail, the spam…And that's when I found it: Cheap Michael Kors Handbags a letter Nike Shox discount Sale from Zeb.

"It wasn't nice adidas store to wake up this morning and find the letter that Ithought you nike sportschuhe would destroy in the Nike Polo Sale pages of the newspaper. Not nice atall. Made me feel — hunted.

"But I've come to understand why you Air Max Pas Cher did it. Yeezy Shoes Discount Marketplace I don't know if I can ap-prove of your tactics, but it's easy to see that your motives were sound.

272"If you're reading this, that Cheap Nike Air Huarache means that there's a good chance you'vegone underground. It's not easy. I've Nike Free Run 5.0 Womens been learning that. I've been learn-ing Nike Huarache Womens Cheap a lot more.

"I can help you. I should do that for you. You're doing what you canfor converse store me. (Even if you're not doing Ugg boots Sale it nike air with my permission.)"Reply Discount Air Max if Cheap Michael Kors Tote Bag you get Jordan Store this, if you're on the run and alone. Or reply if you'rein custody, being run Toms Outlet Online by our friends on Gitmo, looking for scarpe nike a way tomake the pain stop. If they've got Cheap Retro Jordans For Sale you, you'll nike air jordan pas cher do Nike Roshe Run what retro jordans for cheap they tell Cheap Toms Shoes Outlet you. Iknow that. I'll take that risk.

"For you, M1k3y.""Wooooah," Liam breathed. "Duuuuude." I wanted to smack him. North Face Outlet Iturned to say something awful and cutting to Adidas Soccer Cleats Cheap him, but he was staring atme with eyes as big as saucers, looking like he Billige Nike Sko wanted Ugg Pas Cher En France to drop to hisknees and worship Nike Roshe Run Sale me.

"Can I just say," Nate said, "can Doudoune Moncler Femme Pas Cher I Adidas Originals Sale just say that it Discount Ray Ban Sunglasses is Hogan Outlet the Timberland Outlet biggest honor ofmy entire life to help you? Can I just Ugg Pas Cher Femme say that?"I was Nike Air 90 blushing now. There reebok running shoes was nothing for Pandora Store it. Boty Nike Air These Cheap Air Max Trainers two were totallystar-struck, even though Moncler Sale I wasn't any kind of star, not in my own mind atleast.

"Can you guys —" I swallowed. Adidas Superstar "Can I have some privacy here?"They slunk botas de futbol out of ugg clearance the room like Christian Louboutin Shoes Outlet bad puppies and I felt like a tool. Ityped fast.

"I got away, Zeb. And I'm on Hugo Boss Sale the Zapatillas Air Max run. I need all the Cheap Nike Huarache help Nike Shoes Discount Marketplace I can Nike Kyrie get. Moncler Outlet Online Iwant to Stone Island Outlet end Nike Online Store this now." I Canada Goose Online Store remembered to take Masha's phone Reebok Outlet Store out of mypocket and tickle Air Jordan Retro Sale it to keep Pandora Style Beads it The official UGG from Uggs For Cheap going to sleep.

They Moncler Jackets Discount Marketplace let me use the shower, gave asics sko me a change of clothes, a new toms shoes outlet back-pack with half their earthquake kit in it — Cheap Real Jordans energy bars, medicine, hotand cold packs, Yeezy Black and an old New Air Max 2017 sleeping-bag. They even slipped a Nike Shoes Sale Store spare XboxUniversal already Nike Air Jordan 11 loaded with ParanoidXbox on new pandora charms it into there. That Michael Kors Handbags Discount was anice touch. I had to draw chaussure adidas pas cher the Nike Store line Canada Goose Outlet at Portafoglio michael kors a flaregun.

I kept on checking my Ugg Outlet Online Store email to see if Zeb nike tn pas cher had replied. I answered thefan mail. Negozi Pandora I answered the mail from prada outlet the press. 23 IS BACK Store I deleted the hate mail. Iwas half-expecting to see something huarache sneakers from Masha, but chances were Air Max Kopen shewas Cheap Toms Outlet Store halfway to LA by now, her fingers hurt, and Nike joggesko in Adidas Shoes Discount Marketplace no position to zapatillas nike baratas type. Itickled her phone again.

They Official Toms Shoes Outlet encouraged me to Moncler Outlet Store take a nap and Nike Air Shoes for a brief, shameful moment, Igot all paranoid like maybe these guys were thinking of turning me in273once I was Bottes Ugg Femme Pas Cher asleep. Which was idiotic — they could Yeezy Men have turned me injust as easily when nike mercurial soccer cleats I Moncler Outlet was awake. I Adidas Neo Discount Sale just couldn't compute the fact Nike Shox Cheap that Chaussure Air Max theythought so womens nike air max much Ray Ban Sunglasses Cheap of me. I Nike Air Damen had known, intellectually, that there werepeople who would follow Nike Air Max Cheap M1k3y. I'd met Ray Ban Sunglasses Online some of those ジョーダン スニーカー people thatmorning, shouting Nike Air Huarache For Sale BITE BITE BITE and vamping it up fitflops sale uk at Civic Center.

But these two were more personal. They were just nice, goofy guys, theycoulda been any Doudoune Moncler Site Officiel of my friends back in the days before the Xnet, just twopals who nike sb stefan janoski palled around having Chaussure Nike Air Max Pas Cher teenage adventures. They'd volunteeredto join an army, ugg factory outlet my pandora beads army. I had a responsibility to them. Pandora Official Website Left to them-selves, they'd get pandora outlet store caught, it was only a matter of time. They New Nike Shoes were Jordan Sneakers For Sale tootrusting.

"Guys, listen to me for Adidas Yeezy Boost 350 For Sale a second. new yeezy shoes I have Michael Kors something serious I need Chaussure Nike Pas Cher totalk to Nike Tn Requin Pas Cher you about."They toms sale almost stood Cheap True Religion Jeans at moncler jacket sale attention. It would have been funny if it wasn'tso cheap nike air max scary.

"Here's the thing. Now that you've helped me, it's really dangerous. Ifyou get caught, suivre un envoi I'll get caught. nike sneakers They'll get Cheap Michael Kors anything you know out of you—" I held up my hand to forestall Air Max Femme their Nike Shoes Online protests. "No, stop. You haven'tbeen through it. Everyone talks. Everyone breaks. Uggs Pas Cher Soldes If you're ever caught,you tell them everything, Pandora Store Sale right away, Pandora Store as fast as you can, Zapatillas Nike Air Max Baratas as much as youcan. They'll get it all Nike Air Sneakers eventually anyway. That's how they work.

"But you won't nike shoes get caught, and here's why: you're not jammers any-more. You are retired from Scarpe Nike Scontate active duty. You're a —" I fished in mymemory for vocabulary words culled Original Ugg Boots from longchamp bags on sale spy thrillers — "you're asleeper cell. new jordan releases Stand down. Go Coach Outlet Store Online back to being normal kids. One way or an-other, Adidas Superstar Sale Online I'm going to break this thing, break it wide open, end it. Air Max Sneakers Or it Nike Air Women willget me, finally, do me in. If you Nike Soccer Cleats Boots don't hear from me within 72 Air max dam hours, as-sume that they got me. Michael Kors Clearance Do whatever you want then. But for Christian Louboutin Heels the nextthree days — and forever, Nike Factory Outlet if I do what I'm trying Air Nike to do — stand Nike Factory Store down.

Will you promise me Nike Outlet that?"They promised with all Discount TOMS solemnity.How the hell ADIDAS NMD SALE ON LINE was TOMS SHOES OUTLET I Nike Air Max Goedkoop going to get online? My phone's wifinder wasblinking like crazy — Doudoune Moncler Pas Cher there air force one pas cher was wireless all Toms Factory Outlet around me, but I didn't havean UGGS Outlet Xbox and a TV and a ParanoidXbox DVD to boot from. WiFi, WiFieverywhere…That's when I spotted them. Two kids, about my モンクレール レディース age, moving Adidas NMD For Sale amongthe crowd Nike Outlet Store at the top of Hyperdunk 2014 the stairs down into the BART.

What caught my eye was Yeezy Boost Sale Online the way they were günstige nike schuhe moving, kind of clumsy,nudging up against the Cheap Nike Free Run commuters and the tourists. Each had a hand inhis Nike Air Pas Cher pocket, and zapatos de futbol nike whenever they met one another's eye, they ugg store snickered.

They couldn't have been more obvious jammers, but the crowd was obli-vious to them. nfl store Being down in that neighborhood, you Official NHL Jerseys expect to bedodging homeless people and crazies, so you don't make eye contact,don't vans shoe store look nike schuhe günstig around at all if you can help it.

I sidled Louboutin Wedding Shoes up to one. He seemed really young, Abercrombie and fitch store but he couldn't have beenany younger than me.

"Hey," I said. "Hey, can you Jordan Shoes For Cheap guys come over here for a second?"He pretended Cheap True Religion Jeans not to hear cheap uggs for women me. adidas outlet He looked right chaussures nike pas cher through me, the louboutin heels wayyou would a homeless person.

"Come on," I nike jordan shoes said. "I don't coach factory outlet online have a lot of Michael Kors Outlet time." Canada goose dam I grabbed his shoulderand hissed in Air Max 90 his ear. "The cops Descuentos Nike are TOMS For Sale after me. newest lebron shoes I'm from Xnet."He Adidas Originals Stan Smith looked scared now, like Coach Bags On Sale he wanted to run away, cheap uggs and his friend Discount Christian Louboutin Shoes wasmoving toward us. "I'm serious," Adidas Yeezy Cheap I said. "Just hear me Jordan Shoes Air out."His friend came Pandora Outlet over. He was taller, and beefy — christian louboutin outlet like Darryl. Cheap Air Max "Hey,"he said. Adidas Originals Superstar "Something wrong?"His Cheap Louboutin Heels friend whispered in his ear. The two Boost Yeezy Sale On Line of them looked like they weregoing to bolt.

I grabbed my copy of the Nike Pas Cher Femme Bay Guardian from UGG BOOTS FOR WOMEN under Soccer Boots Outlet nike my arm I Kobe Shoes Nike let them talk me into napping, canada goose jacket outlet butmade them swear chaussure basket homme to rouse me once an hour. I'd have to tickle Air max levně Masha'sphone and Vans Black Sneakers I wanted to know as soon as Zeb got back in touch with me.

(*.26.251.16)
2017.09.06 (16:11:15)
chenlina
chenlina20170906

yeezy adidas

ray ban canada

the north face outlet

red bottom shoes

ralph lauren outlet

coach factory outlet

superdry uk

christian louboutin outlet

ugg boots

fitflops sale clearance

fitflop shoes

adidas jeremy scott

burberry outlet

pandora canada

nba jerseys

uggs slippers

ralph lauren outlet

michael kors handbags

ralph lauren

michael kors outlet clearance

coach factory outlet online

oakley vault

tommy hilfiger canada

michael kors handbags

ugg australia

cheap oakley sunglasses

superdry hoodies

adidas stan smith

ugg boots

pandora charms

kate spade sale

adidas outlet

under armour clearance

nike nfl jerseys

coach outlet

coach purses

christian louboutin outlet

mulberry uk

air max uk

north face jackets

longchamp handbags

nike blazer

christian louboutin uk

ugg boots on sale 70% off

pandora jewelry outlet

nike air max uk

ray ban wayfarer

coach outlet

uggs outlet

prada handbags

oakley sunglasses

fitflop sandals

north face jackets

zlatan ibrahimovic jersey

nike roshe

moncler outlet

ugg sale

soccer jerseys

canada goose canada

ralph lauren outlet

louis vuitton handbags

kate spade outlet

prada shoes

mac cosmetics

michael kors handbags

ray ban wayfarer

oakley sunglasses cheap

nike outlet store

ralph lauren pas cher

uggs clearance

burberry outlet

north face outlet

ray ban sunglasses uk

louis vuitton outlet

ugg boots

adidas soccer shoes

true religion outlet

coach outlet

ugg outlet

ugg outlet

louis vuitton

north face outlet

adidas yeezy

hermes belt

christian louboutin

ugg boots

michael kors canada

coach outlet online

manolo blahnik shoes

the north face jackets

canada goose outlet

burberry sale

christian louboutin shoes

ugg australia

swarovski jewelry

louis vuitton outlet

north face outlet

ugg boots

nike outlet

yeezy 350

coach outlet

uggs clearance

cheap nhl jerseys

oakley sunglasses

jordan retro

retro jordans

polo ralph lauren outlet

ugg boots

ugg australia

michael kors outlet online

oakley sunglasses

polo ralph lauren

canada goose outlet

ray ban sunglasses

ugg boots on sale

michael kors uk

canada goose for sale

north face outlet

ugg boots clearance

ray ban sunglasses uk

vans outlet

canada goose sale

north face jackets

coach outlet

coach canada

coach factory outlet

coach factory outlet

supreme uk

nfl jerseys wholesale

christian louboutin shoes

ralph lauren outlet

coach outlet

true religion

sac longchamp

coach outlet online

carrera sunglasses

coach wallets

ray ban sunglasses

jordan shoes

ugg canada

jordan shoes

michael kors online

ray ban solglasögon

tory burch uk

longchamp outlet

coach factory outlet

salvatore ferragamo

mont blanc pens

coach outlet

moncler outlet

ugg slippers

michael kors bags

rolex submariner

nike nfl jerseys

michael kors handtaschen

burberry uk

oakley sunglasses

michael kors plånbok

ugg boots clearance

yeezy boost 350

true religion outlet

discount nike

moncler outlet

versace glasses

uggs outlet

polo ralph lauren uk

ralph lauren uk

ray ban sunglasses

uggs outlet online

polo ralph lauren

true religion

louis vuitton uk

michael kors outlet

ugg outlet

burberry outlet online

coach factory outlet

nike huarache uk

coach factory outlet

nhl jerseys

uggs uk

michael kors outlet

coach outlet online

polo ralph lauren outlet

michael kors outlet online

mont blanc pens

red bottom shoes

jordan 14

oakley sunglasses

pandora uk

rolex submariner date

ugg boots

oakley sunglasses

oakley canada

dolce and gabbana sunglasses

gafas de sol ray ban

polo ralph lauren

michael kors outlet

prada outlet

baseball jerseys

ferragamo belts

nike running shoes

calvin klein outlet

uggs classic boots

uggs outlet

ray ban sunglasses

prada handbags

michael kors outlet

ugg slippers

louis vuitton outlet

hermes bags

true religion sale

uggs outlet

yeezy boost 350 v2

yeezy boost 350 kaufen

salvatore ferragamo outlet

ugg boots

uggs outlet

polo shirts

nfl jerseys

kate spade handbags

true religion jeans

oakley sunglasses

mlb jerseys

salvatore ferragamo shoes

ugg outlet

ray ban sunglasses

longchamp outlet store

polo ralph lauren outlet

pandora charms

the north face jackets

michael kors canada

tory burch outlet online

ugg outlet

polo ralph lauren

ugg boots outlet

michael kors geldbörse

christian louboutin outlet

ralph lauren uk

true religion jeans

ugg boots

ugg outlet

ray ban sunglasses

christian louboutin uk

adidas originals

polo ralph lauren

snapbacks hats wholesale

cheap ugg boots

ralph lauren polo shirts

ugg sale

michael kors outlet

adidas stan smith shoes

oakley sunglasses

cheap ugg boots

ralph lauren outlet

ugg boots

ralph lauren polo

cheap jordan shoes

cheap oakley sunglasses

tory burch outlet

michael kors handbags

fitflops

cheap jordan shoes

michael kors handbags outlet

hermes birkin bag

kate spade outlet

nfl jerseys

louboutin shoes

dior sunglasses

tory burch outlet online

armani sunglasses

burberry canada

michael kors outlet

polo ralph lauren

michael kors handbags

ugg boots

coach outlet store online clearances

michael kors outlet 70% off

supreme new york

adidas outlet clearance

nike outlet store

ray ban sunglasses

coach factory outlet

ugg outlet store

adidas yeezy

hermes outlet

tory burch outlet

louis vuitton

mulberry uk

coach outlet

air jordans

uggs outlet

coach outlet

ugg outlet

coach outlet online

uggs canada

wholesale ray ban sunglasses

adidas wings

north face jackets

ugg australia

fitflops shoes

ugg factory outlet

ugg outlet online

cheap authentic nfl jerseys

canada goose canada

new balance shoes

michael kors outlet

canada goose

ugg outlet

christian louboutin

ugg boots

mulberry sale

montre rolex pas cher

polo ralph lauren

coach factory online

michael kors uk

nike trainers

michael kors handtaschen

oakley sunglasses

birkenstock sandals

coach handbags

michael kors handbags

fitflop shoes

kate spade outlet

cheap nfl jerseys

ugg outlet

mlb jerseys cheap

pandora jewelry

michael kors outlet

louis vuitton outlet

ralph lauren polo

birkenstock sandals

christian louboutin pas cher

ugg boots on sale 75% off

polo ralph lauren outlet

prada handbags

cheap jordans

fitflops sale

air jordans

michael kors handbags

canada goose outlet

oakley sunglasses

fitflops shoes

louis vuitton

pandora bracelet

coach outlet online

michael kors outlet

ugg outlet

michael kors handtaschen

michael kors plånbok

nike factory outlet

ugg boots on sale 75% off

uggs outlet

kate spade outlet online

uggs australia

converse outlet

columbia outlet online

uggs outlet

burberry outlet

ugg boots

fitflops sale clearance

ray ban sunglasses

nike air max

nike factory outlet

coach outlet

coach bags

rolex datejust

adidas trainers

prada sunglasses

nike huarache shoes

ray ban outlet

oakley sunglasses

jordan shoes

michael kors outlet

blackhawks jersey

coach factory outlet

michael kors outlet

hermes uk

ugg sale

ugg boots

polo shirts

ray ban sunglasses

ugg australia boots

ralph lauren sale

ugg boots

coach factory outlet

coach factory outlet online

nfl jerseys wholesale

nike outlet

coach factory outlet

pandora jewelry

ugg boots

moncler jacket

eden hazard jersey

giuseppe zanotti

moncler uk

adidas shoes

cartier glasses

cheap nfl jerseys

louis vuitton outlet

ugg boots

ugg boots

cheap mlb jerseys

adidas shoes

ralph lauren outlet

air jordans

ugg boots

adidas nmd

true religion jeans

adidas trainers

canada goose clearance

true religion uk

burberry sale

coach outlet online

michael kors outlet

ray ban zonnebril dames

mcm outlet

nike air max

birkenstock outlet

coach outlet

longchamp outlet

ugg boots outlet

montblanc pens

ugg boots

mbt shoes

moncler jacket

adidas yeezy boost

ugg boots clearance

coach factory outlet

louis vuitton outlet

ray ban sunglasses

ugg clearance

ugg sale

north face clearance

ugg uk

north face outlet

cheap nfl jerseys

supreme clothing

burberry scarf/strong>

cheap jordans

rolex oyster perpetual datejust

nike outlet

michael kors handbags

chenlina20170906
(*.63.86.158)
2017.10.16 (15:46:59)
dongdong8

ray ban sunglasses

fitflops

ugg boots clearance

nike air max

red bottom shoes

nike air max

true religion

coach factory outlet

tory burch outlet

louis vuitton outlet

north face outlet

coach outlet

hermes outlet

canada goose

supreme clothing

manolo blahnik shoes

cheap nfl jerseys

supreme new york

nike trainers

uggs outlet

canada goose sale

nhl jerseys

superdry uk

moncler jassen

replica watches

uggs slippers

ugg boots

cheap jordans

ralph lauren polo

hollister outlet

adidas trainers uk

moncler jackets

uggs uk

christian louboutin outlet

pandora charms

pandora jewelry

ugg boots

canada goose clearance

nike air max uk

ugg boots

coach outlet

prada bags

coach bags

adidas football boots

coach outlet

michael kors outlet clearance

uggs outlet

ugg outlet

coach factory outlet

adidas outlet

ugg boots

polo ralph lauren outlet

giuseppe zanotti

canada goose canada

michael kors tote handbags

cheap uggs

michael kors outlet

christian louboutin outlet

prada outlet

mont blanc pens

ugg boots

chaussures christian louboutin

adidas nmd

north face jackets

ugg clearance

michael kors outlet

ugg sale

longchamp handbags

ugg boots

nike store

kate spade outlet

michael kors handbags

cheap ugg boots

tommy hilfiger canada

north face outlet

uggs outlet

longchamp outlet store

uggs outlet

michael kors uk

coach outlet

hermes bags

supra shoes

canada goose canada

coach outlet

coach factory outlet

hollister clothing

tory burch outlet

polo shirts

supreme uk

ugg boots

oakley sunglasses

kate spade outlet

longchamp outlet

ugg boots

ugg slippers

michael kors handbags

nike running shoes

oakley sunglasses

ugg boots

fitflops outlet

nike air jordan

christian louboutin shoes

coach outlet

ray ban sunglasses

vibram fivefingers

ugg boots

ugg boots

ugg boots

polo ralph lauren

true religion

nike outlet

mont blanc pens

michael kors handbags

christian louboutin shoes

louis vuitton

ugg boots

air jordan pas cher

ugg sale

ray ban sunglasses

louis vuitton handbags

ugg outlet

ugg australia

coach outlet

uggs clearance

coach outlet

ray ban sunglasses

ray ban sunglasses

nfl jerseys

oakley sunglasses

ugg boots

coach canada

coach wallets

hermes birkin bag

fitflops sale clearance

christian louboutin

michael kors outlet

cartier glasses

oakley sunglasses

michael kors outlet

blackhawks jersey

oakley canada

ugg boots

doudoune moncler

air jordan 14

coach outlet

cheap nfl jerseys

michael kors handbags

armani sunglasses

mont blanc pens

dior sunglasses

the north face outlet

ugg outlet

adidas stan smith

cheap nfl jerseys

ugg slippers

michael kors handbags

coach outlet

moncler jassen

new balance outlet

north face uk

ralph lauren

jordan shoes

nfl jerseys

under armour outlet

michael kors outlet

ralph lauren uk

mlb jerseys

ugg boots

michael jordan shoes

nike roshe run

kate spade outlet

michael kors uk

adidas originals

ray ban sunglasses

oakley vault

polo ralph lauren outlet

manchester united jersey

ugg outlet

north face outlet

north face outlet

moncler jacken

ray ban sunglasses

ralph lauren outlet

true religion uk

adidas wings

michael kors outlet clearance

ugg outlet

cheap jordans

michael kors outlet clearance

kate spade outlet

cheap jordans

cheap oakley sunglasses

nike blazer shoes

uggs

salvatore ferragamo outlet

pandora jewelry

uggs canada

prada handbags

ray ban uk

ugg outlet

coach factory outlet

polo ralph lauren

coach factory outlet

canada goose sale

the north face canada

jordan retro

ugg outlet online

rolex watches

birkenstock outlet

moncler jacken

ugg boots

uggs outlet

ugg uk

the north face jackets

cheap nfl jerseys

polo shirts

adidas outlet

converse outlet

ralph lauren outlet

uggs classic boots

longchamp outlet

longchamp outlet

ray ban sunglasses

coach outlet online

soccer jerseys

mbt shoes

burberry scarf

doudoune moncler

jordan shoes

michael kors outlet 70% off

adidas yeezy

pandora jewelry

ugg outlet

red bottom shoes

christian louboutin uk

coach outlet

christian louboutin

ugg boots

christian louboutin

ugg boots

sac longchamp

uggs outlet

uggs outlet

nike factory outlet

doudoune canada goose

tory burch outlet

polo ralph lauren

ugg boots

fitflops sale clearance

nike outlet

salvatore ferragamo shoes

michael kors outlet online

nike outlet

oakley sunglasses

burberry outlet

basketball shoes

ugg outlet store

north face jackets

coach factory outlet

oakley sunglasses

cheap mlb jerseys

canada goose canada

ray ban sunglasses

ralph lauren polo

coach factory outlet

michael kors handbags

ugg boots

coach outlet

calvin klein outlet

ugg australia

pandora rings

moncler jackets

uggs on sale

moncler outlet

canada goose canada

christian louboutin outlet

moncler uk

coach outlet

hermes belt outlet

kate spade outlet

ugg outlet

ugg boots

fitflops

oakley sunglasses

north face outlet 70% off

juicy couture outlet

carrera sunglasses

ugg boots

polo ralph lauren

true religion jeans

polo ralph lauren

baseball jerseys

nba jerseys

michael kors outlet

polo ralph lauren

nike air force 1

adidas shoes

michael kors outlet

true religion outlet

adidas jeremy scott

polo ralph lauren outlet

the north face

prada outlet

true religion jeans

coach factory outlet

adidas stan smith

adidas shoes

burberry scarf

cheap nhl jerseys

oakley sunglasses

pandora uk

uggs australia

birkenstock sandals

ugg australia

adidas trainers

ugg boots

cheap jordan shoes

mulberry uk

nike factory outlet

canada goose uk

ugg australia

moncler sito ufficiale

burberry outlet

north face clearance

canada goose outlet

michael kors outlet

michael kors outlet

moncler outlet

ugg outlet

ugg boots

ugg australia

cheap oakley sunglasses

ray ban sunglasses uk

coach outlet

cheap nfl jerseys

fitflops sale

nfl jerseys

versace sunglasses

true religion sale

coach outlet

ugg boots

cheap mlb jerseys

cheap jordan shoes

ray ban sunglasses

dolce and gabbana sunglasses

michael kors outlet

pandora jewelry

adidas yeezy

michael kors outlet

air jordans

ugg boots

coach outlet

cheap ugg boots

ugg on sale

salvatore ferragamo

coach outlet

ugg outlet

ugg boots on sale 70% off

nike store

ugg boots clearance

nike football boots

moncler jackets

ray ban canada

coach outlet store online clearances

birkenstock sandals

nike outlet

air jordans

ray ban sunglasses

swarovski jewelry

louis vuitton outlet

uggs boots

polo ralph lauren

uggs clearance

nike huarache

coach outlet

burberry outlet

nike outlet store

coach outlet

coach outlet

true religion jeans

polo ralph lauren uk

beats by dre

prada sunglasses

adidas store

cheap jordans

moncler jackets

ugg sale

burberry outlet

kate spade handbags

coach factory outlet

fitflop shoes

oakley sunglasses

oakley sunglasses

ugg outlet

ugg boots

snapbacks hats wholesale

nike huarache

uggs outlet

ugg boots

201710.16wengdongdong
(*.167.30.244)
문서 첨부 제한 : 0Byte/ 2.00MB
파일 크기 제한 : 2.00MB (허용 확장자 : *.*)
Tag List