MBMNET-App v2.8.2: Quellcode (GPLv3)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
// Miiverse-Patch: leitet die Miiverse-App auf MBMNET um und lässt sie der MBMNET-Zertifizierungsstelle (CA)
|
||||
// vertrauen, denn ihre Seiten lädt sie nur per HTTPS.
|
||||
//
|
||||
// Die Code-Änderungen stammen aus Pretendos Nimbus (patches/miiverse, GPLv3, nach Stary und Sono): mit armips
|
||||
// übersetzt, statt Pretendos Discovery-Adresse und GlobalSign-Zertifikat kommen MBMNET-Adresse und -CA hinein.
|
||||
// Sie gelten für die letzte Version der Miiverse-App (alle Regionen gleich). Vorher wird geprüft, dass die
|
||||
// Nintendo-Discovery-Adresse genau an der erwarteten Stelle steht - sonst wird nichts gepatcht.
|
||||
//
|
||||
// 0x176F28 fügt der HTTP-Verbindung die CA hinzu (httpC:AddRootCA), Länge der CA an Byte 72
|
||||
// 0x1D7FF8 / 0x1D80EC / 0x38DC30 SD-Karte zusätzlich einhängen und wieder aushängen
|
||||
// 0x1E3224 / 0x1E3468 der Browser lädt seine CA aus sdmc:/3ds/mbmnet-ca.pem
|
||||
// 0x38DCB0 die CA selbst (DER, höchstens 889 Bytes)
|
||||
#include <3ds.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "olvpatch.h"
|
||||
|
||||
#define CODE_BASE 0x100000
|
||||
#define DISCOVERY_ADDR 0x15748C
|
||||
#define DISCOVERY_URL "https://discovery.olv.nintendo.net/v1/endpoint"
|
||||
#define CA_ADDR 0x38DCB0
|
||||
#define CA_MAX 889
|
||||
#define CA_PEM_FILE "sdmc:/3ds/mbmnet-ca.pem"
|
||||
|
||||
static const u8 olv_176F28[] = { 0x3C, 0x00, 0x9F, 0xE5, 0x70, 0x4F, 0x1D, 0xEE, 0x0C, 0x10, 0x95, 0xE5, 0x14, 0x80, 0x95, 0xE5, 0x80, 0x00, 0xA4, 0xE5, 0x04, 0x10, 0x84, 0xE5, 0x08, 0x00, 0xA0, 0xE1, 0x24, 0x80, 0x9F, 0xE5, 0x24, 0x10, 0x9F, 0xE5, 0x08, 0x80, 0x84, 0xE5, 0x10, 0x10, 0x84, 0xE5, 0x08, 0x82, 0xA0, 0xE1, 0x0A, 0x80, 0x88, 0xE3, 0x0C, 0x80, 0x84, 0xE5, 0x32, 0x00, 0x00, 0xEF, 0x00, 0x00, 0xA0, 0xE1, 0x08, 0x00, 0x00, 0xEA, 0x82, 0x00, 0x24, 0x00, 0x79, 0x03, 0x00, 0x00, 0xB0, 0xDC, 0x38, 0x00, 0x00, 0x00, 0xA0, 0xE1, 0x00, 0x00, 0xA0, 0xE1, 0x00, 0x00, 0xA0, 0xE1 };
|
||||
static const u8 olv_1D7FF8[] = { 0x0C, 0xD7, 0x06, 0xEA };
|
||||
static const u8 olv_1D80EC[] = { 0xD4, 0xD6, 0x06, 0xEA };
|
||||
static const u8 olv_1E3224[] = { 0x01, 0x20, 0xA0, 0xE3 };
|
||||
static const u8 olv_1E3468[] = "3ds/mbmnet-ca.pem"; // mit Nullbyte: 18 Bytes
|
||||
static const u8 olv_38DC30[] = { 0x00, 0x40, 0x2D, 0xE9, 0x2E, 0x28, 0xF9, 0xEB, 0x18, 0x00, 0x9F, 0xE5, 0x00, 0x40, 0xBD, 0xE8, 0xB6, 0x93, 0xF8, 0xEA, 0x00, 0x40, 0x2D, 0xE9, 0x02, 0x29, 0xF9, 0xEB, 0x04, 0x00, 0x9F, 0xE5, 0x00, 0x40, 0xBD, 0xE8, 0xBB, 0x92, 0xFA, 0xEA, 0x9C, 0x81, 0x1D, 0x00 };
|
||||
#define CA_LEN_BYTE 72 // in olv_176F28: Länge der CA (Literal-Pool)
|
||||
|
||||
// Lädt eine Datei vom MBMNET-Server. Gibt die Länge zurück, 0 bei Fehler.
|
||||
static u32 fetch(const char *server, const char *path, u8 *buf, u32 cap)
|
||||
{
|
||||
char url[160];
|
||||
snprintf(url, sizeof(url), "http://%s%s", server, path);
|
||||
httpcContext ctx;
|
||||
if (R_FAILED(httpcOpenContext(&ctx, HTTPC_METHOD_GET, url, 1))) return 0;
|
||||
httpcAddRequestHeaderField(&ctx, "User-Agent", "MBMNET-Switcher/" APP_VERSION);
|
||||
u32 status = 0, got = 0;
|
||||
Result rc = httpcBeginRequest(&ctx);
|
||||
if (R_SUCCEEDED(rc)) rc = httpcGetResponseStatusCodeTimeout(&ctx, &status, 8ULL * 1000 * 1000 * 1000);
|
||||
if (R_SUCCEEDED(rc) && status == 200) rc = httpcDownloadData(&ctx, buf, cap, &got);
|
||||
httpcCloseContext(&ctx);
|
||||
return R_SUCCEEDED(rc) && status == 200 && got < cap ? got : 0;
|
||||
}
|
||||
|
||||
bool olvpatch_fetch_ca(const char *server, u8 *der, u32 *derLen)
|
||||
{
|
||||
static u8 pem[2048];
|
||||
u32 n = fetch(server, "/olv/ca.der", der, CA_MAX + 1);
|
||||
if (n == 0 || n > CA_MAX) return false;
|
||||
u32 p = fetch(server, "/olv/ca.pem", pem, sizeof(pem));
|
||||
if (p == 0) return false;
|
||||
// Der Browser der Miiverse-App liest die CA von der SD-Karte
|
||||
FILE *f = fopen(CA_PEM_FILE, "wb");
|
||||
bool ok = f && fwrite(pem, 1, p, f) == p;
|
||||
if (f) fclose(f);
|
||||
*derLen = n;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool olvpatch_supported(const u8 *code, u32 size)
|
||||
{
|
||||
u32 off = DISCOVERY_ADDR - CODE_BASE;
|
||||
return off + sizeof(DISCOVERY_URL) <= size && memcmp(code + off, DISCOVERY_URL, sizeof(DISCOVERY_URL)) == 0;
|
||||
}
|
||||
|
||||
static u32 ips_record(u8 *out, u32 n, u32 cap, u32 addr, const u8 *data, u32 len)
|
||||
{
|
||||
if (n + 5 + len + 3 > cap) return 0;
|
||||
u32 off = addr - CODE_BASE;
|
||||
u8 head[5] = { off >> 16, off >> 8, off, len >> 8, len };
|
||||
memcpy(out + n, head, 5);
|
||||
memcpy(out + n + 5, data, len);
|
||||
return n + 5 + len;
|
||||
}
|
||||
|
||||
u32 olvpatch_build(const char *server, const u8 *der, u32 derLen, u8 *out, u32 cap)
|
||||
{
|
||||
// Discovery: "https://discovery.olv.nintendo.net/v1/endpoint" -> "http://<server>/v1/endpoint", Rest Nullbytes
|
||||
u8 discovery[sizeof(DISCOVERY_URL)] = { 0 };
|
||||
int len = snprintf((char *)discovery, sizeof(discovery), "http://%s/v1/endpoint", server);
|
||||
if (len <= 0 || len >= (int)sizeof(discovery) || derLen == 0 || derLen > CA_MAX) return 0;
|
||||
|
||||
u8 caHook[sizeof(olv_176F28)];
|
||||
memcpy(caHook, olv_176F28, sizeof(caHook));
|
||||
caHook[CA_LEN_BYTE] = derLen;
|
||||
caHook[CA_LEN_BYTE + 1] = derLen >> 8;
|
||||
|
||||
u32 n = 5;
|
||||
memcpy(out, "PATCH", 5);
|
||||
struct { u32 addr; const u8 *data; u32 len; } recs[] = {
|
||||
{ DISCOVERY_ADDR, discovery, sizeof(discovery) },
|
||||
{ 0x176F28, caHook, sizeof(caHook) },
|
||||
{ 0x1D7FF8, olv_1D7FF8, sizeof(olv_1D7FF8) },
|
||||
{ 0x1D80EC, olv_1D80EC, sizeof(olv_1D80EC) },
|
||||
{ 0x1E3224, olv_1E3224, sizeof(olv_1E3224) },
|
||||
{ 0x1E3468, olv_1E3468, sizeof(olv_1E3468) },
|
||||
{ 0x38DC30, olv_38DC30, sizeof(olv_38DC30) },
|
||||
{ CA_ADDR, der, derLen },
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(recs) / sizeof(recs[0]); i++)
|
||||
if (!(n = ips_record(out, n, cap, recs[i].addr, recs[i].data, recs[i].len))) return 0;
|
||||
memcpy(out + n, "EOF", 3);
|
||||
return n + 3;
|
||||
}
|
||||
Reference in New Issue
Block a user