Symphony of War: Nephilim Sage Item Scripts

Upload your cheat tables here (No requests)
Littlepain
What is cheating?
What is cheating?
Posts: 1
Joined: Sat Aug 27, 2022 4:30 pm
Reputation: 0

Re: Symphony of War: Nephilim Sage Item Scripts

Post by Littlepain »

So, I realized something after some testing. I could never get the values to update from ?? in my early chapters 2,3 so far (if anyone else can I'd love to know) I could however get it to work on chapters 5 and 6 on my other saves. Progressed past 3 into 5 and works as intended. I don't know why you can't in the early chapters but, at least that might explain why it doesn't work for some.

How to use this cheat table?
  1. Install Cheat Engine
  2. Double-click the .CT file in order to open it.
  3. Click the PC icon in Cheat Engine in order to select the game process.
  4. Keep the list.
  5. Activate the trainer options by checking boxes or setting values from 0 to 1

tehchanman
What is cheating?
What is cheating?
Posts: 1
Joined: Fri Sep 23, 2022 9:34 pm
Reputation: 0

Re: Symphony of War: Nephilim Sage Item Scripts

Post by tehchanman »

Any chance we can get an update? New update today, im assuming pointers are off now but I have no idea

YaBoi
What is cheating?
What is cheating?
Posts: 2
Joined: Wed Oct 12, 2022 1:45 pm
Reputation: 0

Re: Symphony of War: Nephilim Sage Item Scripts

Post by YaBoi »

Please update

User avatar
seikur0
Code Alchemist
Code Alchemist
Posts: 440
Joined: Sat Aug 26, 2017 10:48 am
Reputation: 339

Re: Symphony of War: Nephilim Sage Item Scripts

Post by seikur0 »

Just dropping my table with two options here:
-Never decrease gold
-Never decrease stackable resources (i.e. items, also includes horses etc.)

Feel free to add those to your table @Hentai-san.

(Tech-scrolls are not included, they use a different system, I think they aren't even saved as resouce amount but as experience, more similar to gold.)
Attachments
SymphonyOfWar_SeiKur0_v2.1.CT
>=1.02.2 steam version of game
(7.89 KiB) Downloaded 6378 times
SymphonyOfWar_.SeiKur0_v1.CT
1.02.1 steam version of game
(5.45 KiB) Downloaded 1453 times
Last edited by seikur0 on Wed Nov 23, 2022 4:22 pm, edited 4 times in total.

somberstrekking
Fearless Donors
Fearless Donors
Posts: 6
Joined: Wed Oct 26, 2022 12:18 am
Reputation: 1

Re: Symphony of War: Nephilim Sage Item Scripts

Post by somberstrekking »

seikur0 wrote:
Sat Oct 15, 2022 8:58 pm
Just dropping my table with two options here:
-Never decrease gold
-Never decrease stackable resources (i.e. items, also includes horses etc. and maybe tech scrolls too)

Feel free to add those to your table @Hentai-san.

(for the 1.02.1 steam version)
This has been the best script I have found by far. Would gladly tip for an update

User avatar
seikur0
Code Alchemist
Code Alchemist
Posts: 440
Joined: Sat Aug 26, 2017 10:48 am
Reputation: 339

Re: Symphony of War: Nephilim Sage Item Scripts

Post by seikur0 »

somberstrekking wrote:
Wed Oct 26, 2022 12:19 am
This has been the best script I have found by far. Would gladly tip for an update
I just updated it, wow this update must have broken all trainers and tables, the code looks completely different.

If you're serious about the tip, please give it to the board itself for site maintenance, as the situation is often very dire.
Here's the paypal for that:
STN wrote:
Wed Oct 12, 2022 8:16 am
PayPal
[Link]

somberstrekking
Fearless Donors
Fearless Donors
Posts: 6
Joined: Wed Oct 26, 2022 12:18 am
Reputation: 1

Re: Symphony of War: Nephilim Sage Item Scripts

Post by somberstrekking »

seikur0 wrote:
Wed Oct 26, 2022 10:37 pm
somberstrekking wrote:
Wed Oct 26, 2022 12:19 am
This has been the best script I have found by far. Would gladly tip for an update
I just updated it, wow this update must have broken all trainers and tables, the code looks completely different.

If you're serious about the tip, please give it to the board itself for site maintenance, as the situation is often very dire.
Here's the paypal for that:
STN wrote:
Wed Oct 12, 2022 8:16 am
PayPal
[Link]
Done

NPrime
What is cheating?
What is cheating?
Posts: 2
Joined: Mon Oct 31, 2022 3:54 am
Reputation: 1

Re: Symphony of War: Nephilim Sage Item Scripts

Post by NPrime »

seikur0 wrote:
Sat Oct 15, 2022 8:58 pm
Just dropping my table with two options here:
-Never decrease gold
-Never decrease stackable resources (i.e. items, also includes horses etc.)

Feel free to add those to your table @Hentai-san.
seikur0, thank you so much for your table. I got back into SoW about a week before the Halloween update, and have been really enjoying the simplicity and effectiveness of your table.

However, the updated version is partially working now. Given enough repetitive uses of an item, the quantity will decrease. I've been mostly using apples of agility, but it's been happening with skill books as well. I just save though before using them and then reload and try again if the quantity decreases. The only thing I can think of to possibly explain this phenomena is that little hotfix deployed shortly after the Halloween update was released.

Just wanted to bring this to your attention, in case others might be experiencing the same.

But again, thanks so much for your work and the table.

User avatar
seikur0
Code Alchemist
Code Alchemist
Posts: 440
Joined: Sat Aug 26, 2017 10:48 am
Reputation: 339

Re: Symphony of War: Nephilim Sage Item Scripts

Post by seikur0 »

NPrime wrote:
Mon Oct 31, 2022 4:18 am
seikur0, thank you so much for your table. I got back into SoW about a week before the Halloween update, and have been really enjoying the simplicity and effectiveness of your table.

However, the updated version is partially working now. Given enough repetitive uses of an item, the quantity will decrease. I've been mostly using apples of agility, but it's been happening with skill books as well. I just save though before using them and then reload and try again if the quantity decreases. The only thing I can think of to possibly explain this phenomena is that little hotfix deployed shortly after the Halloween update was released.

Just wanted to bring this to your attention, in case others might be experiencing the same.

But again, thanks so much for your work and the table.
Hey NPrime,
I'm glad you're enjoying it :)

I just tested it and apparently the filter I've been using wasn't quite as good as I thought it was,
well I just fixed it and you shouldn't have these problems anymore.

Happy Halloween!

NPrime
What is cheating?
What is cheating?
Posts: 2
Joined: Mon Oct 31, 2022 3:54 am
Reputation: 1

Re: Symphony of War: Nephilim Sage Item Scripts

Post by NPrime »

seikur0 wrote:
Mon Oct 31, 2022 11:42 am
NPrime wrote:
Mon Oct 31, 2022 4:18 am
seikur0, thank you so much for your table. I got back into SoW about a week before the Halloween update, and have been really enjoying the simplicity and effectiveness of your table.

However, the updated version is partially working now. Given enough repetitive uses of an item, the quantity will decrease. I've been mostly using apples of agility, but it's been happening with skill books as well. I just save though before using them and then reload and try again if the quantity decreases. The only thing I can think of to possibly explain this phenomena is that little hotfix deployed shortly after the Halloween update was released.

Just wanted to bring this to your attention, in case others might be experiencing the same.

But again, thanks so much for your work and the table.
Hey NPrime,
I'm glad you're enjoying it :)

I just tested it and apparently the filter I've been using wasn't quite as good as I thought it was,
well I just fixed it and you shouldn't have these problems anymore.

Happy Halloween!
You are a godsend, seikur0. Just tried your updated table and it is workin' like a charm.

Many thanks, and even more delicious, full-size, non-raisin candy headin' your way on this delightful Halloween night. Take it easy, MVP :)

jasonthe13
Expert Cheater
Expert Cheater
Posts: 81
Joined: Sun Sep 10, 2017 2:59 pm
Reputation: 3

Re: Symphony of War: Nephilim Sage Item Scripts

Post by jasonthe13 »

does it need an update?

fecdan
Noobzor
Noobzor
Posts: 10
Joined: Tue Oct 18, 2022 8:25 am
Reputation: 0

Re: Symphony of War: Nephilim Sage Item Scripts

Post by fecdan »

seikur0 wrote:
Wed Oct 26, 2022 10:37 pm
somberstrekking wrote:
Wed Oct 26, 2022 12:19 am
This has been the best script I have found by far. Would gladly tip for an update
I just updated it, wow this update must have broken all trainers and tables, the code looks completely different.

If you're serious about the tip, please give it to the board itself for site maintenance, as the situation is often very dire.
Here's the paypal for that:
STN wrote:
Wed Oct 12, 2022 8:16 am
PayPal
[Link]
I can't find the stats addresses. I can only use the stats up items, then searching for the increasing value, then I could mod the stats value a bit.

If we don't use the stats up item, characters could still get the stats up by lvl up, butI can't get the addresses from lvl up :? :?

There must be some addresses to store the lvl up stats value.

could you teach me some plz?

Want it so bad.

And I kinda started to learn how to use cheat engine these days, but don't know how to do it with this game.

Now it's version 1.03. I found the exp or hp address, and used "find what code writes to this address" to get this code

x64-msvcrt-ruby240.rb_f_block_given_p+4D2 - 48 89 34 C1 - mov [rcx+rax*8],rsi

After I used find what addresses this code writes to, I got tons of addresses. Then I got totally stuck.

Don't know how to differ the addresses of exp or items from other thousands of I-don't-know-what-they-are addresses.

viewtopic.php?p=270398#p270398

I downloaded the scirpt from here, and open the script which you made. I spent like 10 plus hours to google and think and still don't understand how it works.

Really want to know the basic logic so bad.

User avatar
seikur0
Code Alchemist
Code Alchemist
Posts: 440
Joined: Sat Aug 26, 2017 10:48 am
Reputation: 339

Re: Symphony of War: Nephilim Sage Item Scripts

Post by seikur0 »

fecdan wrote:
Thu Nov 03, 2022 4:41 am
Really want to know the basic logic so bad.
So you've found the line
x64-msvcrt-ruby240.rb_f_block_given_p+4D2 - 48 89 34 C1 - mov [rcx+rax*8],rsi
which is writing to a whole lot of addresses. You can't even use "Find out what addresses this instruction accesses" without the game crashing.
In that case your goal is to somehow filter for the relevant writes.
If you inject directly at that line you have access to the registers as well as the stack and usually and in this case as well that is enough to filter it.

So we're in a function, a function can have different behavior depending on its inputs (and maybe global variables, which isn't relevant here).
To understand the input, take a look at the [Link]. Okay so rcx, rdx ,r8 and r9 are the input arguments and we can focus on these. Our function changes many values to a new value so it would look like this "changeValue(valueId, newValue, ...)".
In theory we could inject at the start of the function and change the input arguments to reach the desired effects, however in this case the function apparently does many things and if we inject at the line where the value is changed that's a good filter too, we filter out all function calls that don't write to the value.

Let's take a look at the calling function, we can find that from the stack trace in the "Find out what writes to this address" window:
Spoiler
Image
I've marked the inputs in yellow. So rcx gets assigned, might be some class pointer, if our target function is a class method.
rdx gets assigned too. r8 will have one of two global values depending on some condition before (r12d). r9 is the pointer to a struct on the stack, which has 6*8 bytes created from the values of rsi, rbx and xmm0 (where xmm0 got some global 16 byte value before).

So to analyze the input arguments, ideally we want a breakpoint at the very start of the function, that only triggers, when the value we're interested in gets changed. Let's take a look at the stack for some ideas:
Spoiler
Image
It is the stack trace from the moment where i used an item and thus changed its amount from 3 to 2, which would be 7 to 5 as decoded value. And sure enough on the stack itself the value of 5 can be found multiple times and even the 7 at [rbp+A8].
Okay cool so we use that as condition, in fact we set the condition as "value changed to 19(39)" that shouldn't occur very often.
And we add another condition, the function caller and the function caller of the function caller need to be the same. Those can be found in [rbp+58] and [rbp+E8]. The logic behind that is "if the function is being called from the same functions" hopefully it does the same thing, which we're interested in.
Now for the value, we really want the lowest value in the stack that has it (as the others might only get written later and might not be set at the start of the function. That is [rbp+D0].
Okay all set, no we do a simple code injection:
Spoiler
Image
We inject after the whole register backup and rbp setup is complete to (hopefully) see the same rbp offsets as at the place where to value actually gets changed within the function. rbp typically only gets changed at the function start.

Set our value to 20(41) (can even freeze that) and prepare the game so that we only need to confirm the item usage with one click (to avoid the function being called for other reasons than the value change), in my case "Salmon of Health".
Set the breakpoint in our injected script at the "lea rax,[rax]" line. (Doesn't break = success) Now use the item (Break = success²).
Okay cool, now let's take a look at rcx, rdx, r8 and r9 as we planned.

For that we use the dissect data tool.
Spoiler
Image
Spoiler
Image
Spoiler
Image
Spoiler
Image
Okay first things first, where is the "new amount" value? It's actually in the pointer to a struct within r9 we saw earlier.
So [r9] == "new amount".
Se second thing we wanted was the id, for that we need a second value, I use "Medal of Valor". Set that to 20 and then used it with our breakpoint active. Bingo.
So rcx looks very much the same as before, in fact it is the same address, so could be a class.
Now rdx is interesting:
Spoiler
Image
The 0x12007 part is the same as before, but [rdx+10] now has a 47 instead of the 45 we saw before. So we could assume that those are item ids. In fact the 0x12007 looks very interesting too, could be an id as well, maybe for the item type.
r8 is the same as before (same address and all) and it doesn't seem as useful. (Not suprising, we saw before it gets assigned one of two globals.)
r9 is the same as well (not suprising, we changed the value to 19(39) in both cases.

Okay cool, let's use that information we gained wisely.
So: "changeValue(valueId, newValue, ...)"
valueId is within the rdx data while newValue is [r9].
Actually since we directly inject at the location where newValue gets written, newValue is not as relevant for us, so we focus on rdx.

Now we need to know where rdx went at the place where we inject. You can step through the code or use "break and trace" or you use the breakpoint where we injected before and once it gets hit, you write down rdx, then you put a breakpoint on the write to our target address and take a look at where you can find rdx (simplest method).

From that I can see that rdx is stored in [rbp+28]. It's the 6th value pushed to the stack after the caller address in [rbp+50]. If we look at the top of the function that is the "push rdi". And sure enough in the calling function we see the mov rdx,rdi we've seen before already. It's kind of random/lucky, but hey it works.

Okay so let's put a breakpoint where we actually want to inject, directly where the value gets written.
It will imediately break, so let's take a look at the [[rbp+28]] data with the dissect data tool again:
But what's this? It's not a pointer?
Spoiler
Image
Great our input apparently isn't always a pointer to a struct..
On the bright side, if it's a pointer, we can probably determine the item type from it. So we need a way to tell if it's a valid pointer, otherwise the game crashes, when we try to access that invalid memory location.
At that point the clean, but also fragile and time-consuming way, would be to figure out, how the function itself knows if it's a pointer or not, i.e. what exactly does it do here. I did that for a while but didn't find any easy solution, so the not so clean method it is.
We saw that rdx, if it's a pointer, is a pointer to the heap memory. (Can also use the "memory regions" tool to verify.)
I think I read somewhere that heap memory for x64 only starts at 0x100000000 for the addresses.
So the first condition to accept rdx is, that ist must be >= 0x100000000.
I also notice, that r10 is always somewhat close to the [rbp+28] address. Okay so for the upper limit I take r10 plus another 0x100000000 and if [rbp+28] is within these limits I'll assume it is a pointer.

We do another injection to take a look at the actual values.
Spoiler
Image
Put the breakpoint at "lea rax,[rax]". Okay seems to be working, all rax values look similar and seem to be pointers now.
Take a look at these with the "data dissect" tool again.
So before for the two values we're interested in we saw that the id at struct offset 0 always had 0x12007 as first value. Now we can see that's not the case. So this seems to be another good filter, the assumption is 0x12007 is the id for "item". Then at offset 0x10 there would be an 8 byte item id, that's the item type, we saw before there.

So the remaining filters we need would be "[[rbp+28]] == 0x12007" and we could even do a whitelist/blacklist for item types, if we evaluate the "[[rbp+28]+10]" value, i.e. "[[rbp+28]+10] == #45" means it is the "Salmon of Health".
The rest is simple, in my script I want to allow increases, not decreases, so i just compare the currentValue to the newValue and execute the write at the end or not.

Another last thing for the filter, sometimes the new value is a pointer, likely that's some internal data structure management and we don't want to modify that, so the last filter we need is for the actual new value. If that's larger than the 0x100000000 we've established before, we always allow the write in the end.


Similarly for stats:
Here [rbp+28] won't be a pointer, but contain the stat id directly, filter those for ids below 0x10000. And I think [rbp+30] might be the class, seems to be always 0, add that to the filter.
Add, that the newValue must be lower than 0x100000000 (as before) and that's enough to only find stat changes (to be exact, stat modifier changes), STR, MAG, SKL, MaxHP, LDR. With the stat items, HP increases by 5, the other stats 2, LDR what it says, if you want to find the values, mind you in term of the "RPG VX type" value type.

fecdan
Noobzor
Noobzor
Posts: 10
Joined: Tue Oct 18, 2022 8:25 am
Reputation: 0

Re: Symphony of War: Nephilim Sage Item Scripts

Post by fecdan »

seikur0 wrote:
Thu Nov 03, 2022 1:03 pm
fecdan wrote:
Thu Nov 03, 2022 4:41 am
Really want to know the basic logic so bad.
So you've found the line
x64-msvcrt-ruby240.rb_f_block_given_p+4D2 - 48 89 34 C1 - mov [rcx+rax*8],rsi
which is writing to a whole lot of addresses. You can't even use "Find out what addresses this instruction accesses" without the game crashing.
In that case your goal is to somehow filter for the relevant writes.
If you inject directly at that line you have access to the registers as well as the stack and usually and in this case as well that is enough to filter it.

So we're in a function, a function can have different behavior depending on its inputs (and maybe global variables, which isn't relevant here).
To understand the input, take a look at the [Link]. Okay so rcx, rdx ,r8 and r9 are the input arguments and we can focus on these. Our function changes many values to a new value so it would look like this "changeValue(valueId, newValue, ...)".
In theory we could inject at the start of the function and change the input arguments to reach the desired effects, however in this case the function apparently does many things and if we inject at the line where the value is changed that's a good filter too, we filter out all function calls that don't write to the value.

Let's take a look at the calling function, we can find that from the stack trace in the "Find out what writes to this address" window:
Spoiler
Image
I've marked the inputs in yellow. So rcx gets assigned, might be some class pointer, if our target function is a class method.
rdx gets assigned too. r8 will have one of two global values depending on some condition before (r12d). r9 is the pointer to a struct on the stack, which has 6*8 bytes created from the values of rsi, rbx and xmm0 (where xmm0 got some global 16 byte value before).

So to analyze the input arguments, ideally we want a breakpoint at the very start of the function, that only triggers, when the value we're interested in gets changed. Let's take a look at the stack for some ideas:
Spoiler
Image
It is the stack trace from the moment where i used an item and thus changed its amount from 3 to 2, which would be 7 to 5 as decoded value. And sure enough on the stack itself the value of 5 can be found multiple times and even the 7 at [rbp+A8].
Okay cool so we use that as condition, in fact we set the condition as "value changed to 19(39)" that shouldn't occur very often.
And we add another condition, the function caller and the function caller of the function caller need to be the same. Those can be found in [rbp+58] and [rbp+E8]. The logic behind that is "if the function is being called from the same functions" hopefully it does the same thing, which we're interested in.
Now for the value, we really want the lowest value in the stack that has it (as the others might only get written later and might not be set at the start of the function. That is [rbp+D0].
Okay all set, no we do a simple code injection:
Spoiler
Image
We inject after the whole register backup and rbp setup is complete to (hopefully) see the same rbp offsets as at the place where to value actually gets changed within the function. rbp typically only gets changed at the function start.

Set our value to 20(41) (can even freeze that) and prepare the game so that we only need to confirm the item usage with one click (to avoid the function being called for other reasons than the value change), in my case "Salmon of Health".
Set the breakpoint in our injected script at the "lea rax,[rax]" line. (Doesn't break = success) Now use the item (Break = success²).
Okay cool, now let's take a look at rcx, rdx, r8 and r9 as we planned.

For that we use the dissect data tool.
Spoiler
Image
Spoiler
Image
Spoiler
Image
Spoiler
Image
Okay first things first, where is the "new amount" value? It's actually in the pointer to a struct within r9 we saw earlier.
So [r9] == "new amount".
Se second thing we wanted was the id, for that we need a second value, I use "Medal of Valor". Set that to 20 and then used it with our breakpoint active. Bingo.
So rcx looks very much the same as before, in fact it is the same address, so could be a class.
Now rdx is interesting:
Spoiler
Image
The 0x12007 part is the same as before, but [rdx+10] now has a 47 instead of the 45 we saw before. So we could assume that those are item ids. In fact the 0x12007 looks very interesting too, could be an id as well, maybe for the item type.
r8 is the same as before (same address and all) and it doesn't seem as useful. (Not suprising, we saw before it gets assigned one of two globals.)
r9 is the same as well (not suprising, we changed the value to 19(39) in both cases.

Okay cool, let's use that information we gained wisely.
So: "changeValue(valueId, newValue, ...)"
valueId is within the rdx data while newValue is [r9].
Actually since we directly inject at the location where newValue gets written, newValue is not as relevant for us, so we focus on rdx.

Now we need to know where rdx went at the place where we inject. You can step through the code or use "break and trace" or you use the breakpoint where we injected before and once it gets hit, you write down rdx, then you put a breakpoint on the write to our target address and take a look at where you can find rdx (simplest method).

From that I can see that rdx is stored in [rbp+28]. It's the 6th value pushed to the stack after the caller address in [rbp+50]. If we look at the top of the function that is the "push rdi". And sure enough in the calling function we see the mov rdx,rdi we've seen before already. It's kind of random/lucky, but hey it works.

Okay so let's put a breakpoint where we actually want to inject, directly where the value gets written.
It will imediately break, so let's take a look at the [[rbp+28]] data with the dissect data tool again:
But what's this? It's not a pointer?
Spoiler
Image
Great our input apparently isn't always a pointer to a struct..
On the bright side, if it's a pointer, we can probably determine the item type from it. So we need a way to tell if it's a valid pointer, otherwise the game crashes, when we try to access that invalid memory location.
At that point the clean, but also fragile and time-consuming way, would be to figure out, how the function itself knows if it's a pointer or not, i.e. what exactly does it do here. I did that for a while but didn't find any easy solution, so the not so clean method it is.
We saw that rdx, if it's a pointer, is a pointer to the heap memory. (Can also use the "memory regions" tool to verify.)
I think I read somewhere that heap memory for x64 only starts at 0x100000000 for the addresses.
So the first condition to accept rdx is, that ist must be >= 0x100000000.
I also notice, that r10 is always somewhat close to the [rbp+28] address. Okay so for the upper limit I take r10 plus another 0x100000000 and if [rbp+28] is within these limits I'll assume it is a pointer.

We do another injection to take a look at the actual values.
Spoiler
Image
Put the breakpoint at "lea rax,[rax]". Okay seems to be working, all rax values look similar and seem to be pointers now.
Take a look at these with the "data dissect" tool again.
So before for the two values we're interested in we saw that the id at struct offset 0 always had 0x12007 as first value. Now we can see that's not the case. So this seems to be another good filter, the assumption is 0x12007 is the id for "item". Then at offset 0x10 there would be an 8 byte item id, that's the item type, we saw before there.

So the remaining filters we need would be "[[rbp+28]] == 0x12007" and we could even do a whitelist/blacklist for item types, if we evaluate the "[[rbp+28]+10]" value, i.e. "[[rbp+28]+10] == #45" means it is the "Salmon of Health".
The rest is simple, in my script I want to allow increases, not decreases, so i just compare the currentValue to the newValue and execute the write at the end or not.

Another last thing for the filter, sometimes the new value is a pointer, likely that's some internal data structure management and we don't want to modify that, so the last filter we need is for the actual new value. If that's larger than the 0x100000000 we've established before, we always allow the write in the end.


Similarly for stats:
Here [rbp+28] won't be a pointer, but contain the stat id directly, filter those for ids below 0x10000. And I think [rbp+30] might be the class, seems to be always 0, add that to the filter.
Add, that the newValue must be lower than 0x100000000 (as before) and that's enough to only find stat changes (to be exact, stat modifier changes), STR, MAG, SKL, MaxHP, LDR. With the stat items, HP increases by 5, the other stats 2, LDR what it says, if you want to find the values, mind you in term of the "RPG VX type" value type.
Aaaawwwweesome !!!

Thank you so much

I can't believe you're gonna reply.

Even in such details.

It's very much for me.

Thank you thank you thank you.

Now let me read it carefully and try to understand it all which I don't think I can.

But I'll try.

fecdan
Noobzor
Noobzor
Posts: 10
Joined: Tue Oct 18, 2022 8:25 am
Reputation: 0

Re: Symphony of War: Nephilim Sage Item Scripts

Post by fecdan »

seikur0 wrote:
Thu Nov 03, 2022 1:03 pm
r9 is the pointer to a struct on the stack, which has 6*8 bytes created from the values of rsi, rbx and xmm0 (where xmm0 got some global 16 byte value before).

In the beginning, I can only understand about 20%.
After another 10 plus hours work on your answer. Now I understand a lot more, about 70% I guess?
If you don't mind, may I ask some more questions, plz?
The first one is that I don't know how to find r9 is the pointer to a struct on the stack, which has 6*8 bytes created from the values of rsi, rbx and xmm0.
Though it seems not that important if I don't know the reason. I can still go on and finish the next step of this tutorial, right?


seikur0 wrote:
Thu Nov 03, 2022 1:03 pm
We inject after the whole register backup and rbp setup is complete to (hopefully) see the same rbp offsets as at the place where to value actually gets changed within the function. rbp typically only gets changed at the function start.

Set our value to 20(41) (can even freeze that) and prepare the game so that we only need to confirm the item usage with one click (to avoid the function being called for other reasons than the value change), in my case "Salmon of Health".
Set the breakpoint in our injected script at the "lea rax,[rax]" line. (Doesn't break = success) Now use the item (Break = success²).

In this part, I want to confirm that, the reason why to use the instruction "lea" on the line lea rax,[rax], is to make sure the changes happen in an address.
Cuz Cheat Engine only can tell save/load in the addresses, If the changes only happens between registers, the breakpoint won't work. Is my understanding right?


seikur0 wrote:
Thu Nov 03, 2022 1:03 pm
valueId is within the rdx data while newValue is [r9].
Actually since we directly inject at the location where newValue gets written, newValue is not as relevant for us, so we focus on rdx.
seikur0 wrote:
Thu Nov 03, 2022 1:03 pm
Now we need to know where rdx went at the place where we inject. You can step through the code or use "break and trace" or you use the breakpoint where we injected before and once it gets hit, you write down rdx, then you put a breakpoint on the write to our target address and take a look at where you can find rdx (simplest method).


I don't understand " put a breakpoint on the write to our target address and take a look at where you can find rdx (simplest method)" part.
I mean, does the target address mean the new rdx that I write down?


seikur0 wrote:
Thu Nov 03, 2022 1:03 pm
From that I can see that rdx is stored in [rbp+28]. It's the 6th value pushed to the stack after the caller address in [rbp+50]. If we look at the top of the function that is the "push rdi". And sure enough in the calling function we see the mov rdx,rdi we've seen before already. It's kind of random/lucky, but hey it works.
Sorry, I don't mean to ask stupid basic questions, but I don't know where is the top of the function. I don't see "push rdi". I thought it's push rbp, push r15, push r14, the whole registers backup part? :? :?

seikur0 wrote:
Thu Nov 03, 2022 1:03 pm
Okay so let's put a breakpoint where we actually want to inject, directly where the value gets written.
It will imediately break, so let's take a look at the [[rbp+28]] data with the dissect data tool again:
But what's this? It's not a pointer?
Spoiler
Image
Great our input apparently isn't always a pointer to a struct..
On the bright side, if it's a pointer, we can probably determine the item type from it. So we need a way to tell if it's a valid pointer, otherwise the game crashes, when we try to access that invalid memory location.
At that point the clean, but also fragile and time-consuming way, would be to figure out, how the function itself knows if it's a pointer or not, i.e. what exactly does it do here. I did that for a while but didn't find any easy solution, so the not so clean method it is.
We saw that rdx, if it's a pointer, is a pointer to the heap memory. (Can also use the "memory regions" tool to verify.)
I think I read somewhere that heap memory for x64 only starts at 0x100000000 for the addresses.
So the first condition to accept rdx is, that ist must be >= 0x100000000.
I also notice, that r10 is always somewhat close to the [rbp+28] address. Okay so for the upper limit I take r10 plus another 0x100000000 and if [rbp+28] is within these limits I'll assume it is a pointer.

We do another injection to take a look at the actual values.
Spoiler
Image
Put the breakpoint at "lea rax,[rax]". Okay seems to be working, all rax values look similar and seem to be pointers now.
Take a look at these with the "data dissect" tool again.
So before for the two values we're interested in we saw that the id at struct offset 0 always had 0x12007 as first value. Now we can see that's not the case. So this seems to be another good filter, the assumption is 0x12007 is the id for "item". Then at offset 0x10 there would be an 8 byte item id, that's the item type, we saw before there.

So the remaining filters we need would be "[[rbp+28]] == 0x12007" and we could even do a whitelist/blacklist for item types, if we evaluate the "[[rbp+28]+10]" value, i.e. "[[rbp+28]+10] == #45" means it is the "Salmon of Health".
The rest is simple, in my script I want to allow increases, not decreases, so i just compare the currentValue to the newValue and execute the write at the end or not.

Another last thing for the filter, sometimes the new value is a pointer, likely that's some internal data structure management and we don't want to modify that, so the last filter we need is for the actual new value. If that's larger than the 0x100000000 we've established before, we always allow the write in the end.


Similarly for stats:
Here [rbp+28] won't be a pointer, but contain the stat id directly, filter those for ids below 0x10000. And I think [rbp+30] might be the class, seems to be always 0, add that to the filter.
Add, that the newValue must be lower than 0x100000000 (as before) and that's enough to only find stat changes (to be exact, stat modifier changes), STR, MAG, SKL, MaxHP, LDR. With the stat items, HP increases by 5, the other stats 2, LDR what it says, if you want to find the values, mind you in term of the "RPG VX type" value type.

The 0x100000000 way is so brilliant and comes from no where to me :roll:

I seem to be able to get the stat modifier now, but only the modifier from seize or item, not lvl up.

If you know how to find lvl up stat modifier, would you plz teach me?

I will continue digesting this last part.

Thank you so much.
Last edited by fecdan on Sat Nov 05, 2022 7:12 pm, edited 3 times in total.

Post Reply

Who is online

Users browsing this forum: 7zW9S5s6, arap, axelv777, Bing [Bot], BLEXBot, DrummerIX, Foracir, jonaaa, kuromigem, Lmfao33xd, Necrosx, trohed