몬스터헌터

백업용) 프론티어 한글화 관련 메모

실버솔 2023. 7. 18. 11:02

참고:

https://k66google.tistory.com/765

https://k66google.tistory.com/543

https://arca.live/b/handtranslator/37003096?p=1

 

 

키워드:
CreateFont를 통해 폰트 인코딩이 결정되므로 그 부분 수정 필요
전각/반각 필터링



프론티어 클라는 mhf.exe -> mhl.dll -> mhfo(_hd).dll 호출 순으로 이루어짐

여기서 mhf.exe랑 mhl.dll은 런처에 가깝고 실제 메인코드는 mhfo.dll에 있음 이때 Enhanced Edition은 mhfo_hd.dll을 사용함

먼저 한글 출력이 되려면 createfont에서 폰트에 사용되는 인코딩을 바꿔주어야 됨
디버깅할땐 ollydbg나 x64dbg가 편할때 분석할땐 ida가 편해서 이걸로 보여줌


ctrl+1 누르면 여러가지 메뉴 단축키가 뜬다

imports에서 createfont 검색해서 xref(cross refrence)로 호출되는 위치를 찾으면 이런곳이 나옴

분기를 타고 createfont에 호출인자가 다르게 들어가는게 보일텐데

http://www.soen.kr/lecture/win32api/reference/Function/CreateFont.htm

0            ANSI_CHARSET
1 DEFAULT_CHARSET (Specifies a character set (1) based on the current system locale; for example, when the system locale is United States English, the default character set (1) is ANSI_CHARSET.)
2 SYMBOL_CHARSET
77 MAC_CHARSET
128  SHIFTJIS_CHARSET
129 HANGUL_CHARSET
130 JOHAB_CHARSET
134 GB2312_CHARSET
136 CHINESEBIG5_CHARSET
161 GREEK_CHARSET
162 TURKISH_CHARSET
163 VIETNAMESE_CHARSET
177 HEBREW_CHARSET
178 ARABIC_CHARSET
186 BALTIC_CHARSET
204 RUSSIAN_CHARSET
222 THAI_CHARSET
238 EASTEUROPE_CHARSET
255 OEM_CHARSET (Specifies a mapping to one of the OEM code pages, according to the current system locale setting.)


여기서 한국어는 129이기 때문에 createfont에 호출인자가 129가 되게 수정해주면 됨

그러니까


대충 이런식으로 수정해주면 됨
81h라고 표시되는건 16진수이기 때문인데 계산기써도 되고, 오른쪽 클릭하면 10진수로 바꿀수도 있음

ida가 assmble 기능이 좀 구린데 keypatch라는 플러그인 있으니까 그거 쓰면 됨

패치 적용은 edit 메뉴 - 패치 - apply to patch 메뉴를 사용하면 된다
수정한 바이트들의 리스트를 보여주기 때문에 수정이 잘못되거나 했을때 되돌리거나 패치할 곳을 관리하기 쉽다

 

 

그다음은 전각/반각 필터링인데 글자를 화면에 그리는 함수는 ExtTextOutA함수임
따라서 이 주변에다가 bp(breakpoint)를 걸고 어떻게 되나 관찰하면 되는데 어떻게 하는지 설명하기는 좀 그렇고
일단 내가 대충 분석해뒀으니까 그걸 토대로 설명하겠음


imports에서 ExtTextOut를 검색하고 ExtTextOutA에다 xref걸어서 이동한후
함수 맨위로 가서 xref를 따라가보면 call sub_114B8C20라고 두번 호출 되는 곳이 있을거임
두번 호출되는 이유는 아마 반각은 1바이트 전각은 2바이트니까...?





ollydbg에서 bp걸고 레지스터를 관찰하면 알겠지만
전각이냐 반각이냐에 따라서 eax에 1바이트냐 2바이트냐 들어옴



일단 가설은 미리 반각인지 아닌지 테이블을 만들어 놓고 00인지 ff인지 비교해서
00이면 반각, ff면 전각이라는 판단.
처음에는 ff면 pick을 부른뒤 다시 이 함수를 호출, 이런식으로 한 글자를 하나씩 잘라서 출력한다





0xff인 이유는 아마 폰트폭이랑 관계되지 않았나 추정중
http://soen.kr/project/dangeun/dg1/12-4-2.htm 참조

원래는 더 제대로 패치를 해야되겠지만 분석이 어려워서 일단 임시로 처리했음
0x80이하면 그냥 이전처럼 처리, 0x80이상이면 edi+eax라는 곳에 0xFFFF을 넣어줌
0x80과 비교하는 이유는 첫바이트가 0x80보다 크면 한글이기 때문임
코드를 추가하기엔 공간이 없으므로, 빈공간으로 이동해서 패치한다



mhfo.dll

.text:114B8C9E jmp loc_16486040
.text:114B8CA3 ; ---------------------------------------------------------------------------
.text:114B8CA3
.text:114B8CA3 loc_114B8CA3: ; CODE XREF: sub_114B8C20+4FCD436j
.text:114B8CA3 nop

.stolen:16486040 loc_16486040: ; CODE XREF: sub_114B8C20+7Ej
.stolen:16486040 cmp edx, 80h
.stolen:16486046 jb short loc_16486050
.stolen:16486048 mov bx, 0FFFFh
.stolen:1648604C mov [edi+eax], bx
.stolen:16486050
.stolen:16486050 loc_16486050: ; CODE XREF: sub_114B8C20+4FCD426j
.stolen:16486050 test [edi+eax], bl
.stolen:16486053 mov eax, [ebp-4]
.stolen:16486056 jmp loc_114B8CA3





mhfo-hd.dll

섹션 추가 하기 귀찮으니 임시로 idata 끝에다 코드설치 하기로...
import 테이블이 있는곳이라 사실 코드패치하기 좋은 곳은 아니지만..

.text:114DF53E jmp loc_1F11B940
.text:114DF543 ; ---------------------------------------------------------------------------
.text:114DF543 nop

.idata:1F11B940 ; START OF FUNCTION CHUNK FOR sub_114DF4C0
.idata:1F11B940
.idata:1F11B940 loc_1F11B940: ; CODE XREF: sub_114DF4C0+7Ej
.idata:1F11B940 cmp edx, 80h
.idata:1F11B946 jb short loc_1F11B950
.idata:1F11B948 mov bx, 0FFFFh
.idata:1F11B94C mov [edi+eax], bx
.idata:1F11B950
.idata:1F11B950 loc_1F11B950: ; CODE XREF: sub_114DF4C0+DC3C486j
.idata:1F11B950 test [edi+eax], bl
.idata:1F11B953 mov eax, [ebp-4]
.idata:1F11B953 ; END OF FUNCTION CHUNK FOR sub_114DF4C0
.idata:1F11B956
.idata:1F11B956 loc_1F11B956:
.idata:1F11B956 jmp loc_114DF544

어쨌거나 마찬가지로 패치



현재문제)
한글출력시에 주변글자에 얼룩처럼 더럽게 표현되는 문제
이유는 아마 글자폭이 글자마다 달라서
임시 해결책: 고정폭글꼴 예를들어 '돋움체'를 사용




mhfo.dll에서 Arial를 string에서 검색해서 가보면 주변에 MS고딕이라는게 보임
이걸 DotumChe로 바꿔도 차이가 없을텐데 왜냐면 mhl.dll에서 설정된값을 사용하기 때문임
그래도 일단 같이 바꿔주는게 나을것


리소스에디터(Resoure로 열고 MS고딕을 DotumChe로 바꿔주면 된다
왜 리소스에서 수정하냐면 createfont 함수의 인자가 이걸 참조하기 때문

mhl.dll에도 createfont가 있는데 이걸 수정하는게 의미있는지는 잘 모르겠는데 일단 방법은 같음



이걸
.text:1000BDC8 mov [ebp+iCharSet], 128
.text:1000BDCF cmp eax, 6
.text:1000BDD2 jnz short loc_1000BDDD
.text:1000BDD4 mov [ebp+iCharSet], 129
.text:1000BDDB jmp short loc_1000BDE9
.text:1000BDDD ; ---------------------------------------------------------------------------
.text:1000BDDD
.text:1000BDDD loc_1000BDDD: ; CODE XREF: sub_1000BD90+42j
.text:1000BDDD cmp eax, 7
.text:1000BDE0 jnz short loc_1000BDE9
.text:1000BDE2 mov [ebp+iCharSet], 136



이렇게

.text:1000BDC8 mov [ebp+iCharSet], 129
.text:1000BDCF cmp eax, 6
.text:1000BDD2 jnz short loc_1000BDDD
.text:1000BDD4 mov [ebp+iCharSet], 129
.text:1000BDDB jmp short loc_1000BDE9
.text:1000BDDD ; ---------------------------------------------------------------------------
.text:1000BDDD
.text:1000BDDD loc_1000BDDD: ; CODE XREF: sub_1000BD90+42j
.text:1000BDDD cmp eax, 7
.text:1000BDE0 jnz short loc_1000BDE9
.text:1000BDE2 mov [ebp+iCharSet], 129

바꾸면 됨

여기까지하면 일단 인코딩관련 수정은 대충 끝났다

*아직 한글입력과 관련해서 문제가 있는데 ime 관련된 문제로 추정되는데 손대기 좀 어렵다
반각/전가 필터링도 남아있는지
영문자가 전각으로 입력되거나 끝글자에 따라 글자를 입력해도 입력이 씹히는 문제가 있는데
ex)상점검색에서 회복은 입력 되는데 회복약은 안됨
임시로 ALT+=로 반각으로 바꿀 수 있고, 채팅할때도 점이나 스페이스를 입력해주면 일단 입력은 된다. 아직 이런저런 문제들이 아직 있다


한글화를 하려면 dat폴더에 있는 대사들을 한글로 수정해야 되는데
그중 메인이라고 할 수 있는 애들이 mhfdat.bin mhfinf.bin mhfpac.bin 얘네들이고
나머지도 수정해야 되는 애들이 좀 있음



예를 NPC대사 같은 경우 stage폴더에 st249.pac 이런거에 텍스처, 3d모델, npc 대사등이 있어서 그것도 일단 풀어서 한글화 해야 됨
그게 끝이 아니고 서버에 있는 퀘스트 파일들, 시나리오 파일같은것도 마찬가지로 한글화 해야 된다



mhfdat.bin mhfinf.bin mhfpac.bin 얘네는 Refrontier라는걸로 압축을 풀 수 있는데 사용법은 까먹었다.
압축이 되어있어서 일단 압축풀고, 수정하고 다시 압축하면 됨


아무튼 압축해제를 하고나면 일본어대사를 한국어대사로 수정해야 되는데
번역도구란걸로 shift-jis로 뽑고 한글로 수정된 대사를 euc-kr로 넣으면 되는데 이건 도스 한글화할때 했던 설명 참조하자



파일 구조를 알면 포인터 주소들을 추출해서, 파일뒤에 한글화된 대사를 넣고, 그 포인터주소를 한글화된 대사를 가르키게 수정할 수도 있는데 파일 구조가 좀 복잡한것 같다. 이럴땐 그냥 대사길이를 벗어나지 않는 선에서 덮어쓰는게 편하다


대신 번역도구를 쓰면 대사길이가 제한되거나, 대사가 일부 안 뽑히거나, 추출이 살짝 밀려서 추출된다거나 할 수 있는데 그건 어쩔 수 없다.

대사 길이 문제는 뒤에 00이 있으면 좀 늘릴 수 있고, 대사가 안뽑히거나 추출이 밀리는건 madedit으로 확인하면 된다


수정이 다 되었다면 다시 압축해서 클라에 넣어주면 된다


https://www.mediafire.com/file/hzxfiyhavvd6vua/

이건 그냥 테스트용 bin파일이랑 dll이랑 exe파일

일단 설명은 다 해준것 같고 굳이 내가 프론티어에 더 손댈거 같지는 않을것 같다
그래도 하겠다면 말리지는 않고



----번외----

추가적으로 혹시 도움이 될까싶어 쓰자면

다들 내가 찾은 아랄코드를 사용중일텐데



비고정주소

mhfo.dll
HOOK(0x114b8c62,TRANS(EAX,OVERWRITE),RETNPOS(SOURCE)),FORCEFONT(5),FONT(CreGothic_NHN M,-13),ENCODEKOR


mhfo-hd.dll
HOOK(0x114DF502,TRANS(EAX,OVERWRITE),RETNPOS(SOURCE)),FORCEFONT(5),FONT(CreGothic_NHN M,-13),ENCODEKOR



고정주소

mhfo.dll
HOOK(mhfo.dll!0x14b8c62,TRANS(EAX,OVERWRITE),RETNPOS(SOURCE)),FORCEFONT(5),FONT(CreGothic_NHN M,-13),ENCODEKOR



mhfo-hd.dll
HOOK(mhfo-hd.dll!0x14DF502,TRANS(EAX,OVERWRITE),RETNPOS(SOURCE)),FORCEFONT(5),FONT(CreGothic_NHN M,-13),ENCODEKOR



그리고 AT코드가 옛날엔 고정이 됐는데 왜 뽑을 때마다 왜 달랐냐 그건 ASLR이란거 때문임(윈도우 설정에서 끌 수 있음)

ASLR이 적용되면 DLL이 로딩될떄마다 주소가 바뀌는데 그래서 AT코드가 계속 달라졌던거였다



비고정주소와 고정주소의 어떻게 차이나는지 보면 알겠지만 mhfo.dll이란곳으로 부터 상대적으로 접근하기 때문에 코드가 달라지지 않는다



두 주소값이 10000000차이나는 이유는 imagebase값을 빼주었기 때문


0x114b8c62라는곳을 가보면 알겠지만 초록색이 우리가 코드를 패치한곳. 빨간색이 AT코드의 위치다

결론적으로 AT코드를 찾을때 ExtTextOutA 주변에서 bp를 걸고 글자열을 가져오는 부분이 AT코드일 가능성이 높고,
고정 AT코드를 찾으려면, exe나 dll파일의 imagebase를 빼면 된다.

 

 https://blog.naver.com/jingukangnc/140187091435?viewType=pc 


물론 그럴수도 있다는거에 가깝고 글자열 검색으로 찾는게 더 편할것이다



어? 하지만 ASLR때문에 dll의 로딩 위치가 달라지지 않나?
어차피 메모리맵을 보면 exe나 dll이 로딩된 주소를 알 수 있다. 따라서 이 값을 빼주면 된다.
물론 설정에서 ASLR꺼도 된다



------ 번외끝---