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 


k_backingfields in monostructs

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine
View previous topic :: View next topic  
Author Message
Eggs_
How do I cheat?
Reputation: 0

Joined: 19 Jun 2025
Posts: 7

PostPosted: Thu Jun 19, 2025 10:05 am    Post subject: k_backingfields in monostructs Reply with quote

Hello,
i've been dealing with an unitygame using mono and here's my question:
when using getmonostruct(classname), i can get the normal fields of said class as offsets so for instance i could do

getmonostruct(Player)

mov rax,[rcx+Player.Id] //this works
mov rax,[rcx+Player.<_playerstats>k__BackingField] //this doesnt work cause, CE can't find the field.

I could not find any relevant information in the wiki.
so my question would be is there a way to automatically grab the offsets of such fields? maybe with lua? an example would be much apprechiated.
Back to top
View user's profile Send private message
Eggs_
How do I cheat?
Reputation: 0

Joined: 19 Jun 2025
Posts: 7

PostPosted: Thu Jul 10, 2025 2:12 am    Post subject: Reply with quote

bump
Back to top
View user's profile Send private message
DhaosCollider
How do I cheat?
Reputation: 0

Joined: 12 Mar 2022
Posts: 7

PostPosted: Thu Jul 10, 2025 4:22 am    Post subject: Reply with quote

I tested whether the BackingField variable would cause any issues, but it worked just fine.

Behind the scenes, getmonostruct is just a call to monoAA_GETMONOSTRUCT.
Code:

function monoAA_GETMONOSTRUCT(parameters, syntaxcheckonly)
  --called whenever an auto assembler script encounters the GETMONOSTRUCT() line

  --parameters: classname or classname,namespace:classname  (or classname,classname)

  --turns into a struct define

  local c,name,classname,namespace

  c=string.find(parameters,",")
  if c==nil then
    --just find this class
    name=parameters
    classname=parameters
    namespace=''
    --print("Format 1")
    --print("name="..name)
    --print("classname="..classname)
    --print("namespace="..namespace)

  else
    --this is a name,namespace:classname notation
    --print("Format 2")

    name=string.sub(parameters, 1, c-1)
    parameters=string.sub(parameters, c+1, #parameters)


    c=string.find(parameters,":")
    if (c~=nil) then
      namespace=string.sub(parameters, 1,c-1)

      classname=string.sub(parameters, c+1, #parameters)
    else
      namespace='';
      classname=parameters
    end

    --print("name="..name)
    --print("classname="..classname)
    --print("namespace="..namespace)

  end

  name=name:match "^%s*(.-)%s*$"
  classname=classname:match "^%s*(.-)%s*$"
  namespace=namespace:match "^%s*(.-)%s*$"

  local class=mono_findClass(namespace, classname)
  if (class==nil) or (class==0) then
    return nil,translate("The class ")..namespace..":"..classname..translate(" could not be found")
  end

  local fields=mono_class_enumFields(class)
  if (fields==nil) or (#fields==0) then
    return nil,namespace..":"..classname..translate(" has no fields")
  end


  local offsets={}
  local i
  for i=1, #fields do
    if (fields[i].offset~=0) and (not fields[i].isStatic) then
      offsets[fields[i].offset]=fields[i].name
    end
  end

  local sortedindex={}
  for c in pairs(offsets) do
    table.insert(sortedindex, c)
  end
  table.sort(sortedindex)

  local result="struct "..name.."\n"
  local fieldsize

  if #sortedindex>0 then
    fieldsize=sortedindex[1]-0;

    result=result.."vtable: resb "..fieldsize
  end

  result=result.."\n"


  for i=1, #sortedindex do
    local offset=sortedindex[i]



    local name=offsets[offset]
    result=result..name..": "
    if sortedindex[i+1]~=nil then
      fieldsize=sortedindex[i+1]-offset
    else
      --print("last one")
      fieldsize=1 --last one
    end

    result=result.." resb "..fieldsize.."\n"

  end 

  result=result.."ends\n"

  --showMessage(result)

  return result
end

You can try it on the Lua Engine. Here's what I got when I tested it:

  • Execute code
    Code:
    return monoAA_GETMONOSTRUCT("AccessibilityManager")

  • This is what it returns
    Code:

    1:struct AccessibilityManager
      vtable: resb 16
      <Enabled>k__BackingField:  resb 8
      config:  resb 8
      OnAssistModeEnabledChanged:  resb 8
      OnGameSpeedChanged:  resb 8
      OnDmgReductionFactorChanged:  resb 8
      OnIgnoreKnockbacksChanged:  resb 8
      OnHyperchargeDurationMultiplierChanged:  resb 8
      OnGuillotineHitboxScaleMultiplierChanged:  resb 8
      shownWarning:  resb 1
      assistModeEnabled:  resb 3
      gameSpeed:  resb 4
      dmgReductionFactor:  resb 4
      ignoreKnockbacks:  resb 4
      hyperchargeDurationMultiplier:  resb 4
      guillotineHitboxScaleMultiplier:  resb 1
      ends

  • AA command
    Code:
    dd AccessibilityManager.<Enabled>k__BackingField

    I checked in memory and it was 0x10.
Back to top
View user's profile Send private message
Eggs_
How do I cheat?
Reputation: 0

Joined: 19 Jun 2025
Posts: 7

PostPosted: Thu Jul 10, 2025 12:40 pm    Post subject: Reply with quote

DhaosCollider wrote:
I tested whether the BackingField variable would cause any issues, but it worked just fine.
[*]AA command
Code:
dd AccessibilityManager.<Enabled>k__BackingField

I checked in memory and it was 0x10.
[/list]


It worked! Thanks!
Though what's confusing was that the moment i wrapped my AA script in lua, it started working.
Code:
[ENABLE]
{$lua}
  monoAA_GETMONOSTRUCT("STEFaceTalentView")
  monoAA_GETMONOSTRUCT("GameCharacterTalentModelBase")
 local script = [[
define(UpdateTalent,RPG.UI.Widgets.Timelines.STEFaceTalentView.UpdateTalentChargeAndCooldown)
alloc(newmem,$1000,UpdateTalent)
label(UpdateTalentBkp)
label(return)

newmem:
  push rax
  mov rax,[rcx+STEFaceTalentView.<Talent>k__BackingField]
  mov [rax+<RechargeCounter>k__BackingField],0  //not even using classname still works
  //mov rax,[rcx+58]      // this.Talent
  //mov [rax+38],#0       // Talent.RechargeCounter = 0
  pop rax
UpdateTalentBkp:
  readmem(UpdateTalent,6)
  jmp return

UpdateTalent:
  jmp newmem
  nop
return:
registersymbol(UpdateTalent UpdateTalentBkp)

  ]]
  autoAssemble(script)
{$asm}



[DISABLE]

UpdateTalent:
  readmem(UpdateTalentBkp,6)

unregistersymbol(*)
dealloc(*)


however the original script using only AA script would give me an error:
Code:
[ENABLE]
define(UpdateTalent,RPG.UI.Widgets.Timelines.STEFaceTalentView.UpdateTalentChargeAndCooldown)
alloc(newmem,$1000,UpdateTalent)
getmonostruct(STEFaceTalentView)
label(UpdateTalentBkp)
label(return)

newmem:
  push rax
  //mov rax,[rcx+STEFaceTalentView.<Talent>k__BackingField]  // |<==gives an error
  mov rax,[rcx+58]  //STEFaceTalentView.Talent
  mov [rax+38],#0  //GameCharacterTalentModel.RechargeCounter
  pop rax
UpdateTalentBkp:
  readmem(UpdateTalent,6)
  jmp return

UpdateTalent:
  jmp newmem
  nop
return:
registersymbol(UpdateTalent UpdateTalentBkp)

[DISABLE]

UpdateTalent:
  readmem(UpdateTalentBkp,6)

unregistersymbol(*)
dealloc(*)


which is to some extend confusing.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine All times are GMT - 6 Hours
Page 1 of 1

 
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