#164412 - pilch - Fri Oct 31, 2008 12:04 am
Hi everyone,
I know this subject has already been discussed a lot, but I still don't understand some things...
I tried to read 512 bytes from ds cart using cardPolledTransfer but it didn't work on my DS (though it works on no$gba) : first 4 bytes are 0xfffffc00, followed by 127 0xffffffff.
I figure it has something to do with encryption (but perhaps I just did an error in my code ?), so I would like to understand how encryption works once for all...
1) after the boot sequence, transfers use only key2 encryption, which is transparent. So why can't my code read the ds cart ?
2) is the boot sequence the same for homebrew and released games ? if no, why ?
thanks for help !
ps : I know I *should* use LibFat or any other lib, but I would like to understand why my code doesn't work
EDIT :
I though my code was good since it worked with no$gba, but I forgot CARD_ENCRYPTED and CARD_13 flags.
Now I get random values (change each time I start the program), which is still bad...
#164420 - thoduv - Fri Oct 31, 2008 5:10 pm
Are you sure your slot-1 hardware is exposing your ROM data on ds card when running homebrew program ? It could be for instance the card's "firmware"...
#164425 - Funky Gibbon - Fri Oct 31, 2008 11:13 pm
I thought the first 512 byte were not encripted anyway, it's just header data
#164441 - pilch - Sat Nov 01, 2008 5:52 pm
thoduv wrote: |
Are you sure your slot-1 hardware is exposing your ROM data on ds card when running homebrew program ? It could be for instance the card's "firmware"... |
I don't know...
But it is possible to run released games (that is why Nintendo don't like these cards, no?), so at least when one releasedGame.nds is run from this card, it can access its ROM data (and not other card data).
If I don't access ROM data, it would mean that homebrew games are not run the same way than released ones, no ? (hence my 2nd question).
I read at differents locations (from 0xd200, step of 512 bytes), and before adding CARD_ENCRYPTED and CARD_13 flags, I always get the same data. It would be *strange* to find 0xfffffc00ffffffffffffffffffffffffffffffff.... patterns in the card, repeated every 512 bytes...
Maybe after adding this 2 flags I still read the same pattern, but it is modified by something related to key2 encryption ?
Does anyone managed to read from cart using libnds function ??
#164442 - pilch - Sat Nov 01, 2008 5:57 pm
Funky Gibbon wrote: |
I thought the first 512 byte were not encripted anyway, it's just header data |
perhaps, but I can't get the header that way :
Quote: |
B7aaaaaaaa000000h (200h) - Get Data
KEY2 encrypted command. The desired ROM address is specifed, MSB first, in parameter bytes (a). Can be used only for addresses 8000h and up, smaller addresses will be silently redirected to address "8000h+(addr AND 1FFh)". There is no alignment restriction for the address. However, the datastream wraps to the begin of the current 4K block when address+length crosses a 4K boundary (1000h bytes). Returned data is KEY2 encrypted.
|
#164454 - yellowstar - Sun Nov 02, 2008 7:27 pm
Try the code from the eeprom example.
card.h wrote: |
// These commands require the cart to not be initialized yet, which may mean the user
// needs to eject and reinsert the cart or they will return random data.
void cardRead00(uint32 address, uint32 * destination, uint32 length, uint32 flags);
void cardReadHeader(uint8 * header);
int cardReadID(uint32 flags);
|
eeprom example's main.cpp wrote: |
Code: |
//---------------------------------------------------------------------------------
int main(void) {
//---------------------------------------------------------------------------------
irqInit();
irqSet(IRQ_VBLANK, 0);
irqEnable(IRQ_VBLANK);
consoleDemoInit();
iprintf("Reading cart info...\n");
static u8 header1[512];
static u8 header2[512];
sysSetBusOwners(true, true); // give ARM9 access to the cart
while(1) {
// Read the header twice to verify.
// If the card is being encrypted, we will get random junk
cardReadHeader(header1);
cardReadHeader(header2);
// Make sure we got the same data twice
while(memcmp(header1, header2, 32) != 0) {
// If not, the card needs ejected and reinserted into the DS
iprintf("Please eject & reinsert DS card.\n");
pause();
cardReadHeader(header1);
cardReadHeader(header2);
}
...
}
|
|
#164505 - pilch - Tue Nov 04, 2008 8:27 pm
yellowstar wrote: |
Try the code from the eeprom example.
|
My goal is not to read the header nor the chip ID... I don't use the 3 commands that require an uninitialized cart, but 0xb7 key2-encrypted command.
Anyway, I copied and past this code, and it doesn't work on my ds : I get infinit 0xfffffffff when I try to read the headers... did you try it on your ds ?
#164510 - Cydrak - Tue Nov 04, 2008 9:54 pm
These flashcards tend to require a patcher, right? Since it's loading off flash or microSD or something, there's no guarantee the media can satisfy Nintendo's timing requirements. Also they would have to do encryption all the time, and map the ROM access onto the right flash sectors. Getting consistent data (with encryption off) suggests they didn't do that. Probably instead, they patch commercial games to use some other method--for example, talking to the card over slot-1's serial bus. (Bear in mind I don't have one, I'm just speculating.)
In that case, Nintendo's commands aren't gonna work.
Homebrew is actually quite similar. You have to use the card's interface--and unless you want to reverse engineer every card out there, it's far easier to use libfat, and let the users patch in the proper DLDI themselves. Once properly set up, C/C++ file i/o works as you would expect.
Also see Noda's EFS library which lets you read data packed inside the NDS file. It works with emulators, DLDI and ROM-based cards, and acts pretty much like libfat now. AFAIK, this is the same filesystem Nintendo uses, so it's about as close to "official" methods as you can get, if that's what you want...
A final note: some people (like me) still use FlashMe with a Supercard, so your program would find slot-1 mysteriously empty. :-) In fact, you could be running entirely in RAM, with nothing in either slot at all. (This isn't so common now, but can be done through DS Download Play on an original/FlashMe'd DS, or potentially through some other loader. I do my testing that way all the time.)
#164513 - pilch - Tue Nov 04, 2008 10:59 pm
Cydrak wrote: |
Probably instead, they patch commercial games to use some other method--for example, talking to the card over slot-1's serial bus. (Bear in mind I don't have one, I'm just speculating.) |
mmhh... you may be right, but patching games is not "easy", no ? I mean, the patched functions must still have the same size (or it will break calling addresses) and *at least* some games don't use fixed flags to acces the cart (warhammer loads from memory a part of the value it writes to ROMCTRL, so how to patch such function ?? and without changing the code size ?)...
it seems difficult...
Cydrak wrote: |
it's far easier to use libfat (...) |
yes (and thanks for the links).
it is more for curiosity in fact... I would like to understand why it doesn't work.
#164514 - pilch - Tue Nov 04, 2008 11:04 pm
one more test :
using the same code as previously to read headers (which didn't work with my flashcard), I ejected the card and replace it with Ace Attorney, Appollo Justice... and it reads its header properly !
what to think about that ? Is it impossible to use Nintendo's commands as suggested by Cydrak, or does the flashcard need to be initialized before it can *emulate* nds cart, or... ?
#164516 - Cydrak - Tue Nov 04, 2008 11:21 pm
pilch wrote: |
mmhh... you may be right, but patching games is not "easy", no ? |
You'll have to ask them... It must be possible, though, since there are slot-2 cards, which couldn't possibly "emulate" Nintendo's commands then.
pilch wrote: |
I mean, the patched functions must still have the same size |
As long as the patch is smaller (most likely hand-coded ASM instead of compiled), it's no problem.
If most games use the same library (along the lines of EFS) then this would turn out to be a little easier. Are you saying that's not true? Note, I'm not sure about this, but the header might have to be stored in RAM anyway, because it can't be read with encrypted reads. I believe one of the header values is supposed to be written to ROMCTRL as you say, so this doesn't sound game specific.
pilch wrote: |
it is more for curiosity in fact... I would like to understand why it doesn't work. |
I guess for curiosity's sake, you could compare files and see what the card's patcher is doing. Or you could get ahold of the DLDI and disassemble that.
As to why it doesn't work, I don't know for sure, but my bet's on the card having a custom interface, or (at the very least) needing some proprietary initialization like you said.
#164519 - pilch - Wed Nov 05, 2008 12:51 am
Cydrak wrote: |
You'll have to ask them... It must be possible, though, since there are slot-2 cards, which couldn't possibly "emulate" Nintendo's commands then.
|
very interresting ! are you sure this kind of device can run official NDS games ? (I guess you are, but it is just to be sure since it has, as you said, important implications)
Cydrak wrote: |
As long as the patch is smaller (most likely hand-coded ASM instead of compiled), it's no problem. (...) |
yes you're right...
ok, so I will investigate to find if games are patched or not...
#164532 - pilch - Wed Nov 05, 2008 7:31 pm
another test:
1) I take a binary dump of an official game, look for the sendCommand functions and change one : I always set command[0] to 0xb9 (only b7 and b8 are normaly expected) and it crashs (normal behaviour).
2) I change the code so that the function still does what it means to do, and it doesn't crash.
3) I change the code to crash if command[0] is < aa, and it crashs only when aa is <= 0xb8.
I change the code to crash if command[0] is >= bb, and it crashs only when bb is >= 0xb7.
4) I change the code so that it crashs if command[5,6 or7] != 0, and it doesn't crash.
Conclusions :
experiments 1 and 2 show that the code is still called (a patcher could change the address of the call), and that it can work or not when modified => it appears not to be patched
experiments 3 and 4 show that the DS still sends "normal" commands to the cart (a patcher could have changed the command == the argument passed to sendCommand function)
So, does the patch option still holds ?? it is not conclusive, but I really doubt that .nds is patched, don't you ?
#164534 - yellowstar - Wed Nov 05, 2008 9:54 pm
Does booting your program, re-inserting your flash card, then reading the header, work?
#164536 - pilch - Wed Nov 05, 2008 11:15 pm
yellowstar wrote: |
Does booting your program, re-inserting your flash card, then reading the header, work? |
No (at least not my program header). I use a DS Linker, so I guess all I can expect this way is to read DS Linker program header (if any...)
But if I reinsert an official cart it reads its header.
#164554 - Cydrak - Fri Nov 07, 2008 2:43 am
Interesting... it certainly is possible it isn't patched. Even so, the flashcard would still need to be initialized and "locked" somehow, so that the official games only see themselves. Which may or may not be done for homebrew, since that expects a different arrangement (namely DLDI, with access to the whole media).
Worth mention is that the old, slot-2 Supercards come with PC software that explicitly does the patching. I ran a comparison yesterday, and on the ARM7, about 2K of card routines were modified, as expected. The ARM9 binary had been decompressed (!) so it must've been changed too, although I couldn't compare directly because of that.
Good luck with your card, and don't lose too much sleep over it. :-)
#166654 - yellowstar - Fri Feb 13, 2009 2:31 am
It appears that flash cards patch homebrew. When I tested reading my Acekard 2 header, all I got was all 0xFF bytes. However, when I booted my program with DSO, the header read perfectly.
#166658 - Normmatt - Fri Feb 13, 2009 5:31 am
yellowstar wrote: |
It appears that flash cards patch homebrew. When I tested reading my Acekard 2 header, all I got was all 0xFF bytes. However, when I booted my program with DSO, the header read perfectly. |
No its just that flashcart firmwares don't init the hardware the same as DSO etc and as such some commands don't work on it straight from the firmware.
#166674 - yellowstar - Fri Feb 13, 2009 8:08 pm
Never mind, when I tried dumping the header again, booting directly from the Ackekard, this time the header dumped fine... I disassembled cardPolledTransfer and cardStartTransfer from ram and hw, and compared the assembly with the disassembled cardPolledTransfer and cardStartTransfer under iDeas, and they were identical.