KOEI

징기스칸4 파워업키트에 한글 메시지를 출력시키고 말겠다.

K66Google 2019. 11. 8. 16:05

징기스칸4... 안타깝게도 한국에는 오리지널만 발매되고 파워업키트는 발매되지 않았다.

그래서 여러 능력자들이 파워업키트 한글화를 시도하였고 메뉴 한글화는 이루어졌으나 메시지 한글화는 반각 처리 루틴에 의해 막히는 바람에 끝내 흐지부지 되고 말았다.


본래 내가 플레이하는 게임은 아니지만, 시행착오 끝에 한글 메시지 출력에 성공했기 때문에 그 출력 과정을 이 게시물을 통해 남기고자 한다.



1. 준비

징기스칸4 파워업키트 일판(링크)과 메뉴 한글패치(링크)를 구하였다. 

ollydbg와 Crystaltile2도 준비하였다.

메뉴 한글패치 된 실행파일을 가지고 한글 출력 작업을 해보도록 하겠다.




2. CreateFontA 로케일 변경


CreateFontA는 오프닝의 시나리오 설명 스크롤 등에 사용된다.


ollydbg로 실행파일을 불러온 뒤 Ctrl + N 으로 함수 창 열어서 CreateFontA 찾은 다음 엔터 키 친다.

그럼 결과 창에 한 개만 뜨는데 거기 들어가서 PUSH 80을 PUSH 81로 바꾼다. (81로 바꾸는 이유는 이 문서를 참고)

이후 Copy to executable - Selection - 새로 뜨는 창에서 마우스 오른쪽 클릭 - Save file 눌러서 exe파일로 저장하고 ollydbg 종료.


* 요약 (ollydbg) : 

0048B875 - PUSH 81로 변경.




3. 폰트 변경


징기스칸4는 기본 폰트로 'MS 明朝' (MS 명조) 를 사용한다. 코에이 게임들 대부분이 MS로 시작하는 폰트를 기본 폰트로 지정해놓는 것 같으니까 다른 게임들도 MS라고 검색하면 얻어 걸릴지도 모르겠다.

아무튼, Crystaltile2 실행 - 실행파일 불러오기 - 코드 페이지 일본어로 변경한 다음에 검색 기능(Ctrl+F)으로 MS 明朝 를 검색해본다. 

그러면 MS 명조가 일판은 3군데, 메뉴 한글판은 2군데에서 발견 될 것이다. (한컴바탕 때문에)

모두 gulim 으로 수정하고 남는 공간은 00 으로 채운다.


* 요약 (Crystaltile2) :

001ADCCC 줄 - MS 明朝 에서 gulim 으로 변경.

001B2F0C 줄 - MS 明朝 에서 gulim으로 변경.

001D7F7C 줄 - MS 明朝 또는 한컴바탕에서 gulim으로 변경.


이후 저장하고 Crystaltile2 종료. 다시 ollydbg로 실행파일을 불러온다.




4. 반각/전각 필터링 (프로그램 관련) 해제


인터넷에서 많이 알려진 반각/전각 필터링 해제 방법이다. 징기스칸4 파킷에는 총 3곳이 있었다.


Ctrl + F로 cmp eax, 81 을 검색한다. (eax, ebx, ecx, edx, ax, bx, cx, dx, ah, bh, ch, dh, al, bl, cl, dl 이렇게 바꿔가면서 다 검색해야 한다.)

그럼 두 줄 밑에 CMP 어쩌구, 9F 이렇게 보이는 패턴이 있는데 9F0C8로 바꾸고, 또 그 밑에 CMP 어쩌구, 0E0이 있는데 0E00A1으로 바꾸면 된다.


* 요약 (ollydbg) :

004BE758 - CMP AL, 0C8 로 변경.

004BE75C - CMP AL, 0A1 로 변경.


004A7F3B - CMP EAX, 0C8 로 변경.

004A7F42 - CMP EAX, 0A1 로 변경.


0048B82B - CMP AX, 0C8 로 변경.

0048B831 - CMP AX, 0A1 로 변경.

(이 주소가 시나리오 설명과 제일 밀접한 연관이 있다)


저장한 뒤 ollydbg는 내버려두고 한번 작업한 실행파일을 켜 본다.



그럼 초기 화면에서 한글 설명이 뜨는 모습을 볼 수 있을 것이다. 그러나 20~2F 영역의 ASCII 문자들이 지저분하게 나오는데 여기 뿐만 아니라 역사이벤트 창에서도 이렇게 뜬다. 이른바 찌꺼기 현상이다. 반각 띄어쓰기(20)를 쓰지 말고 전각 띄어쓰기(A1A1)만 써야 되나? 일단 보류해둔다.




5. CreateFontIndirectA 로케일 변경


CreateFontIndirectA는 메시지 출력 등에서 사용된다.

한글 출력 과정에서 제일 까다로웠던 부분이다.


게임 초기 화면에서 중지 버튼을 누르니 반각 가타카나로 깨진 문장이 나온다. 

이러한 문제는 일본어 로케일 상에서 한글 문장을 출력할 때 벌어지는 일이다. (프린세스메이커5를 윈도우10에서 돌리고 말겠다. 게시물을 참고) 

CreateFontA에서 81로 변경했는데도 이렇게 나오는 걸 보면 이건 CreateFontIndirectA에서 관여하는 게 분명하다. 그럼 해당 함수의 로케일을 ollydbg로 수정하면 되는데...



전혀 보이지 않았다.

CreateFontA는 주변에 바로 PUSH 80이 보여서 그걸 81로 바꾸면 됐지만, 징기스칸4의 CreateFontIndirectA 주변에는 아무것도 보이지 않았다.

인터넷 상에 돌아다니는 변경법은 CreateFontIndirectA 주변에 있는 MOV BYTE PTR 어쩌구, 80을 81로 수정하는 건데 주변에는 MOV DWORD PTR 어쩌구 밖에 없다.

하는 수 없이 CreateFontIndirectA를 호출하는 모든 지점에 F2로 브레이크를 걸고 F9로 실행을 해보았다. 그리고 게임 종료 메시지를 뜨게 하니까 004AE285에서 멈춘다. 그리고 pLogfont가 005B3CF0 이라는 주소를 가져왔다.



도대체 거기에 뭐가 있길래 그러는 건지, Hex dump 창 쪽에서 이동 단축키(Ctrl + G) 눌러서 005B3CF0로 이동해보았다. 

주변에 폰트 이름 밖에 안 보이는데... 어? 이럴 수가!!! 로케일에 관여하는 값이 어셈블리가 아닌 실행파일 내부에 있었다!!!



(출처 : https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-logfonta )


Logfont의 구조 상, 로케일은 폰트명 주변에 붙어있을 수 밖에 없다.

따라서 ollydbg 상에서 MOV DWORD 어쩌구만 판을 쳐서 로케일 값을 찾을 수 없다면 실행파일 내부를 의심해 볼 필요가 있다는 것이다. 특히 폰트 이름이 있는 곳 주변을 말이다.



ollydbg는 종료하고, Crystaltile2를 열어서 작업한 실행파일을 불러온 뒤, gulim을 검색해서 그 주변에 있는 80을 81로 바꾼다. 총 2곳을 확인해야 한다.


* 요약 (Crystaltile2) :

001ADCC7 - 81 로 변경.

001B2F07 - 81 로 변경.


저장한 다음 실행해보자. 어떻게 바뀌었을까? 

한글이 잘 출력되고 있다.

이제 Crystaltile2 상에서 열었던 실행파일을 닫은 뒤 MESSAGE.CK 파일을 불러온다.




6. 반각/전각 필터링 (MESSAGE.CK 관련)


징기스칸의 메시지 파일은 삼국지4,5와는 다르게 LS11로 압축되어 있지 않아서 편하다.

자, 그러면 플레이어 국가의 차례가 되었을때 나오는 문장을 한글로 바꿔보자. 해당 문장은 0000579B 즈음에 있다. 이곳을 '순번이 돌아왔어요' 라고 에딧한 뒤 저장하였다. 과연 어떻게 뜰까?



젠장! 일이 그렇게 잘 풀렸으면 이미 한글화는 되고도 남았을 것이다.

이건 삼국지4,5 일판과 신장의 야망 람세기 등에서 나타나는 반각 가타카나의 전각 히라가나 강제 변환으로 인해 생긴 일이다. 해당 문제가 발생하는 게임들 모두 메시지 파일에 반각 가타카나가 판을 치고 있다. (이 때문에 api 후킹 + 로더 방식이 아니면 글자수 제한으로 한글화하기 힘들다.)


자, 그러면 ollydbg로 실행파일을 불러온 뒤 cmp eax, 0a6 이라고 검색해본다. (eax 자리는 ax, ah, al 등 여러가지로 검색해봐야 한다.)


검색하니 CMP AL, 0A6이라는 값을 찾을 수 있었다. 참고로 두 줄 밑에 CMP AL, 0DF도 있다. 즉, 0A60DF가 주변에 붙어있으면 전각 히라가나 강제 변환 루틴일 거라 의심해도 된다는 것이다.


한글 출력 실험을 하면서, 강제 변환 파훼법은 두 가지가 있다는 걸 알아냈다.

첫번째 방법은 기존에 파악한대로 CMP AL, 0A6 밑의 점프문을 무조건 JMP로 바꾸는 것이다.


* 요약 (ollydbg) - 방법1

004A8097 - JB 에서 JMP로 변경.



두번째 방법은, 아예 판단 기준을 끌어올리는 것이다. 그 방법을 알아보기 전에 어셈블리 코드를 잠시 살펴보도록 하자.

004A8097에 JB... 004A809B는 JA다. JB는 비교해서 값이 작으면 점프하는 거고, JA는 비교해서 값이 커야 점프하는 거다.

값이 크고 작고의 주체는 레지스터인 AL이며, 부등호로 나타내면 이렇게 된다.


81~9f <[JB]< A6~DF <[JA]< eo~ea


앞 바이트가 A6보다 작으면 JB를 통해 빠지고, DF보다 크면 JA를 통해 빠진다. 그럼 A6~DF 구간만 빠지지 않고 남게 되겠지? 남아있는 것들이 바로 전각 히라가나로 강제 변환되는 것이다. 한글 CP949의 앞 바이트는 81~C8 까지라서 81~A5까지는 통과하겠지만 A6~C8이 루틴에 걸려서 문제가 발생한다. 허나 그렇다면, 판단 기준을 끌어올려버리면 되지 않을까?


81~CF <[JB]< D0~DF <[JA]< eo~ea


한글은 C8 대역에서 끝이지만 그냥 CF까지 통과시켜 주자. 그럼 D0부터 DF까지 남겠지만 어차피 여긴 한자 영역이라 한글화에 사용되지도 않는다.

얘기가 너무 길어졌는데, 결론은 CMP AL, 0A6CMP AL, 0D0으로 바꿔버리는 것이다.


* 요약 (ollydbg) - 방법2

004A8095 - CMP AL, 0D0 로 변경.


방법1과 방법2 둘 중 좋아하는 방식을 택하면 된다. 맨 아래에 올려놓은 실행파일은 방법2를 택했다.

그럼 실행해서 메시지가 잘 나오는지 확인해보자.


순번이 돌아왔어요 라고 잘 표시가 된다.




7. 반각 띄어쓰기의 찌꺼기 최소화.


시나리오 소개 화면의 찌꺼기는 일판에서도 동일하게 발생하는 문제인 것 같다. 일판 시나리오 파일에 반각 띄어쓰기(20)를 넣고 일판 실행파일로 실행해보니 마찬가지로 앞 글자의 일부가 계속 찍혀나오는 현상이 벌어진다. 찌꺼기가 남는 것이다.

이 찌꺼기를 어떻게 해야 좋을 지 몰라서 그냥 내버려두다가, Ollydbg로 문자 출력과 관련이 있는 TextOutA 함수를 검색해보았다.


TextOutA 함수가 3개 나왔는데, 그 중 위의 두 개만 살펴보았다. Stringsize가 1인 것과 2인 것이 있다.

어쩌면 StringSize 1인 것이 문제를 일으키는게 아닐까 싶어서 2로 수정하였다.


* 요약 (임시)

0048BAA4 - 2 로 변경.


저장하고 실행해보니까...


기존의 찌꺼기들이 없어지진 않았지만 - 로 바뀌면서 가독성은 좀 더 높아졌다.

완전한 해결법은 아니지만 이걸로 어느정도 보완이 되는 것 같다.




8. 맺음말

Ckw95_han3.zip

이건 내가 작업한 징기스칸4 파워업키트 한글 출력 실행파일이다. (메뉴 한글패치를 수정한 것)

뭐, 어차피 메시지는 한글화도 거의 되지 않았으니 이 실행파일로 플레이해도 뷁어만 주구장창 뜰 것이다.


그리고 징기스칸4PK 립버전에서 음악을 재생시킬 수 있는 방법이 있다. 

두기 무설치 버전에서 bgm, DOOGIE 폴더와 _inmm.dll, _inmm.ini, KOEICDA.DLL 파일을 복사해서 징기스칸4PK 폴더에 붙여넣는다.

그런 다음 DOOGIE 폴더의 _inmm.reg 파일을 클릭해서 등록하고 난 뒤 게임을 실행하면 음악이 나온다.


그럼 이만...