 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
Razi Expert Cheater
Reputation: 1
Joined: 17 Jan 2018 Posts: 205
|
Posted: Mon Jan 13, 2020 4:05 pm Post subject: read specific string |
|
|
I want to read game's specific text (items description). Game stores strings as ASCII values offset - 0x20. But strings contains specific value F9 function. F9: This is an encoding technique designed to make the raw data smaller. A byte following this value will tell the game's memory the location of, and how much, text to read. The byte is set up like this:
In binary:
YYXXXXXX
Where YY is the number of bytes to read and XXXXXX is how far back from the F9 byte to look.
The number of bytes to read uses the formula:
no_of_bytes = (YY) * 2 + 4 [Where YY is binary]
The location starts at the position that the data read the byte F9 and proceeds backwards XXXXXX + 1 times.
Example:
34 48 52 4F 57 00 49 54 45 4D 53 00 44 41 4D 41 47 49 4E 47 00 4F 50 50 4F 4E 45 4E 54 FF 34 52 41 4E 53 46 4F 52 4D F9 92 54 00 49 4E 54 4F 00 41 4E F9 2C 4D FF
- T - h - r - o - w ---- i - t - e - m - s ---- d - a - m - a - g - i - n - g ---- o - p - p - o - n - e - n - t ---- T - r - a - n - s - f - o - r - m - ? - ? - t ------ i - n - t - o ---- a - n - ? - ? - m
where: 0x00: Space, 0xFF: end of text.
Game displays description: Throw items damaging opponent ---- Transform opponent into an item
In the example we have two F9 functions. The first one references the " opponen" in the word " opponent" earlier, in the previous item description and the second one references the " ite" in the " items". The bytes following the F9 describe how to get to those texts:
in hex: 0x92
in binary: 10 010010 - go back (binary:010010=18 +1) 19 bytes and display (binary:10=2; 2 * 2 + 4) eight characters
in hex: 0x2C
in binary: 00 101100 - go back 45 bytes and display four characters
I have function that can read text without F9, but if text contains F9 it does not work (CE error: bad argument #1 to 'char' (value out of range)). And also need to skip the next byte after the F9, and do not read it.
| Code: | local function readDescription(addr, len)
len = len or 92 -- defaults to 92
local bytes = readBytes(addr, len, true)
local chars = {}
for k,v in ipairs(bytes) do
if v == 0xF9 then
local a = readBytes(addr+k) --if v == 0xF9 then read next byte value
local no_of_bytes = (a >> 6) * 2 + 4 --The number of bytes to read: no_of_bytes = (YY) * 2 + 4 [Where YY is binary]
local b = (bAnd(0x3F, a)) + 1 --from F9: proceed backward XXXXXX + 1 times
local bytesss = readBytes(addr+k-1-b, no_of_bytes, true) --from F9: proceed backward
for ke,ve in ipairs(bytesss) do
if ve == 0xFF then break end
chars[#chars+1] = string.char(ve+0x20) -- or: table.insert(chars, string.char(ve+0x20))
end
elseif v == 0xFF then break -- Is it allowed to do this without 'end'?
else
chars[#chars+1] = string.char(v+0x20)
end
end
return table.concat(chars,'')
end |
Can you point where the error is?
Error is found, and function reads string with F9, but how to skip next byte after F9, and not read it?
Also need to know how to change value to word: if byte value == F8, then add the word 'Box:' to the table and read the next byte after F8, if byte == 0x02, then add the word 'Red' to table, so in total it should add words 'Box: Red' to table. And again need to skip next byte after F8, and not read it.
Last edited by Razi on Tue Jan 14, 2020 8:13 pm; edited 3 times in total |
|
| Back to top |
|
 |
panraven Grandmaster Cheater
Reputation: 62
Joined: 01 Oct 2008 Posts: 959
|
Posted: Tue Jan 14, 2020 12:37 am Post subject: |
|
|
CE blocked me for the original text, replied here
https://pastebin.com/fLryitjd
| Quote: | I would separate memory read (slow if byte by byte) and decoding (fast on a piece of string). So the following only suggest a more easier way to do different special code (f8/f9/ff) handling on string.
The point here is to separate the handling into smaller function that specialize itself.
... |
Sorry, missing the part you asked.
To fix your for-loop code you probably need some flag/counter to indicate that next loop/byte has to be SKIPPED, for instance, 0xf9 process 2 bytes each time, while 0xff and literal 1 byte, and, let's say, 0xf8 need 8 bytes, then make some SkipCounter as 0xf9->1; 0xff / literal-> 0 ; 0xf8 -> 7 then first test
| Code: |
if SkipCounter>0 then SkipCounter = SkipCounter - 1 else
.... your other 0xf9/0xff ... processing
|
_________________
- Retarded. |
|
| Back to top |
|
 |
Razi Expert Cheater
Reputation: 1
Joined: 17 Jan 2018 Posts: 205
|
Posted: Tue Jan 14, 2020 7:34 pm Post subject: |
|
|
| panraven wrote: | CE blocked me for the original text, replied here
https://pastebin.com/fLryitjd
| Quote: | I would separate memory read (slow if byte by byte) and decoding (fast on a piece of string). So the following only suggest a more easier way to do different special code (f8/f9/ff) handling on string.
The point here is to separate the handling into smaller function that specialize itself.
... |
|
I'm a complete newbie with strings, haven't worked with them before. What method is needed to pass bytes to a function (which bytes to process), readBytes?
| Code: | local txt = readBytes(0x009AF6B2, 72, true)
unlzo(txt)
| But, of course this does not work.
|
|
| Back to top |
|
 |
panraven Grandmaster Cheater
Reputation: 62
Joined: 01 Oct 2008 Posts: 959
|
Posted: Wed Jan 15, 2020 3:24 am Post subject: |
|
|
I guess you can do it in a for loop on txt, or use CE function byteTableToString
| Code: |
local txt = byteTableToString(readBytes(0x009AF6B2, 72, true))
|
I make another version more like your code, different is it is in a while loop, and addr has to be update according to the 1st byte read in each loop iteration.
| Code: |
autoAssemble[[
globalalloc(__,$1000)
__:
db 34 48 52 4F 57 00 49 54 45 4D 53 00 44 41 4D 41 47 49 4E 47 00 4F 50 50 4F 4E 45 4E 54 FF 34 52 41 4E 53 46 4F 52 4D F9 92 54 00 49 4E 54 4F 00 41 4E F9 2C 4D ff
db fe // our endByte for test
]]
local chr, sub, cat = string.char, string.sub, table.concat
function readDesc(addr, endByte)
addr = GetAddressSafe(addr) -- convert to numeric address
local now = os.clock() -- prevent inf loop
local acc = '' -- our to be return string
while true do
if os.clock()-now>10 then break end -- prevent inf loop
local b = readBytes(addr)
if b==endByte then -- ok done
return acc, addr
elseif b==0xff then --- multiple elseif on same variable is like SWITCH-CASE
-- may same as endByte, but if not the same, 0xff
-- can make output like new-line, and continue scan
-- for new line
addr, acc = addr+1, acc .. '\r\n'
elseif b==0xf9 then
b = readBytes(addr+1) -- the encoded len,ofs byte
local l, o = (b >> 6)*2+4, (b & 0x3f)+1
b = readBytes(addr-o, l, true)
for i=1,l do -- convert byte to valid string
b[i] = chr(b[i]+0x20)
end
addr, acc = addr+2, acc .. cat(b)
-- elseif b==0xf8 then
-- process 0xf8 ...
else -- is literal
addr, acc = addr + 1, acc .. chr(b + 0x20)
end
end
end
print(readDesc("__", 0xfe))
print(readDesc("__", 0xff)) -- endByte is 0xff, will work like your original code
|
-> https://pastebin.com/RMXRXjC9
there will still be error like (CE error: bad argument #1 to 'char' (value out of range)) if the addr input is not right.
_________________
- Retarded. |
|
| Back to top |
|
 |
Razi Expert Cheater
Reputation: 1
Joined: 17 Jan 2018 Posts: 205
|
Posted: Thu Jan 16, 2020 12:42 am Post subject: |
|
|
| panraven wrote: | I make another version more like your code, different is it is in a while loop, and addr has to be update according to the 1st byte read in each loop iteration.
-> https://pastebin.com/RMXRXjC9
there will still be error like (CE error: bad argument #1 to 'char' (value out of range)) if the addr input is not right. |
| Code: |
local chr, sub, cat = string.char, string.sub, table.concat
function readDesc(addr, endByte)
addr = GetAddressSafe(addr) -- convert to numeric address
local now = os.clock() -- prevent inf loop
local acc = '' -- our to be return string
while true do
if os.clock()-now>1 then break end -- prevent inf loop
local b = readBytes(addr)
if b==endByte then-- ok done
return acc
elseif b==0xf9 then
b = readBytes(addr+1) -- the encoded len,ofs byte
local l, o = (b >> 6)*2+4, (b & 0x3f)+1
b = readBytes(addr-o, l, true)
for i=1,l do -- convert byte to valid string
if b[i] == 0xFF then break -- this line prevents from CE error: bad argument #1 to 'char' (value out of range)
else
b[i] = chr(b[i]+0x20)
end
end
addr, acc = addr+2, acc .. cat(b)
-- elseif b==0xf8 then
-- process 0xf8 ...
else -- is literal
addr, acc = addr + 1, acc .. chr(b + 0x20)
end
end
end
UDF1.CEEdit106.Text = readDesc(baseaddr+0x5AF5C0+val, 0xFF)
|
Now it works almost as it should, but if there are two 0xFF in the byte string, then 255 is displayed in the edit box (ex.: 'Steal item255', but should display: 'Steal item'). Example
45 00 49 54 45 4D FF 33 54 45 41 4C F9 4A FF
- e ---- i - t - e - m ----- S - t - e - a - l - ? - ?
0x4A= 01 001010 - go back 11 bytes and display 6 characters
from F9 it goes back and reads bytes (00 49 54 45 4D FF == word ' item' with 0xFF), then returns back after 0x4A and reads another 0xFF. But the description should be: Steal item. How to fix this?
|
|
| Back to top |
|
 |
panraven Grandmaster Cheater
Reputation: 62
Joined: 01 Oct 2008 Posts: 959
|
Posted: Thu Jan 16, 2020 1:04 am Post subject: |
|
|
A quick fix may be (not test)
| Code: |
-- change
if b[i] == 0xFF then break -- this line prevents from CE error: bad argument #1 to 'char' (value out of range)
else
b[i] = chr(b[i]+0x20)
end
-- to
b[i] = b[i]>0xc9 and '' or chr(b[i]+0x20)
|
this collect an empty string instead if the byte will be more than 0xff after +0x20, and not break the loop.
_________________
- Retarded. |
|
| Back to top |
|
 |
Razi Expert Cheater
Reputation: 1
Joined: 17 Jan 2018 Posts: 205
|
Posted: Thu Jan 16, 2020 2:48 am Post subject: |
|
|
| panraven wrote: | A quick fix may be (not test)
| Code: | b[i] = b[i]>0xc9 and '' or chr(b[i]+0x20)
|
this collect an empty string instead if the byte will be more than 0xff after +0x20, and not break the loop. |
It works, thanks a lot for the help.
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|