Rain = nothing to do with DLL. It's only part of the new 1977 Butchered executable I included. The crash (and rain) does not happen with the old Butchered International (without rain) regardless of which version of the DLLs you use.
The only change in the newer game.exe is the rain. Nothing else. So the DLLs work just as well with either version of the game.exe.
As to your other concerns... I'm struggling because your offsets are nothing like the ones in 1977, which is pretty much the only way I can debug them. Any report not based on one or the other 1977 based KPT really is pretty useless to me. But...
In 1977:-
Code:
7043000 = "신성한 마법으로 생명력을 회복 시켜준다."
As for your string at 51666824, that has already been string concatenated from smaller ones into a temporary buffer. (strcat() that's what it does, and where it's name comes from, you know? :wink:)
In KPT 1977 there is only one message (that I have found) "Disconnecting from server" and it appears if you hit the close box, Alt F4, the server goes off-line, or for any other reason, as far as I can tell. The Korean string is always the same, and the address it's located at is also always the same.
!!Good news!!
I've developed a tool that will extract strings, and their location from a section dump and it's hex offset.
If you open the game with CFF Explorer, go to the section headers, select .data or .rdata and right click -> "Dump section" out to a file. Then check the offset of that section in memory in OllyDbg, you can run "ExtractStrings 1977.RData 5C4000 > KoRData.txt", for example, and get a text file that is pretty much a .lng file for the original Korean.
Comparing that text file with one from an English, or Brazilian (or Chinese) executable will quickly give you a good idea of what the string is meant to mean... checking with Google Translate is a good idea too, but it gets you to the source quite quickly. :wink:
Problems I notice, having used this tool to good effect:-
Some strings in PT which are strcat() together, have \n or \r in them (0x0D or 0x0A) and this can't exist in a .ini file... so this program encodes them as "\n" or "\r" and includes "\e" "\t" "\v" and "\\" of course... it encodes double quotes as "\042"... but I'm going to have to include this in the DLLs so that they can include turn those back into the ASCII codes for "new line" "carriage return" etc. So I'm afraid I'm bumping that up ahead of offsets and colours and stuff.
If there is some memory copy routine (and I still suspect there is) which we can pin down that is causing these strings not to appear until after they have been copied out of the executable image, I will add that to the list of APIs patched... but I need to know what it is first.
13-12-10
SheenBR
Re: Beta Technical Demonstration - Translation without Hexing the EXE
WOW, I'll definately check this out.
---------- Post added at 02:48 AM ---------- Previous post was at 02:28 AM ----------
Well, it DOES "help"...
But I mean, its kind hard to find where is that string is from. I mean, with the debugger DLL, you just put the mouse in the Frenzy Armor, stays for a while and then logs out. In the txt file, you just search for Frenzy Armor and you will see everything you need to translate. With this new program, is kinda hard to do that. Can u see what I am talking?
---------- Post added at 03:13 AM ---------- Previous post was at 02:48 AM ----------
One bug, I gues.
This is the Healing skill description:
신성한 마법으로 생명력을 회복 시
켜준다
With the dll debuger:
lstrcat(), 1243828, "신성한 마법으로 생명력을 회복 시
켜준다.", "/* Not Replaced */"
This 1243828 is taken to patch, MP cost, STM cost, required level and so on, so this cant be used. Then, I used your new program and searched the txt for the decription. Found this:
7082880 = "신성한 마법으로 생명력을 회복 시켜준다."
Then, I did:
7082880 = "Cura os personagens escolhidos /n com a benção divina /n"
Nothing happens. Why?
---------- Post added at 03:20 AM ---------- Previous post was at 03:13 AM ----------
I think there's some math we have to do.
ExtractStrings:
7083116 = "홀리 볼트"
Dll debugger:
wsprintf(), 51648548, "홀리 볼트", "/* Not Replaced */"
7083116
-
51648548
=
44565432
So, we need to sum 44565432(in my case) with the number found in the dump section to patch? IDK, its my guess.
---------- Post added at 03:21 AM ---------- Previous post was at 03:20 AM ----------
well, it doenst work with the Healing skill description...
---------- Post added at 03:44 AM ---------- Previous post was at 03:21 AM ----------
and my game is crashing after a few seconds logged in. it doestn matter the map, the game always crash.
13-12-10
bobsobol
1 Attachment(s)
Re: Beta Technical Demonstration - Translation without Hexing the EXE
I can see you've got the hang, and the point of the new program perfectly.
The address it gives is the initial address of the string when the game fist starts, and that is what we should ideally be patching. At that location it is that string and only that string. If we can't see the string being accessed at that location in the log, and therefore can't patch that location, then we are forced to patch too late.
So the question is, what routine moves the string from there to the location in which we first log it... a location which is not guaranteed to always contain that string, and only that string.
You see now why I created it? And, I think you can see it is very easy to look up the address that we should find a string at.
This wouldn't really be needed if we could search for strings in Korean in Olly, but I've not found a sensible way to do that. XD
Anyway, I suspect there is a strcpy() / memcpy() routine, possible from the MSVCRT7.1.lib which is linked into the executable which needs redirecting, but I haven't found strings which aren't being patched in my 1977 translation yet, and I can't use the addresses from your 198x version which are completely different from mine.
I know your goals are different from mine, but I'd appreciate some help from you, so that I can help you in return by making this more "all inclusive". Right now, there is clearly a *major* function which is moving text strings (or blocks of memory) without these DLLs seeing that move, and I / we need to track it down and trap it. :wink:
I hope you can now see why I need playtesting from the same exe. You've already proved that the method is easy to port to a different client exe, but unless we make it rock solid on one, we're quoting page, chapter and sentence numbers from different print editions. They don't match up, and you can't debug or trace back from that.
The section dumps help, but they're still not as good as having the address / offset from the same client version. If I go in and use Olly to trap memory access on the offsets in your client, that isn't going to show the bug in mine, it will just point me to something completely different. And if the Korean string is even slightly different in yours, I'm not going to find it's offset in mine, however I present it. :*:
I'm about ¼, maybe less through my RData section... and so far it's mostly strings that either don't come up often, or are not a problem to patch. Finding the ones you have identified as problematic is not proving easy... but I'm working on it.
Also, I'm considering allowing the .lng file to take offsets in Hex, as that should show clearly which memory section they are in, in the same manner as they are displayed in Olly. Currently, you have to take the offset and convert it to Hex to see where it is in Olly.
eg.
Quote:
Originally Posted by lelejau
wsprintf(), 51648548, "홀리 볼트", "/* Not Replaced */"
51648548 is 03141824 in Olly. I know that's probably part of the Data section which runs from 0x005F9000 to 0x0444EFF0 in my client, but the "initialised" data, only runs up to 0x00222000, which means it's been copied there from somewhere else, and we should patch that copy operation first.
You may notice that there are very few strings which need patching in the .data section... most are in .rdata... so when we can only find them after they have already left there, they are either one of the few that really are in .data, come from a file, or from the server, or are actually moved to the location at which we first find them, and that's the problem point.
What moved them? Is it a DLL API, is it a compile time linked library? Is it some specific routine they wrote directly in the C code for PT? Right now, I don't know, because you seem to find lots of them, and I can only find one... but I don't doubt that you are finding them. I just can't do much with the most of the information you are giving me, because it relates to a different base.
Speaking of which, I hope you don't have any problems with the old game.exe and the new libraries... I certainly haven't had.
Oh yea... I was also thinking to use an Exe Index file, so that we can index offsets, and only the index needs to be changed to make the .lng file work on a different executable. Does that idea appeal?
[Strings]
0000 = "Connecting to Server..."
0001 = "Connection Failed!"
0002 = "Please enter login details!"
0003 = "Invalid user name or password!"
0004 = "Continue this adventure?"
0005 = "Are you sure you want to delete?"
They could also be in the same file, with the .ini style section headers... but since the same index can be used with multiple .lng files, I thought it would save space to keep it in a separate file, unless there is a good argument against doing that. (I'm coding by democracy here XD)
rather complex routine located at 00593D60 in 1977.
Can you confirm a similar routine in your client (almost certainly at a different location) causing these memory moves?
I can see it checking the length of the string, looking for a suitable memory hole, copying it, and then making changes to the colours of the hDC for the display.
Olly thinks it takes 6 parameters, but I can see it checking a 7th, which would be something left on the stack from the former routine... and that I don't understand.
Should I reimplement this entire routine in the assembler DLL (that I probably could never re-work into C) and replace it in the exe with one that redirects to the new DLL routine, or should I force it to call strcpy() to a known clear location and then replace Arg3 with that location? That would make more sense in the long run, but is a little messy... don't you think?
It's not part of MSVCRT7 compiled into the exe... this is clearly something very custom that PT is doing. :/:
--- EDIT2 ---
That routine seems to be preparing the centre of screen dialogue texture for the text to be displayed on top of. Not entirely sure why it doesn't perform the DrawText() API on to that texture, then it wouldn't have to keep performing it on the main display after the dialogue overlay. :?:
Anyway, I've implemented the C string escape codes in IntStr.dll, now at v0.0.2 and come across another minor typo that was eating up silly amounts of memory, so (although it wont fix the texts displayed on to the centre of screen dialogues) seems to run faster, and uses less memory, despite the DLL size increase from properly breaking out C escape codes... please find it attached.
\/\/\/\/\/\/\
Note: Only implemented escape sequences are those found here. C++, and Win32 programmers may expect to find more, most notably \h0d operating the same as \n ... these uses will produce "\* error *\" instead. I don't think most are important, but when I get time I will revise the list of supported escape codes.
/\/\/\/\/\/\/\
Oh, and it's "Logging" version also logs all strings read from the .lng file, and how they are interpreted from a C escaped string (\n carriage return, \l new line etc) into a pure binary string. (This means skipping an indeterminate number of lines when importing into a spreadsheet, but I think it's useful information for developing .lng files. :wink:
13-12-10
SheenBR
Re: Beta Technical Demonstration - Translation without Hexing the EXE
Bob, you didnt answer my questions, about the skill description, etc..
and one great idea is:
Quote:
Originally Posted by 0016.lng
#include descriptions.lng
55555=Test
Quote:
Originally Posted by description.lng
121211=Another Patch
You see? :P
13-12-10
bobsobol
Re: Beta Technical Demonstration - Translation without Hexing the EXE
Quote:
Originally Posted by lelejau
Bob, you didnt answer my questions, about the skill description, etc...
Yes I did. At great length, though I'm not sure it's part of the same code which makes the middle of the screen displays, it will be a similar reason.
The DLLs aren't seeing those strings until they have already been moved to a generic buffer.
I don't understand your description of this "great idea". You just want "#include" so you can break the file down into lots of little ones? That could get confusing pretty fast I think. Complete translation will be under 1meg, since all strings extracted from the game, along with all offsets and other non-string data is 900 odd K in .lng form.
We're talking about a file less than 1000 lines long, even if you patch every URL, Path, INI command, ASE string and LUA instruction.
Though with those features in mind, I can see a use for a file that contains URL, SQL etc patches that will be applied regardless of language.
14-12-10
SheenBR
Re: Beta Technical Demonstration - Translation without Hexing the EXE
bob, would you mind to try to patch any skill description? I cant patch skills description here...
Would you mind?
14-12-10
bobsobol
Re: Beta Technical Demonstration - Translation without Hexing the EXE
Love to. Wanna tell me how? :ott1:
The descriptive strings undergo considerable movement inside game.exe it's self.
Initially they are moved into a new table filled with all the Skill details using simple Rep MovS DWord Ptr[EDI],DWord Ptr[ESI] (this happens just after player select BTW) and later seem to go through some routine which splits them by inserting Carriage Return characters into them every X letters... I can't find that routine, and attempting to debug near it is causing fatal exceptions.
Maybe if I made the Rep MovS DWord Ptr[EDI],DWord Ptr[ESI] a strcpy() that would clear up the rest? Trouble is, I'm not convinced that the string is the only data that routine is moving... but I'll give it a shot, even if I have to move the string, and then use Rep MovS everything that isn't part of the string.
--- EDIT ---
Having humanised the initial offender as best I can, I propose moving the following routine to a space I have already cleared (along with my many XTrap and other defunct code removals) in a state altered like so:-
Code:
004ADA80 mov eax,[30FF368] ; (guessed void)
004ADA85 mov eax,[eax+0B4]
004ADA8B dec eax ; Switch (cases 1..8, 9 exits)
004ADA8C cmp eax,7
004ADA8F push ebp
004ADA90 mov ebp,ecx
004ADA92 ja short .CaseDef
004ADA94 jmp [eax*4+.CaseTab]
.Case1 mov dword ptr [ebp+14],2000000 ; Case 1 of switch
004ADAA2 jmp short .CaseDef
.Case2 mov dword ptr [ebp+14],1000000 ; Case 2 of switch
004ADAAB jmp short .CaseDef
.Case3 mov dword ptr [ebp+14],4000000 ; Case 3 of switch
004ADAB4 jmp short .CaseDef
.Case4 mov dword ptr [ebp+14],3000000 ; Case 4 of switch
004ADABD jmp short .CaseDef
.Case5 mov dword ptr [ebp+14],6000000 ; Case 5 of switch
004ADAC6 jmp short .CaseDef
.Case6 mov dword ptr [ebp+14],5000000 ; Case 6 of switch
004ADACF jmp short .CaseDef
.Case7 mov dword ptr [ebp+14],8000000 ; Case 7 of switch
004ADAD8 jmp short .CaseDef
.Case8 mov dword ptr [ebp+14],7000000 ; Case 8 of switch
.CaseDef mov eax,[ebp+14] ; Default case of switch
004ADAE4 test eax,eax
004ADAE6 je .Label4
004ADAEC push ebx
004ADAED push esi
004ADAEE push edi
004ADAEF mov eax,1
004ADAF4 mov ecx,84
004ADAF9 mov esi,006BC278
004ADAFE mov edi,03136580
004ADB03 rep movs dword ptr [edi],dword ptr [esi]
004ADB05 mov [31365E4],eax
004ADB0A mov [31365E8],eax
004ADB0F mov dword ptr [3136784],3000000
004ADB19 mov [31365EC],eax
004ADB1E mov ebx,6BC278
.Loop0 /mov ecx,[ebx+20]
004ADB26 |mov eax,[ebp+14]
004ADB29 |and ecx,FF000000
004ADB2F |cmp ecx,eax
004ADB31 |jne .Label3
004ADB37 |mov edx,1
004ADB3C |mov eax,31367F4
.Loop1 |/cmp dword ptr [eax],0
004ADB44 ||je short .Label0
004ADB46 ||add eax,210
004ADB4B ||inc edx
004ADB4C ||cmp eax,31388F4
004ADB51 |\jl short .Loop1
004ADB53 |jmp short .Label3
.Label0 |mov eax,edx
004ADB57 |imul eax,eax,210
004ADB5D |lea edi,[eax+3136580]
004ADB63 |mov ecx,84
004ADB68 |mov esi,ebx
004ADB6A |rep movs dword ptr [edi],dword ptr [esi]
004ADB6C |mov edi,[eax+31365A0]
004ADB72 |xor esi,esi
004ADB74 |mov ecx,6B0814
004ADB79 |lea esp,[esp]
.Loop2 |/cmp edi,[ecx]
004ADB82 ||je short .Label1
004ADB84 ||add ecx,12C
004ADB8A ||inc esi
004ADB8B ||cmp ecx,6BC394
004ADB91 |\jl short .Loop2
004ADB93 |jmp short .Label2
.Label1 |imul esi,esi,12C
004ADB9B |add esi,6B06F8
004ADBA1 |lea edi,[eax+3136664]
004ADBA7 |mov ecx,4B
004ADBAC |dec edx
004ADBAD |rep movs dword ptr [edi],dword ptr [esi]
004ADBAF |mov [eax+313678C],edx
.Label2 |mov dword ptr [eax+31365E4],1
push esi
push edi
call dword ptr[<&KERNEL32.lstrcpyA>]
.Label3 |add ebx,210
004ADBC5 |cmp ebx,6D0C78
004ADBCB \jl .Loop0
004ADBD1 mov ecx,88
004ADBD6 mov esi,6D0C78
004ADBDB mov edi,3138890
004ADBE0 rep movs dword ptr [edi],dword ptr [esi]
004ADBE2 mov ecx,ebp
004ADBE4 call 004AAC90
004ADBE9 mov eax,1
004ADBEE mov ecx,ebp
004ADBF0 mov [31365E8],eax
004ADBF5 mov dword ptr [3136784],3000000
004ADBFF mov [31365EC],eax
004ADC04 call 004AC740
004ADC09 pop edi
004ADC0A pop esi
004ADC0B pop ebx
.Label4 xor eax,eax
004ADC0E pop ebp
004ADC0F ret
.CaseTab dd .Case1
004ADC14 dd .Case2
004ADC18 dd .Case3
004ADC1C dd .Case4
004ADC20 dd .Case5
004ADC24 dd .Case6
004ADC28 dd .Case7
004ADC2C dd .Case8
This routine is only called from 3 locations, so those calls will need to be updated to point to the new routine. However, there is no room for manoeuvring extra instructions into this routine, and despite my best efforts I can see no way to "bum this code down". But then I still don't really understand what it is doing properly. Seems to be taking the initial table from constant memory and placing it in a variable data structure in a less compressed form, allowing room for other "properties" to be modified on-the-fly... and only moves out data appropriate to the current character class. This does give all these details a static location, regardless of the current character class, and provide room in writeable memory, but if that is truly what it is doing, why not load this from an external file, or at least use the ZLib library that's included into game.exe to extract a solid lump into the right area? Not sure... don't know that I care right now either.
This should give you an "in" to patching this string before it becomes broken down and moved into a common area for displaying all kinds of stuff.
If anyone can see a blindingly obvious reason why this shouldn't work, please speak now. :lol: I can already see that "004ADB93 |jmp short .Label2" may give me some grief. :(:
14-12-10
SheenBR
Re: Beta Technical Demonstration - Translation without Hexing the EXE
IMHO, I didnt understand nothing you said, lol.
But good luck, I know you can handle it.
15-12-10
bobsobol
Re: Beta Technical Demonstration - Translation without Hexing the EXE
7019600 = "Goes berserk for a short periodof time, but loses health with each attack"
Specifically, you have to make sure words do not stretch over the 32nd and 58th character in the string, where (if the string is long enough) new line characters will be inserted. :(:
This really does have to be fixed in the exe... there isn't a practical way to patch rep movs via DLL, but I think there is more improvement to be made by replacing code of this nature all together.
subClassSkillTable:
mov eax,[30FF368] ; (guessed void)
mov eax,[eax+0B4]
dec eax
cmp eax,7
push ebp
mov ebp,ecx
ja short CaseDef
jmp [eax*4+CaseTab]
Case1 mov dword ptr [ebp+14],02000000
jmp short CaseDef
Case2 mov dword ptr [ebp+14],01000000
jmp short CaseDef
Case3 mov dword ptr [ebp+14],04000000
ja short CaseDef
Case4 mov dword ptr [ebp+14],03000000
jmp short CaseDef
Case5 mov dword ptr [ebp+14],6000000
jmp short CaseDef
Case6 mov dword ptr [ebp+14],5000000
jmp short CaseDef
Case7 mov dword ptr [ebp+14],8000000
jmp short CaseDef
Case8 mov dword ptr [ebp+14],7000000
CaseDef mov eax,[ebp+14]
test eax,eax
je Label4
push ebx
push esi
push edi
mov eax,1
mov ecx,84
mov esi,006BC278
mov edi,03136580
rep movs dword ptr [edi],dword ptr [esi]
mov [31365E4],eax
mov [31365E8],eax
mov dword ptr [3136784],03000000
mov [31365EC],eax
mov ebx,006BC278
Loop0 mov ecx,[ebx+20]
mov eax,[ebp+14]
and ecx,FF000000
cmp ecx,eax
jne Label3
mov edx,1
mov eax,031367F4
Loop1 cmp dword ptr [eax],0
je short Label0
add eax,210
inc edx
cmp eax,031388F4
^jl short Loop1
jmp short Label3
Label0 mov eax,edx
imul eax,eax,210
lea edi,[eax+3136580]
mov ecx,84
mov esi,ebx
rep movs dword ptr [edi],dword ptr [esi]
mov edi,[eax+31365A0]
xor esi,esi
mov ecx,006B0814
lea esp,[esp]
Loop2 cmp edi,[ecx]
je short Label1
add ecx,12C
inc esi
cmp ecx,006BC394
^jl short Loop2
jmp short Label2
Label1 imul esi,esi,12C
add esi,006B06F8
lea edi,[eax+3136664]
mov ecx,4B
dec edx
mov [eax+313678C],edx
Label2 mov dword ptr [eax+31365E4],1
call subStrCpy
Label3 add ebx,210
cmp ebx,006D0C78
^jl Loop0
mov ecx,88
^jl Loop0
mov esi,006D0C78
mov edi,03138890
rep movs dword ptr [edi],dword ptr [esi]
mov ecx,ebp
call 004AAC90
mov eax,1
mov ecx,ebp
mov [31365E8],eax
mov dword ptr [3136784],03000000
mov [31365EC],eax
call 004AC740
pop edi
pop esi
pop ebx
Label4 xor eax,eax
pop ebp
ret
subStrCpy /$ push esi
|. push edi
|. rep movs dword ptr [edi],dword ptr [esi]
|. pop edi
|. pop esi
|. push esi ; /String2 => ARG.ESI
|. push edi ; |String1 => ARG.EDI
|. call [<&KERNEL32.lstrcpyA>] ; \KERNEL32.lstrcpyA
|. add esi,40
|. add edi,40
|. push esi ; /String2 => ARG.ESI+40
|. push edi ; |String1 => ARG.EDI+40
|. call [<&KERNEL32.lstrcpyA>] ; \KERNEL32.lstrcpyA
|. add esi,40
|. add edi,40
\. ret
--- EDIT --- Okay... spent some time play-testing and, no, I'm not getting any crashes during general play... shopping, hunting etc.
I do get severe locukups using the logging version both during loading and displaying player skills... but there is a lot of work put on the DLLs at those points, and that means a lot of work for the FS (which will always be slow) when logging is enabled.
16-12-10
SheenBR
Re: Beta Technical Demonstration - Translation without Hexing the EXE
There isnt enough space to make these modifications: