[해킹] 테트리스 블럭 조작 기법

이 글들을 읽을땐 C나 Asm에 대한 약간의 지식이나 API에 대한 사전 지식은 도움이 됩니다.



테트리스 블럭 조작 기법
Written by A #Dual_Root

서론

이 글에서는 테트리스 게임의
블럭 조작 기법을 소개합니다.

필요한 도구들

– Olly Dbg

대상 프로그램 링크

저작권상의 이유로 링크할순 없습니다. – 넷마블 테트리스+

본문


1.테트리스?
안녕하세요~ Dual입니다. ;) 홈페이지에서 왠만하면 GameHacking기법에 대해선 다루지 않으려고 했지만, 왠지 하나쯤은 있어도 괞찮겠다는 생각이 들어서 글을 쓰게 되었습니다. ;) 그리고 이글에서는 노가다적인 Memory Finding을 쓰면서 하는것이 아닌, 테트리스 게임에 대한 분석을 통해서 얻어낼수 있는 사항들을 가지고 디버거 툴을 가지고 패치하는 법에 대해서 다루도록 해보겠습니다. ;p 예~! 본격적인 패치 작업을 시작하기 전에 블럭 조작을 위해서 필요한 사항이 무엇인지 파악하는것이 중요합니다. 먼저, 테트리스의 블럭(모양)수는 몇개일까요? 위에서의 그림 처럼, 블럭의 갯수는 7개 입니다. ;p (이것을 미리 알아두는 것은 아주 중요합니다.) Tetris게임은 블럭을 Random적으로 생성해내어, 이값을 배열에 저장해두고, 배열의 값을 하나씩 읽어와서 그 해당 블럭을 출력하는 방법을 취하고 있습니다. (미리 블럭 배열을 생성 해두는 이유는 게임의 속도 떄문일것입니다.) 여기서 의문점이 생길수 있습니다. 과연 Random적으로 블럭의 값을 생성해내는 방법은? 어떤 함수를 이용하는 것일까? 라는 의문점이죠. Random Number를 우리 나라 말로 하면 난수가 됩니다. 난수란 어떤 규식성이 없이 무작위로 발생한 수를 말하는 것이죠. 그리고 이 난수를 발생시키는 함수는 VC 내장 함수인 rand() 함수입니다. rand() 함수를 이용하여 블럭의 갯수(=7개)만큼의 난수를 발생시킬떈 밑에와 같이씁니다. rnd = rand() % 7; 아무리 큰수가 되더라도 7로 나눈 나머지(mod연산)을 구하면 7이하의 값이 되게 됩니다. 이를 어셈블리어로 표시해보면 밑에와 같을 것입니다. call rand //rand함수를 호출한다. cdq xor eax,edx //eax와 edx를 xor 연산한다. mov ecx,7 //나누는 수는 ecx에 저장한다. sub eax,edx //eax에서 edx를 뺸다. cdq idiv ecx //eax의 값을 ecx 나눈다. 우리는 이와 같은 형태의 부분을 찾으면 되는 것입니다. ;p 이제 이론적인 부분을 알게 되었으니, 남은 일은 OllyDbg를 이용하여 실제로 저거와 비슷한 부분을 찾아내면 되는것 입니다. ;) OllyDbg를 키고 대상 프로그램으로 넷마블 테트리스+ 를 지정합니다. (Attach) 올리디버거 메뉴 상단의 E<=버튼을 클릭하여 모듈 목록을 띄운후에, Tetrisplus.exe를 마우스 오른쪽 버튼으로 클릭하면 뜨는 메뉴중, View Names 메뉴를 클릭해서 함수목록을 띄웁니다. 함수 목록이 떳다면, rand()함수가 있는지 찾아봅니다. 역시 우리의 기대를 져버리지 않고, rand()함수가 존재하는것을 볼수 있습니다. ;) rand 함수를 마우스 오른쪽 버튼으로 클릭하여 뜨는 메뉴중 Find References 라는 메뉴를 클릭하여 rand()함수를 호출하는 주소들을 볼수 있습니다. 정말 많은곳에서 rand()함수를 호출해다가 쓰는곳을 볼수 있습니다. 이것을 하나씩 Follow In Disassembler 하여 보는 것은 엄청난 노가다 작업이 될듯함으로 ;) Set Break On Every Command 메뉴를 이용해서 모두 브레이크 포인트를 건후, 게임을 시작할떄 브레이크 포인트가 걸리는것중 우리가 찾는 부분과 비슷한것이 있는지 찾아 보는 형식으로 해보겠습니다. ;) 첫번쨰 브레이크 포인트가 걸린지점은, 00442103 E8 A2B40700 CALL TetrisPl._rand 00442108 99 CDQ 00442109 B9 32000000 MOV ECX,32 0044210E 8B1D 20895400 MOV EBX,DWORD PTR DS:[<&WINMM.timeGetTim>; WINMM.timeGetTime 00442114 F7F9 IDIV ECX 우리가 찾는 값은 7인데 여기선 32임으로 아니니, 브레이크 포인트를 해제하고 넘어갑니다. 0044213E E8 67B40700 CALL TetrisPl._rand 00442143 8B8E B8010000 MOV ECX,DWORD PTR DS:[ESI+1B8] 00442149 89BE F4010000 MOV DWORD PTR DS:[ESI+1F4],EDI 0044214F 85C9 TEST ECX,ECX 00442151 74 07 JE SHORT TetrisPl.0044215A 두번째 브레이크 포인트가 걸린 지점역시 아닌듯 합니다. 브레이크 포인틀르 해제하고 넘아갑니다. 00442197 E8 0EB40700 CALL TetrisPl._rand 0044219C 8B86 F0010000 MOV EAX,DWORD PTR DS:[ESI+1F0] 004421A2 85C0 TEST EAX,EAX 004421A4 74 09 JE SHORT TetrisPl.004421AF 004421A6 50 PUSH EAX 004421A7 E8 33E30D00 CALL TetrisPl.??3@YAXPAX@Z 세번쨰 지점 역시 아닌듯 합니다. ;) 00442221 E8 84B30700 CALL TetrisPl._rand 00442226 89BE A8010000 MOV DWORD PTR DS:[ESI+1A8],EDI 0044222C 8B76 0C MOV ESI,DWORD PTR DS:[ESI+C] 0044222F 85F6 TEST ESI,ESI 네번쨰 역시도 아닙니다 T.T 004410EB E8 BAC40700 CALL TetrisPl._rand 004410F0 99 CDQ 004410F1 B9 32000000 MOV ECX,32 다섯번쨰 역시 아닙니다. 00441146 E8 5FC40700 CALL TetrisPl._rand 0044114B 99 CDQ 0044114C B9 0A000000 MOV ECX,0A 00441151 F7F9 IDIV ECX 여섯번쨰 지점은 상당히 흡사하여 보이지만, 우리가 찾는것은 0xA가 아닌 0x7임으로 넘어갑니다. 004339FD E8 A89B0800 CALL TetrisPl._rand 00433A02 99 CDQ 00433A03 B9 0A000000 MOV ECX,0A 00433A08 F7F9 IDIV ECX 일곱번쨰 역시 우리가 찾는 부분이 아닙니다. 004393DC E8 C9410800 CALL TetrisPl._rand 004393E1 99 CDQ 004393E2 33C2 XOR EAX,EDX 004393E4 B9 07000000 MOV ECX,7 004393E9 2BC2 SUB EAX,EDX 004393EB 99 CDQ 004393EC F7F9 IDIV ECX 8번쨰에 우리가 찾던 부분을 찾을수 있었습니다. ;p 아직 확실하지 않음으로 몇번더 OllyDbg를 돌립니다. ;0 00439406 E8 9F410800 CALL TetrisPl._rand 0043940B 99 CDQ 0043940C 33C2 XOR EAX,EDX 0043940E B9 07000000 MOV ECX,7 00439413 2BC2 SUB EAX,EDX 00439415 99 CDQ 00439416 F7F9 IDIV ECX 9번쨰 브레이크 포인트가 걸린지점은 8번쨰 부분과 똑같이 생겼으며, 8번쨰 포인트 바로 아래부분에 있는것으로 보아 넷마블 테트리스+의 프로그래머 분께서 블럭 체크를 위해 같은 부분을 두곳만들어 둔것이 아닌가 생각됩니다. ;) 우리는 패치해야할 주소를 알아낸 것입니다. 이제 패치하는 방법에는 두가지 방법이 있습니다. ———————————————— ① ecx의 값을 수정하여 범위를 좁아지게 만든다. ② eax의 값을 수정하여 무조건 어떤 블럭이 나오도록 만든다. ———————————————— 2번쨰 방법은 넷마블 테트리스+의 경우 같은 블럭이 연속으로 여러번 떨어질 경우 잘못된 패킷이라 간주하고, 방에서 접속이 끊어짐으로 첫번쨰 방법을 사용 하도록 해보겠습니다. ;) 8번쨰와 9번쨰 부분의, 004393E4 B9 07000000 MOV ECX,7 0043940E B9 07000000 MOV ECX,7 를 각각 MOV ECX,2로 바꾸었습니다. ;) 이제 테트리스에서 패치가 적용되었는지 확인해 보겠습니다. ;) 이제 어디 부분을 패치해줘야 되는지 알았음으로 Memory Patch식으로 만들거나(추천), 실행 파일에 직접 수정을 가해줄수 있겠습니다. (이방법 쓰면 게임이 재미없어지겠죠) 우리는 테트리스의 블럭의 계수가 7개이며, 난수를 발생시키는 함수는 rand() 함수였다는 사실을 통해 rand()함수에 브레이크 포인트를 걸고 적절한 부분을 찾는 방법을 통해 성공적으로 패치 해낼수 있었습니다. ;) 이것은 테트리스 만의 것이 아님으로 여러가지 게임에 응용해 볼수 있을것입니다. ;) 간단한 예로 지뢰찾기 같은 프로그램 부터 시작해서 N뭐 게임사의 MxxxxxSxxxy 같은 게임에서 초기 스텟을 주사위로 정하는거 같은 게임까지 말이죠 ;) 그럼 오늘 글도 여러분에게 많은 도움이 됬었길 바라며, 오늘도 즐거운 밤입니다. 출처: http://dualpage.muz.ro/

Advertisements

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중