Skip to content

Commit

Permalink
Upload frog materials
Browse files Browse the repository at this point in the history
  • Loading branch information
zoogie authored and zoogie committed Sep 27, 2018
1 parent 0ec414d commit 2af2876
Show file tree
Hide file tree
Showing 8 changed files with 316 additions and 2 deletions.
Binary file added Frogtool.3dsx
Binary file not shown.
2 changes: 0 additions & 2 deletions README.md

This file was deleted.

Binary file not shown.
54 changes: 54 additions & 0 deletions readme.txt
@@ -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!
12 changes: 12 additions & 0 deletions src/fcram2dsiram.py
@@ -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.")
48 changes: 48 additions & 0 deletions src/flipnote_notes.txt
@@ -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.
50 changes: 50 additions & 0 deletions src/frog.py
@@ -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)
152 changes: 152 additions & 0 deletions src/main.c
@@ -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;
}

0 comments on commit 2af2876

Please sign in to comment.