Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to find out this way that can reads eveonline memory data #81

Open
thouger opened this issue Apr 1, 2023 · 4 comments
Open

How to find out this way that can reads eveonline memory data #81

thouger opened this issue Apr 1, 2023 · 4 comments

Comments

@thouger
Copy link

thouger commented Apr 1, 2023

This function is not specific to EVE Online but can be used with other game clients as well.
But i tried several game and this only way seems to be tailor-made only for eveonline.Why do i say this seems to only work for eve online game.

  1. EnumeratePossibleAddressesForUIRootObjects function will find str which change to bytes is type and UIRoot,Why you'll know what to look for?i use function ReadNullTerminatedAsciiStringFromAddressUpTo255,not all processes have type and UIRoot.
  2. ReadUITreeFromAddress function has use memoryReader.ReadBytes.Sometimes it use 0x10 and sometimes is use 0x20 or 0x30,how to know this bytes length.

I guess the secret is in ReadUITreeFromAddress function.I don't know how do you know that this function is written like this.i'm good at Android Reverse but not good at PC Reverse.
Can you share how you know to read eveonline memory this way?I would be grateful!
If it bothers you a lot of time this time, would you like to share information similar to this and I can learn by myself

@Viir
Copy link
Collaborator

Viir commented Apr 4, 2023

Some commands in the program are specific to EVE Online.
But the command to save a process sample is not specific to EVE Online. You can use that one with any game.

Can you share how you know to read eveonline memory this way?I would be grateful!

I recommend reading the discussion at https://forum.botlab.org/t/advanced-do-it-yourself-memory-reading-in-eve-online/68

And here is the diagram that was linked in that discussion:
https://github.com/Arcitectus/Sanderling/blob/91f518cb1e0851b1423d0e0ecbd34234c454f1dc/guide/image/2015-01.eve-online-python-ui-tree-structure.png?raw=true

Also related: https://forum.botlab.org/t/understanding-memory-reading/3485/2?u=viir

@thouger
Copy link
Author

thouger commented Apr 10, 2023

thank Viir!I found some conclusive things in the information you provided, but I didn't find what I was looking for.
I want to know how you knew the structure format of its stored data, and even how you knew it was written in python.
But it doesn't matter, I expanded my exploration from your conclusion, and I found the following points

  1. I searched all the files in the eve directory, there is no file name contain "ui" or "tree", so I started to look at some dll files, and then I found this,a code.ccp file is a zip.so i unzip
    image
  2. according tohttps://github.com/Arcitectus/Sanderling/blob/91f518cb1e0851b1423d0e0ecbd34234c454f1dc/guide/image/2015-01.eve-online-python-ui-tree-structure.png?raw=true,it look like has something to do with UITree and 'children',so i find this
    image
  3. in this code,it has 0x28 and 0x18,this correspondence,
    image

Is my inference correct? Did you use this method to discover the principle? But how did you know that it will use the elementtree file, and why its data will pass through getchildren?

@Viir
Copy link
Collaborator

Viir commented Apr 16, 2023

The discovery happened circa ten years ago. At the moment, I only remember a few details.

Did you use this method to discover the principle?

No, here is what I remember ATM:
How did I know there was something written in Python? CCP, the developers said that somewhere.
Initially, I followed a more generic approach that was independent of the specifics introduced with Python. But that did not yield enough information quickly enough, so I pivoted to exploring paths using Python.
CPython is a popular project that implements a Python interpreter. Therefore I guessed that the memory layout for many interesting objects might be aligned with CPython. That turned out to work very well. You can derive many offsets by reading the CPython program code.

@thouger
Copy link
Author

thouger commented Apr 16, 2023

i has analyze a little.Just because I analyzed a part, I understand how difficult this step is. I think this part is the most difficult part of the whole program, but you can do them so perfectly. This part is enough for me to learn It's been a long time, really a great explorer, but I think my method should not be the optimal solution, I will continue to explore the method you used at the beginning, a scientific method, I am very interested in this

  1. a1 is a PyDictObject, and a2 is a tuple.
  2. PyArg_ParseTuple parses the a2 tuple and calls the getchildren method in the xml module.
  3. a1 + 40 retrieves the keys and assigns them to v4. It then checks if the length of the keys is 0, and if so, returns an empty list.
  4. v4 + 8 retrieves the keys and assigns them to v6.
  5. Inside the if statement, a1 retrieves its dictionary and checks if its length is 0.
  6. v9 = *(_QWORD **)(v8 + *(_QWORD *)(v7 + 0x10)); Here, v7 is a dictionary, and v7 + 0x10 points to the ma_values member of the dictionary object, which is the address of an array storing all values in the dictionary. This statement retrieves the values.
  7. *(_QWORD *)(v8 + *(_QWORD *)(v6 + 0x18)) = v9; This statement looks like the PyList_SET_ITEM macro, where *(_QWORD *)(v6 + 0x18) represents the address of the PyListObject structure of v6 in memory, and v8 is the element offset of the v6 array. Therefore, v8 + *(_QWORD *)(v6 + 0x18) is the address of the element to be set, and *(_QWORD *)(v8 + *(_QWORD *)(v6 + 0x18)) is the value of this element. This statement sets a certain element of the v6 list to v9.
  8. Finally, v6 is returned.

image

typedef struct {
    PyObject_HEAD

    /* Number of items in the dictionary */
    Py_ssize_t ma_used;

    /* Dictionary version: globally unique, value change each time
       the dictionary is modified */
    uint64_t ma_version_tag;

    PyDictKeysObject *ma_keys;

    /* If ma_values is NULL, the table is "combined": keys and values
       are stored in ma_keys.

       If ma_values is not NULL, the table is splitted:
       keys are stored in ma_keys and values are stored in ma_values */
    PyObject **ma_values;
} PyDictObject;

PyObject_HEAD is a macro definition that expands to a structure containing a reference count and type information. Depending on the Python version, PyObject_HEAD may be implemented differently, but it usually takes up 16 bytes.
Py_ssize_t ma_used is a signed integer type, typically 4 or 8 bytes, depending on the platform and compiler.
uint64_t ma_version_tag is an unsigned 64-bit integer, occupying 8 bytes.
PyDictKeysObject *ma_keys is a pointer type, typically 8 bytes.
PyObject **ma_values is also a pointer type, typically 8 bytes.
Therefore, a1 is a dictionary with keys at a1+40, and adding 8 retrieves the keys, while adding 16 retrieves the values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants