Hacking RPC Execute Assembly

BullyWiiPlaza

Nintendo Hacking <3
OP
Member
Joined
Aug 2, 2014
Messages
1,932
Trophies
0
XP
2,477
Country
Germany
For executing assembly in the form of a char array I wrote the following code:
Code:
#define ASSEMBLY_BUFFER_SIZE 0x190
Code:
void receiveString(struct pygecko_bss_t *bss,
                   int clientfd,
                   char *stringBuffer,
                   int bufferSize) {
    // Receive the string length
    char lengthBuffer[4] = {0};
    int ret = recvwait(bss, clientfd, lengthBuffer, 4);
    ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (string length)")
    int stringLength = ((int *) lengthBuffer)[0];

    if (stringLength >= 0 && stringLength <= bufferSize) {
        // Receive the actual string
        ret = recvwait(bss, clientfd, stringBuffer, stringLength);
        ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (string)")
    } else {
        OSFatal("String buffer size exceeded");
    }
}
Code:
case COMMAND_EXECUTE_ASSEMBLY: {
    char assemblyBuffer[ASSEMBLY_BUFFER_SIZE] = {0};

    // Receive the assembly
    receiveString(bss, clientfd, assemblyBuffer, ASSEMBLY_BUFFER_SIZE);

    // Execute the assembly
    void (*function)() = (void *) assemblyBuffer;
    function();

    break;
}
The client sends the length of the assembly bytes and the assembly bytes themselves:
Code:
public void executeAssembly(byte[] assembly) throws Exception
{
    int assemblyLength = assembly.length;
    if (assemblyLength <= 0 || assemblyLength % 4 != 0)
    {
        throw new IllegalStateException("Bad assembly bytes length: " + assemblyLength);
    }

    assembly = Assembler.forceReturnStatement(assembly);

    try (CloseableReentrantLock ignored = reentrantLock.acquire())
    {
        sendCommand(Command.EXECUTE_ASSEMBLY);
        dataSender.writeInt(assembly.length);
        dataSender.write(assembly);
        dataSender.flush();
    }
}
When I use this e.g. like with the following assembly:
Code:
byte[] bytes = Assembler.assembleBytes("lis r12, 0x1200\n" +
        "ori r12, r12, 0x0000\n" +
        "li r11, 0x1337\n" +
        "stw r11, 0 (r12)");
executeAssembly(bytes);
The console crashes with an Exception ISI:
z9d1OvA.jpg

The code dump shows the assembly I gave it to execute and how a blr instruction is added at the end so the code returns to the caller. Furthermore, the link register LR contains an invalid address which might have been the reason for the crash.

Why is this happening and how to fix it? I guess the intention is clear: I want to send over some bytes and have them execute via the TCP Gecko Installer thread and continue its execution right after.

@NWPlayer123
@QuarkTheAwesome
@FIX94
@dimok
@Maschell
@CosmoCortney
 
Joined
Apr 19, 2015
Messages
1,023
Trophies
1
Location
Stuck in the PowerPC
Website
heyquark.com
XP
3,913
Country
Australia
For executing assembly in the form of a char array I wrote the following code:
Code:
#define ASSEMBLY_BUFFER_SIZE 0x190
Code:
void receiveString(struct pygecko_bss_t *bss,
                   int clientfd,
                   char *stringBuffer,
                   int bufferSize) {
    // Receive the string length
    char lengthBuffer[4] = {0};
    int ret = recvwait(bss, clientfd, lengthBuffer, 4);
    ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (string length)")
    int stringLength = ((int *) lengthBuffer)[0];

    if (stringLength >= 0 && stringLength <= bufferSize) {
        // Receive the actual string
        ret = recvwait(bss, clientfd, stringBuffer, stringLength);
        ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (string)")
    } else {
        OSFatal("String buffer size exceeded");
    }
}
Code:
case COMMAND_EXECUTE_ASSEMBLY: {
    char assemblyBuffer[ASSEMBLY_BUFFER_SIZE] = {0};

    // Receive the assembly
    receiveString(bss, clientfd, assemblyBuffer, ASSEMBLY_BUFFER_SIZE);

    // Execute the assembly
    void (*function)() = (void *) assemblyBuffer;
    function();

    break;
}
The client sends the length of the assembly bytes and the assembly bytes themselves:
Code:
public void executeAssembly(byte[] assembly) throws Exception
{
    int assemblyLength = assembly.length;
    if (assemblyLength <= 0 || assemblyLength % 4 != 0)
    {
        throw new IllegalStateException("Bad assembly bytes length: " + assemblyLength);
    }

    assembly = Assembler.forceReturnStatement(assembly);

    try (CloseableReentrantLock ignored = reentrantLock.acquire())
    {
        sendCommand(Command.EXECUTE_ASSEMBLY);
        dataSender.writeInt(assembly.length);
        dataSender.write(assembly);
        dataSender.flush();
    }
}
When I use this e.g. like with the following assembly:
Code:
byte[] bytes = Assembler.assembleBytes("lis r12, 0x1200\n" +
        "ori r12, r12, 0x0000\n" +
        "li r11, 0x1337\n" +
        "stw r11, 0 (r12)");
executeAssembly(bytes);
The console crashes with an Exception ISI:
z9d1OvA.jpg

The code dump shows the assembly I gave it to execute and how a blr instruction is added at the end so the code returns to the caller. Furthermore, the link register LR contains an invalid address which might have been the reason for the crash.

Why is this happening and how to fix it? I guess the intention is clear: I want to send over some bytes and have them execute via the TCP Gecko Installer thread and continue its execution right after.

@NWPlayer123
@QuarkTheAwesome
@FIX94
@dimok
@Maschell
@CosmoCortney

I'm pretty sure MEM2 isn't executable by default. You'll either need to read the data into somewhere executable (HBL area?) or make MEM2 executable with a BAT.
The crash is because the PowerPC has separate memory mappings for data and instructions. If an area is mapped for data but not instructions it essentially becomes non-executable, since trying to execute it is trying to run instructions at an unmapped address.
 
  • Like
Reactions: BullyWiiPlaza

BullyWiiPlaza

Nintendo Hacking <3
OP
Member
Joined
Aug 2, 2014
Messages
1,932
Trophies
0
XP
2,477
Country
Germany
I'm pretty sure MEM2 isn't executable by default. You'll either need to read the data into somewhere executable (HBL area?) or make MEM2 executable with a BAT.
The crash is because the PowerPC has separate memory mappings for data and instructions. If an area is mapped for data but not instructions it essentially becomes non-executable, since trying to execute it is trying to run instructions at an unmapped address.
Alright, what would be a good solution code-wise? mmap() does not exist so I'm not sure how to make it executable in a generic fashion.
 

BullyWiiPlaza

Nintendo Hacking <3
OP
Member
Joined
Aug 2, 2014
Messages
1,932
Trophies
0
XP
2,477
Country
Germany
Nevermind. I got it to work. The trick was like @QuarkTheAwesome said, to write the assembly to an executable data section and then executing it from there:
Code:
case COMMAND_EXECUTE_ASSEMBLY: {
    // Receive the assembly
    receiveString(bss, clientfd, (char *) buffer, DATA_BUFFER_SIZE);

    // Write the assembly to an executable code region
    int destinationAddress = 0x10000000 - DATA_BUFFER_SIZE;
    pygecko_memcpy((unsigned char *) destinationAddress, buffer, DATA_BUFFER_SIZE);

    // Execute the assembly from there
    void (*function)() = (void (*)()) destinationAddress;
    function();

    // Clear the memory contents again
    memset((void *) buffer, 0, DATA_BUFFER_SIZE);
    pygecko_memcpy((unsigned char *) destinationAddress, buffer, DATA_BUFFER_SIZE);

    break;
}
L33t h4x0r way of poking a value :D
74f96sc7.png
 
Last edited by BullyWiiPlaza,

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
  • SylverReZ @ SylverReZ:
    Worst would be getting a DRM rootkit from using audio CDs and then Sony getting sued.
  • K3Nv2 @ K3Nv2:
    Least I can throw the nvme at neighbors now
  • DinohScene @ DinohScene:
    get a 2 TB NVMe from amazon, return the fucked one, get replacement and send that one to me
  • K3Nv2 @ K3Nv2:
    Easier way buy one with a preadded heatsync pop the heat sync open
  • K3Nv2 @ K3Nv2:
    Some nerd at Amazon warehouse may tell the end of the colors off
  • DinohScene @ DinohScene:
    I'd like a 990 pro tyvm <З
  • K3Nv2 @ K3Nv2:
    Gen 5s going to be crazy expensive at like 10k transfer
  • K3Nv2 @ K3Nv2:
    $300for 2tb
  • DinohScene @ DinohScene:
    don't have anything that can take PCIe5
  • K3Nv2 @ K3Nv2:
    It's still m.2 form just the next gen
  • DinohScene @ DinohScene:
    ew crucial
  • K3Nv2 @ K3Nv2:
    13,600 MB/s though
  • DinohScene @ DinohScene:
    I got a 980 pro iirc
  • K3Nv2 @ K3Nv2:
    Soldigms been pretty solid
  • DinohScene @ DinohScene:
    yeh 980 pro
  • DinohScene @ DinohScene:
    good enough tbf
  • K3Nv2 @ K3Nv2:
    https://a.co/d/gMNhZNI never heard about them but reviews are good
  • SylverReZ @ SylverReZ:
    @DinohScene, Crucial SSDs work fine. I have one installed in my Xbox.
  • SylverReZ @ SylverReZ:
    Reviews seem positive.
  • DinohScene @ DinohScene:
    I believe I had some Patriot RAM running in a computer somewhere
  • K3Nv2 @ K3Nv2:
    $250 is pretty solid considering
  • K3Nv2 @ K3Nv2:
    With the refund it'll be about $150
  • K3Nv2 @ K3Nv2:
    6tb nvme pc ftw
    K3Nv2 @ K3Nv2: 6tb nvme pc ftw