설치 프로그램 크랙...
글쓴이: partout / 작성시간: 수, 2003/08/27 - 11:16오전
보통 인스톨러를 작성할 때,...
사용자가 입력한 시리얼을 확인하기 위해서 보통 이런 식으로 구현하지 않나요?
if (!check_serial()) { // 경고 문구 출력 !! exit(0); } // 설치 진행 .....
근데 이렇게 구현한 경우 인스톨러를 디어셈블해서 if 문의 위치를 찾은 다음에
시리얼이 틀렸을 경우의 처리루틴을 NOP(0x90)으로만 바꿔 버리면...
시리얼을 틀리게 입력한 경우라도 설치가 그대로 진행되게 할 수 있습니다.
이런 류의 크랙킹에 대응하려면 어떤 식으로 인스톨러를 작성하는 것이 좋을까요?
크랙이라면 하겠는데, 막상 막을려니 별로 방법이 없어 보이네요.
Forums:
생각입니다만 방법은 없다는 편이 아닌가 합니다. 동일 바이너리에 대해 (
생각입니다만 방법은 없다는 편이 아닌가 합니다. 동일 바이너리에 대해 (복수의) 시리얼에 따라 동작을 허용하는 구조라면 어떻게든 시리얼을 체크하는 루틴이 필요하게 됩니다. 좀 복잡한 (크랙하기 귀찮은) 방법을 사용해서 전의를 상실케 하는 정도가 전부일 것 같습니다. (물론 더욱 불타오르는 사람도 있겠습니다.)
다만 프로그램의 실행이 유일한 패스워드에만 대응하도록 하기 위해서는 단순하지만 강력한 방법이 있습니다. 통상 프로그램 내부에는 중요한 (문자열) 상수가 있게 마련인데, 이를테면
const char* p = "some important const str";
이 문자열이 없으면 프로그램의 기동 단계에서 네트웍 연결을 하지 못한다던가 그런 정도의 역할을 해야합니다. 그러면 encode 된 문자열을 변수로 바이너리에 포함시키고, 런타임에 입력받은 패스워드를 key 로 세트하고 decode 해서 사용하는 방법으로 말씀하신 취약점을 둘러갈 수 있습니다. encode/decode 루틴은 shift 처럼 단순한 것이라도 별 상관없겠죠. 결국은 key 든 decoded str 이든 추측하는 수 밖에 없을테니까요. 이렇게 하시면 프로그램이 제대로 기동하지 못한 상태로 머물기 때문에 디스어셈블을 해보거나 메모리 덤프를 떠 보아도 패스워드 체크를 벗어날 수 없습니다. 이것은 마치 어떤 url 을 알지 못하는 사용자는 해당 웹페이지에 접근할 수 없는 것과 비슷합니다.이 방법을 시리얼에 적용할 수는 없어 보이는데 그 이유는 두 가지 정도입니다. 첫째로, 복수의 시리얼에 대해 동일한 decoding 결과를 내는 함수를 작성하기가 까다롭습니다. 만약 작성할 수 있다 하더라도 해당 함수를 디스어셈블하면 시리얼 생성의 알고리듬을 유추해내기가 쉬워질 수 있습니다. 둘째로, 시리얼이라는 것은 기본적으로 복수의 사용자를 가정하고 있기 때문에, 어떤 악의적인 사용자가 올바른 시리얼을 입수해서 프로그램을 기동할 수 있습니다. 그 이후로는 메모리 덤프를 통해 마음먹은 일은 모두 할 수 있겠죠. (하급의 크랙이겠습니다만..)
의견입니다만. 잠정적인 결론으로는 "소스코드를 보고도 패스워드를 알아낼 수 없는 정도가 아니라면 언제나 크랙은 가능하다" 는 것입니다. 바이너리라는 것이 사실 사람이 보기에 불편할 따름이지 사실상 소스코드와 다를 것이 있겠습니까?
War doesnt determine whos right, just whos left.
이건 좀 다른 방식의 접근입니다만,일단 저런 곳을 찾아서 때우려면
이건 좀 다른 방식의 접근입니다만,
일단 저런 곳을 찾아서 때우려면
디버깅을 해야한다는 걸 이용하는 방법도 있습니다.
디버깅을 어렵게 하면 되죠.
( 이것도 방법이 만만찮겠지만요. )
예전엔 CPU의 instruction cache를 이용한 방법을
많이 썼던것으로 알고 있는데요.
지금도 쓰일만한지는 잘 모르겠습니다. -_-a
멀티 태스킹 환경엔 왠지 적합하지 않은듯도 하고요.
요즘은 어떤 방법이 쓰일려나. -_-;
여튼 instruction cache를 이용한 방법은
CPU가 명령을 미리 읽어들여 실행한다는 걸 이용한건데요.
가물가물한데 아마 이런식으로 코딩을 했을겁니다.
L1에 있는 code를 jmp not_ok로 변경해도,
이미 CPU의 cache에는 L1에 있는 code인 jmp ok가 미리 읽혀져 있어서
jmp ok가 실행이 된다는 걸 이용한 것이죠.
디버거로 명령을 하나하나 trace하면 jmp not_ok라고 실행이 되고요.
뭐-_- 피하는 방법은 간단하지만 옛날엔 종종 쓰였습니다.
여튼 디버깅을 어렵게 만드는 것도
하나의 테크닉이 아닐까 싶네요.
디버거가 좋아진 요즘 현실엔 적합하지 않을지도 -_- 모르겠습니다만요.
답변 감사 드립니다.예측하기 힘들게 코드를 약간씩 꼬아봐야 겠군요
답변 감사 드립니다.
예측하기 힘들게 코드를 약간씩 꼬아봐야 겠군요.
어찌나 졸린지..~~
댓글 달기