Skip to content

Commit

Permalink
Add integrated CFW: OTP/Seeprom and haxchi disc dumping fixes
Browse files Browse the repository at this point in the history
Will do more cleanup later, just want to get this version out the door finally!

Fixes #4, #5, #2
  • Loading branch information
Crementif committed Nov 18, 2020
1 parent c85d6a7 commit 706cd36
Show file tree
Hide file tree
Showing 56 changed files with 2,506 additions and 259 deletions.
22 changes: 21 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,24 @@
/build
/dist
dumpling.rpx
dumpling.elf
dumpling.elf

source/cfw/ios_kernel/ios_kernel.bin
source/cfw/ios_kernel/ios_kernel.elf
source/cfw/ios_kernel/ios_kernel.s
source/cfw/ios_kernel/ios_kernel.h

source/cfw/ios_mcp/ios_mcp.bin
source/cfw/ios_mcp/ios_mcp.elf
source/cfw/ios_mcp/ios_mcp.s
source/cfw/ios_mcp/ios_mcp.h

source/cfw/ios_odm/ios_odm.bin
source/cfw/ios_odm/ios_odm.elf
source/cfw/ios_odm/ios_odm.s
source/cfw/ios_odm/ios_odm.h

source/cfw/ios_usb/ios_usb.bin
source/cfw/ios_usb/ios_usb.elf
source/cfw/ios_usb/ios_usb.s
source/cfw/ios_usb/ios_usb.h
16 changes: 12 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ include $(DEVKITPRO)/wut/share/wut_rules
#-------------------------------------------------------------------------------
TARGET := dumpling
BUILD := build
SOURCES := source
SOURCES := source/app
DATA := data
INCLUDES := include

#-------------------------------------------------------------------------------
# options for code generation
#-------------------------------------------------------------------------------
CFLAGS := -g -Wall -Os -O2 -ffunction-sections \
CFLAGS := -g -Wall -Os -O2 -ffunction-sections -Wno-narrowing \
$(MACHDEP)

CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__wiiu__
Expand All @@ -36,7 +36,7 @@ CXXFLAGS := $(CFLAGS) -std=c++20
ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map)

LIBS := -lfat -lstdc++ -lwut -liosuhax
LIBS := -lstdc++ -lwut -lfat -liosuhax

#-------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level
Expand Down Expand Up @@ -97,12 +97,20 @@ all: $(BUILD)

$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(CURDIR)/source/cfw/ios_usb -f $(CURDIR)/source/cfw/ios_usb/Makefile
@$(MAKE) --no-print-directory -C $(CURDIR)/source/cfw/ios_odm -f $(CURDIR)/source/cfw/ios_odm/Makefile
@$(MAKE) --no-print-directory -C $(CURDIR)/source/cfw/ios_mcp -f $(CURDIR)/source/cfw/ios_mcp/Makefile
@$(MAKE) --no-print-directory -C $(CURDIR)/source/cfw/ios_kernel -f $(CURDIR)/source/cfw/ios_kernel/Makefile
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile

#-------------------------------------------------------------------------------
clean:
@echo clean ...
@echo Clean files from app...
@rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf
@$(MAKE) clean --no-print-directory -C $(CURDIR)/source/cfw/ios_kernel -f $(CURDIR)/source/cfw/ios_kernel/Makefile
@$(MAKE) clean --no-print-directory -C $(CURDIR)/source/cfw/ios_mcp -f $(CURDIR)/source/cfw/ios_mcp/Makefile
@$(MAKE) clean --no-print-directory -C $(CURDIR)/source/cfw/ios_odm -f $(CURDIR)/source/cfw/ios_odm/Makefile
@$(MAKE) clean --no-print-directory -C $(CURDIR)/source/cfw/ios_usb -f $(CURDIR)/source/cfw/ios_usb/Makefile

#-------------------------------------------------------------------------------
dist:
Expand Down
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ Use the Wii U App Store to download and install it in the homebrew launcher. See
**Method 2:**
Download the [latest release from Github](https://github.com/emiyl/dumpling/releases), and extract the `dumpling.zip` file to the root of your SD card.

Using it is as simple as running Mocha or Haxchi and launching Dumpling in the homebrew launcher.
## How to use
Using it just requires you to open up the homebrew launcher and launch the app. No Mocha or Haxchi required!

For an always up-to-date guide to dump your games for Cemu using Dumpling, see [cemu.cfw.guide](https://cemu.cfw.guide/dumping-games)! It also goes through the steps of installing and running homebrew and Dumpling for the first time!


## How to compile
Expand All @@ -28,17 +31,17 @@ Using it is as simple as running Mocha or Haxchi and launching Dumpling in the h

## Features
- Dumps everything related to your games! Game, updates, DLC and saves are all dumpable!
- Dumps both disc and digital games in an extracted format, making for easy modding.
- Dumps both disc and digital games in an extracted format, making for easy modding and usage with Cemu.
- Creates 1:1 copies of data with proper meta data.
- Allows dumping to an SD or USB stick/drive (must be formatted as fat32).
- Allows you to dump system applications too.
- Quickly dump files required for online dumping
- Feature to quickly dump all the files needed for Cemu online play
- You must dump `otp.bin` and `seeprom.bin` separately with [wiiu-nanddumper](https://github.com/koolkdev/wiiu-nanddumper) (for now!)
- Feature to quickly dump compatibility files which can be used to improve graphics and game compatibillity in Cemu.
- Feature to quickly dump everything needed to play online with Cemu, including the otp.bin and seeprom.bin!
- Also dumps extra compatibility files for Cemu when dumping online files.
- Has features to dump the base game files, update files and DLC files separately.

## Credits
- [Crementif](https://github.com/Crementif) for [dumpling-rework](https://github.com/emiyl/dumpling)
- [emiyl](https://github.com/emiyl) for [dumpling-classic](https://github.com/emiyl/dumpling-classic)
- chrissie for testing
- FIX94, Maschell and Quarky for making and maintaining homebrew (libraries)
- smea, plutoo, yellows8, naehrwert, derrek, dimok and kanye_west for help making exploits and CFW possible
15 changes: 11 additions & 4 deletions source/common.h → source/app/common.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
#pragma once

#include <coreinit/screen.h>
#include <coreinit/mcp.h>
#include <coreinit/thread.h>
#include <coreinit/time.h>
#include <coreinit/ios.h>
#include <coreinit/cache.h>
#include <coreinit/dynload.h>
#include <coreinit/cache.h>
#include <coreinit/event.h>
#include <sysapp/launch.h>
#include <nn/act.h>
#include <whb/log.h>
#include <whb/log_console.h>

#include <string>
#include <string.h>
#include <malloc.h>
#include <limits.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string>
#include <sstream>
#include <vector>
#include <array>
Expand All @@ -19,9 +29,6 @@
#include <iterator>
#include <functional>
#include <fstream>
#include <limits.h>
#include <dirent.h>
#include <sys/stat.h>

// Enums and Structs

Expand Down
103 changes: 48 additions & 55 deletions source/dumping.cpp → source/app/dumping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,26 @@
#include "navigation.h"
#include "titles.h"
#include "users.h"
#include "iosuhax.h"

// Dumping Functions

#define BUFFER_SIZE_ALIGNMENT 64
#define BUFFER_SIZE (1024 * BUFFER_SIZE_ALIGNMENT)

bool copyFile(const char* filename, std::string srcPath, std::string destPath) {
bool copyFile(const char* filename, std::string srcPath, std::string destPath, uint64_t* totalBytes) {
// Check if file is an actual file first
struct stat fileStat;
if (stat(srcPath.c_str(), &fileStat) == -1 || !S_ISREG(fileStat.st_mode)) {
return true;
}

// If totalBytes is set, it's just a file size scan
if (totalBytes != nullptr) {
*totalBytes += fileStat.st_size;
return true;
}

// Allocate buffer to copy bytes between
uint8_t* copyBuffer = (uint8_t*)aligned_alloc(BUFFER_SIZE_ALIGNMENT, BUFFER_SIZE);
if (copyBuffer == NULL) {
Expand Down Expand Up @@ -91,19 +98,10 @@ bool copyFolder(std::string srcPath, std::string destPath, uint64_t* totalBytes)
struct dirent *dirEntry;
while((dirEntry = readdir(dirHandle)) != NULL) {
if (dirEntry->d_type == DT_REG) {
if (totalBytes != nullptr) {
// Get the amount of bytes for each file
struct stat fileStat;
if (stat(std::string(srcPath+"/"+dirEntry->d_name).c_str(), &fileStat) == 0 && S_ISREG(fileStat.st_mode)) {
*totalBytes += fileStat.st_size;
}
}
else {
// Copy file
if (!copyFile(dirEntry->d_name, srcPath+"/"+dirEntry->d_name, destPath+"/"+dirEntry->d_name)) {
closedir(dirHandle);
return false;
}
// Copy file
if (!copyFile(dirEntry->d_name, srcPath+"/"+dirEntry->d_name, destPath+"/"+dirEntry->d_name, totalBytes)) {
closedir(dirHandle);
return false;
}
}
else if (dirEntry->d_type == DT_DIR) {
Expand Down Expand Up @@ -230,24 +228,7 @@ void dumpMLC() {

bool dumpDisc() {
// Loop until a disk is found
std::vector<std::reference_wrapper<titleEntry>> queue;
while(queue.empty()) {
mountDisc();
// Reload titles
if (!loadTitles(false)) {
showDialogPrompt("A fatal error occured while trying to check for game discs!", "OK");
showDialogPrompt("Dumpling will now forcefully be closed...", "OK");
return false;
}

// Check if there's a disc title
for (auto& title : installedTitles) {
if (title.hasBase && title.base.location == titleLocation::Disc) {
queue.emplace_back(std::ref(title));
break;
}
}

while(!isDiscInserted()) {
// Print menu
clearScreen();
WHBLogPrint("Looking for a game disc...");
Expand All @@ -256,12 +237,33 @@ bool dumpDisc() {
WHBLogPrint("===============================");
WHBLogPrint("B Button = Back to Main Menu");
WHBLogConsoleDraw();
OSSleepTicks(OSMillisecondsToTicks(20));
OSSleepTicks(OSSecondsToTicks(2));

updateInputs();
if (pressedBack()) {
unmountDisc();
return true;
if (pressedBack()) return true;
}

// Disable iosuhax to perform getting the titles, which uses the currently hooked MCP
closeIosuhax();
OSSleepTicks(OSSecondsToTicks(2));

clearScreen();
WHBLogPrint("Reloading games list:");
WHBLogPrint("");
WHBLogConsoleDraw();
if (!(getTitles() && openIosuhax() && mountDisc() && loadTitles(false))) {
showDialogPrompt("Fatal error while reloading titles!\nExiting Dumpling instantly...", "OK");
unmountDisc();
return false;
}

// Make a queue from game disc

std::vector<std::reference_wrapper<titleEntry>> queue;
for (auto& title : installedTitles) {
if (title.hasBase && title.base.location == titleLocation::Disc) {
queue.emplace_back(std::ref(title));
break;
}
}

Expand Down Expand Up @@ -308,23 +310,14 @@ void dumpOnlineFiles() {
queue.emplace_back(std::ref(scertsEntry));
queue.emplace_back(std::ref(accountsEntry));

if (!dumpQueue(queue, onlineConfig)) showDialogPrompt("Failed to dump the online files...", "OK");
else showDialogPrompt("Successfully dumped all of the online files!", "OK");
}

void dumpCompatibilityFiles() {
std::vector<std::reference_wrapper<titleEntry>> queue;
dumpingConfig compatConfig = {.dumpTypes = (dumpTypeFlags::CUSTOM)};
titleEntry miiEntry{.shortTitle = "Mii Files", .hasBase = true, .base = {.path = "storage_mlc01:/sys/title/0005001b/10056000/content", .outputPath = "/Compatibility Files/mlc01/sys/title/0005001b/10056000/content"}};
titleEntry keyboardEntry{.shortTitle = "Keyboard Files", .hasBase = true, .base = {.path = "storage_mlc01:/sys/title/0005001b/1004f000", .outputPath = "/Compatibility Files/mlc01/sys/title/0005001b/1004f000"}};
titleEntry rplEntry{.shortTitle = "RPL Files", .hasBase = true, .base = {.path = "storage_mlc01:/sys/title/00050010/1000400a", .outputPath = "/Compatibility Files/mlc01/sys/title/00050010/1000400a"}};
std::ofstream otpFile(getRootFromLocation(onlineConfig.location)+"/dumpling/Online Files/otp.bin", std::ofstream::out | std::ofstream::binary);
std::ofstream seepromFile(getRootFromLocation(onlineConfig.location)+"/dumpling/Online Files/seeprom.bin", std::ofstream::out | std::ofstream::binary);

if (!showOptionMenu(compatConfig, false)) return;

queue.emplace_back(std::ref(miiEntry));
queue.emplace_back(std::ref(keyboardEntry));
queue.emplace_back(std::ref(rplEntry));

if (!dumpQueue(queue, compatConfig)) showDialogPrompt("Failed to dump the compatibility files...", "OK");
else showDialogPrompt("Successfully dumped all of the compatibility files!", "OK");
}
if (!dumpQueue(queue, onlineConfig) || otpFile.fail() || seepromFile.fail()) {
showDialogPrompt("Failed to dump the online files...", "OK");
return;
}
otpFile.write((char*)0xF5E10400, 1024);
seepromFile.write((char*)0xF5E10400+1024, 512);
showDialogPrompt("Successfully dumped all of the online files!", "OK");
}
2 changes: 1 addition & 1 deletion source/dumping.h → source/app/dumping.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ bool dumpQueue(std::vector<std::reference_wrapper<titleEntry>>& queue, dumpingCo
bool dumpDisc();
void dumpMLC();
void dumpOnlineFiles();
void dumpCompatibilityFiles();
void dumpAmiibo();
78 changes: 78 additions & 0 deletions source/app/exploit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include "exploit.h"

static IOSHandle exploitHandle = -1;

static int32_t* firstChain = (int32_t*)0xF5E00000;
static int8_t* secondChain = (int8_t*)0xF5E20000;
static int8_t* thirdChain = (int8_t*)0xF5E30000;
static int32_t* pretendRootHub = (int32_t*)0xF5E60640;


int uhsWrite32(int32_t physicalAddr, int32_t value) {
// Put address in first chain which is referenced in the pretend root hub
firstChain[520] = physicalAddr - 24; // Address that needs to be written to, minus 24 bytes
DCStoreRange(firstChain, 0x840); // Flush current CPU cache so that we're sure that IOSU can read it
OSSleepTicks(0x200000); // Improve stability by waiting for caches to refresh

// Use pretendRootHub with a negative index (0 being at 0x10149A6C) to write values that come before the IOSU USB module
// Each index is 0x144 bytes long, so the pretend root hub needs to be at the exact end of that address: 0x10149A6C + (0x144*-0xB349B) = 0x01E60640.
// 0x01E60640's physical address is 0xF5E60640, which is free to manipulate since it's in MEM1 memory.
int32_t messageBuffer[] = {-0xB349B, value};
int32_t replyBuffer[32];
return IOS_Ioctl(exploitHandle, 0x15, messageBuffer, sizeof(messageBuffer), replyBuffer, sizeof(replyBuffer));
}


void setupExploit() {
// Clear out memory used for the exploit
memset(firstChain, 0, 0x00070000);
DCStoreRange(firstChain, 0x00070000);

firstChain[5] = 1;
firstChain[8] = 0x01E00000;

memcpy(secondChain, secondChainBin, sizeof(secondChainBin));
memcpy(thirdChain, thirdChainBin, sizeof(thirdChainBin));
memcpy((char*)(0xF5E40000), ios_kernel_bin, sizeof(ios_kernel_bin));
memcpy((char*)(0xF5E50000), ios_usb_bin, sizeof(ios_usb_bin));
*(volatile unsigned int*)0xF5E70000 = sizeof(ios_mcp_bin);
memcpy((char*)(0xF5E70020), ios_mcp_bin, sizeof(ios_mcp_bin));

pretendRootHub[33] = 0x01E00000;
pretendRootHub[78] = 0;

//! Store current CPU cache into main memory for IOSU to read
DCStoreRange(firstChain, 0x840);
DCStoreRange(secondChain, sizeof(secondChainBin));
DCStoreRange(thirdChain, sizeof(thirdChainBin));
DCStoreRange((void*)0xF5E40000, sizeof(ios_kernel_bin));
DCStoreRange((void*)0xF5E50000, sizeof(ios_usb_bin));
DCStoreRange((void*)0xF5E70000, sizeof(ios_mcp_bin) + 0x40);

DCStoreRange(pretendRootHub, 0x160);
}


bool executeExploit() {
WHBLogPrint("Executing exploit...");
WHBLogConsoleDraw();

exploitHandle = IOS_Open("/dev/uhs/0", IOSOpenMode::IOS_OPEN_READ);
if (exploitHandle < IOS_ERROR_OK) {
WHBLogPrintf("Can't initialize /dev/uhs/0! Error: %ld", exploitHandle);
IOS_Close(exploitHandle);
return false;
}

// Setup other chains and payloads
setupExploit();

// Setup the first chain that'll lead to the second chain
uhsWrite32(CHAIN_START+0x14, CHAIN_START + 0x14 + 0x4 + 0x20);
uhsWrite32(CHAIN_START+0x10, 0x1011814C);
uhsWrite32(CHAIN_START+0x0C, SOURCE);
uhsWrite32(CHAIN_START+0x00, 0x1012392b); // pop {R4-R6,PC}

IOS_Close(exploitHandle);
return true;
}
Loading

0 comments on commit 706cd36

Please sign in to comment.