카테고리 없음

[리버싱/프로젝트] 지뢰 찾기 게임 분석 1

공지혜 2026. 4. 9. 14:56

 

Winmine_XP.exe
0.11MB

 

리버싱 프로젝트로, 지뢰 찾기 게임을 분석하고, 가능하다면 새로운 기능을 넣어 패치까지 해 보기로 했다.

인터넷에서 위와 같은 실행 파일을 다운로드받아 사용했다.

 

IDA에서 해당 파일을 디컴파일했더니 이런 의사 코드가 나왔다.

전체 코드가 101줄밖에 안 돼서 '역시 간단한 게임이라서 코드도 진짜 간단하구나' 생각했는데, 자세히 보니까 함수 이름이 start()였다. 이건 그냥 게임을 시작하는 함수고, 진짜 게임은 sub_10021F0() 함수에 있다고 한다.

95번째 줄에 있는 함수다. 그 전까지는 실행 파일 시작을 위해서 세팅하는 코드고, 95번째 라인에서 '진짜 게임' 함수를 불러서 리턴값을 반환받고 게임을 끝내는 것이다.

 

함수 이름이 sub_10021F0()면 계속 찾기 힘들 것 같아서, 왼쪽 functions 창에서 함수 이름을 realGame으로 바꿔 주었다.

바꾸고 나서 다시 디컴파일했더니 start에서도 함수 이름이 바뀌어 있는 것을 볼 수 있었다.

 

이제 realGame을 클릭해서 realGame 함수를 살펴보았다. 이 함수도 전체가 72줄밖에 안 되고, 그 안에서 또 여러 함수를 호출하는 형식이었다.

코드를 조금씩 잘라서 중요한 부분을 보겠다.

(한 줄 한 줄 보는 건 너무 오래 걸릴 것 같고, 난 중요한 부분을 잘 모르겠어서 ai 도움을 받았다. ㅠㅠ)

  • WndClass.lpfnWndProc (line 17): 우변에 있는 sub_1001BC9() 함수가 윈도우 프로시저(Window Procedure)이다. 사용자가 마우스를 클릭하거나 키보드를 누를 때 발생하는 모든 메시지를 처리한다. 지뢰를 클릭했을 때 어떤 일이 벌어질지는 이 함수 안에 작성되어 있다.
  • WndClass.lpszClassName (line 25): 게임 창의 고유 이름을 설정한다. 게임 창을 만들 때 윈도우가 이름을 참조해서, 수많은 창 중에서 해당 창의 함수를 실행시킨다.
  • LoadIconW (line 15): 리소스로부터 게임 아이콘을 불러온다.
  • LoadCursorW (line 22): 리소스로부터 마우스 커서를 불러온다.

  • LoadMenuW (line 28): 게임 상단의 [도움말]과 같은 메뉴 바를 불러와서, hMenu에 저장.
  • LoadAcceleratorsW (line 29): 단축 키 테이블을 불러와서, hAccTablea에 저장.
  • sub_1002BC2 (line 30): 이전에 저장된 게임 설정(난이도, 사용자 이름, 최고 기록 등)을 읽어오는 초기화 함수로 추측됨. 왜냐하면 line 31부터 CreateWindowExW라는 창을 생성하는 함수인데, 창을 만들기 직전에 여러 설정이 필요하기 때문에.

  • CreateWindowExW (line31-43): 앞서 WndClass.lpszClassName로 만든 클래스 이름을 사용해 실제 윈도우 객체 생성.
  • * (_DWORD *) &X - dword_1005A90 (line 36): 해당 창이 화면의 어디에 뜰지, 크기는 얼마일지를 계산하는 로직. 게임 판의 크기가 난이도(초급/중급/고급) 등에 따라 가변적으로 변하기 때문에 이런 연산이 필요함.
  • ShowWindow (line 57), UpdateWindow (line 58): 생성된 창을 실제로 모니터에 출력.

while loop: 게임이 종료될 때까지 무한 반복하는 핵심 구간!!

  • GetMessageW (line 60): 운영 체제가 던져 주는 메시지(마우스 클릭, 타이머 등)를 기다림.
    * 지뢰가 터져도 이 값은 false가 되지 않음. 게임 오버 상태가 되는 거지, 창이 꺼지면 안 되기 때문. 사용자가 [X]나 [종료] 버튼을 눌러서 창을 닫으면, 운영 체제가 이 프로그램의 메시지 큐에 WM_QUIT이라는 메시지를 보냄. 그러면 GetMessageW값이 false가 되어서 루프 탈출하고 프로그램 종료됨.
  • TranslateAcceleratorW (line 62): 단축키가 눌렸는지 확인. 눌렸으면 그 단축키에 해당하는 '메시지'로 변환해서 윈도우 프로시저에 전달.
  • DispatchMessageW (line 65): 받은 메시지를 아까 등록했던 sub_1001BC9 (윈도우 프로시저)로 전달. 여기서 드디어 "지뢰 클릭" 등의 게임 로직이 실행됨.
    * 여기서 sub_1001BC9 (윈도우 프로시저) 호출이 없는데, 어떻게 거기로 전달이 될까? 아까 line 17에서 '등록'을 했기 때문이다. WndClass.lpfnWndProc = sub_1001BC9; 는 "운영 체제야, 앞으로 이 창(ClassName 기준)으로 오는 모든 메시지는 sub_1001BC9 함수가 처리할게."라고 말한 것과 같다. 따라서 DispatchMessageW(&Msg)로 받은 메시지를 운영 체제가 알아서 저 함수를 호출해서 넘겨 주는 것이다.

~while loop 끝남: 사용자가 게임을 종료함~

  • sub_100263C(line 68), sub_1002DAB(line 70): 최고 기록 저장, 점수 업데이트 등의 뒷정리 작업. 이 함수들 수행 후 프로그램이 완전히 종료됨. 

 

대충 realGame의 대략적인 구조를 파악해서, 이제 다음에 또 보기 쉽도록 주요 함수들의 이름을 바꿔 주었다.

  • sub_1001BC9 -> MainWindProc
    WndClass.lpfnWndProc = sub_1001BC9; 라고 명시되어 있다. (line 17)
  • sub_1002BC2 -> LoadSettings
    CreateWindowExW로 창을 만들기 직전에 호출되는 함수이므로, 창을 띄우는 데 필요한 정보들을 불러오는 함수일 것이다. (line 30)
  • sub_1001950 -> InitGame
    창을 띄운 직후 실행되는 함수이므로, 지뢰를 배치하고 게임 판 데이터를 메모리에 생성하는 동작을 실행할 것이다. 특히 인자로 1을 넘기고 있는 것을 보아, 게임의 초기 상태를 세팅하는 로직일 확률이 높다. (line 49)

 

여기까지가 지뢰 찾기 게임 실행 파일의 전체적인 흐름이다.

다음 번에는 각 함수 내부 로직을 분석하려고 한다.