안녕하세요. EroGame 이며 前피시 입니다.
이 내용은 어디까지나 제가 찾는 방법을 기준으로 작성하기 때문에
다른 분과는 약간(?) 다를 수도 같을 수도 있습니다.
이점을 유의해주시고 읽어주세요.
!주의!
피시는 코드를 파는데 무조건 중시하는 것이 있습니다.
첫째. 코드로 내놓는건 띄어쓰기를 제거하지 않아야 하며, 글잘림이 없어야 한다.
둘째. 디나이워드의 무시설정도(PASS)를 사용하거나 Cmd필터를 사용하는 등 원문이 첫째에 반하는 형태로 나오거나 저런 필터를 사용하지 않고서는 게임이 튕기는 코드는 버려야 한다.
셋째. 모든글을 최대한 번역하는 코드를 내놓고 추후에 다른 미번역 글이 발견되면 코드를 업데이트 한다.
피시의 엔진별 야메찾기 리스트 ... 라고 뭔가 거대해 보이는 풍으로 썼지만
내용은 그다지 별것 없습니다.
단순 치트에요.
해당 야메 찾기 목록은
생각날때나 게임을 다시 잡았을때 추가하도록 하겠습니다.
너무 빨리 공개하는게 아닌가 싶기도 하지만
일부만 공개하는 것이기 때문에
그리 문제가 될것 같지는 않네요.
메모장에 대충 적어놓고 최근에서야 조금 정리를 하긴 했습니다만
저만 알아보게 암호같이 적어놔버려서 다른 분이 보셔도 이해 못 할 가능성이 높다고 생각됩니다.
나중에 시간 나는대로 천천히 다시 정리하겠습니다.
그 이전에 서버 닫아야 하는 처지가 되어서 (국가의 철퇴)
살짝 옮겨놓은 자료라도 여기에 잠깐 이전해 놓고 가려고 합니다.
1. rUGP 엔진
게임내에 vm60.dll 을 디버거로 열고
MOV EDI,DWORD PTR SS:[ESP+28] 명령어 찾기
약 3~5개 중 디폴트문 찾기
찾은 부분 [ESP+28] 포인트 바꿔치기 후킹
필터 : FixLine{},DenyWord{CUT(2)}
rUGP 공용 픽스 필터 : FixLine.dat
2. cmvs 엔진
GetDC 함수 약 4~6개 부르는 곳 중
스위치문 이 포함된 장소 2개소(2개소 밖에 없음)
해당 스위치문이 포함된 함수들의 맨 처음 명령어 주소에서 후킹
[ESP+0x4] 포인터 바꿔치기
3. cs2 엔진
004A2CD8 . 803F 00 CMP BYTE PTR DS:[EDI],0
004A2CDB . 74 7F JE SHORT cs2.004A2D5C
004A2CDD . 8D49 00 LEA ECX,DWORD PTR DS:[ECX] <-- EAX
004A2CE0 > 803C3E 24 CMP BYTE PTR DS:[ESI+EDI],24
004A2CE4 . 75 6F JNZ SHORT cs2.004A2D55
004A2CE6 . 807C3E 01 73 CMP BYTE PTR DS:[ESI+EDI+1],73
004A2CEB . 75 68 JNZ SHORT cs2.004A2D55
004A2CED . 807C3E 02 74 CMP BYTE PTR DS:[ESI+EDI+2],74
004A2CF2 . 75 61 JNZ SHORT cs2.004A2D55
004A2CF4 . 807C3E 03 72 CMP BYTE PTR DS:[ESI+EDI+3],72
004A2CF9 . 75 5A JNZ SHORT cs2.004A2D55
004A2CFB . 8D4424 20 LEA EAX,DWORD PTR SS:[ESP+20]
004A2CFF . 50 PUSH EAX
004A2D00 . 8D4C24 1C LEA ECX,DWORD PTR SS:[ESP+1C]
004A2D04 . 51 PUSH ECX
004A2D05 . 8D543E 04 LEA EDX,DWORD PTR DS:[ESI+EDI+4]
004A2D09 . 52 PUSH EDX
004A2D0A . E8 81EA0500 CALL cs2.00501790
0051209D |. 0FB6D0 MOVZX EDX,AL
005120A0 |. 85D2 TEST EDX,EDX
005120A2 |.v 74 1B JE SHORT cs2.005120BF
005120A4 |. 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C]
005120A7 |. 50 PUSH EAX
005120A8 |. 8D4D EC LEA ECX,DWORD PTR SS:[EBP-14]
005120AB |. E8 A0E8EFFF CALL cs2.00410950 <-- [ESP], = EAX
005120B0 |. 83C0 04 ADD EAX,4
005120B3 |. 8BC8 MOV ECX,EAX
005120B5 |. E8 46A3F1FF CALL cs2.0042C400
005120BA |. E9 A0000000 JMP cs2.0051215F
005120BF |> 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
005120C2 |. 51 PUSH ECX
005120C3 |. 8D4D 88 LEA ECX,DWORD PTR SS:[EBP-78]
예제 코드
HOOK(0x004A2CDD,TRANS(EAX,OVERWRITE(IGNORE)))
HOOK(0x005120AB,TRANS([ESP],PTRCHEAT))
4. ExHIBIT 엔진
ExHIBIT
retouch.info
?printEngine@RetouchSystem@@UAEXHHPBD0_NHHHHPAVRetouchPrintParam@@@Z
해당 함수 시작부분에서 [ESP+0xc],[ESP+0x10] 메모리 덮어쓰기
?ldfPrintList@RetouchSystem@@AAEXAAVscobjPrintArea@@PBDHHHK@Z
해당 함수내에서 아래와 같은 곳 중
8B8424 C8000000 MOV EAX,DWORD PTR SS:[ESP+C8]
8B4E 14 MOV ECX,DWORD PTR DS:[ESI+14]
6A 00 PUSH 0
6A 00 PUSH 0
6A 00 PUSH 0
6A 00 PUSH 0
50 PUSH EAX
E8 D8050C00 CALL resident.10196370 <-- 들어간장소에서 [ESP+0x4] 메모리 덮어쓰기
68 C8000000 PUSH 0C8
?printSub@RetouchPrintManager@@AAE_NPBDAAVUxPrintData@@K@Z +72
해당 함수내에서 아래와 같은 곳 중
|. /EB 03 JMP SHORT resident.1004BA80
| |8D49 00 LEA ECX,DWORD PTR DS:[ECX]
|> \8BCE /MOV ECX,ESI
|. E8 49B71400 |CALL resident.101971D0 <-- 들어가면↓
|. 8BE8 |MOV EBP,EAX
|. 85ED |TEST EBP,EBP
|. 74 37 |JE SHORT resident.1004BAC4
CALL resident.101971D0 <-- 들어온곳에서
/$ 8B11 MOV EDX,DWORD PTR DS:[ECX] <-- EAX 메모리 덮어쓰기
|. 33C0 XOR EAX,EAX
|. 85D2 TEST EDX,EDX
|. 74 08 JE SHORT resident.03CA71E0
|. 51 PUSH ECX ; /Arg1
|. 8BCA MOV ECX,EDX ; |
|. E8 E0FBFFFF CALL resident.03CA6DC0 ; \resident.03CA6DC0
\> C3 RETN
예제 코드
HOOK(resident.dll!0x001492E0,TRANS([ESP+0xc],OVERWRITE(IGNORE)),TRANS([ESP+0x10],OVERWRITE(IGNORE)))
HOOK(resident.dll!0x00196370,TRANS([ESP+0x4],OVERWRITE(IGNORE)))
HOOK(resident.dll!0x001971D0,TRANS(EAX,OVERWRITE(IGNORE)))
5. PAL 엔진
PAL.dll 내에서
PalFontDrawText 함수를
실행파일에서 참조하는 위치에 보이는 함수의 최초 시작부분에 후킹 [esp+0x4] 메모리 덮어쓰기
PalSpriteCreateText 함수의 시작부분 [esp+0x8] 포인터 바꿔치기
예제 코드
HOOK(aina.exe!0x0001D890,TRANS([ESP+0x4],OVERWRITE(IGNORE)))
HOOK(PAL.dll!0x00011B80,TRANS([ESP+0x8],PTRCHEAT))
6. ADVプレイヤHD 엔진
PUSH 3 ; |CodePage = 3
CALL DWORD PTR DS:[<&KERNEL32.MultiByteT>; \MultiByteToWideChar
MultiByteToWideChar 함수중 CodePage 값을 3으로 스택으로 넣는곳이 있는
함수에서 시작부분 맨 위쪽의 콜스택을 참조하면
맨밑에서부터 위로 2번째부터 위로 2개의 장소
맨밑에서부터 위로 47번째의 장소
해당 장소들에 들어간 위치로부터 명령어+1 위치에
[esp+0x4]+0x4 스마트, 유니코드, 포인터
예제 코드
HOOK(0x004996BD,TRANS([esp+0x4]+0x4,SMSTR,UNICODE))
HOOK(0x00499D09,TRANS([esp+0x4]+0x4,SMSTR,UNICODE))
HOOK(0x0047C69E,TRANS([esp+0x4]+0x4,SMSTR,UNICODE))
7. YU-RIS 엔진
디버거로 바이너리 검색(해당 실행파일 CPU 창에서)
0F BE 50 1C 85 D2
찾은 장소가 후킹장소
인자 값은 엔진 버전별로 가변 값이므로 조금 내려보면
0043EE3E . 8B40 3C MOV EAX,DWORD PTR DS:[EAX+3C] ; (EAX+3C - 0x4) 값이 가변값
0043EE41 . C60401 43 MOV BYTE PTR DS:[ECX+EAX],43
후킹 인자값 = EAX+0x38
03 D8 0F B6 (2C 3E) ; 괄호값이 유동적인 것을 확인, 앞의 4개의 바이너리로 검색
찾은 지역의 명령어 -1 Line 에 Call 문이 있음
CALL 들어가서 바로나온 지점
- 더미다가 붙을 경우 이장소 후킹이 안될 수 도 있음.
구버전의 경우
81 E6 00 00 FF 00 바이너리 검색
찾은 곳에 함수의 첫부분
위 두가지 통합 방법
TextOutA 함수 사용하는 함수 위쪽에서 콜스택을 보면
첫번째 부분으로 가서 다시 맨 위쪽 위치(결국 3가지 다 동일한 장소)
예제 코드
HOOK(0x0043EE27,TRANS(eax+0x38,SMSTR(YURIS,IGNORE)))
HOOK(0x00425983,TRANS(EDI,OVERWRITE(IGNORE)))
KoFilter{},FixLine{}
유리스 엔진 과거 버전부터 현재 최신판까지 사용 가능한 공용 픽스 사용 : FixLine.dat
유리스 엔진 리스트 : http://yu-ris.net/list/index.html#list2
8. QLIE 엔진
referenced text strings 검색으로 -> c,$%8x 값을 검색함
가리키는 장소가 아래와 같을때
0050130C . FFFFFFFF DD FFFFFFFF
00501310 . 06000000 DD 00000006
00501314 . 63 2C 24 25 3>ASCII "c,$%8x",0
0050131B 00 DB 00
0050131C /$ 55 PUSH EBP <- 바로 아래 있는 함수를 Ctrl + R 로 레퍼런스 조회
0050131D |. 8BEC MOV EBP,ESP
0050131F |. 6A 00 PUSH 0
00501321 |. 53 PUSH EBX
00501322 |. 56 PUSH ESI
검색된 리스트중
4번째 콜문에서
005465BA |. BA 01000000 MOV EDX,1
005465BF |. 8B45 E8 MOV EAX,DWORD PTR SS:[EBP-18]
005465C2 |. 8B18 MOV EBX,DWORD PTR DS:[EAX]
005465C4 |. FF53 0C CALL DWORD PTR DS:[EBX+C]
005465C7 |. 8B8D 38FEFFFF MOV ECX,DWORD PTR SS:[EBP-1C8]
005465CD |. 8D85 3CFEFFFF LEA EAX,DWORD PTR SS:[EBP-1C4]
005465D3 |. BA FC685400 MOV EDX,かのいな.005468FC
005465D8 |. E8 0FF2EBFF CALL かのいな.004057EC
005465DD |. 8B85 3CFEFFFF MOV EAX,DWORD PTR SS:[EBP-1C4]
005465E3 |. E8 0CCEF3FF CALL かのいな.004833F4
005465E8 |> 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4] ; Default case of switch 0054658E //여기가 후킹지점
005465EB |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
005465EE |. E8 29ADFBFF CALL かのいな.0050131C <- 이곳에서 부른곳
해당 함수는 스택을 쌓지 않고 레지 자체에서 수행
(PUSH 하지 않고 들어간단 소리)
[EBP-4] 포인터 내 대사 있음
[[EBP-4]-0x4] 위치에 대사 길이 누적되어 있음
길이보정 하면 LEN(-4) 나 LEN([[EBP-4]-0x4]) 로 동작됨
예제 코드
HOOK(0x005465E8,TRANS([EBP-0x4],PTRCHEAT,LEN(-4)))
해당 지역에 후킹해서 게임진행시 몇가지 쓰레기 문자가 오는데
그걸 번역하면 에러.
따라서 픽스로 추가 할것을 요망.
(타이틀 부분에서만 덤텍으로 쌓이는거 추가하면 됨.)
확인한 쓰레기(에러나는) 문자
이상한 네모박스 문자
아아아아아 일어로 들어간 문자
테스트 라는 문자가 들어간 명령어
[n] 문자는 개행이므로 그냥 제거
픽스로 해보면 : FixLine.dat
어플실행 추천 (최신버전에서는 노 어플도 가능한걸 확인)
xp 에서는 단순사전 초기화 요망, 7은 관계 없음
9. SiglusEngine 엔진
51 83 C6 0C CPU 창에서 바이너리 검색
찾은 지점 명령어+3 line 지점에 콜문 들어서
스마트로 후킹 [esp+0x4]+0x4
주의. 일부 게임에서는 명령어도 싸그리 오는 경우 발견,
스탠딩 CG가 깨지거나 타이틀 진입시 에러.
그럴 경우는 대사들이 오는 지역을 찾아 코드 분할 후킹, 아래 참조.
______________________________________________________
위 방법은 그다지 좋지 않습니다.
코드가 짧고 손쉬운 점이 있지만
명령어가 일어일 경우 아랄이 참조를 해버리면 깨지기 때문에
에러가 나옵니다.
(캐릭터 이미지가 안나온다던가, 배경음이 안나온다던가 등)
따라서 출력포인트 별로 코드를 분할하는게 좋습니다.
______________________________________________________
코드 분할된것으로 찾기
코드는 무조건 상대주소화
후킹 방식은 "복사본"이 아닌 "원본" 방식으로 모두 전환.
8B 28 8B 48 04 89 6C 24 (18 89 4C 24 1C) ; 괄호 값은 유동성이 있음을 확인
찾은 지역 함수의 맨 윗부분을 스마트로 ecx+0x4 후킹 [이름, 대사, 선택지가 오는장소]
(51) 8B FD 33 DB ; 괄호 값은 유동성이 있음을 확인
찾은 지역에서 명령어 +2 line
스마트로 edi+0x4 후킹 [일부 게임(리라이트)에서 Navi 출력으로 사용]
*이것만 메모리 덮어쓰기로 하는게 낳으려나?(추후 확인해볼 예정)
(51, 52) 83 C6 0C E8 ; 괄호 값은 51과 52값 중 선택하여 포함검색
수없이 찾아지는 장소에서 제일 많이 검색되는 콜문 함수 명령어 복사 후
(예. CALL 0041A990 와 CALL 00496620 가 검색된다고 할때 CALL 0041A990만 수없이 검색된다면 CALL 004A990를 기억)
다시 맨 위로 올려서 바이너리 검색후 기억한 콜문을 Ctrl+L로 다음검색을 하면서 몇번째인지 기억하면서 진행
4~5번째중 한 함수내에 중첩으로 사용하는 곳이 있음(없다면 51,52를 바꿔서 검색)
그곳이 첫부분
세이브,로드 타이틀 4번째 혹은 5번째 (어떻게 생겨먹은지는 머리속에 있으니 알겠지)
세이브,로드 대사 5번째 혹은 6번째
세이브,로드 메모 6번째 혹은 7번째
CALL 0041A990 들어가서 Ctrl+R 로 전체참조 보았을때
해당라인
해당 번째에 있는 4개를
전부 스마트로 [esp]+0x4 후킹
예제코드
FORCEFONT(5),NOASLR,ENCODEKOR,UNIKOFILTER(5),FONT(HY동녘M,-13),
HOOK(SiglusEngine.exe!0x00081C10,TRANS(ECX+0x4,SMSTR,UNICODE,ADDNULL,ONEBYTE),RETNPOS(SOURCE)),
HOOK(SiglusEngine.exe!0x0015FB20,TRANS(EDI+0x4,SMSTR,UNICODE,ADDNULL,ONEBYTE),RETNPOS(SOURCE)),
HOOK(SiglusEngine.exe!0x0015FD0F,TRANS([ESP]+0x4,SMSTR,UNICODE,ADDNULL,ONEBYTE),RETNPOS(SOURCE)),
HOOK(SiglusEngine.exe!0x00168CB6,TRANS([ESP]+0x4,SMSTR,UNICODE,ADDNULL,ONEBYTE),RETNPOS(SOURCE)),
HOOK(SiglusEngine.exe!0x00168D2F,TRANS([ESP]+0x4,SMSTR,UNICODE,ADDNULL,ONEBYTE),RETNPOS(SOURCE)),
HOOK(SiglusEngine.exe!0x00168DA2,TRANS([ESP]+0x4,SMSTR,UNICODE,ADDNULL,ONEBYTE),RETNPOS(SOURCE))
10. KiriKiri 엔진
KAGParser.dll 이 없는경우
66 C7 04 5F 00 00 8B CB 03 C9 83 C4 0C
바이너리 검색 나온지점 포인터 교체
______________________________________________________
KAGParser.dll 를 사용해서 출력하는 경우 (기리기리 이름 처리 기능 사용)
MOV EDI,DWORD PTR DS:[EAX+EDX*8] <-명령어 검색하든지
00A3AA62 68 AC7FA500 PUSH KAGParse.00A57FAC ; UNICODE "TVPLabelOrScriptInMacro" <- 값 찾아도 됨
예제코드
HOOK(KAGParserEx.dll!0x0000AA3A,TRANS([eax+edx*0x8],UNICODE,PTRCHEAT,KIRINAME))
MOV EDX,DWORD PTR DS:[ECX+EAX*8] 이하 동일
00A3B362 68 C880A500 PUSH KAGParse.00A580C8 ; UNICODE " : " <-"띄어쓰기:띄어쓰기" 를 찾아보면 나옴
HOOK(KAGParserEx.dll!0x0000B352,TRANS([ecx+eax*0x8],UNICODE,PTRCHEAT,KIRINAME))
*해당 코드가 사용될경우 사용할 DenyWord 와 FixLine 파일 : DenyWord.ini FixLine.dat
______________________________________________________
psdfile.dll 을 사용해서 UTF-8 <-> WideChar 전환을 하는경우
03 4E 0C 03 45 F8 바이너리 검색하여 첫번째로 검색된 부분 +2 Line
콜문에 [EDX] TJS 스트링방식, 문자열길이보정 [EDX]+0x34, 기리기리는 무조건 유니코드
예제코드
HOOK(0x0041207F,TRANS([EDX],SMSTR(TJSSTR),LEN([EDX]+0X34),UNICODE))
______________________________________________________
공통 사항 (위 3가지중 맞는걸 후킹한 후 이것은 디폴트 적으로 무조건 후킹)
- 컨피그, 선택지, 메시지 창, 마우스 오버 글 등이 번역됩니다.
엔진의 텍스트 스트링 전체에서 drawText 를 찾으면 2개가 검색된다
첫번째로 검색된것으로 가서 맨위로 올라가서 후킹.
[[esp+0x24]] TJS 스트링방식, 문자열길이보정 [[ESP+0X24]]+0X34
예제코드
HOOK(0x00528760,TRANS([[esp+0x24]],SMSTR(TJSSTR),LEN([[ESP+0X24]]+0X34),UNICODE))
11. GSD 엔진(3.0.x.x)
이건 개조가 답이다.
텍스트 스트링이 들어있는 메모리 내에서
83 4A 83 58 83 5E 83 바이너리 검색
나온곳 1개 함수 아래에 첫번째부터 가로채서 개조.
(개조내용은 나중에)
D2 D3 D8 B1 DB B9 B0
마찬가지로 바이너리 검색
나온곳 2개 함수 아래에 좀더 내리면
ADD xxx, 184 가 2중으로 겹친게 있다면
그 사이 콜문 [esp]+0x4 스마트 방식으로
(Fizz 사에 뚫었던 3.0.1.0 버전인가는 스마트가 아닌 그냥 포인터 바꿔치기)
12~. 차후 하나씩 늘려갈 계획.
(시간나면 말이죠..)
일단 해당 야메 찾기 방법들은
제가 엔진들을 대충(?열심히) 분석후 컴파일시 발생되는 일부 패턴을 모아
차후 게임에서도 손쉽고 빠르게 코드를 찾기 위해
(이른바 귀찮아서) 작성한 것들입니다.
물론 찾아내가는 과정은 너무 길고 설명하기 복잡(귀찮아)하기에
나중에 미루기로..(할지 안할지 자신도 모르기에) 하겠습니다.
어디까지나 개인적인 꼼수며 굳이 이런 방법으로 찾지 않으셔도 됩니다.
머리속에 박혀있는 수많은 엔진 패턴을 글로 나열하기란
과연 귀찮아서 무리에요.
(오래된 게임을 다시하려고 할때 팟팟 코드 찾아서 할 수 있다는건 역시.....좋은겁니다)
.....훗.
그리고 아직 밝히지 않은 개인적인 꼼수 스킬 마져도 더 남아 있다는게 에러.
언젠가 전부 적는 날이 오겠지요?
(.......일거리를 자신이 늘리고 괴로워한다지)
파일은 다 깨졌군요. ㅠㅠ