티스토리 뷰

오늘 하루종일 파고들어서 처음으로 크랙이라는걸 만들어 보았습니다. 정말 머리 아픈 작업이더군요^^; 구현 내용물은 윈도우에 기본으로 내장되어 있는 "지뢰찾기" 게임의 맵핵인데 쉽게 말해서 가려져 있는 지뢰를 전부다 표시해버리는 일종의 치트 프로그램입니다.

 

원리는 간단합니다. 지뢰찾기 게임중 지뢰를 밟았을때 모든 지뢰를 표시해주는 함수가 있는데 WM_PAINT메시지가 처리될때마다 그 루틴을 수행하도록 조작하면 게임은 종료되지 않고 항상 지뢰가 표시되더군요.

 

그런데 전 원리만 알 뿐이지 실제 역어셈된 코드를 잘 볼줄 모릅니다. 간단한 명령어 정도만 알뿐..

그래서 그 핵심 번지는 인터넷에서 얻었고 그 번지를 임의의 값으로 변경하는 루틴은 직접 API로 작성했습니다. 이 프로그램의 핵심은 ReadProcessMemory와 WriteProcessMemory가 되겠죠.

 

앞으로 어셈을 깊이 파고들게 되면 이쪽관련 작업(?)을 많이 해봐야 겠다는 생각을 하고 있습니다. 너무너무너무너무 재밌네요~~ 아.. 이 들뜬 기분을 주체할 길이 없네.

 

이건 여담인데 제 친구중 어떤 녀석한테 예전에 이런말을 했었죠. 지뢰찾기 게임은 절대 첫번째 클릭지점에서 지뢰가 터지지 않는다고.. 이런 문서를 어디 인터넷에선가 읽었다고 말이죠. 그런데 믿지를 않는 것이였어요 참 의심 많은 녀석 같으니라구... 그러다가 오늘 문득 그게 생각나서 처음부터 지뢰구역을 클릭했더니 역시나 안터지더군요. 그럼 지뢰위치가 모두 재배치 되느냐? 그것도 아니구요.. 맨처음 지뢰를 밟았다면 맨윗줄의 맨 왼쪽으로 그 지뢰가 옮겨지게 됩니다. 예를들어 1x1셀에 지뢰가 없다면 그쪽으로 해당지뢰만 옮겨지고, 만약 1x1셀에 지뢰가 있다면 1x2번셀로..

지뢰찾기 하시는 분들 가능하면 맨 왼쪽위는 클릭하지 않는게 좋을거라는 아주 유익한 정보였음^.^

 

 

#include <windows.h>

#include <stdio.h>

 

#define HACK_ADDR            0x01004971  // DASM으로 얻어낸 주소. 이 주소를 변경한다.

 

void main( void )

{

     DWORD dwEdit = 0;

     BOOL bResult = FALSE;

 

     HWND hWnd = FindWindow( NULL, "지뢰 찾기" );

     if( !hWnd )     return;

 

     DWORD dwProcessID = 0;

     GetWindowThreadProcessId( hWnd, &dwProcessID );

     HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS,

                                                           FALSE, dwProcessID );

     if( !hProcess )     return;

 

     // HACK_ADDR 번지에 있는 어셈 명령어를 읽어 들인다. 한 명령어가 차지하는 공간은

     // DWORD이다. 이 주소로 역어셈해서 들어가 보면 B8 0A 로 되어 있는데 인텔계열에선

     // 이게 반대로 값이 들어온다 0A B8 으로.. 그래서 조작역시 반대로 해주어야 한다.

     bResult = ReadProcessMemory( hProcess, (LPCVOID)HACK_ADDR,

                                                  &dwEdit, sizeof( DWORD ), 0 );

     if( !bResult ) {

          CloseHandle( hProcess );

          return;

     }

 

     // 메모리를 조작!

     // 0A 80 이렇게 들어오는데 B8은 MOV EAX, 이므로 바꾸지 않고 EAX레지스터에 넣을 0A

     // 만을 조작해준다. 0A를 0C로 바꾸어주면 빨간배경의 지뢰밟은 모양이 출력된다

     // 여기에선 변경전 기계어코드와 변경후의 기계어코드를 출력하고 있다

     printf( "BEFORE DATA : %X\n" );

     dwEdit = ( 0x0c << 8 ) + ( 0xb8 << 0 );

     printf( "AFTER    DATA : %X\n" );

 

     // 조작한 메모리를 실제 메모리상으로 올린다.

     // 이때 메모리 쓰기 전용함수 WriteProcessMemory API함수를 사용한다.

     bResult = WriteProcessMemory( hProcess, ( LPVOID )HACK_ADDR,

                                                   &dwEdit, sizeof( DWORD ), 0 );

     if( !bResult ) {

          printf( "Could not crack winmine..\n" );

          CloseHandle( hProcess );

     }

 

     // winmine의 화면을 다시 그리도록 한다. 그래야 변경사항이 적용될테니깐

     InvalidateRect( hWnd, NULL, TRUE );

 

     CloseHandle( hProcess );

}

저작자 표시
신고

'Window API' 카테고리의 다른 글

VK_ 가장키값  (0) 2011.12.21
[API] C++ 메모리값 주소 조작 ReadProcessMemory 벨류 출력  (0) 2011.03.14
지뢰 찾기(Winmine) 맵핵소스!  (0) 2011.03.14
댓글
댓글쓰기 폼