Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Discovering unknown address after known function is executed
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine
View previous topic :: View next topic  
Author Message
ymiu
Cheater
Reputation: 0

Joined: 16 Dec 2018
Posts: 41

PostPosted: Fri Dec 28, 2018 5:58 pm    Post subject: Discovering unknown address after known function is executed Reply with quote

In Atom RPG, I can easily find my Action Points (AP) and the code that decreases my AP as I take actions during my turn. Mono helped me identify the function that handles that, and it's rather short:

Code:
Character:set_AP - 55                    - push rbp
Character:set_AP+1- 48 8B EC              - mov rbp,rsp
Character:set_AP+4- 57                    - push rdi
Character:set_AP+5- 48 83 EC 08           - sub rsp,08 { 8 }
Character:set_AP+9- 48 8B F9              - mov rdi,rcx
Character:set_AP+c- 48 89 55 F0           - mov [rbp-10],rdx
Character:set_AP+10- 48 8B C2              - mov rax,rdx
Character:set_AP+13- 89 87 AC000000        - mov [rdi+000000AC],eax <- this causes my AP to drop
Character:set_AP+19- 48 8B CF              - mov rcx,rdi
Character:set_AP+1c- 48 83 EC 20           - sub rsp,20 { 32 }
Character:set_AP+20- 49 BB F0CB970600000000 - mov r11,Character:DebugCheckAP { (149717832) }
Character:set_AP+2a- 41 FF D3              - call r11
Character:set_AP+2d- 48 83 C4 20           - add rsp,20 { 32 }
Character:set_AP+31- 48 8B 7D F8           - mov rdi,[rbp-08]
Character:set_AP+35- C9                    - leave
Character:set_AP+36- C3                    - ret


I can use aobscanregion() to easily replace this line with NOPs, but then I realized that this is the same function used by enemies, so that gives them infinite AP as well. I'm not savvy enough to know how to figure out who's using the function during each call.

To work around this, I've been manually figuring out my AP location for each session and locking it, but this gets tedious.

When Character:set_AP+13 executes during one of my turns, [rdi+000000AC] points to my AP. Is there a way to take advantage of this knowledge to auto-populate that AP address in my list, so that I may lock it more easily?

Of course I'm also open to better solutions. Thanks!
Back to top
View user's profile Send private message
OldCheatEngineUser
Whateven rank
Reputation: 20

Joined: 01 Feb 2016
Posts: 1587

PostPosted: Fri Dec 28, 2018 6:20 pm    Post subject: Reply with quote

cheat engine tutorial final step will teach you how to cheat in such case (when you and enemy affected by the same instruction), as for a better solution:

memory view -> view -> run "referenced functions" then patch the call that belongs to you, and keep calls that affect enemies.

_________________
About Me;
I Use CE Since Version 1.X, And Still Learning How To Use It Well!
Jul 26, 2020
STN wrote:
i am a sweetheart.
Back to top
View user's profile Send private message Visit poster's website
ymiu
Cheater
Reputation: 0

Joined: 16 Dec 2018
Posts: 41

PostPosted: Fri Dec 28, 2018 9:18 pm    Post subject: Reply with quote

Never quite understood that tutorial until I found more detailed instructions for 64-bit in the Wiki just now. So I finally got that working, but time will tell if I can actually do that on my own without a helpful pre-made script.

As for your better solution, I'm looking at the Referenced Functions window now, but not seeing anything obviously helpful. When I scroll down a bit, I see entries like "AtomRPG_x64.exe+1000", but none of the Mono names I have back in the Memory Viewer. So I'm not sure where this function exists in this list.

I'm in a fight now, and figured I'd move around to see if I could find one of these entries incrementing the Refcount, but the list is pretty long. Any tips for narrowing this down?
Back to top
View user's profile Send private message
OldCheatEngineUser
Whateven rank
Reputation: 20

Joined: 01 Feb 2016
Posts: 1587

PostPosted: Sat Dec 29, 2018 4:16 am    Post subject: Reply with quote

ymiu wrote:
Mono helped me identify the function that handles that

my bad, it wont work with mono.
because it follows the module address, not the dynamically allocated memory.

anyway, here is a solution:

panraven wrote:
Try to associate the dissect function with a hotkey, but found ce will duplicate same reference with each hotkey pressed.
Work around is to add an artificial call reference to the target function starting address, the artificial call/jump is in between that function start and end.
This may affect some other extension using the dissect function references, since it is not an actual call, it may cause problem.

Hotkey is CTRL-ALT-J, may change.

Usage: Save the text to a *.lua and put in autorun directry.


Updated:
-- add one more 'already' check.

Code:
function mono_func_range(addr, bInRange)
  local addy = addr
  if type(addy)=='string' then addy = GetAddressSafe(addy)end
  if type(addy)=='number' and readInteger'mono_domain_get' and 0~=LaunchMonoDataCollector() then
    local info = mono_getJitInfo(addy)--GetAddress(na))
    if info then
      if bInRange~=true then
        return info.code_start, info.code_size
      else
        return info.code_start, info.code_size+info.code_start
      end
    end
  end
  return 0,0,'failed, addr = '..math.tointeger(addr) and
    string.format("%X",0+addr) or tostring(addr)
end

function mono_dissect_currentDisassembleAddress()
  local addr = getMemoryViewForm().DisassemblerView.SelectedAddress
  local from,size = mono_func_range(addr)
  if from and from~=0 and size>0 then
    local dsc = getDissectCode()
    local already = dsc.getReferences(from)
    if not already or already[from+size]~= jtCall then
      dsc.dissect(from,size)
      dsc.addReference(from+size,from,jtCall)
      dsc.addReference(from,from+size,jtUnconditional)
    end
  else
    speak"mono dissect address failed"
  end
end

if not _mono_dsc_hotkey then
  _mono_dsc_hotkey = createHotkey(mono_dissect_currentDisassembleAddress,
    VK_CONTROL, VK_MENU, VK_J
  )
end

_________________
About Me;
I Use CE Since Version 1.X, And Still Learning How To Use It Well!
Jul 26, 2020
STN wrote:
i am a sweetheart.
Back to top
View user's profile Send private message Visit poster's website
ymiu
Cheater
Reputation: 0

Joined: 16 Dec 2018
Posts: 41

PostPosted: Sat Dec 29, 2018 8:03 am    Post subject: Reply with quote

I'm trying to understand, but it feels like I'm stabbing around in the dark.

I took panraven's code and put it into my Cheat Table LUA Script (ctrl-alt-L), which already had the line 'LaunchMonoDataCollector()' at the top. I hope that doesn't interfere somehow. Then I clicked Execute and highlighted the correct line in my memory viewer and hit ctrl-alt-J to run his script. I hope that was what I was supposed to do with it.

Now I see a couple bold addresses saying "(Conditional)" below this line. I have no idea what they mean.

On a guess, I re-opened the Referenced Functions window and now I see only this one function listed there with a single address in the right pane. That single address is the very last one from this function.

I'm not sure what I just gained by doing this. You said to patch the call that belongs to me and keep the one affecting enemies. How do I identify these calls and how do I patch one?

Thanks for your help so far!
Back to top
View user's profile Send private message
OldCheatEngineUser
Whateven rank
Reputation: 20

Joined: 01 Feb 2016
Posts: 1587

PostPosted: Sat Dec 29, 2018 9:32 am    Post subject: Reply with quote

ymiu wrote:
I'm not sure what I just gained by doing this. You said to patch the call that belongs to me and keep the one affecting enemies. How do I identify these calls and how do I patch one?

this is hard to explain, i will try my best:

the bold address is the address of a call instruction and jcc or JMP that either calls or jumps to the piece of code that you are interested in.

address(text) where text is either, call, conditional or unconditional.

since this function is shared, there must be at least 2 bold addresses on push rbp. (and it should be a call instruction)

you can double-click on the bold address to jump to that location and do your analysis, in your case you may want to find what call belongs to you.

the easiest way (after you double-click the any of the bold addresses) is to place a breakpoint, once it hit look for rcx register and copy the address into calculator then add offset AC and see if it match your AP address.

if so then this call belongs to you, to patch it simply replace it with nops. (or right-click replace with code that does nothing)



and if you didnt like using the script, here is another way but make sure mono-features turned on:

ParkourPenguin wrote:
celua.txt:
Code:
getDissectCode().dissect(base, size)

Go to "Memory View -> View -> Memory Regions" for base and size info.


ParkourPenguin wrote:
  1. Look at an instruction in the disassembler
  2. Look at the address that instruction is at (turn off symbols in the view menu)
  3. Open the Memory Regions window
  4. Find the memory region that address is in
  5. Open the Lua engine window (Memory View -> Tools -> Lua Engine)
  6. Copy and paste that code into the bottom part of that window (left of the "Execute" button)
  7. Replace the "base" parameter with the number under the "Address" column in the memory regions window
  8. Replace the "size" parameter with the number under the "Size" column in the memory regions window
  9. Make sure the arguments are prepended with "0x" to tell Lua they are hexadecimal literals
  10. Click on the "Execute" button

_________________
About Me;
I Use CE Since Version 1.X, And Still Learning How To Use It Well!
Jul 26, 2020
STN wrote:
i am a sweetheart.
Back to top
View user's profile Send private message Visit poster's website
ymiu
Cheater
Reputation: 0

Joined: 16 Dec 2018
Posts: 41

PostPosted: Sat Dec 29, 2018 11:44 am    Post subject: Reply with quote

OK, I made a mistake in my last post-- I was trying to use panraven's code on a different function. I went back to the Character:set_AP function and used the script. Here's what I see:

Code:
0695E60E - 00 00                 - add [rax],al
0695E647(Call)
Character:set_AP - 55                    - push rbp
Character:set_AP+1- 48 8B EC              - mov rbp,rsp
Character:set_AP+4- 57                    - push rdi
Character:set_AP+5- 48 83 EC 08           - sub rsp,08 { 8 }
Character:set_AP+9- 48 8B F9              - mov rdi,rcx
Character:set_AP+c- 48 89 55 F0           - mov [rbp-10],rdx
Character:set_AP+10- 48 8B C2              - mov rax,rdx
Character:set_AP+13- 89 87 AC000000        - mov [rdi+000000AC],eax
Character:set_AP+19- 48 8B CF              - mov rcx,rdi
Character:set_AP+1c- 48 83 EC 20           - sub rsp,20 { 32 }
Character:set_AP+20- 49 BB 70E6950600000000 - mov r11,Character:DebugCheckAP { (149717832) }
Character:set_AP+2a- 41 FF D3              - call r11
Character:set_AP+2d- 48 83 C4 20           - add rsp,20 { 32 }
Character:set_AP+31- 48 8B 7D F8           - mov rdi,[rbp-08]
Character:set_AP+35- C9                    - leave
Character:set_AP+36- C3                    - ret
0695E610(Unconditional)
0695E647         - 00 00                 - add [rax],al


Now when I double click on 0695E647(Call), it jumps down to 0695E610(Unconditional). When I double click that one, it jumps back up to the same Call address. Importantly, there are not two Call addresses as you were expecting.
Back to top
View user's profile Send private message
OldCheatEngineUser
Whateven rank
Reputation: 20

Joined: 01 Feb 2016
Posts: 1587

PostPosted: Sat Dec 29, 2018 12:10 pm    Post subject: Reply with quote

no, more calls are there.

indirect call cant be dissected, because it require debugging.

place a breakpoint on
Code:
mov [rdi+000000AC],eax

if the effective address is same as AP, then continue pressing F8 hotkey.

after the leave&ret instruction you should find the call related to you, in case the effective address wasnt yours just press F9.

_________________
About Me;
I Use CE Since Version 1.X, And Still Learning How To Use It Well!
Jul 26, 2020
STN wrote:
i am a sweetheart.
Back to top
View user's profile Send private message Visit poster's website
ymiu
Cheater
Reputation: 0

Joined: 16 Dec 2018
Posts: 41

PostPosted: Sat Dec 29, 2018 2:51 pm    Post subject: Reply with quote

I see. I'm glad to finally learn something useful about debugging =)

I went back and tried your second suggestion for code dissection. It revealed the following:

Code:
0690FD3E - 00 00                 - add [rax],al
 069019C8(Code/Data)
 0690ED12(Code/Data)
 0690ED59(Code/Data)
Character:set_AP - 55                    - push rbp
Character:set_AP+1- 48 8B EC              - mov rbp,rsp
Character:set_AP+4- 57                    - push rdi
Character:set_AP+5- 48 83 EC 08           - sub rsp,08 { 8 }
Character:set_AP+9- 48 8B F9              - mov rdi,rcx
Character:set_AP+c- 48 89 55 F0           - mov [rbp-10],rdx
Character:set_AP+10- 48 8B C2              - mov rax,rdx
Character:set_AP+13- 89 87 AC000000        - mov [rdi+000000AC],eax
Character:set_AP+19- 48 8B CF              - mov rcx,rdi
Character:set_AP+1c- 48 83 EC 20           - sub rsp,20 { 32 }
Character:set_AP+20- 49 BB A0FD900600000000 - mov r11,Character:DebugCheckAP { (149717832) }
Character:set_AP+2a- 41 FF D3              - call r11
Character:set_AP+2d- 48 83 C4 20           - add rsp,20 { 32 }
Character:set_AP+31- 48 8B 7D F8           - mov rdi,[rbp-08]
Character:set_AP+35- C9                    - leave
Character:set_AP+36- C3                    - ret
0690FD77         - 00 00                 - add [rax],al


069019C8(Code/Data) corresponds with CharacterComponent:Update+1E38 and I can't figure out when this is used. It could be related to combat actions (shooting or hitting), but it could also be the AP spent when I open my inventory. I can't figure it out because it gets called constantly even when no action is being taken, with RCX addresses unrelated to me or my enemies, and there isn't enough lag between shooting or inventory opening to allow me to quickly alt-tab and toggle the breakpoint with F5.

0690ED12(Code/Data) corresponds with CharacterComponent:UpdateMovement+B42 and I've figured out that this only gets called when spending an additional AP point for making diagonal movements during combat. It affects both my player and my enemies' AP values.

0690ED59(Code/Data) corresponds with CharacterComponent:UpdateMovement+B89 and I've figured out that this gets called for every adjacent movement during combat. It affects both my player and my enemies' AP values.

Like the first call, the latter two also occasionally get called with RCX addresses for non-combat entities, but not very often. I suspect these relate to the sporadic movements of NPCs within the map but outside of the combat area.

So this feels like progress, but so far the only solid calls I can identify still affect both me and my enemies alike.
Back to top
View user's profile Send private message
OldCheatEngineUser
Whateven rank
Reputation: 20

Joined: 01 Feb 2016
Posts: 1587

PostPosted: Sat Dec 29, 2018 3:21 pm    Post subject: Reply with quote

something missing, not sure what.

i think you mixed up things, sounds messy lol.

_________________
About Me;
I Use CE Since Version 1.X, And Still Learning How To Use It Well!
Jul 26, 2020
STN wrote:
i am a sweetheart.
Back to top
View user's profile Send private message Visit poster's website
ymiu
Cheater
Reputation: 0

Joined: 16 Dec 2018
Posts: 41

PostPosted: Sat Dec 29, 2018 3:47 pm    Post subject: Reply with quote

Perhaps. To be fair, I solved this particular AP issue using a script I modified from the tutorial you mentioned. But I'm sure there's value in your alternate suggestions, and I'm glad to have learned about using the debugger features nonetheless.

The reason I kept coming back to this is because I tried applying the same tutorial script solution to maintain infinite ammunition without giving the same to enemies. I wasn't able to find a friend vs foe identifier in that related data structure, so I was hoping this exercise might help me figure out another way.

Still stuck on the ammo bit for now... it's a much larger function.

I appreciate your assistance =)
Back to top
View user's profile Send private message
ymiu
Cheater
Reputation: 0

Joined: 16 Dec 2018
Posts: 41

PostPosted: Tue Jan 01, 2019 8:26 am    Post subject: Reply with quote

I've been playing with these concepts for the past few days, and I'd like to get back to the original intent of this post: a good way to hold onto an unknown address that gets accessed within a known mono function.

Deviating from the AP (and Ammo) functions described above, I'm now using a Hunger function to work on this since the game doesn't compute hunger for NPCs. In this context, I want Hunger = 0. Consider the following:

Code:
HungerAddiction:OnUpdate+14e - 49 BB B02D8B0600000000 - mov r11,UnityEngine:Mathf:Clamp { (686588744) }
HungerAddiction:OnUpdate+158 - 41 FF D3              - call r11
HungerAddiction:OnUpdate+15b - 48 83 C4 20           - add rsp,20 { 32 }
HungerAddiction:OnUpdate+15f - 89 47 10              - mov [rdi+10],eax
HungerAddiction:OnUpdate+162 - 48 8B 47 18           - mov rax,[rdi+18]
HungerAddiction:OnUpdate+166 - B9 80EE3600           - mov ecx,0036EE80 { (0) }
HungerAddiction:OnUpdate+16b - 49 63 D7              - movsxd  rdx,r15d


HungerAddiction:OnUpdate+15f is the line that modifies my hunger value, which is stored in [rdi+10] at the time of execution. So rather than just nop'ing this, I wanted to write something to pull that address into my table. Based on some research, here's what I've used to do that:

Code:
usemono()

[ENABLE]
aobscanregion(HUNGERINC,HungerAddiction:OnUpdate+000,HungerAddiction:OnUpdate+1fe,48 83 C4 20 89 47 10 48 8B 47 18 B9) // should be unique
alloc(hungermem,$1000,HUNGERINC)
registersymbol(HUNGER)
alloc(HUNGER, 4) // change to 8 if storing entire rdi (Hunger base ptr)
label(return)

hungermem:
  add rsp,20 // original code, unknown purpose
  mov eax,0 // eax has adjusted hunger, so overwrite with 0
  mov [rdi+10],eax // original code, modifies my hunger.  [rdi+10] points to my hunger.
  mov [HUNGER],edi // hunger base ptr is rdi, but only uses 4-bytes of it, hence edi
  jmp return

HUNGERINC:
  jmp hungermem
  nop
  nop

return:
  registersymbol(HUNGERINC)

[DISABLE]
HUNGERINC:
  db 48 83 C4 20 89 47 10
unregistersymbol(HUNGERINC)
unregistersymbol(HUNGER)
dealloc(HUNGER)
dealloc(hungermem)


So far, this works pretty well, but I have a few minor problems, and I'd also like to ensure I'm following good practice and not making things harder on myself.

1) I used aobscanregion() to speed up the aob scan by limiting the search to only this hunger function. But I know that the code injection line will always be HungerAddiction:OnUpdate+15b, so can I use that knowledge to directly inject the code in that location without having to scan? If so, what would that look like?

2) I tried removing unregistersymbol(HUNGER) and dealloc(HUNGER) and moving the corresponding alloc() and registersymbol() commands above the [ENABLE] tag. I hoped that this would let me keep the HUNGER pointer in my table even after I disable this script, but it doesn't. My HUNGER pointer always gets wiped when I disable this script. I could understand if it gets wiped upon executing the script a second time, but that's not how it works. The pointer stops working as soon as I disable the script. Is there any way to make that pointer persistent?

3) Do I need to worry about unintended side-effects from any of my injections? I'm only executing additional mov and jmp commands, so I don't think that modifies any flags and stuff.

4) Is it pointless that I zeroed out eax and executed the original mov [rdi+10],eax code rather than just omitting them?

5) Is there a better way to do any of this?
Back to top
View user's profile Send private message
OldCheatEngineUser
Whateven rank
Reputation: 20

Joined: 01 Feb 2016
Posts: 1587

PostPosted: Tue Jan 01, 2019 9:48 am    Post subject: Reply with quote

1. you can use code injection and hook the symbol, but you must activate mono-features.

2. you need two scripts, here is an example:
Code:
[enable]

alloc(hunger,04)
registersymbol(hunger)

hunger:
dd 0

[disable]

dealloc(hunger)
unregistersymbol(hunger)

first you have to enable this one, then the second script. (and simply move edi into hunger)

3. not really, unless the game checks some conditions after the injection point or the instructions you are using modify the flags.

4. not pointless in some games, in your case eax is written to that address some games may check the value of eax and the address is written to. (but in your case no, eax is replaced by whatever in rdi+18.)

5. you can completely disable this function, either by patching the call or placing a nop on HungerAddiction:OnUpdate
assuming HungerAddiction:OnUpdate is push rbp then:

mono-features must be enabled in order to enable this one.
Code:
[enable]

HungerAddiction:OnUpdate:
db C3

[disable]

HungerAddiction:OnUpdate:
db 55

_________________
About Me;
I Use CE Since Version 1.X, And Still Learning How To Use It Well!
Jul 26, 2020
STN wrote:
i am a sweetheart.
Back to top
View user's profile Send private message Visit poster's website
ymiu
Cheater
Reputation: 0

Joined: 16 Dec 2018
Posts: 41

PostPosted: Tue Jan 01, 2019 10:18 am    Post subject: Reply with quote

That makes sense =)

Based on your last example, I realized I could just directly inject using HungerAddiction:OnUpdate+15b: in place of HUNGERINC: So I got rid of my aob scan and used that.

You said to hook the symbol, so I left the registersymbol(HUNGERINC) but CE complained that I hadn't declared the symbol first. I tried throwing an alloc() up top for it, but that didn't put it in the right place. So how exactly do I hook the symbol?

EDIT (can't double-post yet):

Ah, I stumbled past the solution accidentally during my first search. Didn't realize what I was looking at. Figured out to just leave HUNGERINC: after the HungerAddiction:OnUpdate+15b:

Thanks again!
Back to top
View user's profile Send private message
OldCheatEngineUser
Whateven rank
Reputation: 20

Joined: 01 Feb 2016
Posts: 1587

PostPosted: Tue Jan 01, 2019 10:32 am    Post subject: Reply with quote

Code:
[ENABLE]

alloc(newmem,128,"HungerAddiction:OnUpdate"+15f)
label(return)
label(code)

newmem:
xor eax,eax
mov [hunger],edi // ensure the first script that registers hunger symbol is enabled

code:
mov [rdi+10],eax
mov rax,[rdi+18]
jmp return

"HungerAddiction:OnUpdate"+15f:
jmp newmem
nop
nop
return:


[DISABLE]

dealloc(newmem)
"HungerAddiction:OnUpdate"+15f:
mov [rdi+10],eax
mov rax,[rdi+18]
//Alt: db 89 47 10 48 8B 47 18

_________________
About Me;
I Use CE Since Version 1.X, And Still Learning How To Use It Well!
Jul 26, 2020
STN wrote:
i am a sweetheart.
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine All times are GMT - 6 Hours
Goto page 1, 2, 3  Next
Page 1 of 3

 
Jump to:  
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


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites