Avoid crash for invalid MapObj item

05/31/2023 00:58 ManuLeLe#1
Hey everyone!

I just wanted to let you know that I've recently started diving back into in-memory hacking in NosTale. I'm patiently recreating the game's internal structures from scratch to gain a deeper understanding of its inner workings.

In-memory hacking requires a lot of patience and dedication, but it's incredibly fascinating and rewarding. I'm working hard to comprehend the data structures used within the game and finding safe ways to access pointers to items in the lists without encountering crashes or invalid memory access issues.

I would love to hear your advice and suggestions on safely accessing pointers to objects in the lists without crashing or encountering invalid memory issues. If you have any techniques or best practices to share, I'm all ears!

Right now I'm looping around lists like in this code snippet:
Code:
static bool IsPointerValid(const void* ptr)
{
    MEMORY_BASIC_INFORMATION mbi;
    SIZE_T result = VirtualQuery(ptr, &mbi, sizeof(mbi));
    return (result != 0 && mbi.Protect != PAGE_NOACCESS);
}

...

for (int i = 0; i < sceneMgr->NpcListPointer->Length; i++) {
                auto itemPtr = (MapNpcObj*)(sceneMgr->NpcListPointer)->FirstItemPtr[i];
                if(IsPointerValid(itemPtr) && IsPointerValid(itemPtr->NpcName))
                    std::cout << std::dec << itemPtr->NpcName << " " << itemPtr->MapX << ";" << itemPtr->MapY << std::endl;
}
but nevertheless, sometimes it takes 5 minutes to crash, sometimes 1, I guess it access the memory of an item deleted right after it checker for the list length.

Thank you in advance!
05/31/2023 10:29 JONNST4R#2
If you reference or do -> on an address which is 0 you crash. And because all item information depend on SceneManager you only have to check if its 0. I do it like this maybe it can help you:

Code:
uint32_t GetSceneManager()
{
    DWORD TSceneManager = test::SignatureScan().Scan("NostaleClientX.exe",
        "10 A0 A9 0B FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF", 0); // old pattern

    if (TSceneManager == 0) // check if 0
    {
        std::cout << "TSceneManager not found!" << std::endl;
        return 1;
    }

    uint32_t* ptr = (uint32_t*)TSceneManager; // if (TSceneManager == 0) you crash at this point 
    uint32_t val = *ptr;

    return val;
}
I think in your case you crash because SceneManager address can change over time its just luck you dont crash on start.