Hacking Replacing (Disk) Files

BullyWiiPlaza

Nintendo Hacking <3
OP
Member
Joined
Aug 2, 2014
Messages
1,932
Trophies
0
XP
2,477
Country
Germany
For the TCP Gecko Installer I tried to implement a function to replace files on games. However, I'm getting an ACCESS_ERROR when calling FSOpenFile():
Code:
case COMMAND_REPLACE_FILE: {
    // Receive the file path
    char file_path[FS_MAX_FULLPATH_SIZE] = {0};
    receiveString(bss, clientfd, file_path, FS_MAX_FULLPATH_SIZE);

    considerInitializingFileSystem();

    // Create an empty file for writing. Its contents will be erased
    int handle;
    int status = FSOpenFile(client, commandBlock, file_path, "w", &handle, FS_RET_ALL_ERROR);

    if (status == FS_STATUS_OK) {
        // Send the OK status
        ((int *) buffer)[0] = status;
        ret = sendwait(bss, clientfd, buffer, 4);
        ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (OK status)")

        // Set the file handle position to the beginning
        ret = FSSetPosFile(client, commandBlock, handle, 0, FS_RET_ALL_ERROR);
        ASSERT_FUNCTION_SUCCEEDED(ret, "FSSetPosFile")

        // Allocate the file bytes buffer
        unsigned int file_buffer_size = 0x2000;
        char *fileBuffer = (char *) OSAllocFromSystem(file_buffer_size, FS_IO_BUFFER_ALIGN);
        ASSERT_ALLOCATED(fileBuffer, "File buffer")

        // Send the maximum file buffer size
        ret = sendwait(bss, clientfd, &file_buffer_size, 4);
        ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (maximum file buffer size)")

        while (true) {
            // Receive the data bytes length
            unsigned int dataLength;
            ret = recvwait(bss, clientfd, &dataLength, 4);
            ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (File bytes length)")
            ASSERT_MAXIMUM_HOLDS(file_buffer_size, dataLength, "File buffer overrun attempted")

            if (dataLength > 0) {
                // Receive the data
                ret = recvwait(bss, clientfd, fileBuffer, dataLength);
                ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (File buffer)")

                // Write the data (and advance file handle position implicitly)
                ret = FSWriteFile(client, commandBlock, fileBuffer, 1,
                                  dataLength, handle, 0, FS_RET_ALL_ERROR);
                ASSERT_FUNCTION_SUCCEEDED(ret, "FSWriteFile")
            } else {
                // Done with receiving the new file
                break;
            }
        }

        /*// Flush the file back
        ret = FSFlushFile(client, commandBlock, handle, FS_RET_ALL_ERROR);
        CHECK_FUNCTION_FAILED(ret, "FSFlushFile")*/

        // Close the file
        ret = FSCloseFile(client, commandBlock, handle, FS_RET_ALL_ERROR);
        ASSERT_FUNCTION_SUCCEEDED(ret, "FSCloseFile")

        // Free the file buffer
        OSFreeToSystem(fileBuffer);
    } else {
        // Send the status
        ((int *) buffer)[0] = status;
        ret = sendwait(bss, clientfd, buffer, 4);
        ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (status)")
    }

    break;
}
Client code in Java:
Code:
public FileSystemStatus replaceFile(String remoteFilePath, String localFilePath) throws IOException
{
    // Read the file bytes
    Path localFile = Paths.get(localFilePath);
    byte[] fileBytes = Files.readAllBytes(localFile);

    try (CloseableReentrantLock ignored = reentrantLock.acquire())
    {
        // Send the command and remote file path
        sendCommand(Command.REPLACE_REMOTE_FILE);
        writeString(remoteFilePath);
        dataSender.flush();

        FileSystemStatus status = readFileSystemStatus();

        // Continue if the file has been opened successfully
        if (status == FileSystemStatus.OK)
        {
            sendFileBytes(fileBytes);
        }

        return status;
    }
}

private void sendFileBytes(byte[] fileBytes) throws IOException
{
    int maximumChunkSize = dataReceiver.readInt();
    int fileBytesIndex = 0;

    // Send the file bytes in chunks
    while (fileBytesIndex < fileBytes.length)
    {
        int chunkSize = fileBytes.length - fileBytesIndex;

        if (chunkSize > maximumChunkSize)
        {
            chunkSize = maximumChunkSize;
        }

        // Send the current chunk size
        dataSender.writeInt(chunkSize);
        sendPartialBytes(fileBytes, fileBytesIndex, chunkSize);
        dataSender.flush();

        fileBytesIndex += chunkSize;
    }

    // Let the server know that we're done
    dataSender.writeInt(0);
    dataSender.flush();
}

private void sendPartialBytes(byte[] bytes, int startingIndex, int length) throws IOException
{
    byte[] sendBytes = new byte[length];
    System.arraycopy(bytes, startingIndex, sendBytes, 0, length);
    dataSender.write(sendBytes);
}
In case you're wondering, Cafiine does not actually replace files the same way I'm trying to. It only fools the Wii U into pulling the files from the network instead of the disk. However, I'm trying to just replace the file so the replacement file is being used from now on instead without requesting it over the network over and over again. I'm not sure if this is even possible since the SDK says this about the error message:
Code:
Access mode is invalid (e.g. specified "r+" for read-only media).
It might mean that disks just aren't writable (I'm using the digital version though) but isn't there maybe a way to do it? This project might help as well. Thanks :)

@dimok
@QuarkTheAwesome
@Maschell
@FIX94
@wj44
@NWPlayer123
 
Last edited by BullyWiiPlaza,

wj44

Well-Known Member
Member
Joined
Jun 18, 2015
Messages
477
Trophies
0
XP
506
Country
Gambia, The
If you really want to replace the file you either need to use libiosuhax or the MCPCopyFile Command(eShop games only). Alternativly You can just write the file to the sd and open It everywhere with libiosuhax.
 
  • Like
Reactions: BullyWiiPlaza

BullyWiiPlaza

Nintendo Hacking <3
OP
Member
Joined
Aug 2, 2014
Messages
1,932
Trophies
0
XP
2,477
Country
Germany
If you really want to replace the file you either need to use libiosuhax
Wouldn't that be permanent? A temporary replacement would be better I guess since FTPiiu everywhere is probably best suited for permanent replacements. How would go about using libiosuhax to replace the file(s)?
Usually odd03 has the content. Some games have content on odd04. The data you get from there is /code /content /meta, as required by loadiine.
The code should look similar to this then?
Code:
// initialize IOSUHAX
int res = IOSUHAX_Open();

// initialize FSA fd
int fsaFd = IOSUHAX_FSA_Open();

// mount "/dev/odd03" to "/vol/storage_virt_odd" and bind it to our virt PPC path "odd:/"
// if 3rd parameter is NULL it only binds the /vol path (e.g. /vol/system)  to our virt PPC path
res = mount_fs("odd", fsaFd, "/dev/odd03", "/vol/storage_virt_odd");

// Open the file, write and close it again
IOSUHAX_FSA_OpenFile(fsaFd, systemXmlPath, "wb", &slcFd);
IOSUHAX_FSA_WriteFile(fsaFd, data, size, cnt, pFile, flags);
IOSUHAX_FSA_CloseFile(fsaFd, slcFd);
// ...
Haxchi makes a nice example of writing with iosuhax :P
 
Last edited by BullyWiiPlaza,
  • Like
Reactions: KiiWii

wj44

Well-Known Member
Member
Joined
Jun 18, 2015
Messages
477
Trophies
0
XP
506
Country
Gambia, The
Wouldn't that be permanent? A temporary replacement would be better I guess since FTPiiu everywhere is probably best suited for permanent replacements. How would go about using libiosuhax to replace the file(s)?

The code should look similar to this then?
Code:
// initialize IOSUHAX
int res = IOSUHAX_Open();

// initialize FSA fd
int fsaFd = IOSUHAX_FSA_Open();

// mount "/dev/odd03" to "/vol/storage_virt_odd" and bind it to our virt PPC path "odd:/"
// if 3rd parameter is NULL it only binds the /vol path (e.g. /vol/system)  to our virt PPC path
res = mount_fs("odd", fsaFd, "/dev/odd03", "/vol/storage_virt_odd");

// Open the file, write and close it again
IOSUHAX_FSA_OpenFile(fsaFd, systemXmlPath, "wb", &slcFd);
IOSUHAX_FSA_WriteFile(fsaFd, data, size, cnt, pFile, flags);
IOSUHAX_FSA_CloseFile(fsaFd, slcFd);
// ...
Haxchi makes a nice example of writing with iosuhax :P
Of course this would be permanent. If you want temporaly you need to make fs patches like in Cafiine.
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    K3Nv2 @ K3Nv2: Att did offer a $500gc tempting to use it for 6 months and cancel