이전에 만들었던걸 좀 더 개량했다. 광고를 받아다 보여주는 것으로 보이는 함수 (00577F40)의 시작을 RETN으로 덮어쓰고, 리소스를 편집해 상단부 뉴스티커가 아예 애초부터 안보이게 고쳤다. 덤으로 채팅창의 광고도 제거했다.
과정 보기
일단, 광고 창의 class를 spy++ 등으로 보면 #30770으로 다이얼로그인 것을 확인할 수 있다. 다이얼로그를 생성하는 API함수는 CreateDialogParam이나 CreateDialogIndirectParam, DialogBoxParam 등이 있는데, DialogBox... 는 Modal 다이얼로그를 생성하지만 광고창은 실제로 떠 있는 동안 다른 창을 선택할 수 있는 Non-modal이다. 따라서 USER32.DLL 모듈에서 CreateDialogParam, CreateDialogIndirectParam을 찾아 브레이크를 걸어준다. 물론, 이 두 함수 모두 스트링을 다루기 때문에 A/W가 붙은 변종들이 있다. XP 이상에서는 A류는 W를 부르는 래퍼일 뿐이므로 W에만 걸어도 무방하다.
그 다음 적당히 실행시켜보면서, 몇 번째 호출때 광고창이 생성되는지 본다. 횟수를 확인한 후에는 광고 창을 만드는 CreateDialogIndirectParam(해 보면 CreateDialogParam은 호출되지 않음을 알 수 있다)을 실행하기 전에, 이 함수를 호출한 Caller들을 Calling Stack을 확인해서 하나씩 브레이크를 걸어본다.
함수의 calling convention에 따라서 stdcall인지 cdecl인지에 맞게 함수 호출를 무시하고 지나가보면, 적당한 위치에서 죽지 않고 무사히 실행되는 부분을 확인할 수 있다. 현재 네이트온(버전 4.0.10.4 (1481))에서는 그 위치가 00671d08이다.
잘 보면, CALL 뒤에 스택을 정리하는 부분이 보인다. 따라서 저 함수는 cdecl이고, 함수의 리턴 방법은 RETN 명령으로 바로 리턴하는 것이다.
RETN은 기계어로 C3이므로, 함수 호출을 따라 가서 00577F40을 C3으로, 명령이 2byte였으니까 다음을 90으로 넣어주면 함수가 완전히 무시된다. 그러고 실행시켜보면 켜자마자 뜨는 광고가 사라진다! 만세ㅋ
그 외의 광고 제거는 리소스 해커 등의 툴을 이용해서 132번과 163번 다이얼로그의 전광판, 광고티커에 주어진 스타일 중 WS_VISIBLE 을 빼면 된다.
압축을 푼 다음, nateoff.bat 을 실행시키면 패치가 진행된다. 이전에 네이트온을 종료시켜주는건 센스.
넷북을 쓰다 보면, 무선 연결이 불안정할 때가 많아 수시로 끊어진다. 그 자체는 문제가 아닌데, 그러다 보면 메신저들이 신나게 재접을 해대는 상황이 벌어지기 마련이다. 이 때 문제가 되는 것이, 네이트온의 경우 쓸데없는 광고가 뜬다는 것이다.
이 쓸데 없는 광고는 얼마나 쓸 데가 없냐면, 광고가 떠도 앞에 안 나오고 뒤에 숨어 있다가 네이트온 쪽지가 와서 보려고 쪽지창을 클릭할 때 광속의 속도로 전면으로 튀어나와서는 대신 클릭당한다. 그러면 Internet Explorer가-심지어 기본 브라우저를 딴 것으로 바꾸어두어도!-뜨면서 그게 완전히 뜨기까지 네이트온은 먹통이 되고, 그게 뜬 뒤에도 한동안 버벅거리는 것은 상당한 짜증을 동반시킨다.
그래서 나는 광고를 없애버리기로 다짐했다. 하는 김에 네이트온 접속 후의 스킨을 수정해서 광고를 떼보았다. 요놈도 상당히 자리를 차지해 넷북으로썬 상당히 귀찮다.
이것도 저것도 모르겠다, 하는 사람은 첨부된 파일을 받아다 적당히 풀면 되겠다. xml파일은 C:\Program Files\NATEON\Skins\DefSkin 에, exe파일은 C:\Program Files\NATEON\BIN에 넣으면 된다.
수정한 부분은 xml 파일에서는 아랫쪽에 주석처리된 부분 밑의 tr 태그를 죄다 지웠다. 그러고 나니까 별로 안예뻐서 miniview 들어가 있는 행과 그 아래 행은 살려뒀더니 원래부터 광고가 없었던 것 마냥 이뻐졌다ㅋ
exe파일에서는 '아마도' 광고 관련 처리하는 루틴을 전부 NOP으로 때워넣었는데, 위치가 0271d08부터 약 32byte 정도 된다. add esp, 24h 까지 덮으면 된다.
JunkOn, DShower 프로젝트(?)를 추진 할 때, DirectShow 필터 생성을 추적할 필요가 있어서 제작해 보았던 툴이다.
디버거나 디버깅 스트링 뷰어 등을 연결해서 이 DLL을 인젝션시키면 대상 프로그램에서 생성되는 COM Object의 생성과 interface 요청을 추적하여 디버그스트링으로 COM Object의 사용을 추적할 수 있다.
핵심은 COM Object를 키로, 해당 Object가 소유한 QueryInterface를 값으로 쓰는 해시를 이용해 모든 QueryInterface를 감시하는 것이다. import table에 들어있을 리가 없기 때문에 후킹은 타겟 메소드의 처음 명령을 후킹하고자 하는 함수의 시작 주소로 점프하는 것으로 덮어쓰는 방법을 써서 후킹한다.
인터넷을 뒤지다가 같은 제목의 글이 맨 앞에 나오길래 패스했었는데, 읽어보니 내 쪽이 더 간단한거 같아서 글로 남길만한 가치가 있을 거 같아 다시 쓰기로 했다 -_-..
차례
소개
소스코드
설명
참고
소개
어떤 프로그램을 해킹하려 할 때는, 그 프로그램의 메모리에 접근하는 것이 필수적이다. 옛날 DOS와 같은 메모리 보호 기능이 없던 OS에서는 어렵지 않게 해당 프로그램의 메모리에 접근할 수 있었지만, 요즘과 같이 멀티태스킹과 메모리 보호가 기본인 상황에서는 그렇게 접근하는 것이 쉽지 않다. 그래서 자주 이용되는 방법이 디버거를 사용하는 방법이다.
하지만 이 디버거를 사용하는 경우에는 상당히 번거로운 것이 사실이다. 간단한 작업만 하면 되는데 그 커다란 디버거를 불러와야한다거나, 디버깅 API를 사용하려면 여러가지로 준비할 것이 많다거나, 해당 프로그램에서 디버거 디텍션 루틴을 넣어놨다면 또 복잡해지기도 해서 좀 더 간단한 방법을 사용할 수 있다면 쓰는 편이 낫다.
여기서 소개하려는 방법은 CreateRemoteThread()라는 API 함수를 통해 타겟 프로세스에 내가 만들어둔 DLL을 주입시키는 방법이다. DLL은 별도의 프로그램이지만, LoadLibrary 함수 등을 통해서 동적으로 링크되면 해당 프로세스의 주소 공간 내에 매핑되어 마치 처음부터 원래 프로그램과 같이 실행된 것 처럼 메모리 공간을 헤집을 수 있다는 특징이 있다. 매번 디버깅 API를 통해 메모리에 접근하는 것이 아니라, 이러한 부분을 DLL로 만들어서 주입함으로써 더 간단하게 타겟 프로세스를 주무를 수 있다.
CreateRemoteThread()는, 원래는 “다른 프로세스에 스레드를 생성할 때” 사용하는 함수다. 맨 앞에서 지정해주는 hProcess로 대상 프로세스를 지정해 줄 수 있다. 그런데 여기서, 스레드의 시작 주소를 지정해주는 lpStartAddress를 살펴보면 재밌는 사실을 하나 발견할 수 있다.
보다시피, 타입만 약간 다르고 실질적인 함수 호출에 있어서는 두 함수가 서로 똑같다는 것을 알 수 있다. 만약 타겟 프로세스 내의 LoadLibrary() 주소를 알 수 있다면 CreateRemoteThread()에 스레드 시작 주소로 LoadLibrary()를 넘겨주어 어렵지 않게 DLL을 주입할 수 있다는 것이 된다. 그리고 또 하나의 희소식은, Windows는 빠른 동적 링크를 위해서 각 DLL마다 선호하는 Base Address가 기록되어 있으며 충돌하지 않는 한 Base Address는 항상 고정되어 있다는 것이다. 따라서, 제일 먼저 로드되기 마련인 KERNEL32.DLL의 base address는 어떤 프로세스가 됐든 특별한 일 없이는 전부 똑같다는 말이 된다!
그러면 VirtualAllocEx()는 왜 필요할까? 바로 LoadLibrary()의 패러미터를 넘기기 위해 필요하다. LoadLibrary()는 고맙게도 시작 주소가 모든 프로세스마다 동일하지만 패러미터로 넘겨줄 DLL의 이름은 타겟 프로세스 내에서 찾아야 한다. 당연히, 이쪽의 주소를 넘겨주게 되면 해당 프로세스 내에서는 쓰레기 값이 참조되거나, 심지어는 잘못된 메모리 접근이 발생할 수도 있다. 그래서, 패러미터로 넘겨줄 DLL의 path를 넘기기 위해 VirtualAllocEx()로 타겟 프로세스 내에 메모리를 할당하고, 반환된 그 주소를 CreateRemoteThread()의 lpParameter로 넘겨주게 되면 LoadLibrary()의 스레드가 동작하면서 DLL을 주입시켜주게 되는 것이다. 주입과 동시에 실행되어야 할 코드들은 DLL 내의 DllMain() 함수 내에 집어넣으면 수행되게 된다. 구체적인 것은 MSDN의 DllMain() 항목을 참조하는 것이 좋을 것이다.
주의할 점은, 이 방법이 100% 동작하지 않을 수 있다.
참고
해킹, 파괴의 광학 (와이미디어, 김성우 저) - 복잡한 방법밖에 실려있지 않지만, 상당한 참고가 될 것이다.
꽤 예전에 배워서 구현한 파일인데, 그러다보니 참조했던 곳이 다 사라져버렸다 -_-;; 여튼, 나중에 소개할지도 모르는 DirectShow 기반의 간단한 스트리밍 서비스 뚫기 등에서도 API 후킹에 많이 써먹었던 매우 유용한 툴이라, 많은 사람들이 유용하게 쓸 수 있으리라 믿는다.
사실, 여기다 적어논 글은 어디까지나 본인이 직접 크랙했던 것을 그대로 일기 형식으로 쓴 것이고, 이걸 보고 공부에 도움이 되길 바라는 마음에서 쓴 글이다. 따라서 이걸 따라 크랙을 못 하는 사람이 수천만-_-이 나오고 날 욕하더라도, 완전히 크랙된 바이너리는 첨부할 생각이 없다.
하지만, 불편해 하는 사람이 너무 많으니까 -_-;; 팁을 하나 주자면, 중간에 있는 내용 다 무시하고 맨 마지막에 실행파일을 패치하는 방법만 살짝 따라하면 크랙된 CBSearch를 얻을 수 있으니까, 그 것만 해 보시라.
급한 일이 생겨서 클럽박스 파일을 찾아야 하는데, 메이저한 사이트는 어느 하나도 제대로 된 링크를 제공해 주지 않기에 -_-... 구글에서 찾다 보니 CBsearch란걸 발견했다.
프리웨어라고 당차게 주장하길래 다운받아 주었더니, 이상한 사이트에 내 개인정보를 팔아야 쓸 수 있도록 한 애드웨어였다 -_- 게다가 개인정보 팔아봐야 인증 안되는거 같기도 하고...
그래서 짜증도 나고, 어차피 파일 하나만 받고 말텐데 하는 생각에 한번 크랙해보았다.
근데 이거 업데이트도 제대로 안됐는지 검색된 결과에 이미 사라진 박스도 많고 공식 사이트를 들어가봐도 제대로 관리되고 있는거 같지 않아서 일종의 VB 어플리케이션 크래킹 예제 정도의 가치가 있을 것 같다.
먼저, CBsearch를 실행시켜서 프로그램 인증->사이트 가입을 통한 인증을 선택해본다.
당연하지만, 인증하기를 누르면 반항한다. 그러면 이 메시지 박스가 호출되는 위치를 찾아내보자.
OllyDbg를 attach 기능을 통해 ClubboxSearch.exe(CBsearch)에 붙인다. 붙인 직후에는 브레이크포인트에 가 있기 때문에, 오른쪽 버튼을 눌러 컨택스트 메뉴를 띄운 후 View → Module 'ClubboxS' 를 선택해서 ClubboxSearch 본 프로그램으로 이동하자. 이동한 후에는 마찬가지로 컨택스트 메뉴를 띄우고 Search For → Intermodular calls를 선택해 ClubboxSearch.exe 프로그램 외의 함수를 호출하는 것들의 목록을 구해보자.
비베에서 MsgBox 함수를 호출할 때는 rtcMsgBox를 호출하니까, 키보드로 rtcMsgBox를 쳐서 이걸 찾는다. 찾았으면 Enter를 쳐서 호출하는 코드를 찾아 rtcMsgBox의 주소를 알아내자. rtcMsgBox의 주소를 알려면 호출하는 함수에서 다시 한번 Enter를 치면 호출되는 함수의 주소로 이동된다.
그 뒤에는 F2를 눌러 rtcMsgBox의 시작부분에 브레이크포인트를 걸고 F9를 눌러 프로그램을 계속 수행시킨다.
그리고 나서 다시 인증하기를 눌러보면, 아까 브레이크포인트를 건 곳에 딱 멈추는 것을 볼 수 있다.
이제, 이게 호출된 위치를 정확히 알아야 하니까 Ctrl+F9를 눌러 Execute till return, 즉 함수가 끝날 때까지 수행을 시킨다. 그러면 이 함수의 수행 결과는 뜬 메시지박스를 닫아야 뜨니까 생겨난 인증실패 창을 없애면 리턴 명령 위에 포인터가 위치해 있는 것을 볼 수 있다.
이제, 한 스텝만 F8로 수행시켜주자. 그러면 이 메시지박스를 호출한 위치를 알 수 있다.
근데 이 근처를 살펴보면, 적절한 코드가 잘 보이질 않는다. 하지만 이 함수가 인증절차를 수행하는 함수라는건 어렴풋이 짐작이 가능하니까, 일단 마찬가지로 Ctrl+F9를 또 눌러보자.
이상하게 이번엔 F8을 눌러도 바로 호출한 곳으로 이동하지 않지만, 당황하지 말고 F8을 몇 번 더 눌러주면 호출한 곳으로 이동한다.
흠... 비주얼 베이직 런타임이다. 그래도 여기서 호출한건 확실히 맞으니까, 호출하는 명령인 CALL EAX에다가 브레이크포인트를 걸어주자.
이제 다시 F9를 눌러준 뒤에, 인증하기 버튼을 다시 눌러보자. 그러면 방금 건 곳에 다시 멈추는 것을 볼 수 있다. 이때는 F8이 아닌 F7을 눌러서 함수 호출 안으로 들어갈 필요가 있다. 그리고 나서 한 칸씩 F8로 수행하면서 조건 점프를 찾아본다. (JNZ나 JE 같은 것들)
하다보면 이런 부분을 찾을 수 있다. 흠... 서울대 학생 or 졸업생 이시구나.
빙고, 조건 점프를 찾았다. 이렇게 하는 중에 가끔 exception이 발생해서 사람 짜증나게 하는데, 처음엔 Shift+F9를 눌러 넘어가주고 그 뒤에 다시 시도할 때는, 보통 함수 수행시 exception이 나기 때문에, CALL 다음에 브레이크포인트를 건 다음 F9로 넘어가는 시도를 하는게 괜찮다.
여기서 EAX를 보면 -1이다. 0이 아니면 점프하는데, 우리는 아직 인증을 받지 않았기 때문에 저거대로 따라가면 아마도 인증실패가 뜰거다. 그럼 저걸 어찌할까 하니, nop명령으로 바꿔 넘어가지 않도록 해보자. 바꾸려면 Space를 친 다음 nop이라고 치면 된다. 다시 올 때를 대비해 브레이크포인트를 걸고 F9로 계속 수행시켜보자.
ㅋ... 성공이다.
이제 검색해보자.
잘 된다ㅋ
자 이제, 이걸 영구히 저렇게 되게끔 만들어보자.
먼저 ClubboxSearch.exe의 시작 주소를 보면, 일반적인 win32 어플과 마찬가지로 00400000인 것을 쉽게 확인할 수 있다. 아까 nop으로 바꿨던 주소가 00577FAE 였으니까, 시작 주소를 뺀 00177FAE가 실제 파일에서의 offset이다.
실행중인 OllyDbg를 끄기 전에, 근처의 명령들의 기계어 코드를 어디에 메모해놓고 끈다. 왜냐하면, 저 주소가 진짜 nop으로 바꿔야할 명령의 주소인지 확인하기 위해서이다. 끄는 이유는 끄지 않으면 편집이 안된다.
85C0 TEST EAX,EAX 90 NOP ;여섯번 C745 FC 05000000 MOVE DWORD PTR SS:[EBP-4], 5
HxD를 열어 ClubboxSearch.exe를 열어보자. 그리고 Ctrl+G(이동)명령을 이용해서 00177FAE로 이동해보자.
위에 메모한 것과 같이 적혀 있는 곳을 발견했다. 아직 수정되기 전이라 JNZ가 그대로 있는 것을 볼 수 있다. 저 6 byte를 90으로 때우자.
실행시켜보면 알 수 있을 테지만, 이름을 넣고 시리얼을 넣은 뒤 체크를 하는 형태로 되어 있다. 디스어셈블러로 살펴보면 비베로 짜여져 있음을 알 수 있다.
접근
비교하는 함수인 MSVBVM60.__vbaVarTstNe 를 찾아본다. 이 때 매개변수로 넘어가는 값을 잘 살펴보면 원하는 키를 얻을 수 있다. 하지만 목표인 키젠을 만들기 위해서는 이 방법만으로는 부족하다.
위로 잘 훑어가다 보면, 이 비교를 수행하는 프로시저의 시작 부분을 찾을 수 있다. 일단, 자세히 보면 이름이 4글자 이상이어야 함은 쉽게 알 수 있다. 테스트를 위해 aaaa를 넣었을 때의 키를 알아보면 C5C5C5C5임을 알 수 있다. 두 번째로 abcd를 넣어보면, C5C6C7C8이 되는 것을 알 수 있다. 간단하게 추측해 보면, a의 아스키코드가 61이고, C5 - 61 = 64인 것으로 미루어보아 이 크랙미는 이름의 아스키코드에 64h를 더하여 시리얼을 구한다 라는 사실을 추론할 수 있다.
간단하게 키젠을 만들 수 있으나, VB는 유니코드를 사용하고 있으며 이는 한글과 같이 안시 코드페이지에서의 표현 방법과 유니코드상에서의 표현 방법이 다른 문자를 사용하게 되면 잘못된 결과를 도출한다는 문제점이 있다. 이를 해결하기 위해 살펴보면, 이 크랙미는 한 글자씩 떼어서 안시 코드 페이지로 바꾼 다음 64h를 더하여 16진수 형태로 시리얼을 출력한다는 것을 찾을 수 있다. 이를 이용하면 쉽게 키젠을 만들 수 있다.