PlayerBase ([[[0x00A6D420] + 0x48] + 0x24]) - How to find? menu

User Tag List

Results 1 to 7 of 7
  1. #1
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    PlayerBase ([[[0x00A6D420] + 0x48] + 0x24]) - How to find?

    All-

    So I know easily enough how to find my player's base address by looping through the object list + comparing by GUID. I was just curious, for those using:

    Code:
    DWORD PlayerBasePointer = 0x00A6D420;
    DWORD PlayerBaseOffset1 = 0x48;
    DWORD PlayerBaseOffset2 = 0x24;
    How did you originally discover this? I'm attempting to find it on OS X, and since they changed the compiler (on the 5.x drop) I haven't been able to find it anywhere, even though I can locate the functions it used to be referenced in.

    Edit: Above offsets are for 16057/16135 windows

    Thanks in advance!
    ~ Tanaris
    https://tanaris4.com

    PlayerBase ([[[0x00A6D420] + 0x48] + 0x24]) - How to find?
  2. #2
    DarkLinux's Avatar Former Staff
    CoreCoins Purchaser Authenticator enabled
    Reputation
    1627
    Join Date
    May 2010
    Posts
    1,846
    Thanks G/R
    193/539
    Trade Feedback
    16 (100%)
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    I hook CGObject_C::GetObjectDisplayTransportGUID and pull the playebase from ecx Simple and easy!

    It looks like this,
    Code:
    .text:00811F00                 mov     eax, [ecx]
    .text:00811F02                 mov     edx, [eax+0ACh]
    .text:00811F08                 jmp     edx
    Code:
    int __thiscall sub_811F00(void *this)
    {
      return (*(int (**)(void))(*(_DWORD *)this + 172))();
    }
    If your out of process I guess you could still use this method to initially find the pointer...
    Last edited by DarkLinux; 11-28-2012 at 10:17 AM.

  3. #3
    abuckau907's Avatar Active Member
    Reputation
    49
    Join Date
    May 2009
    Posts
    225
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You use 'tricks' to find it..like if you guess the code that updates local player's health uses localPlayer.Base, you'd be right. something like mov [reg+offset], reg

    you can use a codecave and patching to copy the valuable register to some arbitrary ram location.
    In my example, because it's super simple, I use Cheat Engine to find all the wow code sections that access my local player's health. One of them stores lp.base in a register.

    1. Find actual health loc (via CE scan/rescan)
    2. From that, find the wow code that accesses the health loc
    3. In the wow code you should see some offset, like MOV [register + offset], register
    4. offset is HEALTH_OFFSET (based on object.base, not object.UnitFields, another topic), first register should be localplayer.base
    patch this code loc and copy out register

    I do this (a little more complicated --> I copy the register to an array allocated in wow.exe ram -- you could change it to just copy it once and un-patch itsself)
    in http://www.ownedcore.com/forums/worl...-codecave.html ([theory] alt method to get object list via codecave)

    note: the actual function I patch can have more than local player.base in the register! I'm a hunter and once in a while my pet's .base will be there if it's being attack, and presumably any part members? --> I only do the patch once, manually, when I know i'm not in combat (sloppy, but acceptable), copy the register and store it. never changes (unless you teleport etc. in which case you have to re-find it).

    might not help you much, being on mac, but here is how I codecave/patch to copy a register in vb.net fr3.5
    [code]
    You use 'tricks' to find it..like if you guess the code that updates local player's health uses localPlayer.Base, you'd be right. something like mov [reg+offset], reg

    you can use a codecave and patching to copy the valuable register to some arbitrary ram location.
    In my example, because it's super simple, I use Cheat Engine to find all the wow code sections that access my local player's health. One of them stores lp.base in a register.

    1. Find actual health loc (via CE scan/rescan)
    2. From that, find the wow code that accesses the health loc
    3. In the wow code you should see some offset, like MOV [register + offset], register
    4. offset is HEALTH_OFFSET (based on object.base, not object.UnitFields, another topic), first register should be localplayer.base
    patch this code loc and copy out register

    I do this (a little more complicated --> I copy the register to an array allocated in wow.exe ram -- you could change it to just copy it once and un-patch itsself)
    in http://www.ownedcore.com/forums/worl...-codecave.html

    note: the actual function I patch can have more than local player.base in the register! I'm a hunter and once in a while my pet's .base will be there if it's being attack, and presumably any part members? --> I only do the patch once, manually, when I know i'm not in combat (sloppy, but acceptable), copy the register and store it. never changes (unless you teleport etc. in which case you have to re-find it).

    might not help much, being on mac, but this is how I codecave/patch to copy a register. in vb.net 3.5
    (credits due to fasm_managed.dll for making it easy to turn asm into bytecode)
    Code:
        Public Function GetRegisterOnce(ByVal sourceLoc As IntPtr, ByVal register As CpuRegister) As IntPtr
            Dim _codeCaveStartLoc As IntPtr = Malloc(200) 'in wow.exe ram, used to store (then run) bytecode. todo: auto-sized
            Dim _codeCaveCode(0) As Byte ' stores bytecode to inject into process
            Dim _origAsmLoc As IntPtr = _codeCaveStartLoc.ToInt32 + 100 'executable's orig. code copied here (8 bytes)
            Dim _rtnValueLoc As IntPtr = _codeCaveStartLoc.ToInt32 + 175 'where our asm code copies the register to
            Dim _origProcessByteCode() As Byte = ReadBytes(sourceLoc, 8) 'orig. wow.exe code (must be restored by codecave code)
            WriteBytes(_origAsmLoc, _origProcessByteCode)
            'Create codeCave byte code (copy,cleanup,return)
            'copy register to our dump location
            Dim registerAsString As String = System.Enum.GetName(GetType(CpuRegister), register) 'awk
            Dim sb As New System.Text.StringBuilder
            With sb
                'save registers (that I use) to avoid corrupting stack
                .AppendLine("push eax")
                .AppendLine("push ebx")
                .AppendLine("push edx")
                'copy our rtnValueLoc to a register
                .AppendLine("mov eax, " & _rtnValueLoc.ToInt32.ToString)
                'copy register into the [value] at rtnValueLoc
                .AppendLine("mov [eax], " & registerAsString) 'the magic happens right here
                'clean-up
                .AppendLine("mov eax, " & sourceLoc.ToInt32.ToString)
                .AppendLine("mov ebx, " & _origAsmLoc.ToInt32.ToString)
                .AppendLine("mov edx, [ebx]") 'copy 4 bytes from _origAsmLoc to exe source_loc
                .AppendLine("mov [eax], edx") ' ie. unpatch using exe's orig source code
                .AppendLine("add ebx, 4")
                .AppendLine("add eax, 4")
                .AppendLine("mov edx, [ebx]") 'copy next/last 4 bytes back into wow.exe
                .AppendLine("mov [eax], edx") '
                .AppendLine("pop edx") 'pop order is important. duh.
                .AppendLine("pop ebx")
                .AppendLine("pop eax")
    
            End With
            Dim _individualAsmStrings() As String = Split(sb.ToString, Environment.NewLine)
            If _individualAsmStrings(_individualAsmStrings.Length - 1) = "" Then ReDim Preserve _individualAsmStrings(_individualAsmStrings.Length - 2) 'chop off empty string: last call should use ASM.Append() Not AppendLine() ? works.
            Dim _cdc() As Byte 'codecave bytecode, except 5 bytes for a JMP command.
            _cdc = GetByteCode(_individualAsmStrings)
            Dim _jmpAsm(4) As Byte ' hand crafted JMP command : instead of using managed_fasm.assemble("JMP address")..Educational.
            _jmpAsm(0) = &HE9 'opcode for Relative jump
            ReDim _codeCaveCode(_cdc.Length - 1 + 5) '5 = _jmpAsm.Length in bytes, 'E9' + 4 byte ram address
    
            Dim _bts() As Byte = BitConverter.GetBytes(sourceLoc.ToInt32 - _codeCaveStartLoc.ToInt32 - _codeCaveCode.Length) 'address where codecave jmps back to. (ie. sourceLoc, but relative* because I use 'E9' for JMP not 'FF') !!!
            _bts.Reverse() 'endianness of bytecode
            Array.Copy(_bts, 0, _jmpAsm, 1, 4) 'copy the 4 byte address into the asm jmp command
            Array.Copy(_cdc, _codeCaveCode, _cdc.Length) 'copy the codecavecode(w/o jmp) to array
            Array.Copy(_jmpAsm, 0, _codeCaveCode, _codeCaveCode.Length - 5, 5) 'copy jmp command to end of array
    
            WriteBytes(_codeCaveStartLoc, _codeCaveCode) 'write the bytecode (100% complete now) into process's ram.
            ''Write Jmp command to sourceLoc. ie. WILL make it re-route
            _bts = BitConverter.GetBytes(_codeCaveStartLoc.ToInt32 - (sourceLoc.ToInt32 + 5)) 'address of beginning of codecave. +5 because in asm, JMP is relative* to the NEXT instruction. Jmp is 5 bytes long.
            _bts.Reverse() 'indianness of byte code
            Array.Copy(_bts, 0, _jmpAsm, 1, 4) '_jmpAsm is now complete, again.
            Dim scanStartTime As DateTime = Date.Now
            Dim scanTimeLapse As TimeSpan
            'enable ram to be written to
            Dim _origAccessRights As UInt32 = 0
            Dim _mbi As MEMORY_BASIC_INFORMATION
            VirtualQueryEx(_targetProcessHandle, sourceLoc, _mbi, _mbiSize)
            If Not (_mbi.Protect And MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE) Then
                'change rights
                If Not VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, MemoryAllocationProtectionType.PAGE_EXECUTE_READWRITE, _origAccessRights) Then
                    modPublic.DoOutput("CodeCave::CopyRegisterOnce::VirtualProtectEx fail 0x" & sourceLoc.ToString("X"))
                    Return IntPtr.Zero 'can't write to this memory?
                End If
            End If
            'if we get here, orig perms. were exec_r_w or VirtualProtect worked
            WriteBytes(sourceLoc, _jmpAsm) ' .Patch()
            'modPublic.DoOutput("scanning for rtn value...")
            Dim _origJumpLocCode As UInt64 = BitConverter.ToUInt64(_origProcessByteCode, 0) 'because orig asm is only 8 bytes i used int64. should use byte array.
            Do Until ReadUInt64(sourceLoc) = _origJumpLocCode 'do until the codecave unpatches itsself!(ie. orig code has been restored) nifty.
                scanTimeLapse = Date.Now.Subtract(scanStartTime)
                If scanTimeLapse.TotalSeconds > 10 Then
                    'we need to manually put the source Bcode back
                    WriteBytes(sourceLoc, _origProcessByteCode)
                    If _origAccessRights <> 0 Then
                        'we changed rights, change them back.
                        VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origAccessRights, New UInt32)
                    End If
                    modPublic.DoOutput("Time limit exceeded. 10s")
                    Return IntPtr.Zero ' wow.exe code never got called. or other asm/codecavecode error?...
                End If
            Loop
            'if we get here, success!
            Dim _rtnPtr As IntPtr = ReadIntPtr(_rtnValueLoc) ' == register value !
            'modPublic.DoOutput("success: val=" & _rtnPtr.ToString("x"))
            'free mem allocated for codecave inside wow
            VirtualFreeEx(_targetProcessHandle, _codeCaveStartLoc, 200, MemoryAllocationState.Decommit)
            'restore rights?
            If _origAccessRights <> 0 Then
                VirtualProtectEx(_targetProcessHandle, _mbi.BaseAddress, _mbi.RegionSize, _origAccessRights, New Int32)
            End If
            Return _rtnPtr
        End Function
    Last edited by abuckau907; 11-29-2012 at 10:09 AM.
    Some things that can be counted, don't matter. And some things that matter, can't be counted.

  4. #4
    namreeb's Avatar Legendary

    Reputation
    668
    Join Date
    Sep 2008
    Posts
    1,029
    Thanks G/R
    8/222
    Trade Feedback
    0 (0%)
    Mentioned
    9 Post(s)
    Tagged
    0 Thread(s)
    The first offset is a pointer to an instance of the CModelShared type. In the alpha PDB, it is called CWorldScene::camTargEntity. You can find it by looking at CWorldScene::Initialize(). In the alpha, 1.12.1 and 2.4.3 it is the DWORD set above the "mov dword_foobar, 0Fh" instruction.

    That's all I have so far, but I am about to start looking to the results from your analysis of the Mac binary earlier in the year to try and identify some of the functions at work here.

  5. #5
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yea for some reason it doesn't exist in that function anymore. Probably because they switched compilers is my only guess. Here is that function as of 16309 (it did exist in 15595)

    https://tanaris4.com

  6. #6
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So I tried the trick of watching the health address (read or written to) in GDB. Of course the referenced address in EAX is a pointer to the player's descriptors. :/

    Wasn't able to find anything else strange writing to it.

    One thing I did find (by searching memory for pointers to player base) was a LIST of all units. And the current player is always the first. The list is just of base addresses for all the units, and it's ONLY units. Has anyone ever seen/heard of this before?

    ~ Tanaris

    Edit: The list is at 0x1235CB8 for the 16309 OS X binary. Here is an example of it in memory [0x1235CB8] (the top one is my player):
    Last edited by Tanaris4; 12-06-2012 at 06:51 PM.
    https://tanaris4.com

  7. #7
    namreeb's Avatar Legendary

    Reputation
    668
    Join Date
    Sep 2008
    Posts
    1,029
    Thanks G/R
    8/222
    Trade Feedback
    0 (0%)
    Mentioned
    9 Post(s)
    Tagged
    0 Thread(s)
    Interesting. Did you find a function that references it or some way for me to check if it is present in the Windows binary as well?

Similar Threads

  1. How to find WoW Memory Offset?
    By pegaa in forum World of Warcraft General
    Replies: 0
    Last Post: 08-03-2007, 12:02 AM
  2. How To Find Item ID's?
    By Finalwish in forum WoW ME Questions and Requests
    Replies: 1
    Last Post: 07-25-2007, 08:50 PM
  3. How to find a bot who work...
    By tamipop in forum World of Warcraft General
    Replies: 4
    Last Post: 02-19-2007, 08:14 PM
  4. How To: Find put ur IP address by clicking on an icon
    By ttttllllrrrr in forum Community Chat
    Replies: 1
    Last Post: 01-27-2007, 08:47 PM
  5. How to find a get a rogue stealthed -- Warlock only
    By koalaz2004 in forum World of Warcraft Exploits
    Replies: 5
    Last Post: 08-26-2006, 10:53 AM
All times are GMT -5. The time now is 05:26 AM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search