Categories > Coding > C++ >

[HELP] printsploit C++

Posts: 8

Threads: 5

Joined: Jul, 2024

Reputation: 0

Posted

i have printsploit in C++ bypassing byfron and its source code how can i use it to execute Lua scripts besides print?

  • 1

Posts: 7

Threads: 1

Joined: May, 2024

Reputation: 1

Replied

I split this guide into 3 parts to avoid the character limit.

 

Part 1: Finding offsets

First, you need to get the task scheduler, which can be found by searching for the string "FrameTime" in memory. You need to find the reference that calls a function right above and assigns it to the variable, like this.

 

FrameTime

 

In this case, sub_102E74FE0 is the function that gets the FrameTime offset from TaskScheduler. Decompile it and you will find something like this.

 

TaskScheduler

 

Near the end, you will see a variable being assigned to a qword, in my case it is qword_1050CAF18. This qword is the task scheduler, so it is the address of it.

 

Now you need to find some offsets from the TaskScheduler. First is JobsStart and JobsEnd. These can be found from a function that uses a while loop and references the TaskScheduler address. Look around references and you should be able to find it. You should see something like this, however it varies.

 

Job Offsets

 

The JobsStart offset should be smaller than the JobEnd offset and should be incremented like you see in the for loop. So in my case JobsStart is element 55 and JobsEnd is element 56. These are not the actual offsets, they are an index. Now TaskScheduler could be described as an array of pointers, which is 4 bytes on a 32 bit computer and 8 bytes on a 64 bit computer. Multiply the index by the number of bytes, 8 in my case, and you should get the offset. I have a 64 bit computer and I get 440 for JobsStart and 448 for JobsEnd. Convert these to hex if you want, 0x1b8 and 0x1c0 respectively.

 

You only need to find one more offset, which is the offset that gets ScriptContext from the job we are going to use. Search for the string "WaitingHybridScriptsJob", it should be referenced once. You will see something similar to this.

 

WaitingHybridScriptsJob

 

Near the end, you can see the offset, which is 536 in my case. However, unlike the previous two offset, here it will be easier if you divide this number by the size of the pointer. It would get me 67, which in hex is 0x47.

  • 0

Added

Part 2: Finding function addresses

 

You will need getstate for this to work. This can be found by finding a reference to the string "Unable to create a new thread for %s". In that same function where the string is referenced, you should see a string "Script Start", right before it is the function that is getState.

getState

In my case, getState is sub_100A5786A.

 

To execute scripts, you need luau_load, find it by searching for the string "GameLdr-PerformanceCheck0,GameLdr-PerformanceCheck2". It should be used in a function that gets called in luau_load. Find the function reference and scroll up if using IDA, since it would not be initialized as a sub and would be a location. The first location you see while scrolling up is luau_load which is loc_1028459A7 in my case.

luau_load

 

You will also need to get the spawn address. Search for the string "Spawn function requires 1 argument". The function it is referenced in the spawn function.

spawn

sub_1009EAFCE is the spawn function in my case.

 

To push things off the Luau stack, you need lua_settop. You can try to find it yourself by looking at the Luau source, but if you can't, I will help you.

 


That is basically it for the functions, however you can get some Luau C functions to confirm if the Lua state you have is correct. That is not necessarily needed, so I will not find them in this guide.

  • 0

Added

Part 3: Making the exploit

 

In your exploit source, you have to use the offsets. I recommend giving the offsets a variable name so that you can change them easily once an update happens. Ensure you import all the necessary header files. Make sure to replace the function addresses and offsets.

const int jobs_start = 0x1b8;
const int jobs_end = 0x1c0;
const int jobs_offset = 0x10;

uint64_t taskscheduler_address = 0x1050CAF18 + GetModuleHandleA(0);

typedef uint64_t (*getstate_typedef)(uint64_t script_context, int* type, const int64_t* argument);
uint64_t getstate_address = 0x100A5786A + GetModuleHandleA(0);
getstate_typedef rbx_getstate = reinterpret_cast<getstate_typedef>(getstate_address);

typedef int64_t (*load_typedef)(uint64_t state, const char* source, const char* bytecode, int len, int env);
uint64_t load_address = 0x1028459A7 + GetModuleHandleA(0);
load_typedef rbx_load = reinterpret_cast<load_typedef>(load_address);

typedef int64_t (*spawn_typedef)(uint64_t state);
uint64_t spawn_address = 0x1009EAFCE + GetModuleHandleA(0);
spawn_typedef rbx_spawn = reinterpret_cast<spawn_typedef>(spawn_address);

typedef int64_t (*settop_typedef)(uint64_t state, int size);
uint64_t settop_address = 0x10282448B + GetModuleHandleA(0);
settop_typedef rbx_settop = reinterpret_cast<settop_typedef>(settop_address);

jobs_offset should be 0x10 and is mandatory.

I am not sure how finding the address of a function or object is done on Windows, I think it is GetModuleHandleA(0), you know since your print function works.

 

Define a structure for the TaskScheduler.

namespace scheduler {
    struct job {
        void** vtable;
        char padding[0x88]; //0x10
        std::string job_name; // 0x18
    };

    std::vector<job*> scheduler_jobs;
}

 

The next few steps will be complicated so I will describe them first.

  1.  Define a function called getGlobalState or similar to get the Lua state and use the offsets.

2. Make a while loop in the function to iterate through jobs.

3. Check if the job name matches and that we do not have a Lua state yet.

4. Find ScriptContext and get the Lua state.

5. Return the Lua state.

 

This is the getGlobalState function.

uint64_t getRobloxState() {
    // Define a function called getGlobalState or similar to get the Lua state and use the offsets.
    uint64_t state = 0;

    uint64_t scheduler = *(uint64_t*)taskscheduler_address;
    uint64_t start = *(uint64_t*)(scheduler + jobs_start);
    uint64_t end = *(uint64_t*)(scheduler + jobs_end);

    // Make a while loop in the function to iterate through jobs.
    while (start < end) {
        auto job = *(scheduler::job**)start;
        scheduler::scheduler_jobs.push_back(job);
        
        // Check if the job name matches and that we do not have a state yet.
        if (job->job_name == "WaitingHybridScriptsJob" && state == 0) {
            // Find ScriptContext and get the Lua state.
            int thread_type = 0;
            const int64_t trigger = 0;
            void** job_address = (void**)job;
            uint64_t script_context = (uint64_t)job_address[script_context];
            uint64_t rbx_state = rbx_getstate(script_context, &thread_type, &trigger);
            
            // Return the Lua state.
            return rbx_state;
        }

        start += offsets::jobs_offset;
    }

    return 0;
}

 

Next, create a function that executes Luau scripts. Download the Luau source from GitHub, initialize the header files and library files in your project. I will not go into this, if you need help ask me.

I will outline the function below.

 

  1. Define a function called execute_script or similar to execute Luau scripts.

2. Compile the script to Luau bytecode.

3. Load the bytecode and check if it is successful.

4. If loading is unsuccessful, push the function off the stack.

5. If loading is successful, call spawn to execute the function pushed to the stack, and push the function off the stack.

// Define a function called execute_script or similar to execute Luau scripts.
bool execute_script(uint64_t state, std::string script) {
    // Compile the script to Luau bytecode.
    std::string script_bytecode = Luau::compile(script);

    // Load the bytecode and check if it is successful.
    if (rbx_load(state, script_author.c_str(), script_bytecode.c_str(), script_bytecode.size(), 0) != 0) {
        // If loading is unsuccessful, push the function off the stack.
        rbx_settop(state, 0);
        return false;
    }

    // If loading is successful, call spawn to execute the function pushed to the stack, and push the function off the stack.
    rbx_spawn(rl);
    rbx_settop(rl, 0);
    return true;
}

 

Do this in your main function.

// Get the Lua state
uint64_t roblox_thread = getRobloxState();

// Execute a script
std::string teststring = R"(print("hi"))";
execute_script(roblox_thread, teststring);

The teststring variable has to be a raw string.

 

Reply to this thread if you have questions.

Comments

RoBloxedHacked 0 Reputation

Commented

What level would this be executing code at?

  • 0

Cherpixel 1 Reputation

Commented

It doesn't change the identity so it would be at 0.

  • 0

Deux 0 Reputation

Commented

how can I improve it?

  • 0

HexDX_nbVKCH 0 Reputation

Commented

I have 2 question how do you dump roblox and also the address finding methods above do they work? Like on roblox i mean because on roblox studio they don't.

  • 0

Deux 0 Reputation

Commented

make a dump using IDA

  • 0

  • 0

Posts: 2

Threads: 0

Joined: Jul, 2024

Reputation: 0

Replied

Do you have a discord? I want to message you because I need help with this. My IDA is not doing the same things yours is. At least not showing what yours shows

  • 0

Posts: 14

Threads: 5

Joined: Jul, 2024

Reputation: 0

Replied

Same for me though i use roblox studio since i don't know how to exploit on roblox yet since byfron.

  • 0

Posts: 7

Threads: 1

Joined: May, 2024

Reputation: 1

Replied

If you have any questions, message me on Discord, user is "cherpixel" without the quotes. I will help you dump Roblox and get anything you need.

 

You can also DM me if you want help setting the identity.

  • 0

Users viewing this thread:

( Members: 0, Guests: 1, Total: 1 )