HelpMemory reading, structures, and pointers

Posts 1–9 of 9 · Page 1 of 1
Memory reading, structures, and pointers
Hi all. I am having a bit of a problem with my code ive been working on lately. What I am trying to do is (from the base address that doesnt change) grab all the data from memory and include it in a structure. Essentially what i want to do is recreate the structure like how it is in the game and simply point my structure to the address and use it.

What I am having troubles with is getting to the correct address in C. I have found my base address though CE and it looks like this. BaseAddress->AnotherAddress+0x34->My Data to fill my structure.

I have reversed enough of my structure to know what is in it and everything is aligned properly I just cant get the correct address. Here is my code.

Code:
typedef unsigned char BYTE;

typedef struct
{
    BYTE Unknown01[0x468]; //Unknown stuff
    DWORD Id;
    DWORD Level;
    DWORD Cultivation;
    DWORD Current_HP;
    DWORD Current_MP;
    DWORD Exp;
    DWORD Spirit;
    DWORD Attribute_Points;
    DWORD Current_Chi;
    DWORD Attack_Level;
    DWORD Defence_Level;
    float Critical_Rate;
    float Rage_Damage;
    DWORD Stealth_Level;
    DWORD Stealth_Detection_Level;
    DWORD Slaying_Level;
    DWORD Warding_level;
    DWORD Vitality_Points;
    DWORD Magic_Points;
    DWORD Strength_Points;
    DWORD Dextarity_Points;
    DWORD Max_HP;
    DWORD Max_MP;
    DWORD HP_Regen;
    DWORD MP_Regen;
    float Walk_Speed;
    float Run_Speed;
    float Swim_Speed;
    float Fly_Speed;
    DWORD Accuracy;
    DWORD Min_Attack_Damage;
    DWORD Max_Attack_Damage;
    float Attack_Rate;
    float Range;
    DWORD Min_Metal_Damage;
    DWORD Max_Metal_Damage;
    DWORD Min_Wood_Damage;
    DWORD Max_Wood_Damage;
    DWORD Min_Water_Damage;
    DWORD Max_Water_Damage;
    DWORD Min_Fire_Damage;
    DWORD Max_Fire_Damage;
    DWORD Min_Earth_Damage;
    DWORD Max_Earth_Damage;
    DWORD Min_Magic_Damage;
    DWORD Max_Magic_Damage;
    DWORD Metal_Defence;
    DWORD Wood_Defence;
    DWORD Water_Defence;
    DWORD Fire_Defence;
    DWORD Earth_Defence;
    DWORD Physical_Defence;
    DWORD Evasion;
    DWORD Max_Chi;
    DWORD Coins;
    DWORD Max_Coins;
}PLAYER;

typedef struct
{
    BYTE Unknown[0x34];
    PLAYER *p_player;
}VARBASE;

DWORD WINAPI function()
{
    VARBASE *Stats = (VARBASE*)0x00BBC9CC;
    char lol[1000];

    sprintf(lol, "stats pointer: %p  |  player pointer: %p  |  player pointer + 34: %ld", (void*)Stats, (void*)Stats->p_player, Stats->p_player->Level);
    SomeFunction(lol);

    return NULL;
}
What should be happening is when I create my VARBASE structure it will add 0x34 bytes to the address 0x00BBC9CC is pointing to and then set that new address as a pointer to my player struct where I can use all my variables.

It should look like 0x00BBC9CC->0x0A15CDC0+34->14DEE5F0(the beginning of the games structure i want to point to)
but instead it looks like 0x00BBC9CC->0x00000301->0x00001501 which causes a segment fault when i try to read it.

maybe someone here can help point me in the right direction for trying to find the correct memory address.

thanks for any help!
Are you in your target process's memory space? If not, then you're just reading your own process's memory. Also, sometimes the compiler will align structures to some boundary for optimization reasons. In MSVS, you can surround your structures with #pragma pack directives in order to specify alignment (in this case you want a one byte boundary). Look for an equivalent directive/option if you are not using MSVS.
Quote Originally Posted by Fovea View Post
Are you in your target process's memory space? If not, then you're just reading your own process's memory. Also, sometimes the compiler will align structures to some boundary for optimization reasons. In MSVS, you can surround your structures with #pragma pack directives in order to specify alignment (in this case you want a one byte boundary). Look for an equivalent directive/option if you are not using MSVS.
How can i make sure I am indeed in the target process's memory? ive done some tests and if i remove the `BYTE Unknown[0x34]` line and print the pointers for `Stats` and `Stats->p_player` they both point to the proper addresses (more so p_player being what Stats is currently pointing at so I am almost sure I am in the targets process memory. after all i am injecting the dll into it.)

Just to make sure is it possible to create a double pointer to grab the data of one variable. The HP variable is loacated at `BASE->ADDR+34->ADDR+494`

Also I am using Code::Blocks with mingw gcc so I will have to look into this structure padding. Thank you for the reply

edit:: I just used `#pragma pack(push,1)` and outputted the size of VARBASE and it was 56, although when i removed it the struct was still 56 (52 bytes + 4 bytes for the pointer) going to read into this more

heres an image of my addresses for `Stats` and `Stats->p_player`



Stats is pointing to the right address but when I have that `BYTE Unknown[0x34]` line in the structure it points to the wrong address where as if i remove it it points to what Stats is pointing to (0x0A**CDC0). if that makes any sense.
Just read your edit, it seems like 0x00BBC9CC is actually a pointer to a pointer to a VARBASE structure and not the VARBASE structure (the latter is what your code is assuming). Dereference 0x00BBC9CC and then store that as the pointer to VARBASE.
Quote Originally Posted by Fovea View Post
Just read your edit, it seems like 0x00BBC9CC is actually a pointer to a pointer to a VARBASE structure and not the VARBASE structure (the latter is what your code is assuming). Dereference 0x00BBC9CC and then store that as the pointer to VARBASE.
ah yes im sorry if i explained that wrong. it is a pointer to a pointer to a structure holding my information.

fake edit:: thank you so much for that hint. ive managed to fix it by first creating a DWORD pointer to my base address and then using that derefenced pointer to my VARBASE structure like you said.

here is the new code if anyone else has this problem in the future.

Code:
DWORD WINAPI function()
{
    FILE *fp;
    fp = fopen("testaddr.txt", "a+");
    DWORD *ptr = (DWORD*)0x00BBC9CC;
    VARBASE *Stats = (VARBASE*)*ptr;
    fprintf(fp, "size of varbase:%d\n", sizeof(*Stats));
    fprintf(fp, "stats pointer: %p  |  player pointer: %p\n", (void*)Stats, Stats->p_player);
    fprintf(fp, "stats pointer: %p  |  player pointer: %p\n\n", (void*)Stats, Stats->p_player);
    fprintf(fp, "current hp %ld/%ld\n", Stats->p_player->Current_HP, Stats->p_player->Max_HP);
    fclose(fp);
    return NULL;
}
output:

size of varbase:56
stats pointer: 0A12CDC0 | player pointer: 225DE678
stats pointer: 0A12CDC0 | player pointer: 225DE678

current hp 2745/2745
because this is fixed for a 2 level pointer (i also have to work with up to 5 level pointers) is there a ReadProcessMemory() but for local memory? Wouldnt that just be the same thing as memcpy? I am trying to write up a function that will allow me to pass the BASE ADDRESS, array of offsets, and how many levels the pointer is and i want to be able to follow all the pointers (adding the offsets each level) to come to my final destination address which i will return from the function.

tl;dr: ReadProcessMemory() same thing as memcpy() except memcpy can be use locally during dll injection?
This could have bugs but you should get the picture. Also it's not safe, read this. Wrote it in C as this seems to be what you're using (although I would use the builder pattern / initializer_list if you plan to use C++, as well as implementing it as a function template).

Code:
unsigned long ReadPointer(void* base, unsigned int level, ...) {
  unsigned long* output;
  va_list        offsets;

  output = *(unsigned long*)output;
  
  va_start(offsets, level);

  for (unsigned int i = 0; i < level; i++)
    output = *(output + va_arg(offsets, unsigned int));

  va_end(offsets);

  return (unsigned long)output;
}
For a pointer, you just set the level to zero, for a pointer to a pointer you set the level to one and provide an offset, etc. Keep in mind that this will give you the value you want, not a pointer to a structure/variable you want. If this isn't what you want, just tweak the code.
Quote Originally Posted by Fovea View Post
This could have bugs but you should get the picture. Also it's not safe, read this. Wrote it in C as this seems to be what you're using (although I would use the builder pattern / initializer_list if you plan to use C++, as well as implementing it as a function template).

Code:
unsigned long ReadPointer(void* base, unsigned int level, ...) {
  unsigned long* output;
  va_list        offsets;

  output = *(unsigned long*)output;
  
  va_start(offsets, level);

  for (unsigned int i = 0; i < level; i++)
    output = *(output + va_arg(offsets, unsigned int));

  va_end(offsets);

  return (unsigned long)output;
}
For a pointer, you just set the level to zero, for a pointer to a pointer you set the level to one and provide an offset, etc. Keep in mind that this will give you the value you want, not a pointer to a structure/variable you want. If this isn't what you want, just tweak the code.
thanks that looks exactly like what i need. i will test it out and post back with my findings here if it doesnt work (with a working code snippet hopefully).

---------- Post added at 09:58 PM ---------- Previous post was at 08:26 PM ----------

Quote Originally Posted by abduct View Post
thanks that looks exactly like what i need. i will test it out and post back with my findings here if it doesnt work (with a working code snippet hopefully).
after playing with the function a bit and fixing some compile errors (variable was unsigned long but was using unsigned long* kind of stuff) i managed to get it to sort of work

Code:
unsigned long ReadPointer(void* base, unsigned int level, ...)
{
  unsigned long *output = (unsigned long*)base; //correctly points to the next address the BASE is pointing to
  va_list        offsets;

  va_start(offsets, level);

  for (unsigned int i = 0; i < level; i++)
  {
    output = (unsigned long*)*(output + va_arg(offsets, unsigned int)); //This is the problem code. I cant figure out how to properly dereference
                                                              //the pointers and add the offsets
  }

  va_end(offsets);

  return (unsigned long)output;
}
other then that I cant figure out how to add the offsets this should work. (only other minor detail that im going to change is that it returns DWORD addresses rather than unsigned long integers.

---------- Post added at 10:12 PM ---------- Previous post was at 09:58 PM ----------

Quote Originally Posted by abduct View Post
thanks that looks exactly like what i need. i will test it out and post back with my findings here if it doesnt work (with a working code snippet hopefully).

---------- Post added at 09:58 PM ---------- Previous post was at 08:26 PM ----------



after playing with the function a bit and fixing some compile errors (variable was unsigned long but was using unsigned long* kind of stuff) i managed to get it to sort of work

Code:
unsigned long ReadPointer(void* base, unsigned int level, ...)
{
  unsigned long *output = (unsigned long*)base; //correctly points to the next address the BASE is pointing to
  va_list        offsets;

  va_start(offsets, level);

  for (unsigned int i = 0; i < level; i++)
  {
    output = (unsigned long*)*(output + va_arg(offsets, unsigned int)); //This is the problem code. I cant figure out how to properly dereference
                                                              //the pointers and add the offsets
  }

  va_end(offsets);

  return (unsigned long)output;
}
other then that I cant figure out how to add the offsets this should work. (only other minor detail that im going to change is that it returns DWORD addresses rather than unsigned long integers.
fixed it:

usage: ReadPointer((void*)0x00BBC9CC, 1, 0x34)

this will follow the base address (0x00BBC9CC) to the address it points to. add a 0x34 byte offset to that address, and then return what that address points to.

Code:
DWORD *ReadPointer(void* base, unsigned int level, ...)
{
  unsigned long *output = (unsigned long*)base;
  va_list        offsets;

  va_start(offsets, level);

  for (unsigned int i = 0; i <= level; i++)
  {
    output = ((unsigned long*)(*output + va_arg(offsets, unsigned int)));
  }

  va_end(offsets);

  return (DWORD*)output;
}
Posts 1–9 of 9 · Page 1 of 1

Post a Reply

Similar Threads

Tags for this Thread

None

Talk with us