• Welcome to Valhalla Legends Archive.
 

[C#] ReadProcessMemory - Getting life

Started by Insolence, June 29, 2007, 10:21 PM

Previous topic - Next topic

Smarter

Quote from: Insolence on July 05, 2007, 05:51 AM
What are "autos"?

Like I said, I looked at the memory dump, and 0x6FBCC1E0 + 0x5c is 0x00 00 00 00. 

Not sure what you mean by "autos", but as I said a second ago, try changing your variable to a byte instead of an integer?
Since '99

BrutalNet.Net

Insolence

Like I said on AIM, a DWORD isn't a byte, it's 4 bytes. :)

Smarter

Ah! After hours of Reversing and running around, I found out the RIGHT address:
            int MemA = 0x0012FBC0;
            int MemB = 0x0012FBC8;
            int MemC = 0x0012FBD0;
            int MemD = 0x0012FBD8;
            ProcessMemoryReader pmr = new ProcessMemoryReader(Proc[0]);
            int p1 = BigEndianBitConverter.Big.ToInt32(pmr.Read(MemA, 8), 4);
            int p2 = BigEndianBitConverter.Big.ToInt32(pmr.Read(MemB, 8), 0);
            int p3 = BigEndianBitConverter.Big.ToInt32(pmr.Read(MemC, 8), 3);
            int p4 = BigEndianBitConverter.Big.ToInt32(pmr.Read(MemD, 8), 0);


Here's the dump of that ;):
0012FBB8  4C 00 69 00 66 00 65 00  L.i.f.e.
0012FBC0  3A 00 20 00 31 00 38 00  :. .1.8.
0012FBC8  30 00 34 00 20 00 2F 00  0.4. ./.
0012FBD0  20 00 31 00 38 00 30 00   .1.8.0.
0012FBD8  34 00 00 00 00 00 00 00  4.......
..


As you can see, my characters life is: 1804 / 1804. The life is stored in UNICODE format, and is grabbed by calling:
0012FB98   6F8EF069  RETURN to D2Win.6F8EF069 from D2Lang.?strlen@Unicode@@SIHPBU1@@Z
which is called by:
0012FBA0   6FB65EB8  RETURN to d2client.6FB65EB8 from <JMP.&D2Win.#10128>

:-D However, i'm having trouble converting the Hex to ASCII/Text in C#, it's quite hard :'(. Can you tell I worked hard? .... This required using ollydbg, putting mouse over red ball:
1) Press ALT-E to open the module list of Diablo II (lists all .dll files that Diablo II is using)
2) Find d2lang.dll and select it. Now Press CTRL-N to get a list of imported/exported function names
3) Find the mangled "strlen(UNICODE)" function and set an execution breakpoint (F2)

Then once it breaks you've found the function, select the 2nd one on the right, and right click and click Follow in Dissasembler :-D!!! and you've got the hex on the left! (Now someone just help me convert hex to text in C# and we're set!)
Since '99

BrutalNet.Net

Insolence

Nice--thanks :D

I see you used Jan's tutorial, that's awesome, however I need to be able to get the actual life value, not a string representation.  I appreciate you putting a ton of work into that, thanks.

I need to be able to interpret structs, here's the UnitAny struct:
struct UNITANY
{
DWORD dwType; //0x00
DWORD dwClassId; //0x04
DWORD _1; //0x08
DWORD dwUnitId; //0x0C
DWORD dwMode; //0x10
union
{
LPPLAYERDATA pPlayerData;
LPITEMDATA pItemData;
LPMONSTERDATA pMonsterData;
LPOBJECTDATA pObjectData;
//LPTILEDATA pTileData doesn't appear to exist anymore
}; //0x14
DWORD dwAct; //0x18
LPACT pAct; //0x1C
DWORD dwSeed[2]; //0x20
DWORD _2; //0x28
union
{
LPPATH pPath;
LPITEMPATH pItemPath;
LPOBJECTPATH pObjectPath;
}; //0x2C
DWORD _3[5]; //0x30
DWORD dwGfxFrame; //0x44
DWORD dwFrameRemain; //0x48
WORD wFrameRate; //0x4C
WORD _4; //0x4E
LPBYTE pGfxUnk; //0x50
LPDWORD pGfxInfo; //0x54
DWORD _5; //0x58
LPSTATLIST pStats; //0x5C
LPINVENTORY pInventory; //0x60
LPLIGHT ptLight; //0x64
DWORD _6[9]; //0x68
WORD wX; //0x8C
WORD wY; //0x8E
DWORD _7; //0x90
DWORD dwOwnerType; //0x94
DWORD dwOwnerId; //0x98
DWORD _8[3]; //0x9C
LPINFO pInfo; //0xA8
DWORD _9[6]; //0xAC
DWORD dwFlags; //0xC4
DWORD dwFlags2; //0xC8
DWORD _10[5]; //0xCC
LPUNITANY pChangedNext; //0xE0
LPUNITANY pRoomNext; //0xE4
LPUNITANY pListNext; //0xE8
};


If I can find the Player instance of the UnitAny struct, I should be able to do its address + 0x5C and get the address to the LPSTATLIST struct, however that doesn't seem to be working.

Smarter

It does fucked up things when you add bytes like that, so maybe that's why, maybe you need to be skipping (like in a Packet Buffer), not adding up?
Since '99

BrutalNet.Net

l2k-Shadow

the struct is stored in memory as a whole. he's adding up the amount of memory each part of the struct takes up.
Quote from: replaced on November 04, 2006, 11:54 AM
I dunno wat it means, someone tell me whats ix86 and pmac?
Can someone send me a working bot source (with bnls support) to my email?  Then help me copy and paste it to my bot? ;D
Já jsem byl určenej abych tady žil,
Dával si ovar, křen a k tomu pivo pil.
Tam by ses povídaj jak prase v žitě měl,
Já nechci před nikym sednout si na prdel.

Já nejsem z USA, já nejsem z USA, já vážně nejsem z USA... a snad se proto na mě nezloběj.

Smarter

So then why would it not be working ? .... :'(
Since '99

BrutalNet.Net

MyndFyre

Have you considered porting the structure itself?

[StructLayout(LayoutKind.Explicit)]
public struct UnitAny
{
    [FieldOffset(0)]
    uint dwType;
    [FieldOffset(4)]
    uint dwClassId;
    [FieldOffset(8)]
    uint _1;
    [FieldOffset(0x0c)]
    uint dwUnitId;
    [FieldOffset(0x10)]
    uint dwMode;

// first union
    [FieldOffset(0x14)]
    IntPtr pPlayerData;
    [FieldOffset(0x14)]
    IntPtr pItemData;
    [FieldOffset(0x14)]
    IntPtr pMonsterData;
    [FieldOffset(0x14)]
    IntPtr pObjectData

    [FieldOffset(0x18)]
    uint dwAct;
    [FieldOffset(0x1c)]
    IntPtr pAct;
    [FieldOffset(0x20)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
    uint[] dwSeed;
    [FieldOffset(0x28)]
    uint _2;

// second union
    [FieldOffset(0x2c)]
    IntPtr pPath;
    [FieldOffset(0x2c)]
    IntPtr pItemPath;
    [FieldOffset(0x2c)]
    IntPtr pObjectPath;

    [FieldOffset(0x30)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=5)]
    uint[] _3;
    [FieldOffset(0x44)]
    uint dwGfxFrame;
    [FieldOffset(0x48)]
    uint dwFrameRemain;
    [FieldOffset(0x4c)]
    ushort wFrameRate;
    [FieldOffset(0x4e)]
    ushort _4;
    [FieldOffset(0x50)]
    IntPtr pGfxUnk;
    [FieldOffset(0x54)]
    IntPtr pGfxInfo;
    [FieldOffset(0x58)]
    uint _5;
    [FieldOffset(0x5c)]
    IntPtr pStats;
    [FieldOffset(0x60)]
    IntPtr pInventory;
    [FieldOffset(0x64)]
    IntPtr ptLight;
    [FieldOffset(0x68)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=9)]
    uint[] _6;
    [FieldOffset(0x8c)]
    ushort wX;
    [FieldOffset(0x8e)]
    ushort wY;
    [FieldOffset(0x90)]
    uint _7;
    [FieldOffset(0x94)]
    uint dwOwnerType;
    [FieldOffset(0x98)]
    uint dwOwnerId;
    [FieldOffset(0x9c)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
    uint[] _8;
    [FieldOffset(0xa8)]
    IntPtr pInfo;
    [FieldOffset(0xac)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=6)]
    uint[] _9;
    [FieldOffset(0xc4)]
    uint dwFlags;
    [FieldOffset(0xc8)]
    uint dwFlags2;
    [FieldOffset(0xcc)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=5)]
    uint[] _10;
    [FieldOffset(0xe0)]
    IntPtr pChangedNext;
    [FieldOffset(0xe4)]
    IntPtr pRoomNext;
    [FieldOffset(0xe8)]
    IntPtr pListNext;
}


Marshal that structure and then marshal the pointer to your statlist structure too.  Remember that you'll have to read the process's memory for the pStats structure too - simply dereferencing the pointer or using Marshal.PtrToStructure() on it won't work because the pStats pointer points to memory in a different process.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Insolence

#23
Wow.

I had no idea you could do that--and to go further, you did it for me.  Thank you very much, I'll try that right now.

EDIT:
                byte[] data = game.Memory.Read((int)Chief.DllBase.D2Client + 0x11C1E0, 232);

                IntPtr pnt = Marshal.AllocHGlobal(data.Length);
                Marshal.Copy(data, 0, pnt, data.Length);

                Chief.Structs.UnitAny PlayerUnit = (Chief.Structs.UnitAny)Marshal.PtrToStructure(pnt, typeof(Chief.Structs.UnitAny));


It seems to be working--however the values I'm getting can't be right (PlayerUnit.dwUnitId, PlayerUnit.wX, etc.).  The PlayerUnit UID is changing whenever I move the character around.

MyndFyre

Just as an aside, I covered a lot of advanced marshaling topics in this blog post which primarily deals with using the WinVerifyTrust API.  I didn't cover unions (which I have hit here in the .NET forum IIRC), but it should be insightful.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Insolence

Thanks--I went over it and saw a _lot_ of examples I can use later.

Smarter

Awww, now I feel out of the loop again ... :'(
Since '99

BrutalNet.Net

Insolence

The address I had was to a pointer to the PlayerUnit struct, not the base of it.  Thanks to AntiRush for pointing that out.

Works now :)

TheMinistered

#28
Smart, its more likely that the memory address you found is a string.  The string is built and then passed to a print text function for display.  Its likely the health is actually stored in a different address, some sort of numerical data type, probably a unsigned short.  But, your method works either way I guess ;)

Insolence


|