Tutorial Runtime memory editor library

Discussion in 'Tutorials & Tools' started by Ruit, Jan 26, 2019.

View Users: View Users
  1. Ruit

    Ruit Adminstrator Adminstrator

    [​IMG]

    I will explain in this tutorial how code patching & generally editing memory at runtime.

    First let's talk about requirements and my environment that I'm using for this.

    Environment:
    - Make installed and added to the PATH environment variable.
    - NDK r17c installed and added to the PATH environment variable.

    Requirements:
    C++ knowledge.

    many modders can apply their patches by editing binary file with any hex editor, but I've been asked how to apply them at real time.
    editing self process memory does not require root access or anything special, and can be done directly. for this tutorial I'm using memcpy to copy bytes from a buffer into an address and vice versa.
    I'll be using this only for code patching, but for pointers, they can be directly dereferenced and assigned to any value as long as the object isn't a constant object.
    You can check the functions readPointer & writePointer to see how it works with pointers. I won't explain how to work with pointers in this tutorial because It's really some basic stuff in c++ that you can learn on internet.

    Let's now start with a simple code patch example because i don't really like to write long articles.
    First we include the necessary headers to work with patches:
    Code:
    #include "KittyMemory/MemoryPatch.h"
    I'm going to use a posix thread to run my patches, this would be smart because we don't want to slow or interrupt the execution of the main process thread.
    So we are going to include that as well:
    Code:
    #include <pthread.h>
    Now we define our thread function, the prototype of pthread functions is like:
    Code:
    void *functionName(void *args);
    Code:
    void *my_test_thread(void *) {
        LOGD("I have been loaded...");
        sleep(15);
        return NULL;
    }
    We sleep for 15 seconds here, just to make sure our target lib has been loaded into process already.
    You can probably do better checks for this purpose, but we will take this in our example.

    Now i'm going to create a struct to put my patches there, this is optional but it has better formatting:
    Code:
    struct My_Patches {
         // let's assume we have patches for these functions for whatever game
         // like show in miniMap boolean function
         MemoryPatch canShowInMinimap;
         // etc...
    }my_cool_Patches;
    Now after setting up patches and our custom thread, we will start with code patching.
    HTML:
       my_cool_Patches.canShowInMinimap = MemoryPatch("libil2cpp.so", 0x6A6144,
                                              "\x01\x00\xA0\xE3\x1E\xFF\x2F\xE1", 8);
    
        LOGD("===== New Patch Entry =====");
        LOGD("Patch Address: %p", (void *)my_cool_Patches.canShowInMinimap.get_TargetAddress());
        LOGD("Patch Size: %zu", my_cool_Patches.canShowInMinimap.get_PatchSize());
        LOGD("Current Bytes: %s", my_cool_Patches.canShowInMinimap.ToHexString().c_str());
    
        // modify & print bytes
        if (my_cool_Patches.canShowInMinimap.Modify()) {
            LOGD("canShowInMinimap has been modified successfully");
            LOGD("Current Bytes: %s", my_cool_Patches.canShowInMinimap.ToHexString().c_str());
        }
        // restore & print bytes
        if (my_cool_Patches.canShowInMinimap.Restore()) {
            LOGD("canShowInMinimap has been restored successfully");
            LOGD("Current Bytes: %s", my_cool_Patches.canShowInMinimap.ToHexString().c_str());
        }
    
        LOGD("===========================");
    In the code above, first we initialize canShowInMinimap patch that i have declared in my patches struct, we see the MemoryPatch constructor arguments here are first library name which is "il2cpp.so", then a relative address of the function that i want to patch, and then the patch bytes that which is mov r0, #1 & bx lr AKA return true for arm.
    the bytes are in little endian, I personally use this online assembler & disassembler, and last argument is how many bytes which I'm writing 8 for this.
    I think functions names are self explained, like "Modify" function which is going to apply patch bytes to the address, and "Restore" which is going to write old bytes (Before Patch) to the address.
    ToHexString function is also very helpful for debugging as you can see, I keep printing address bytes to see the current state of the patch.

    To put this together in the thread function:
    Code:
    void *my_test_thread(void *) {
        LOGD("I have been loaded...");
    
        sleep(15);
    
        my_cool_Patches.canShowInMinimap = MemoryPatch("libil2cpp.so", 0x6A6144,
                                              "\x01\x00\xA0\xE3\x1E\xFF\x2F\xE1", 8);
    
        LOGD("===== New Patch Entry =====");
        LOGD("Patch Address: %p", (void *)my_cool_Patches.canShowInMinimap.get_TargetAddress());
        LOGD("Patch Size: %zu", my_cool_Patches.canShowInMinimap.get_PatchSize());
        LOGD("Current Bytes: %s", my_cool_Patches.canShowInMinimap.ToHexString().c_str());
    
        // modify & print bytes
        if (my_cool_Patches.canShowInMinimap.Modify()) {
            LOGD("canShowInMinimap has been modified successfully");
            LOGD("Current Bytes: %s", my_cool_Patches.canShowInMinimap.ToHexString().c_str());
        }
        // restore & print bytes
        if (my_cool_Patches.canShowInMinimap.Restore()) {
            LOGD("canShowInMinimap has been restored successfully");
            LOGD("Current Bytes: %s", my_cool_Patches.canShowInMinimap.ToHexString().c_str());
        }
    
        LOGD("===========================");
    
        return NULL;
    }
    And we finally define our library constructor which will be invoked when our library is loaded:
    Code:
    __attribute__((constructor))void initializer() {
        pthread_t ptid;
        pthread_create(&ptid, NULL, my_test_thread, NULL);
    }
    You can learn more about constructor attribute Here.

    [​IMG]

    I hope this wasn't complicated, I have tried to make it as clean and simple as possible.
    > Library Source <

    ~Ruit
     
    Last edited: Jan 29, 2019
    PixelYT, Ted2, ITR and 6 others like this.
  2. Sebby Seb

    Sebby Seb New Member

    As you know, I am still very ignorant. But even I understood most of that. Nice one
     
    PixelYT likes this.
  3. Jbro129

    Jbro129 New Member

    Awesome :eek:
     
    PixelYT likes this.
  4. Sebby Seb

    Sebby Seb New Member

    Nice cat btw.
     
    PixelYT likes this.
  5. Programmer from Moscow

    Programmer from Moscow Public Moderator Russian Support GOB - L2 CO - L2

    Good job Ruit.
     
    Ebbac, PixelYT and Sebby Seb like this.
  6. saiaapiz

    saiaapiz New Member

    Well written, really good for newcomer like me.
     
    PixelYT likes this.
  7. Ted2

    Ted2 VIP GOB - L1

    Sick <3
     
    PixelYT and Sebby Seb like this.
  8. Enderking808

    Enderking808 New Member

    Seems more difficult than what I’m doing now, I’ll give it a shot.