Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 3개 있습니다.)
한 대의 PC에서 여러 개의 키입력 매크로 프로그램이 가능할까?


저는 SDK 레벨의 개발자입니다. 그래서 때로 DDK 레벨의 개발자들이 부럽습니다. ^^

마침, 이번 마소 3월호의 248 페이지에 "리버싱으로 분석하는 온라인 게임 해킹툴"이라는 재미있는 ^^ 기사를 읽게 되었는데요. 역시 DDK하는 사람들은 리버싱 실력 자체가 다릅니다. 너무 너무 멋있다는! ^^

이야기를 좀 벗어나서.

한때 저도 "모" 게임에 푹 빠졌을 때가 있었다는 사실... 아셨나요? ^^
그 게임에서 구현한 3차원 세계는 정말이지 온라인 게임을 처음 접한 저에게는 신세계와 같았습니다. (결과적으로 지금 생각해 보면, 이때 온라인 게임의 폐해를 알았기에 나중에 WOW가 나왔어도 심드렁할 수 있었던 것 같습니다. ^^;)

제가 그렇게 게임에 빠져있을 때, 나름대로 ^^ 만든 매크로 프로그램을 만들어서 아주 잘 활용했었습니다. 그렇다고 무슨 자동 사냥하는 프로그램은 아니었고, 컴퓨터 2대에서 게임 클라이언트를 각각 실행하고, 한 대에서 제가 게임을 하면서 다른 한대에 실행된 캐릭터를 같이 조정할 수 있는 프로그램이었습니다. 예를 들어, 제 컴퓨터의 "a" 키를 누르면 다른 PC의 캐릭터가 같이 공격해 주고, "h" 키를 누르면 제 캐릭터에 에너지를 보충 할 수 있도록 한 것이었습니다.

"리버싱으로 분석하는 온라인 게임 해킹툴" 기사를 보면서, 그때 제가 만든 그 프로그램이 생각났습니다. 기사에서는 "고전적인 매크로 구현 방법"이라고 하면서 "keybd_event", "mouse_event"를 예로 들었는데 실제로 제가 만든 그 프로그램에서도 "keybd_event" API를 사용해서 구현했었습니다.

기사에서 언급되고 있지만, "keybd_event, mouse_event" API는 게임 보안 솔루션에서 사용을 막았기 때문에 이젠 구식이 되어버린 기술이라고 합니다.

그때 기억도 되새길 겸. 정말로 모 업체의 3-D 게임 하나를 다운로드 받아서 테스트를 해봤습니다. 오호... 정말 안됩니다. ^^; 재미있게도 게임 프로그램이 전면에 뜰 때만 keybd_event 함수가 동작 안하고 다시 다른 응용 프로그램이 전면으로 오면 동작을 합니다. keybd_event 유의 함수가 다른 프로그램에서는 "유용한" 매크로로 쓰인다는 점에 대한 세심한 배려가 돋보입니다.




해보는 김에. 기사에서 언급된 0x64, 0x60 포트를 이용해서 제어를 해보고 싶었습니다. 말씀드린 데로 저는 SDK 개발자이기 때문에 드라이버 개발은 해본적이 없습니다. (사실 Hello World 수준의 dummy 드라이버는 실습해봤지만, 그 이상은 해본 적이 없습니다.)

그래서 검색을 해봤더니. 아하... ^^ 공개된 프로그램이 하나 눈에 띄입니다.

NTPort Library
; http://www.zealsoftstudio.com/ntport/

평가판을 다운로드 할 수 있는데, 그렇다고 기능 제약이 있는 것은 아니고 최초 구동시에 라이선스 알림 대화창이 뜬다는 제약만 있기 때문에 테스트 용으로는 전혀 손색이 없습니다.

그럼. 일단 포트를 읽고 쓰는 드라이버는 구했고. 다음 문제는 어떻게 사용해야 키 입력을 흉내낼 수 있느냐는 것인데.

생각보다, 이 방법을 언급하고 있는 자료를 찾기가 쉽지 않았습니다. 겨우 찾은 방법이 아래 문서의 11페이지에 나온 정도입니다.

Keylogging Analysis
; http://codeengn.com/?module=file&act=procFileDownload&file_srl=233&sid=7f06fd348c558e70720143533138db07

위의 내용을 NTPortLibrary 코드로 다시 쓰면.

bool is_buffer_empty(void)
{
    int timeout;
    
    for(timeout = 200; timeout && (Inport(0x64) & 0x02); timeout--) 
    {
      Sleep(1);
    }

    retrn timeout != 0;
}

if (is_buffer_empty() == false)
{
    return;
}
Outport(0x64, 0xD2);

if (is_buffer_empty() == false)
{
    return;
}
Outport(0x60, scanCode);

위의 코드에서 scanCode 값은 아래 문서의 16페이지에서 찾아볼 수 있습니다.

Keyboard Scan Code Specification
; http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc

keyboard_port_io_scancode_1.png

즉, scanCode 값에 10을 넣으면 키보드로 "9" 숫자키를 입력한 것과 동일한 효과를 발생합니다.

자, 이 정도 하고 다시 게임 프로그램을 실행시키고 테스트 해봅니다. 우와~~~ 이번에는 정상적으로 문자가 전달됩니다. ^^ 아직 여기까지는 보안 프로그램이 막지 않았나 봅니다. (이 프로그램에 쓰인 보안 프로그램만 이것을 막지 않은 것인지, 아니면 이것을 원천적으로 막을 수 없는 것인지는 잘 모르겠습니다.)




그런데. 재미있는 방법이 하나 더 있습니다.
"Remote Desktop" 아시죠? mstsc.exe 프로그램으로 원격 접속하는.

예전에는 RDS 환경이 그다지 좋지 않아서 RDS 세션 환경에서는 3-D 프로그램이 실행되지 않았었는데, 어느새 시간은 흘러 ^^ 그것도 이젠 옛날 이야기가 되어버렸습니다. 그러니까, Windows Server 2008 R2에서 제공되는 RDS 환경에서는 3-D 프로그램도 정상적으로 실행이 됩니다. (제가 테스트 해본 바에 의하면 Vista 원격 접속 지원에서도 3-D 프로그램이 실행되었기 때문에 아마도 Windows Server 2008에서도 되지 않을까... 예상합니다.)

그렇다면 RDS 환경에서 게임 프로그램을 실행한 경우에는 키 입력을 위한 매크로 프로그램이 어떻게 작동할 수 있을까요? 우선, RDS 환경 내에서 포트 제어를 통한 키입력 방법은 효과가 없습니다. 짐작으로는, RDP 클라이언트 측에서 마우스/키 입력이 RDS 세션으로 전달되어 처리되는 방식이기 때문에 물리적인 하드웨어의 포트를 제어하는 방식으로는 RDS 세션 내의 프로그램에 영향을 주지는 않는 것 같습니다.

또한, "keybd_event, mouse_event" API도 RDP 환경 내에서 동작은 하지만 여전히 보안 프로그램이 설치된 게임 클라이언트에는 동작하지 않습니다.

그런데! ... 이쯤 되면 눈치채신 분도 계시겠지만.

어차피 게임 클라이언트는 그것이 실행된 윈도우 세션 내에서의 "keybd_event, mouse_event"에 대해서만 막을 수 있기 때문에, "RDP 클라이언트가 실행된 환경"에서 "keybd_event, mouse_event" API를 실행시켜 전달하는 것은 가능하다는 것입니다. 말로 설명하는 것보다 아래의 화면을 보면 이해가 되시겠죠. ^^

keyboard_port_io_scancode_2.png

위의 그림에서는 Windows 7 운영체제에 키 입력을 keybd_event 함수를 이용해서 발생시키는 "MainWindow"라는 제목을 가진 프로그램과 mstsc.exe 프로그램이 실행되어 있습니다. 보는 것처럼, MainWindow 프로그램에서 발생하는 keybd_event에 의해서 mstsc.exe에 숫자 키 "9"가 전달되는 것을 확인할 수 있습니다. 일단 메모장을 실행시켜서 테스트하고 있지만 게임 클라이언트라고 하더라도 정상적으로 키 입력을 "받아들일 수밖에" 없습니다. 왜냐하면 그 입력이 keybd_event에 의한 것인지 사용자에 의한 것인지 "RDS 세션에서 작동 중인 게임 프로그램에 설치된 보안 프로그램 입장"에서는 구별할 수 있는 방법이 없기 때문입니다.

그렇다면!
손쉬운 자동 사냥 프로그램을 못하게 하려고 keybd_event 함수를 막았던 보안 업체는, 위와 같은 방식의 자동 사냥 프로그램은 어떻게 막을 수 있을까요? 아마도, 아예 RDS 환경에서는 게임이 실행되지 못하도록 만들어야 하지 않을까 싶은데요. 정말... 그렇게 막아버리게 될까요? ^^

한 가지 더 재미있는 사실이 있습니다.

그동안, "전면에 띄워진 윈도우"에만 키 입력이 전달되었기 때문에 "하나의 PC"에서 하나의 매크로 프로그램만을 동작시킬 수 있었지만 RDS 세션을 활용하게 되면 "하나의 PC"에서 다중 RDS 세션을 열어서 여러 개의 매크로 프로그램을 돌리는 것이 가능합니다.

이런 거 보면, 정말이지 ^^ 컴퓨터는 다양한 기술의 조합에 따른 운영의 묘미가 있는 것 같습니다.

이게 끝일까요? ... 알 수 없습니다. 언제나 기술은 변화하기 때문에.
2003년 PDC에서 언급된 "Multiple Input Queues"가 구현된다면... 위와 같이 다중 세션을 열어놓을 필요도 없을 테니까요.




마지막으로 한 가지 더 재미있는 사실.
Windows Server 2008 R2의 RDS 연결 제한은 기본적으로 "Administration" 모드로 제공되는 라이선스로 인해 2개이고, 라이선스 서버를 제공하는 경우에만 2개의 제한을 없앨 수가 있습니다.

그런데, 예전에 제가 Windows 7의 RDP 연결에서 1개의 연결 제한을 해제하는 (정식이 아닌) 패치를 알려드렸었지요.

Windows 7 - 다중 원격 접속(Remote Desktop) 허용
; https://www.sysnet.pe.kr/2/0/782

재미있게도 그 패치를 적용하면 RDP 연결 수에 제한이 없습니다.

이번 글을 쓰면서, VPC에 설치해 둔 Windows Server 2008 R2에도 해당 termsrv.dll을 테스트해 보았습니다. 오호... 2개의 연결 제한을 갖는 "Administration Mode"가 해제되었다는!




첨부한 파일은 본문에서 설명한 2개의 문서와 소스 코드입니다.

polling.pdf: 위에서 설명한 Keylogging Analysis PPT 문서
scancode.doc: 위에서 설명한 Keyboard Scan Code Specification 문서
Console.zip: NTPortLibrary를 이용한 키입력 테스트 프로젝트 (VS2010)



[이 토픽에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/10/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2010-12-16 12시22분
The AT keyboard controller
; http://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html

Hardware Manipulation (Keyboard LED)
; http://ezbeat.tistory.com/294
정성태
2011-02-10 11시03분
[지나가다] 포트를 이용한 키입력 전달을 보안 프로그램에서 막고 있다고 하셨는데요. 키보드 후킹 후 SendMessage는
상관 없을런지..? 이와 관련해서는 말씀이 없으셔서 관련 주제라 한번 댓글을 달아봅니다. ^^;

스크립트를 지원하는 매크로 프로그램에서 키입력 전달 스크립트를 만들어서 사용하면 키입력이 전달되더군요.
(보안 프로그램이 해당 매크로 프로그램을 막지는 않았음. 막힐경우 불탐으로 클라이언트 종료.)

해당 매크로는 키보드 후킹 후 SendMessage를 하는것 같던데, 해당 매크로의 특정 키워드를 사용하는 거라서
내부에서 어떤 식으로 키입력을 게임(활성창)에 전달하는지 자세히 모르겠네요.

매크로의 원본 C소스까지 공개되어 있던데.. 저는 뭐 소스 분석할 실력이 아니라서^^
[guest]
2011-02-10 11시43분
DirectX 게임 유는 직접 키보드 하드웨어로부터 입력을 받아들이기 때문에 SendMessage 같은 윈도우 메시지 API 전달 함수로는 키 입력을 할 수 없습니다. 말씀하신 스크립트 지원 매크로 프로그램이 뭔지는 모르겠지만, 정확히 SendMessage를 사용하는 것이 맞나요? 맞다면, 그리고 그것으로 DirectX 게임 유에 테스트 하신 건가요?
정성태
2011-02-10 03시24분
[지나가다] 글을 삭제하려고 했는데 댓글을 주셨네요. 감사드립니다. :-)

매크로 프로그램의 소스를 자세히 확인해 보니 SetWindowsHookEx()로 후킹 후 활성화된 윈도우에 keybd_event()를 사용하는 형태 였습니다.
그리고 위의 방식 말고, 직접적으로 SendMessage()를 지원했지만 제가 테스트 해볼 당시에는 작동하지 않았던것으로 기억합니다.

말씀하신 내용이 맞는듯.. 해당 게임은, 유명 온라인 게임으로 DirectX 류가 맞는것 같습니다. 엉뚱한 내용으로 귀찮게 해드려서 죄송합니다. ^^;;
[guest]
2017-06-02 12시59분
첨부 파일 - Operating Systems Development Series.mht

Operating Systems Development - Scan Codes
; http://www.brokenthorn.com/Resources/OSDevScanCodes.html
정성태

1  2  [3]  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13568정성태2/27/20241889닷넷: 2220. C# - .NET Framework 프로세스의 LoaderOptimization 설정을 확인하는 방법파일 다운로드1
13567정성태2/27/20241836오류 유형: 898. .NET Framework 3.5 이하에서 mscoree.tlb 참조 시 System.BadImageFormatException파일 다운로드1
13566정성태2/27/20241894오류 유형: 897. Windows 7 SDK 설치 시 ".NET Development" 옵션이 비활성으로 선택이 안 되는 경우
13565정성태2/23/20241735닷넷: 2219. .NET CLR2 보안 모델에서의 개별 System.Security.Permissions 제어
13564정성태2/22/20241983Windows: 259. Hyper-V Generation 1 유형의 VM을 Generation 2 유형으로 바꾸는 방법
13563정성태2/21/20241962디버깅 기술: 196. windbg - async/await 비동기인 경우 메모리 덤프 분석의 어려움
13562정성태2/21/20242012오류 유형: 896. ASP.NET - .NET Framework 기본 예제에서 System.Web에 대한 System.IO.FileNotFoundException 예외 발생
13561정성태2/20/20242083닷넷: 2218. C# - (예를 들어, Socket) 비동기 I/O에 대한 await 호출 시 CancellationToken을 이용한 취소파일 다운로드1
13560정성태2/19/20242130디버깅 기술: 195. windbg 분석 사례 - Semaphore 잠금으로 인한 Hang 현상 (닷넷)
13559정성태2/19/20242954오류 유형: 895. ASP.NET - System.Security.SecurityException: 'Requested registry access is not allowed.'
13558정성태2/18/20242207닷넷: 2217. C# - 최댓값이 1인 SemaphoreSlim 보다 Mutex 또는 lock(obj)를 선택하는 것이 나은 이유
13557정성태2/18/20241943Windows: 258. Task Scheduler의 Author 속성 값을 변경하는 방법
13556정성태2/17/20242003Windows: 257. Windows - Symbolic (hard/soft) Link 및 Junction 차이점
13555정성태2/15/20242153닷넷: 2216. C# - SemaphoreSlim 사용 시 주의점
13554정성태2/15/20241876VS.NET IDE: 189. Visual Studio - 닷넷 소스코드 디컴파일 찾기가 안 될 때
13553정성태2/14/20241969닷넷: 2215. windbg - thin/fat lock 없이 동작하는 Monitor.Wait + Pulse
13552정성태2/13/20241917닷넷: 2214. windbg - Monitor.Enter의 thin lock과 fat lock
13551정성태2/12/20242107닷넷: 2213. ASP.NET/Core 웹 응용 프로그램 - 2차 스레드의 예외로 인한 비정상 종료
13550정성태2/11/20242271Windows: 256. C# - Server socket이 닫히면 Accept 시켰던 자식 소켓이 닫힐까요?
13549정성태2/3/20242736개발 환경 구성: 706. C# - 컨테이너에서 실행하기 위한 (소켓) 콘솔 프로젝트 구성
13548정성태2/1/20242533개발 환경 구성: 705. "Docker Desktop for Windows" - ASP.NET Core 응용 프로그램의 소켓 주소 바인딩(IPv4/IPv6 loopback, Any)
13547정성태1/31/20242318개발 환경 구성: 704. Visual Studio - .NET 8 프로젝트부터 dockerfile에 추가된 "USER app" 설정
13546정성태1/30/20242159Windows: 255. (디버거의 영향 등으로) 대상 프로세스가 멈추면 Socket KeepAlive로 연결이 끊길까요?
13545정성태1/30/20242008닷넷: 2212. ASP.NET Core - 우선순위에 따른 HTTP/HTTPS 호스트:포트 바인딩 방법
13544정성태1/30/20242034오류 유형: 894. Microsoft.Data.SqlClient - Could not load file or assembly 'System.Security.Permissions, ...'
13543정성태1/30/20242067Windows: 254. Windows - 기본 사용 중인 5357 포트 비활성화는 방법
1  2  [3]  4  5  6  7  8  9  10  11  12  13  14  15  ...