Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
zoogie
authored and
zoogie
committed
Sep 27, 2018
1 parent
0ec414d
commit 2af2876
Showing
8 changed files
with
316 additions
and
2 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
FROGminer Beta Test | ||
|
||
What is this? | ||
tl;dr ~ Free CFW for USA, EUR, JPN ~ | ||
|
||
!tl;dr - This differs from previous iterations of seedminer in that homebrew, instead of System Settings, is used to import/export the dsiware (this eases size restrictions). | ||
Also, eshop dsiware is not needed or used this time. Instead, a different dsihax game, flipnote studio JPN v0, is injected into an internal dsi system app. | ||
This particular v0 of flipnote is needed because all 4 other regions/versions throw an error and kick you back to home menu if it cannot find its | ||
save file on NAND. System dsiware titles do not have saves and you cannot import a modified system dsiware that has one. | ||
|
||
Needed files: | ||
boot.nds https://github.com/zoogie/b9sTool/releases/latest - put this on the sd root | ||
Frogtool.3dsx included - put this in your sdmc:/3DS folder | ||
private/ included - drag this directory to the root of your sd card - this is the flipnote exploit file | ||
srl.nds This is the Flipnote Studio JPN v0 file. MD5 362e288964d8228f4025be4f34a26529 filename "Ugoku Memo Chou (Japan).nds" | ||
This file is copyrighted so you have to find it on your own! | ||
TADpole (offline) https://github.com/zoogie/TADpole/releases Note: Online services like https://jisagi.github.io/TADpole-Online/ | ||
and https://jenkins.nelthorya.net/job/DSIHaxInjector/ are not currently supported as this exploit method is brand new. Give it time. | ||
FROGminer should also be added to 3ds.guide in due time after the beta. | ||
movable.sed Get this from the steelminer process linked below | ||
src/ Everything in this folder can be ignored by end users | ||
|
||
1. Get Steel Diver: Sub Wars and do the steelminer process at the link below. Save your movable.sed! | ||
http://steelminer.jisagi.net/ | ||
|
||
2. EXPORT your DS Download Play with Frogtool.3dsx (484E4441.bin on sd root). exit the app by pressing start. | ||
|
||
3. Use the offline TADpole program to dump 484E4441.bin then inject Flipnote Studio JPN v0 into it, then rebuild it. | ||
a. place the movable.sed you got from the steelminer process inside the TADpole/resources folder. Copy and paste 484E4441.bin in the TADpole folder. | ||
Don't cut or move the 484E4441.bin file from the sd card as this is the clean version of DS dlp that you will need to RESTORE the app post hax installation (optional). | ||
a. drop the 484E4441.bin on _dump.bat | ||
b. place the srl.nds file into the 484E4441 directory and overwrite the existing file | ||
c. drop the 484E4441.bin on _rebuild.bat again. this will create 484E4441.bin.patched | ||
No save file is needed. It will mess things up so don't inject one. The srl size will increase - that's alright. | ||
|
||
4. Copy the patched DS download play (484E4441.bin.patched) back to your sd card. Don't rename it. IMPORT it back with FROGtool.3dsx. | ||
|
||
5. Use the app to BOOT DS download play (now infused with frog power) and perform the custom FROGminer ugopwn exploit. | ||
Demonstration (the steps are a bit different from regular flipnote lenny process): | ||
https://streamable.com/ti9jk | ||
|
||
6. You should now be running b9sTool. | ||
Continue on at: | ||
https://3ds.hacks.guide/installing-boot9strap-(dsiware-game-injection)#section-v---flashing-the-target-3dss-firm | ||
|
||
|
||
Thanks: | ||
Martin Korth (nocash) - location hints for flipnote privkeys, no$gba, excellent Gbatek docs. I could go on. | ||
Shutterbug2000 - ugopwn exploit. brilliant stuff! | ||
Fincs and Wintermute - Flipnote Lenny, a revised version of ugopwn. This is the version I ported. Very clean, elegant work which made it a more managable task for me. | ||
zacchi4k and Chromaryu - for tools assistance, thanks a bunch! | ||
All my peeps on the Nintendo Homebrew Discord and GBAtemp for constant support of seedminer and its users! | ||
|
||
Gero! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import os,sys | ||
offset=0 | ||
|
||
with open("fcram.mem","rb") as f: | ||
buf=f.read(0x4000000) | ||
|
||
print("Dumping...") | ||
with open("dsiram.bin","wb") as f: | ||
while offset < 0x4000000: | ||
f.write(buf[offset:offset+2]) | ||
offset+=8 | ||
print("Done.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
My scratch notes for porting ugopwn (Lenny version) to FN JPN v0. | ||
It was a lot messier than this at one point. | ||
|
||
-Region[Version] | ||
-Payload RAM offset (minitwlpayload) | ||
-Flipnote RAM offset (PARA) | ||
-Hax code positioning offset relative to PARA (?) | ||
|
||
|
||
USA | ||
0217AE70 70 AE 17 02 | ||
02829A20 | ||
-5AEBE1 = FFA5141F 1F 14 A5 FF | ||
|
||
EUR | ||
021B00D0 D0 00 1B 02 | ||
028AAE40 | ||
-630001 = FF9CFFFF FF FF 9C FF | ||
|
||
JPN2 | ||
0213AFB0 B0 AF 13 02 | ||
02843920 | ||
-5C8AE1 = FFA3751F 1F 75 A3 FF | ||
|
||
JPN1 | ||
0216C730 | ||
028195C0 | ||
-59E781 = FFA6187F | ||
|
||
JPN0 | ||
02116C70 | ||
026E56E0 | ||
-46A8A1 = FFB9575F | ||
|
||
Additional notes: | ||
|
||
* The loaded flipnote positon in memory and the positioning variable always has the same distance apart, 227AE3F. | ||
02829A20-5AEBE1=227AE3F | ||
028AAE40-630001=227AE3F | ||
02843920-5C8AE1=227AE3F | ||
028195C0-59E781=227AE3F | ||
026E56E0-46A8A1=227AE3F | ||
|
||
* v0 doesn't let you copy frames between different flipnote files so I had to work around this by appending the | ||
payload/hax frame (800031_...) to the target frame file (T00031_...). As a nice side effect, this makes the exploit triggering process easier. | ||
|
||
* Couldn't get useful RAM dumps from no$gba for JPN flipnote versions due to title screen crashes, but it's possible to dump dsiram by rebooting the 3ds and immediately chainloading godmode9, then dumping fcram.mem. | ||
I use the included fcram2dsiram script to decode the weird "spread out" chunked format of dsi ram in fcram. the first half meg or so is overwritten by the 3ds but that's not an issue in most cases. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import os,sys | ||
from Cryptodome.PublicKey import RSA | ||
from Cryptodome.Signature import PKCS1_v1_5 | ||
from Cryptodome.Hash import SHA1 | ||
|
||
def verify_sign(keys, signature, message, ppm): | ||
rsakey = RSA.importKey(keys) | ||
signer = PKCS1_v1_5.new(rsakey) | ||
digest = SHA1.new() | ||
digest.update(message) | ||
|
||
if signer.verify(digest, signature): | ||
print("ppm is already signed correctly!") | ||
return | ||
print("ppm sig is incorrect, let's sign it...") | ||
sigdump=signer.sign(digest) | ||
|
||
with open(sys.argv[1]+".bak","wb") as f: | ||
f.write(ppm) | ||
with open(sys.argv[1],"rb+") as f: | ||
f.write(message+sigdump+b"\x00"*0x10) | ||
print("\nFixed!\nOutput file: %s\nBackup file: %s.bak\nGero!" % (sys.argv[1],sys.argv[1])) | ||
|
||
with open(sys.argv[1],"rb") as f: | ||
ppm=f.read() | ||
if b"\x50\x41\x52\x41" not in ppm[:4]: | ||
print("This is not a ppm file!") | ||
sys.exit(0) | ||
|
||
size=len(ppm) | ||
message=ppm[:size-0x90] | ||
sig=ppm[size-0x90:size-0x10] | ||
|
||
keys_pem="""-----BEGIN RSA PRIVATE KEY----- | ||
MIICXAIBAAKBgQDCPLwTL6oSflv+gjywi/sM0TUB90xqOvuCpjduETjPoN2FwMeb | ||
xNjdKIqHUyDu4AvrQ6BDJc6gKUbZ1E27BGZoCPH49zQRb+zAM6M9EjHwQ6BABr0u | ||
2TcF7xGg2uQ9MBWz9AfbVQ91NjfrNWo0f7UPmffv1VvixmTk1BCtavZxBwIDAQAB | ||
AoGAJqdTfjX0EG4Y/JMKZM/Wi/xuIhAGovVN6/gL+9lthtQqgV2V24fW6FwTBU8j | ||
tKXdeVoh4Hr7nZ/ZO6wmM9tyTVSHo37XdF/1bsPM7iu/0M8A6+jJr94l6PYpCP5y | ||
apPEj2RR154gTaVK7/J/OePZy6tRlgcI1awsqgCDcvweEsECQQD4KnxSdyJD0Oqa | ||
xaIIhLkLZEuvkBmrLG+YQUezVOB60MjMC1DyIiZzc5otkQZ0RiopRm/57a6pXA58 | ||
1xSN9JiRAkEAyF5uvKCbA9+PORUn668W0N+uRWZ2+WaqC46HkUDnrVEa4FsnLsFD | ||
0NlVmH2BXifPUPLMR6WzP+OJ9hKfve78FwJAQQJgLvomb716t7CuEa0zDFjpusP0 | ||
9XJeiXQQZFoHtCSddVZBjiyEBhpyeR1Uo4D96nIZQ0+QQa1r3ig5qjY5AQJAWvZD | ||
324p8YA0TP3FucEq4ngpbWgu6tooqEZ0VQTaKFyBjwjSqO8kElQX/7o6WLxJ6b3P | ||
71bSIVby8rtRubAc0QJBAJ1zhk7/d6PA4+J9aQ+jBi/OW+ljiD8yjatLq+4fqRfx | ||
YsFzLqmzjxfiiX+6BzuHHcWJzBUmIcPyu+Y2N0BdT7M= | ||
-----END RSA PRIVATE KEY----- | ||
""" #huge greetz to martin korth and his gbatek docs for the pub/privkey locations! | ||
verify_sign(keys_pem, sig, message, ppm) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
#include <3ds.h> | ||
|
||
#define menu_size 4 | ||
|
||
Result import(u64 tid, u8 op, u8 *workbuf, char *ext){ | ||
Handle handle; | ||
Result res; | ||
FS_Path filePath; | ||
FS_Path archPath = { PATH_EMPTY, 1, (u8*)"" }; | ||
char fpath[64]={0}; | ||
uint16_t filepath16[256]; | ||
ssize_t units=0; | ||
u32 len=255; | ||
|
||
memset(fpath, 0, 64); | ||
sprintf(fpath,"sdmc:/%08lX%s",(u32)tid, ext); | ||
memset(filepath16, 0, sizeof(filepath16)); | ||
units = utf8_to_utf16(filepath16, (u8*)(fpath+5), len); | ||
|
||
filePath.type = PATH_UTF16; | ||
filePath.size = (units+1)*sizeof(uint16_t); | ||
filePath.data = (const u8*)filepath16; | ||
|
||
printf("import:%d %s\n", op, fpath); | ||
res = FSUSER_OpenFileDirectly(&handle, ARCHIVE_SDMC, archPath, filePath, FS_OPEN_READ, 0); | ||
printf("fsopen: %08X\n",(int)res); | ||
res = AM_ImportTwlBackup(handle, op, workbuf, 0x20000); | ||
printf("twl import: %08X %s\n\n",(int)res, res ? "FAILED!" : "SUCCESS!"); | ||
FSFILE_Close(handle); | ||
|
||
return res; | ||
} | ||
|
||
Result export(u64 tid, u8 op, u8 *workbuf, char *ext){ | ||
Result res; | ||
char fpath[256]={0}; | ||
memset(fpath, 0, 128); | ||
sprintf(fpath,"sdmc:/%08lX%s",(u32)tid, ext); | ||
if(access(fpath, F_OK ) != -1 ) { | ||
printf("DS dlp already exists on SD\n"); | ||
return 1; | ||
} | ||
printf("export:%d %016llX to %s\n", op, tid, fpath); | ||
res = AM_ExportTwlBackup(tid, op, workbuf, 0x20000, fpath); | ||
printf("twl export: %08X %s\n\n",(int)res, res ? "FAILED!" : "SUCCESS!"); | ||
|
||
return res; | ||
} | ||
|
||
Result menuUpdate(int cursor){ | ||
consoleClear(); | ||
printf("Frogtool - zoogie\n\n"); | ||
char menu[menu_size][128] = { | ||
"IMPORT patched DS Download Play", | ||
"EXPORT clean DS Download Play", | ||
"RESTORE clean DS Download Play", | ||
"BOOT patched DS Download Play" | ||
}; | ||
|
||
for(int i=0;i<menu_size;i++){ | ||
printf("%s %s\n", cursor == i ? "->" : " ", menu[i]); | ||
} | ||
|
||
printf("\nPress START to exit\n\n"); | ||
|
||
return 0; | ||
} | ||
|
||
Result waitKey(){ | ||
printf("\nTap bottom screen to continue ...\n"); | ||
|
||
while(1){ | ||
gspWaitForVBlank(); | ||
gfxSwapBuffers(); | ||
|
||
hidScanInput(); | ||
u32 kDown = hidKeysDown(); | ||
if(kDown & KEY_TOUCH) break; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
int main(int argc, char* argv[]) | ||
{ | ||
gfxInitDefault(); | ||
consoleInit(GFX_TOP, NULL); | ||
u32 BUF_SIZE = 0x20000; | ||
u64 tid=0; | ||
u8 op=5; | ||
u32 SECOND=1000*1000*1000; | ||
int cursor=0; | ||
|
||
u8 *buf = (u8*)malloc(BUF_SIZE); | ||
Result res = nsInit(); | ||
printf("nsInit: %08X\n",(int)res); | ||
res = amInit(); | ||
printf("amInit: %08X\n\n",(int)res); | ||
svcSleepThread(1*SECOND); | ||
tid = 0x00048005484E4441; //dlp | ||
//tid = 0x0004800542383841; | ||
//tid = 0x000480044b385545; | ||
//tid = 0x000480044b454e4a; | ||
|
||
menuUpdate(cursor); | ||
|
||
while (aptMainLoop()) | ||
{ | ||
gspWaitForVBlank(); | ||
gfxSwapBuffers(); | ||
hidScanInput(); | ||
|
||
u32 kDown = hidKeysDown(); | ||
if (kDown & KEY_START) | ||
break; // break in order to return to hbmenu | ||
if(kDown & KEY_A){ | ||
switch(cursor){ | ||
case 0: import(tid, op, buf, ".bin.patched"); break; | ||
case 1: export(tid, op, buf, ".bin"); break; | ||
case 2: import(tid, op, buf, ".bin"); break; | ||
case 3: printf("Booting dlp now ...\n"); | ||
NS_RebootToTitle(0, tid); | ||
while(1)gspWaitForVBlank(); | ||
default:; | ||
} | ||
waitKey(); | ||
menuUpdate(cursor); | ||
} | ||
else if(kDown & KEY_UP){ | ||
cursor--; | ||
if(cursor<0) cursor=0; | ||
menuUpdate(cursor); | ||
} | ||
else if(kDown & KEY_DOWN){ | ||
cursor++; | ||
if(cursor>=menu_size) cursor=menu_size-1; | ||
menuUpdate(cursor); | ||
} | ||
|
||
} | ||
|
||
free(buf); | ||
nsExit(); | ||
amExit(); | ||
gfxExit(); | ||
|
||
return 0; | ||
} |