Deprecated: The behavior of unparenthesized expressions containing both '.' and '+'/'-' will change in PHP 8: '+'/'-' will take a higher precedence in /home/iano/public_html/tpforums-vb5/forum/includes/class_core.php on line 5842

PHP Warning: Use of undefined constant MYSQL_NUM - assumed 'MYSQL_NUM' (this will throw an Error in a future version of PHP) in ..../includes/init.php on line 165

PHP Warning: Use of undefined constant MYSQL_ASSOC - assumed 'MYSQL_ASSOC' (this will throw an Error in a future version of PHP) in ..../includes/init.php on line 165

PHP Warning: Use of undefined constant MYSQL_BOTH - assumed 'MYSQL_BOTH' (this will throw an Error in a future version of PHP) in ..../includes/init.php on line 165

PHP Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in ..../includes/functions_navigation.php on line 588

PHP Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in ..../includes/functions_navigation.php on line 612

PHP Warning: Use of undefined constant misc - assumed 'misc' (this will throw an Error in a future version of PHP) in ..../global.php(29) : eval()'d code(6) : eval()'d code on line 1

PHP Warning: Use of undefined constant index - assumed 'index' (this will throw an Error in a future version of PHP) in ..../global.php(29) : eval()'d code(6) : eval()'d code on line 1

PHP Warning: Use of undefined constant misc - assumed 'misc' (this will throw an Error in a future version of PHP) in ..../includes/class_bootstrap.php(1422) : eval()'d code(4) : eval()'d code on line 1

PHP Warning: Use of undefined constant index - assumed 'index' (this will throw an Error in a future version of PHP) in ..../includes/class_bootstrap.php(1422) : eval()'d code(4) : eval()'d code on line 1

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6
C# Memory Reading Tutorial [revised]
Results 1 to 10 of 10

Thread: C# Memory Reading Tutorial [revised]

  1. #1
    Senior Member
    Join Date
    Jan 2008
    Location
    Cambridge, England
    Posts
    725

    C# Memory Reading Tutorial [revised]

    If you just want code
    If you just want code, as you learn better from it, this piece of software can be found on google code at http://code.google.com/p/tibia-reader/source/browse/trunk/MemoryReader/Form1.cs

    Note that it may not work fully, and it will probably contain some bugs. It was written as an example only, and for the purpose of demonstrating how easy it is to extract information from the Tibia client. The information can be used in a variety of ways, the most common of course being to create a cavebot. The best understanding of this will come from the tutorial detailed below, but I have not followed best practice, as I am not a professional programmer, just a hobbyist. There is also a compiled version of the software on the google code page, so if you want to see the results you are welcome to take a look at that.

    Getting Started

    So, first off, we need to set out some variables to work with. This will allow us to store and call data as we need it.
    Here are the two process based ones, which will allow us to obtain information from our computer about which pieces of memory Tibia is using. The first variable will store the base address, and the second will store the process itself (as in task manager, but with more information!)
    [code=c#] public static UInt32 Base = 0;
    public static Process Tibia = null;[/code]

    Now for our memory addresses
    [code=c#] UInt32 Pxor = 0x3B3ED0;
    UInt32 HpAdr = 0x549000;
    UInt32 XpAdr = 0x3B3EE0;
    UInt32 MpAdr = 0x3B3F24;
    UInt32 CpAdr = 0x580E94;
    UInt32 SlAdr = 0x3B3F10;
    UInt32 StAdr = 0x3B3F58;
    UInt32 MlAdr = 0x3B3ED4;
    UInt32 IdAdr = 0x580EA4;[/code]

    If the client is updated, the addresses are all we need to update. Here are a few more, which are only used in the battle list
    [code=c#] UInt32 BlStart = 0x549008;
    UInt32 BlStep = 0xB0;
    public int MaxCreatures = 1300;[/code]
    These dictate where (in the memory) the battle list starts - BlStart, and how big each entry in the battle list is - BlStep. The third shows how many creatures the Tibia client can store information on at once - MaxCreatures. The tibia client itself will only allow 1300, so we will too.


    Using Windows functions, our way
    The next step is to import a function from a windows library, which will allow us to access Tibias memory.
    [code=c#] [DllImport("kernel32.dll")]
    public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
    [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead);[/code]

    Now we want to use this function (ReadProcessMemory) to read memory addresses, and convert the contents to a format which will be useful to us. So we will start off by creating something to simplify this function (otherwise we would need to enter more information than we should).

    ?
    [code=c#] public static byte[] ReadBytes(IntPtr Handle, Int64 Address, uint BytesToRead)
    {
    IntPtr ptrBytesRead;
    byte[] buffer = new byte[BytesToRead];
    ReadProcessMemory(Handle, new IntPtr(Address), buffer, BytesToRead, out ptrBytesRead);
    return buffer;
    }[/code]
    ReadBytes will now read bytes, and return the bytes, so we can do for instance byte[] myvariable = ReadBytes(Handle, Address, BytesToRead);

    To use this more to our benefit, we can also convert the bytes into integer values, as shown.
    [code=c#] public static int ReadInt32(IntPtr Handle, long Address)
    {
    return BitConverter.ToInt32(ReadBytes(Handle, Address, 4), 0);
    }[/code]

    And we can read strings, using an ASCII converter. This also removes all “null characters” from the extracted string, after reading 32 bytes. Because we are reading exactly 32 bytes each time we run this, we will always have 32 bytes of data. We can store a name, like XtrmJosh in fewer than 32 bytes, in fact I believe it would take 8 bytes (don’t take my word for that though, I’m no memory buff!) As a result of this, using ASCII encoder, we would end up with a string like XtrmJosh000000000000000000000000, or something of a similar length, at least. These 0s all represent “\0”, which is a null character in C#. We are replacing those, using temp3 (the variable our read string is stored in) as shown.
    [code=c#] public static string ReadString(IntPtr Handle, long Address)
    {
    string temp3 = ASCIIEncoding.Default.GetString(ReadBytes(Handle, Address, 32));
    return temp3.Replace("\0", string.Empty);
    }[/code]

    Ease of Access to memory
    To make it easier to access the memory, we can now write some functions which will read the memory at the addresses we declared earlier. Here are a few I’ve put together, see what addresses you can find, and see how you get on with them.
    [code=c#]
    public int hp() { return ReadInt32(Tibia.Handle, HpAdr + Base) ^ ReadInt32(Tibia.Handle, (Pxor + Base)); }
    public int xp() { return ReadInt32(Tibia.Handle, XpAdr + Base); }
    public int mp() { return ReadInt32(Tibia.Handle, MpAdr + Base) ^ ReadInt32(Tibia.Handle, (Pxor + Base)); }
    public int cp() { return (ReadInt32(Tibia.Handle, CpAdr + Base) ^ ReadInt32(Tibia.Handle, (Pxor + Base))) / 100; }
    public int id() { return ReadInt32(Tibia.Handle, IdAdr + Base); }
    public int ml() { return ReadInt32(Tibia.Handle, MlAdr + Base) ^ ReadInt32(Tibia.Handle, (Pxor + Base)); }
    public int sl() { return ReadInt32(Tibia.Handle, SlAdr + Base); }
    public string st() { int minb = ReadInt32(Tibia.Handle, StAdr + Base); int houa = minb / 60; int mina = minb % 60; return houa.ToString() + ":" + mina.ToString("D2"); }
    [/code]

    Now, that's our general structure assembled.

    We must now just declare our client, for which I've written another function we can call:

    [code=c#] private void selectclient()
    {
    Process[] TibiaProcess = Process.GetProcessesByName("Tibia");
    Tibia = TibiaProcess[0];
    Base = Convert.ToUInt32(Tibia.MainModule.BaseAddress.ToIn t32());
    }[/code]

    This will select the first client it finds, if you want, I will add a tutorial for creating a list of clients. This also gets the base address of the client (the starting address, explained further in the battle list tutorial).

    Stay tuned for some guide to reading the battle list.

    For anyone really newbie, I'll point out that to read memory, after having implemented this code, you just need to do:

    [code=c#]
    MessageBox.Show("Health: " + Convert.ToString(hp()));
    [/code]

    Of course change hp() to xp() or whatever you want.
    [hr]
    Reading the Battle List

    Structure
    So first off, we need to make a structure. It’s an easy thing to do, just add some code similar to this into your form. Generally speaking, people create a new class for their structures, but for those who don’t know how to do this, you can do it this way for now. If you intend to make some massive advanced program, you will want to learn about using multiple classes and how to pass data between them.

    [code=c#] public struct blist
    {
    public int cid;
    public int type;
    public string name;
    public int z;
    public int y;
    public int x;
    public int iswalking;
    public int direction;
    public int outfit;
    public int outfithead;
    public int outfitbody;
    public int outfitlegs;
    public int outfitfeet;
    public int outfitaddon;
    public int light;
    public int lightcolour;
    public int hpbar;
    public int walkspeed;
    public int unknown;
    public int skull;
    public int party;
    public int war;
    public int blocking;
    public int visible;
    }[/code]

    Offsets
    Offsets are simple, really, they are exactly what they say. Take the number 1, and consider that the start of a street is house number 1. The house at number 5 would have an offset of 4, because it is 4 houses along from 1! If, however, the first house was 3, house number 5 would have an offset of just 2! I hope this makes sense. The offsets are as follows, though don’t use this code in your form as it is space consuming, and probably confusing. I recommend adding a text file to your project and saving this list there, for future reference.

    UInt32 OFFSET_CREATURE_ID = 0;
    UInt32 OFFSET_CREATURE_TYPE = 3;
    UInt32 OFFSET_CREATURE_NAME = 4;
    UInt32 OFFSET_CREATURE_Z = 36;
    UInt32 OFFSET_CREATURE_Y = 40;
    UInt32 OFFSET_CREATURE_X = 44;
    UInt32 OFFSET_CREATURE_IS_WALKING = 80;
    UInt32 OFFSET_CREATURE_DIRECTION = 84;
    UInt32 OFFSET_CREATURE_OUTFIT = 100;
    UInt32 OFFSET_CREATURE_OUTFIT_HEAD = 104;
    UInt32 OFFSET_CREATURE_OUTFIT_BODY = 108;
    UInt32 OFFSET_CREATURE_OUTFIT_LEGS = 112;
    UInt32 OFFSET_CREATURE_OUTFIT_FEET = 116;
    UInt32 OFFSET_CREATURE_OUTFIT_ADDON = 120;
    UInt32 OFFSET_CREATURE_LIGHT = 124;
    UInt32 OFFSET_CREATURE_LIGHT_COLOR = 128;
    UInt32 OFFSET_CREATURE_HP_BAR = 140;
    UInt32 OFFSET_CREATURE_WALK_SPEED = 144;
    UInt32 OFFSET_CREATURE_IS_VISIBLE = 148;
    UInt32 OFFSET_CREATURE_SKULL = 152;
    UInt32 OFFSET_CREATURE_PARTY = 156;
    UInt32 OFFSET_CREATURE_WARICON = 164;
    UInt32 OFFSET_CREATURE_ISBLOCKING = 168;
    UInt32 OFFSET_CREATURE_WITHINVIEW = 172;

    The offsets are pretty self-explanatory, if you need help with one in particular, just ask.

    I’m confused, where are we?
    So what we’ve done previously is we’ve found a Tibia client, and gotten the base address for it. We’ve then read memory using the address of each element we wanted (e.g the address of our experience, or the address of our health). What we will now do is read the battle list. To do this we basically have to do start address (Base), added onto the battle lists start address (BlStart), then added to the offset of each piece of information (e.g 4 for creature name). Are you still with me?

    Finally, the actual “reading”
    So here what we will do is read each offset one by one, for the first entry in the battle list. We will then add the step for the creature on to a variable, “current”, so we can track which entry into the battle list we are on. We will then repeat the process until we have read all (up to 1300) entries.

    The function looks a little like this:
    [code=c#] private void readBlist()
    {
    // Declare an integer “max”, which will calculate the highest memory address to read.
    int max = Convert.ToInt32(BlStep) * MaxCreatures;
    // Declare a list of blist (the struct we made earlier) to store the information into.
    lst = new blist[1300];
    // Declare the current variable, to show where we are each time we start the loop
    UInt32 current = BlStart;
    // Basically declare I to be 0, and whilst I is under 250, do the contents of the braces and add 1 to i.
    for (int i = 0; i < 1300; i++)
    {
    // If the current creature id is not 0, read the information about the entry. This saves us from reading 1300 entries if we don’t need to, we will always read 1300 creature ids, but we won’t waste time reading all the other shit.
    if (ReadInt32(Tibia.Handle, current + Base) != 0)
    {
    int[] offsets = new int[24] { 0, 3, 4, 36, 40, 44, 80, 84, 100, 104, 108, 112, 116, 120, 124, 128, 140, 144, 148, 152, 156, 164, 168, 172 };
    int b = 0;
    lst[i].cid = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].type = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].name = ReadString(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].z = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].y = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].x = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].iswalking = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].direction = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].outfit = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].outfithead = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].outfitbody = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].outfitlegs = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].outfitfeet = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].outfitaddon = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].light = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].lightcolour = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].hpbar = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].walkspeed = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].unknown = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].skull = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].party = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].war = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    lst[i].blocking = ReadInt32(Tibia.Handle, current + offsets[b] + Base);
    lst[i].visible = ReadInt32(Tibia.Handle, current + offsets[b] + Base); b = b + 1;
    }
    // Add the step to the variable current, so next time we read the next entry.
    current = current + BlStep;
    }
    }[/code]

    Each line is explained where applicable, so please read this carefully to help you understand.

    Once this function has been run, we can simple call lst.Name, lst.cid or whatever to get that piece of information about the creature.

  2. #2
    Senior Member
    Join Date
    Jan 2008
    Location
    Cambridge, England
    Posts
    725

    RE: C# Memory Reading Tutorial [revised]

    Generating a client list
    To generate a list of clients is very simple. The easiest way is to create a list based on the process ID, though I will very briefly explain how this is done using the player name, as opposed to the Process ID. First off, let’s look at a simple loop through the currently active processes with the correct name (Tibia).
    [code=c#] private void refreshclients()
    {
    Process[] TibiaProcess = Process.GetProcessesByName("Tibia");
    listBox1.Items.Clear();
    foreach (Process p in TibiaProcess)
    {
    listBox1.Items.Add(“Process ID:” + Convert.ToString(P.Id));
    }
    }[/code]

    This will add each process with the name “Tibia” to listBox1. Note that I didn’t insert a space after the colon in the string “Process ID:”. This is important as it prevents the misuse of a function, string.Split, which we will use later. Now we have a list of clients, let’s look at how to handle the use of this list, and make it so that when we select one of the clients it updates the rest of the software.

    Selecting a client
    So this function will select a new client when called, based on what is selected in listBox1. It will loop, once again, through the list of active processes with the name “Tibia”, and look at the process ID. It will then take the process ID which we stored in listBox1 earlier, and compare it to the process ID of each active process named “Tibia”, until it finds a match. Once it finds a match it will set our variables “Tibia” and “Base” to the values of that process, allowing us to use those 2 variables in the future for any reading.
    [code=c#] private void reselectclient()
    {
    Process[] TibiaProcesses = Process.GetProcessesByName("Tibia");
    string[] strs = Convert.ToString(listBox1.SelectedItem).Split(':') ;
    foreach (Process pr in TibiaProcesses)
    {
    if (Convert.ToString(pr.Id) == strs[1])
    {
    Tibia = pr;
    Base = Convert.ToUInt32(Tibia.MainModule.BaseAddress.ToIn t32());
    }
    }
    }[/code]
    It’s a pretty simple function, but it does what it is supposed to, and it does it efficiently and well.

    Using the character name for the client list
    To do this we need to use the same loops as above, but each time we loop we need to read the memory to find the creature ID of the character logged into the client, and check it against the battle list of the client. In the example code I have integrated this well, but not tested it so thoroughly, so please excuse any tolerances. The simple way to do this is to pass the process into the function which reads the battle list, and read it using that passed in process.

  3. #3
    Super Moderator
    Join Date
    May 2007
    Posts
    1,191

    RE: C# Memory Reading Tutorial [revised]

    Sorry to say, but the code you've provided contains barely any OO and is overall poorly written.

  4. #4
    Senior Member
    Join Date
    Jan 2008
    Location
    Cambridge, England
    Posts
    725

    RE: C# Memory Reading Tutorial [revised]

    I feel the annotations written here would've been enough for me to have learnt from it, so I can't see how much more is required. The code itself was written from midnight until 2am, and parts of it don't even work. But as you, I'm only trying to help people and point them in the right direction, not give them source code. When I first started programming with Tibia this entire thing was what confused me, so I've written 2 tutorials which would've helped me, hoping they will help others.

    Could you also do me a massive favor & confirm my ML address, I don't have olly or CE on this pc so can't check it, but the value is returning wrongly.

  5. #5
    I've made a battle list loop like showed in this thread with the actual tibia global addresses. I was on port hope DP, and it returned to me, my name, 2 characters that was inside depot, every NPC on up floors, and 2 characters that was far south east from depot.

    I missing something here, can someone gimme a hint ? XD

  6. #6
    Senior Member
    Join Date
    Mar 2009
    Location
    Brazil
    Posts
    266
    You're probably doing it right.

    Thing is battlelist cache isn't cleaned when a creature leaves your screen. So, yes, there will be a lot of shitty data (including creatures you'd killed).

  7. #7
    Quote Originally Posted by Ash Katchup View Post
    You're probably doing it right.

    Thing is battlelist cache isn't cleaned when a creature leaves your screen. So, yes, there will be a lot of shitty data (including creatures you'd killed).
    aaaaaaah! so i'll need to do a check if its alive/around etc to check the real battle list? xD

  8. #8
    In the BattleList structure you can get those values, like if the player is in your floor (Z position), if it's in your screen ("On Screen" flag) and many other things, TibiaAPI has most of those distances, probably not all will work since they might changed since its last update.

  9. #9
    Senior Member
    Join Date
    Mar 2009
    Location
    Brazil
    Posts
    266

  10. #10
    @Casky, @Ash Katchup i'll check asap, and give you guys feedback!

    Thankz!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •