Skip to content

Load plugins in usermode lv2 module_start#65

Open
illusionyy wants to merge 3 commits intoEvilnat:masterfrom
illusionyy:my-484-stuff
Open

Load plugins in usermode lv2 module_start#65
illusionyy wants to merge 3 commits intoEvilnat:masterfrom
illusionyy:my-484-stuff

Conversation

@illusionyy
Copy link

@illusionyy illusionyy commented Feb 11, 2026

For 4.84 REX and 4.92 PEX only, can be easily ported to other fws.
will look for /dev_hdd0/game_plugin_bootloader.sprx and start it. if you have exceptions enabled in shellcode, you'll get exceptions to find out any errors.

@illusionyy

This comment was marked as outdated.

@illusionyy illusionyy marked this pull request as draft February 11, 2026 08:23
@illusionyy illusionyy marked this pull request as ready for review February 11, 2026 10:41
@illusionyy
Copy link
Author

illusionyy commented Feb 12, 2026

Updated to be able to modify argc/argv.

Code (Click to expand)
#if defined(__PRX__)
typedef union bigint
{
    struct _c
    {
        char* hi;
        char* lo;
    } c;
} bigint;
#define pChar bigint
#define pChar2 bigint*
#else
#define pChar uint64_t
#define pChar2 uint32_t
#endif

typedef struct program_args
{
    uint32_t argc;
    pChar2 argv;
    uint32_t replace_args_size;
    uint32_t replace_args_per_buf_size;
    pChar new_argv[max_args];
    char replace_args[max_args][max_arg_buf + 1];
    struct change_flag
    {
        uint64_t changed : 1;
    } flag;
} program_args;
#if defined(__cplusplus)
static_assert(__builtin_offsetof(program_args, argc) == 0, "");
static_assert(__builtin_offsetof(program_args, argv) == 4, "");
static_assert(__builtin_offsetof(program_args, replace_args_size) == 8, "");
static_assert(__builtin_offsetof(program_args, replace_args_per_buf_size) == 12, "");
static_assert(__builtin_offsetof(program_args, new_argv) == 16, "");
static_assert(__builtin_offsetof(program_args, replace_args) == 272, "");
#endif
extern "C" int module_start(unsigned int argc, program_args& arg)
{
    printf("program_args size %d\n", sizeof(program_args));
    printf("arg %p argc %d argv %p\n", &arg, arg.argc, arg.argv);
    printf("replace_arg_buf %ld\n", arg.replace_args_size);
    for (uint32_t i = 0; i < arg.argc; i++)
    {
        printf("arg[%d]: (%p) %s\n", i, &arg.argv[i].c.lo, arg.argv[i].c.lo ? arg.argv[i].c.lo : "");
    }
#if defined(enable_arg_modify)
    size_t diff_bytes = 0;
    if (!check_bytes(arg.replace_args, 0, arg.replace_args_size, diff_bytes))
    {
        printf("WARNING: replacement arg buf contains %ld bytes that was not zero! was the stack ever truly cleared?\n", diff_bytes);
    }
    else
    {
        printf("checked replacement buf of %ld bytes and it was all clear!\n", arg.replace_args_size);
    }
#endif

#if defined(enable_arg_modify)
    bool no_copy = false;
    if (!copy_main_args(&arg, arg.argc, arg.argv))
    {
        printf("failed to copy main argc/argv\n");
        no_copy = true;
    }
    if (!no_copy)
    {
        append_arg(&arg, "-novsync");
    }
    printf("argc now %d\n", arg.argc);
    for (uint32_t i = 0; i < arg.argc; i++)
    {
        printf("arg[%d]: (%p) %s\n", i, arg.new_argv[i].c.lo, arg.new_argv[i].c.lo ? arg.new_argv[i].c.lo : "");
    }
#endif

    sys_timer_sleep(5);
    return SYS_PRX_NO_RESIDENT;
}
Output (Click to expand)
program_args size 9656
arg 0xd003e830 argc 1 argv 0xd0040fb0
replace_arg_buf 9376
arg[0]: (0xd0040fb4) /dev_hdd0/game/NPUB90119/USRDIR/EBOOT.BIN
checked replacement buf of 9376 bytes and it was all clear!

pargs->replace_args[1]: -novsync
argc now 2
arg[0]: (0xd0040fd0) /dev_hdd0/game/NPUB90119/USRDIR/EBOOT.BIN
arg[1]: (0xd003ea65) -novsync
# In main()
Commandline init...
CommandLine: -novsync 

@illusionyy illusionyy force-pushed the my-484-stuff branch 3 times, most recently from 90c64ab to 9086236 Compare February 12, 2026 06:20
@illusionyy illusionyy marked this pull request as draft February 13, 2026 03:06
@illusionyy illusionyy marked this pull request as ready for review February 13, 2026 04:52
@illusionyy
Copy link
Author

illusionyy commented Feb 13, 2026

Ported to 4.92 PEX. Checked CEX and DEX kernels and they seem to work.

*** network ready. myaddr: 192.168.1.26 ***
===== Start agent =====
Debug Agent Version: 4.9.2 (62)
Mini Debug Agent Version 4.9.2 (62) (Built - Mar  5 2025 12:00:00)
...
Game: game exec processID = [0x01010200]
Load module: /dev_flash/sys/external/libsysmodule.sprx (_main_EBOOT.BIN)
passed check
lv2 base 0x1e50000 0x1e63b68
lv2 read 39c00000 check 39c00000 ret 0
lv2 base 1e50000 size 13b68 (max 1e63b68)
code size 204 seeked 1e63960
Load module: /dev_hdd0/game_plugin_bootloader.sprx (_main_EBOOT.BIN)

@illusionyy
Copy link
Author

@Evilnat ready for merge.

@illusionyy illusionyy force-pushed the my-484-stuff branch 2 times, most recently from 3f97160 to 2f9c1fa Compare February 13, 2026 04:56
For 4.84 REX only, can be easily ported to other fws.
will look for `/dev_hdd0/game_plugin_bootloader.sprx` and start it. if you have exceptions enabled in shellcode, you'll get exceptions to find out any errors.
@Evilnat
Copy link
Owner

Evilnat commented Feb 15, 2026

Could you explain a little about what I could do with your new changes? Thanks in advance

@illusionyy
Copy link
Author

illusionyy commented Feb 15, 2026

Could you explain a little about what I could do with your new changes? Thanks in advance

@Evilnat it can load plugins on app startup. Previously you'd have to patch game executable manually, resign it correctly for CEX or DEX and it was just a mess.

Now it's just as simple as putting a plugin somewhere, adding it to /dev_hdd0/game_plugins.yml and shellcode in liblv2 from this PR and bootloader plugin will take care of the rest.

Also this shellcode also sets up a struct for argc/argv to be edited by plugins, so users may add their own cmdline before start() in executable is executed.

@LuanTeles
Copy link

Could you explain a little about what I could do with your new changes? Thanks in advance

@Evilnat it can load plugins on app startup. Previously you'd have to patch game executable manually, resign it correctly for CEX or DEX and it was just a mess.

Now it's just as simple as putting a plugin somewhere, adding it to /dev_hdd0/game_plugins.yml and shellcode in liblv2 from this PR and bootloader plugin will take care of the rest.

Also this shellcode also sets up a struct for argc/argv to be edited by plugins, so users may add their own cmdline before start() in executable is executed.

That's a much needed feature :)

@Evilnat
Copy link
Owner

Evilnat commented Feb 20, 2026

Could you explain a little about what I could do with your new changes? Thanks in advance

@Evilnat it can load plugins on app startup. Previously you'd have to patch game executable manually, resign it correctly for CEX or DEX and it was just a mess.

Now it's just as simple as putting a plugin somewhere, adding it to /dev_hdd0/game_plugins.yml and shellcode in liblv2 from this PR and bootloader plugin will take care of the rest.

Also this shellcode also sets up a struct for argc/argv to be edited by plugins, so users may add their own cmdline before start() in executable is executed.

Thanks mate!

I need to check that the final size of stage2 doesn't exceed the maximum allowed, although I also want to increase it to avoid problems. Give me a few days so I can check and test it.

Thank you very much for your contribution

@illusionyy
Copy link
Author

Even in debug, it doesn't exceed 127k for me in PEX build. In release it's about 110k I believe so it should be okay.

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

Successfully merging this pull request may close these issues.

3 participants