SimpleIsBest.NET

유경상의 닷넷 블로그

불가능은 없다... 대략 귀찮을 뿐...

by 블로그쥔장 | 작성일자: 2005-05-27 오후 2:29:00
이 글은 오래된 전에 작성된 글입니다. 따라서 최신 버전의 기술에 알맞지 않거나 오류를 유발할 수 있습니다. 저자는 이 글에 대한 질문을 받지 않을 것입니다. 하지만 이 글이 리뉴얼 되면 이 글에 대한 질문을 하거나 토론을 할 수도 있습니다.

간만에 글을 올립니다. 이번 주에는 상당히 바쁘게 한 주일을 보내는 바람에 블로그를 남기지 못했습니다. 그래서 이번 주에 제가 작업한 내용을 좀 끄적거려 볼려구 합니다.

삽질의 개요

이번 주에 애를 먹었던 부분은 ChartFX의 라이센스 문제였습니다. 지금 제가 관여된 프로젝트는 소위 스마트 클라이언트를 이용한 프로젝트인데, 여기서 말하는 스마트 클라이언트는 IE 웹 브라우저 안에 닷넷으로 작성한 UserControl을 띄워 UI를 구현하는 것을 말합니다. 머 쉽게 생각하면 개발 환경은 닷넷이고 브라우저 안에 ActiveX 와 같은 방법으로 UI를 개발하는 거죠.

그런데... 이 스마트 클라이언트 시나리오상에서 윈폼(WinForm)용 ChartFX가 항상 라이센스 오류를 발생한다는 것이였습니다. 원래 ChartFX와 같은 컨트롤 제품들은 개발자 라이센스 기반이어서 개발할 때만 설치해 주면 배포는 자유롭게 할 수 있기 때문에 ChartFX가 설치되지 않은 사용자 컴퓨터에서도 ChartFX의 DLL들이 스마트 클라이언트 기반 기술(MS 에서는 No-Touch-Deployment 라 부릅니다)에 의해 다운로드 되면 라이센스 문제 없이 정상 작동해야 하는 거죠. 게다가 동일한 스마트 클라이언트 시나리오에서 동일한 버전 !!!(6.2.1342.0)의 ChartFX를 1년 전에 S 기업에서 이미 사용을 했었고 그때는 약간의 삽질 끝에 별 문제 없이 해결을 했었다는 겁니다.

삽질의 시작

이번주 초인가요...(폭소 클럽 버전. 모르면 말고... -_-) 출근을 떡 해보니 ChartFX 라이센스 문제가 있다는 보고를 받았습니다. 속으론 내심 '아하~ 그거...' 하면서 S 기업에서 한대로 하면 되겠지 하며 대수롭지 않게 생각했습니다. 그런데... 웬걸... 1년 전 S 기업에서 했던 방법대로 아무리 해도 ChartFX는 런타임 라이센스를 읽을 수 없다며 오류를 찍찍 뱉어 내곤 했습니다.

1년전에 했던것 처럼 SoftwareFX(ChartFX 개발사) 사이트를 가서 뒤져보니 역시 1년전 자료가 아무런 변화 없이 그대로 남아 있더군요. SoftwareFX 자료 왈, "ChartFX를 사용하는 코드가 DLL 이라면 DLL 이 아닌 EXE에 라이센스 정보가 포함되어 컴파일 되어야 한다." 이 말은 1년 전에도 본 내용이고, 1년 전에 해결했던 방식대로 ChartFX를 사용하는 DLL을 로드하는 DLL (메뉴 컨트롤이 있는 DLL 입죠)의 license.licx 파일에 라이센스 정보를 넣었습니다만 여전히 오류가 발생하는 것이였습니다.

드디어 저의 삽질은 시작되었습니다. System.ComponentModel 네임스페이스에 있는 라이센스 관련 클래스들(LicenseManager, LicenseContext, RuntimeLicenseContext 클래스 등)의 코드를 까보기 시작했습니다. 그리고 ChartFX DLL의 소스도 까봐야 했죠.

크~헉~. ChartFX DLL은 Ofuscator가 사용되어 Non-Public 멤버들의 이름이 죄다 맹글링(mangling)되어 코드 보기가 대략 뷁스러웠습니다. 그래도 코드를 추적하고 심지어 어셈블리 언어(기계어 코드. 닷넷의 어셈블리가 아님) 수준까지 디버깅 하면서 결론에 도달한 것은... 닷넷 프레임워크(적어도 버전 1.1에서는)와 ChartFX가 공히 Entry Assembly에 기록된 라이센스 정보만을 읽는다는 것을 알아 냈습니다. 하지만 스마트 클라이언트 시나리오에서는 Entry Assembly가 지정되지 않는다는 문제가 있었죠. 그래서 ChartFX가 자꾸 라이센스 오류를 뱉어 낸 겁니다.

불가능은 없다... 대략 귀찮을 뿐...

이를 해결하기 위해서는 ChartFX의 라이센스 확인 루틴을 우회해야 했습니다. ChartFX는 Entry Assembly의 존재 유무를 확인하고, 만약 Entry Assembly가 존재하지 않는 다면, 레지스트리에서 라이센스 정보를 읽기 때문이였습니다. 해결 방법으로는 클라이언트 PC의 레지스트리에 라이센스 정보를 기록하는 방법이 있지만 요것이 암호화 확인 절차를 거치기 때문에 문제가 있었습니다. 또한 별도의 설치를 필요로 하지 않는다는 스마트 클라이언트 시나리오와도 잘 맞지 않아서, 다른 해결 방법을 찾아야 했습니다.

저의 해결책은 ChartFX의 라이센스 확인 루틴을 가로채서, Entry Assembly 존재 유무에 관계 없이 DLL 내에 기록된 라이센스 정보를 읽도록 하는 것이였습니다. 이렇게 하려면 ChartFX의 내부에 internal 이나 private 로 선언된 클래스와 클래스의 필드를 액세스 해야 했고 이를 위해 이번에도 저의 든든한 후원자 Reflection을 사용했습니다. 그 결과 ChartFX는 멋지게 잘 작동했죠. 이 방법은 일반적인 라이센스 확인루틴을 우회하는 기법은 아니고 오직 ChartFX에만 적용되는 사항이며, 또한 클래스 이름, 메소드 이름, 필드 이름이 맹글링된 결과에 대해 Reflection을 사용했으므로 ChartFX가 새로운 버전(정확히 말하면 DLL에 대해 맹글링을 다시 해버리면)에 대해서는 코딩을 다시 해줘야 한다는 문제가 있습니다. 그래도 작동하니 어딥니까... 그건 그때 가서 생각하기로 하고...

여전히 궁금한 것

지금 프로젝트는 라이센스 확인을 가로채는 삽질로 해결을 했지만, 1년전 S 기업은 왜 ChartFX가 잘되었을까요? 궁금해서 이전 프로젝트 코드(파일럿 코드)를 불러서 Entry Assembly 가 무엇인가 확인해 보았지만 여전히 스마트 클라이언트 시나리오에서는 Entry Assembly가 null 이였습니다. 그렇다면 S 기업에서도 ChartFX는 라이센스 문제가 발생했어야 하는데...

저는 고민을 했습니다... 그때 제 뇌리를 스친건... 혹 ChartFX DLL이 서로 다른 건 아닐까 하는 생각이였죠. S 기업에서 사용했던 ChartFX의 코드를 까 보았습니다. 아니나 다를까... 이 DLL은 Entry Assembly를 확인하는 코드가 없었습니다. ChartFX의 DLL은 닷넷 어셈블리 버전과 파일 버전이 따로 놀고 있었던 겁니다. 즉, S 기업에서 썼던 DLL은 어셈블리 버전이 6.2.1342.0 이였고 파일 버전이 6.2.1539.21391 이였고 이 DLL은 Entry Assembly 유무에 관계 없이 DLL 에서 라이센스 정보를 읽고 있었습니다. 그리고 지금 프로젝트에서 사용하는 ChartFX DLL은 어셈블리 버전이 6.2.1342.0 으로 같았지만 파일 버전이 6.2.1859.20587으로 달랐던 겁니다. 이전 버전에서는 빠져있던 Entry Assembly 확인 루틴이 포함되어 버림으로써 스마트 클라이언트 시나리오에서 ChartFX는 라이센스 문제가 발생되었던 거죠.

교훈

이번 주에도 상당한 삽질과 뷁스런 일을 겪고 얻은 교훈같지 않은... 버전 확인을 확실히 할 것(어셈블리 버전이 같다고 같은 버전은 아니다?) ! 그리고 이번에도 저의 삽질에 많은 도움을 준 Reflector 와 Reflection에게 심심한 감사의 뜻을... -_-

WinForm용 ChartFX를 쓰신다고요? 라이센스 문제가 발생한다고요? EXE 프로젝트의 license.licx에 라이센스 정보를 추가하십시요. 스마트 클라이언트 라구요? 삽을 준비 하십시요... 그리고 저처럼 삽질하십시요... 텨텨텨~~~



Comments (read-only)
#re: 불가능은 없다... 대략 귀찮을 뿐... / 종호 / 2005-05-30 오후 3:38:00
그런데 Entry Assembly 가 무엇인가요?
#re: 불가능은 없다... 대략 귀찮을 뿐... / Loner / 2005-05-30 오후 3:47:00
Entry Assembly(진입 어셈블리 정도?) 란 Assembly.GetEntryAssembly() 메쏘드가 반환하는 어셈블리를 말합니다.
일반적으로 EXE 어셈블리를 지칭하지만, 정확하게 말해서는 Default 어플리케이션 도메인의 경우에만
EXE 로 수행된 어셈블리를 말하고 그외의 어플리케이션 도메인에서는 AppDomain.ExecuteAssembly() 메쏘드에
의해 수행된 어셈블리가 Entry Assembly 입니다. (MSDN의 GetEntryAssembly() 도움말 참조)

이 정의를 따르면 일반적으로 EXE 로 작성된 어셈블리가 entry assembly 가 되며, ASP.NET과 같은 웹 어플리케이션은
EXE 도 아니고, ExecuteAssembly() 에 의해 수행되지 않으므로 Entry Assembly 가 없는 겁니다.
(GetEntryAssembly() 메쏘드가 null 을 반환)
#ChartFX의 라이센스 확인 루틴을 가로채서, Entry Assembly 존재 유무에 관계 없이 DLL 내에 기록된 라이센스 정보를 읽도록 하는 방법좀 알켜주세요.. 부탁.. / waist24 / 2006-01-27 오전 9:52:00
ChartFX의 라이센스 확인 루틴을 가로채서, Entry Assembly 존재 유무에 관계 없이 DLL 내에 기록된 라이센스 정보를 읽도록 하는 방법좀 알켜주세요.. 부탁..
#re: 불가능은 없다... 대략 귀찮을 뿐... / 블로그쥔장 / 2006-01-30 오후 8:59:00
아... 그게... 방법이란게 ChartFx 의 내부 루틴을 분석해서
라이센스를 최초의 DLL에서 읽도록 코드를 가로채는 것입니다만...
이것이 일반적인 방법이 아닌 DLL 마다 다르게 적용되는 것입니다.
ChartFX의 버전이 다르거나 버전이 같더라도 컴파일이 어떻게 되느냐에 따라 코드가 달라지기 때문에
일반적인 방법을 아르켜 드리기 곤란합니다.

도움이 못되서 죄송합니다.
#일반적인 방법이 아니어도 괜찮습니다. / 이경찬 / 2006-01-31 오후 3:06:00
일반적인 방법이 아니어도 괜찮습니다.
단지 방식을 알기위한거니까요?
어떤 형태로 응용되었나가 궁금합니다. 곤란하지 않으시다면 부탁드립니다.
#re: 불가능은 없다... 대략 귀찮을 뿐... / 블로그쥔장 / 2006-01-31 오후 3:22:00
사실 좀 곤란하군요. 이게 컨트롤의 라이센스를 피해갈 수 있는 방법이 될 수 있기 때문에
법적인 문제를 일으킬 수도 있습니다.

개략적인 방법은 이미 블로그에 알려드린 내용과 같습니다.
LicenseManager 클래스에서 라이센스를 관리하는 방법을 reflector 로 분석한 후,
ChartFx 의 코드 역시 reflector로 분석하여 ChartFx의 라이센스 코드가 수행되기 전에
님이 작성한 라이센스 체크 루틴이 돌도록 수정해야 합니다.
작성한 라이센스 체크 루틴은 Entery Assembly가 아닌 최초의 DLL에서 라이센스 정보를 읽도록
ChartFX의 라이센스 루틴을 강제 호출하도록 합니다.

더 자세히 설명하기는 분량, 제 개인적인 시간 등의 제약으로 좀 곤란할 듯 싶습니다.
죄송...
#re: 불가능은 없다... 대략 귀찮을 뿐... / 즈믄 / 2006-04-20 오후 10:39:00
저도 곧 스마트 클라이언트로 삽시간(-_-;) 안에 개발을 마쳐야 하는 건이 있은데, 이거 또한 ChartFX입니다. 이거 Development 버전으로 설치 하려 하니..
install오류가 나네요.. ChartFX.ResourceCenter.Net 이라는 사람 벙찌게 만드는 오류인데,
님에 말을 잠시 빌자면, 이걸 해결하기 위해 다짜고짜 구글신에게 물어봐도.. 결과가 없더군요.. 어찌 해야 하는 시츄레이션인지.. 쩝..
#re: 불가능은 없다... 대략 귀찮을 뿐... / 블로그쥔장 / 2006-04-21 오후 4:56:00
설치 오류에 대해서는 저도 어떤 도움을 드리기가 난감하다는... -_-;
건투를 빕니다...
#re: 불가능은 없다... 대략 귀찮을 뿐... / 황원철 / 2007-01-18 오후 1:34:00
좀~~~내공이 필요한 글이네요~~하지만 트랜드를 알수 있다는 것만으로도 넘 감사합니다~~~
#re: 불가능은 없다... 대략 귀찮을 뿐... / 조승태 / 2008-03-05 오후 4:15:00
이 블로그의 내용을 다 읽겠다고 다짐했었는데,
업무에 쫓겨 거의 1주일만에 들어왔네요.
아직 제가 알기 힘든 내용이지만,,, ^^;
잘 읽었습니다.