I wrote a proof of concept to show you how to traverse the containers tree. I coded it in C#, since it's not my prefered language, I may not be quite familiar with it. I hope that's what you are looking for.
Code:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Containers
{
class Program
{
[DllImport("kernel32.dll")]
static extern int ReadProcessMemory(
IntPtr pHandle,
UInt32 address,
IntPtr buffer,
int size,
out int readedBytes
);
struct TTreeNode {
public UInt32 left, parent, right;
public byte color;
public byte isNil;
public UInt32 key, containerAddress;
}
struct TTreeEntry {
public UInt32 proxy, head; //Head is not the tree root, instead, Head.Parent is.
public int count;
}
static TTreeNode ReadTreeNode(IntPtr pHandle, UInt32 nodeAddress)
{
int readedBytes;
Type nodeType = typeof(TTreeNode);
int typeSize = Marshal.SizeOf(nodeType);
IntPtr buffer = Marshal.AllocHGlobal(typeSize);
ReadProcessMemory(pHandle, nodeAddress, buffer, typeSize, out readedBytes);
TTreeNode node = (TTreeNode)Marshal.PtrToStructure(buffer, nodeType);
if (node.isNil == 0)
{
Console.WriteLine("Index: {0} Container address: 0x{1:X}", node.key, node.containerAddress);
ReadTreeNode(pHandle, node.left);
ReadTreeNode(pHandle, node.right);
}
return node;
}
static void ReadTree(IntPtr pHandle, UInt32 entryAddress)
{
int readedBytes;
Type entryType = typeof(TTreeEntry);
int typeSize = Marshal.SizeOf(entryType);
IntPtr buffer = Marshal.AllocHGlobal(typeSize);
ReadProcessMemory(pHandle, entryAddress, buffer, typeSize, out readedBytes);
TTreeEntry entry = (TTreeEntry) Marshal.PtrToStructure(buffer, entryType);
Marshal.FreeHGlobal(buffer);
TTreeNode node = ReadTreeNode(pHandle, entry.head);
ReadTreeNode(pHandle, node.parent);
}
static UInt32 ReadContainerAddress(IntPtr pHandle, UInt32 pointertAddress)
{
int readedBytes;
int intSize = sizeof(UInt32);
IntPtr buffer = Marshal.AllocHGlobal(intSize);
ReadProcessMemory(pHandle, pointertAddress, buffer, intSize, out readedBytes);
UInt32 result = (UInt32)Marshal.PtrToStructure(buffer, typeof(UInt32));
Marshal.FreeHGlobal(buffer);
return result;
}
static void Main(string[] args)
{
Process process = Process.GetProcessesByName("tibia")[0];
UInt32 containers_PointerAddress = 0xB7A2A4;
ReadTree(process.Handle, ReadContainerAddress(process.Handle, ((UInt32) process.MainModule.BaseAddress.ToInt32()) + containers_PointerAddress - 0x400000));
Console.ReadLine();
}
}
}