source: rtems/c/src/lib/libbsp/arm/nds/tools/ndstool/source/header.cpp @ 9a12c7e5

4.104.115
Last change on this file since 9a12c7e5 was 9a12c7e5, checked in by Joel Sherrill <joel.sherrill@…>, on 05/04/09 at 02:04:42

2009-05-03 Joel Sherrill <joel.sherrill@…>

  • ndstool/include/banner.h, ndstool/include/header.h, ndstool/include/ndstree.h, ndstool/source/banner.cpp, ndstool/source/header.cpp, ndstool/source/ndscreate.cpp, ndstool/source/ndstool.cpp, ndstool/source/passme.cpp: Remove warnings for deprecated character conversions.
  • Property mode set to 100644
File size: 19.9 KB
Line 
1#include "ndstool.h"
2#include "banner.h"
3#include "sha1.h"
4#include "crc.h"
5#include "bigint.h"
6#include "arm7_sha1_homebrew.h"
7#include "arm7_sha1_nintendo.h"
8#include "encryption.h"
9
10/*
11 * Data
12 */
13unsigned char publicKeyNintendo[] =
14{
15        0x9E, 0xC1, 0xCC, 0xC0, 0x4A, 0x6B, 0xD0, 0xA0, 0x6D, 0x62, 0xED, 0x5F, 0x15, 0x67, 0x87, 0x12,
16        0xE6, 0xF4, 0x77, 0x1F, 0xD8, 0x5C, 0x81, 0xCE, 0x0C, 0xD0, 0x22, 0x31, 0xF5, 0x89, 0x08, 0xF5,
17        0xBE, 0x04, 0xCB, 0xC1, 0x4F, 0x63, 0xD9, 0x5A, 0x98, 0xFF, 0xEB, 0x36, 0x0F, 0x9C, 0x5D, 0xAD,
18        0x15, 0xB9, 0x99, 0xFB, 0xC6, 0x86, 0x2C, 0x0A, 0x0C, 0xFC, 0xE6, 0x86, 0x03, 0x60, 0xD4, 0x87,
19        0x28, 0xD5, 0x66, 0x42, 0x9C, 0xF7, 0x04, 0x14, 0x4E, 0x6F, 0x73, 0x20, 0xC3, 0x3E, 0x3F, 0xF5,
20        0x82, 0x2E, 0x78, 0x18, 0xD6, 0xCD, 0xD5, 0xC2, 0xDC, 0xAA, 0x1D, 0x34, 0x91, 0xEC, 0x99, 0xC9,
21        0xF7, 0xBF, 0xBF, 0xA0, 0x0E, 0x1E, 0xF0, 0x25, 0xF8, 0x66, 0x17, 0x54, 0x34, 0x28, 0x2D, 0x28,
22        0xA3, 0xAE, 0xF0, 0xA9, 0xFA, 0x3A, 0x70, 0x56, 0xD2, 0x34, 0xA9, 0xC5, 0x9E, 0x5D, 0xF5, 0xE1,
23};
24
25/*
26 * CalcHeaderCRC
27 */
28unsigned short CalcHeaderCRC(Header &header)
29{
30        return CalcCrc16((unsigned char *)&header, 0x15E);
31}
32
33/*
34 * CalcLogoCRC
35 */
36unsigned short CalcLogoCRC(Header &header)
37{
38        return CalcCrc16((unsigned char *)&header + 0xC0, 156);
39}
40
41/*
42 * DetectRomType
43 */
44int DetectRomType()
45{
46        fseek(fNDS, 0x4000, SEEK_SET);
47        unsigned int data[3];
48        fread(data, 1, sizeof(data), fNDS);
49        if (header.arm9_rom_offset < 0x4000) return ROMTYPE_HOMEBREW;
50        if (data[0] == 0x00000000 && data[1] == 0x00000000) return ROMTYPE_MULTIBOOT;
51        if (data[0] == 0xE7FFDEFF && data[1] == 0xE7FFDEFF) return ROMTYPE_NDSDUMPED;
52        fseek(fNDS, 0x200, SEEK_SET);
53        for (int i=0x200; i<0x4000; i++)
54                if (fgetc(fNDS)) return ROMTYPE_MASKROM;        // found something odd ;)
55        return ROMTYPE_ENCRSECURE;
56}
57
58/*
59 * CalcSecureAreaCRC
60 */
61unsigned short CalcSecureAreaCRC(bool encrypt)
62{
63        fseek(fNDS, 0x4000, SEEK_SET);
64        unsigned char data[0x4000];
65        fread(data, 1, 0x4000, fNDS);
66        if (encrypt) encrypt_arm9(*(u32 *)header.gamecode, data);
67        return CalcCrc16(data, 0x4000);
68}
69
70/*
71 * CalcSecurityDataCRC
72 */
73unsigned short CalcSecurityDataCRC()
74{
75        fseek(fNDS, 0x1000, SEEK_SET);
76        unsigned char data[0x2000];
77        fread(data, 1, 0x2000, fNDS);
78        return CalcCrc16(data, 0x2000);
79}
80
81/*
82 * CalcSegment3CRC
83 */
84unsigned short CalcSegment3CRC()
85{
86        fseek(fNDS, 0x3000, SEEK_SET);
87        unsigned char data[0x1000];
88        fread(data, 1, 0x1000, fNDS);
89        for (int i=0; i<0x1000; i+=2)   // swap bytes
90        {
91                unsigned char t = data[i+1]; data[i+1] = data[i]; data[i] = t;
92        }
93        return CalcCcitt16(data, 0x1000);       // why would they use CRC16-CCITT ?
94}
95
96/*
97 * FixHeaderCRC
98 */
99void FixHeaderCRC(char *ndsfilename)
100{
101        fNDS = fopen(ndsfilename, "r+b");
102        if (!fNDS) { fprintf(stderr, "Cannot open file '%s'.\n", ndsfilename); exit(1); }
103        fread(&header, 512, 1, fNDS);
104        header.header_crc = CalcHeaderCRC(header);
105        fseek(fNDS, 0, SEEK_SET);
106        fwrite(&header, 512, 1, fNDS);
107        fclose(fNDS);
108}
109
110/*
111 * ShowHeaderInfo
112 */
113void ShowHeaderInfo(Header &header, int romType, unsigned int length = 0x200)
114{
115        printf("0x00\t%-25s\t", "Game title");
116
117        for (unsigned int i=0; i<sizeof(header.title); i++)
118                if (header.title[i]) putchar(header.title[i]); printf("\n");
119
120        printf("0x0C\t%-25s\t", "Game code");
121        for (unsigned int i=0; i<sizeof(header.gamecode); i++)
122                if (header.gamecode[i]) putchar(header.gamecode[i]);
123        for (int i=0; i<NumCountries; i++)
124        {
125                if (countries[i].countrycode == header.gamecode[3])
126                {
127                        printf(" (NTR-");
128                        for (unsigned int j=0; j<sizeof(header.gamecode); j++)
129                                if (header.gamecode[j]) putchar(header.gamecode[j]);
130                        printf("-%s)", countries[i].name);
131                        break;
132                }
133        }
134        printf("\n");
135       
136        printf("0x10\t%-25s\t", "Maker code"); for (unsigned int i=0; i<sizeof(header.makercode); i++)
137                if (header.makercode[i]) putchar(header.makercode[i]);
138        for (int j=0; j<NumMakers; j++)
139        {
140                if ((makers[j].makercode[0] == header.makercode[0]) && (makers[j].makercode[1] == header.makercode[1]))
141                {
142                        printf(" (%s)", makers[j].name);
143                        break;
144                }
145        }
146        printf("\n");
147
148        printf("0x12\t%-25s\t0x%02X\n", "Unit code", header.unitcode);
149        printf("0x13\t%-25s\t0x%02X\n", "Device type", header.devicetype);
150        printf("0x14\t%-25s\t0x%02X (%d Mbit)\n", "Device capacity", header.devicecap, 1<<header.devicecap);
151        printf("0x15\t%-25s\t", "reserved 1"); for (unsigned int i=0; i<sizeof(header.reserved1); i++) printf("%02X", header.reserved1[i]); printf("\n");
152        printf("0x1E\t%-25s\t0x%02X\n", "ROM version", header.romversion);
153        printf("0x1F\t%-25s\t0x%02X\n", "reserved 2", header.reserved2);
154        printf("0x20\t%-25s\t0x%X\n", "ARM9 ROM offset", (int)header.arm9_rom_offset);
155        printf("0x24\t%-25s\t0x%X\n", "ARM9 entry address", (int)header.arm9_entry_address);
156        printf("0x28\t%-25s\t0x%X\n", "ARM9 RAM address", (int)header.arm9_ram_address);
157        printf("0x2C\t%-25s\t0x%X\n", "ARM9 code size", (int)header.arm9_size);
158        printf("0x30\t%-25s\t0x%X\n", "ARM7 ROM offset", (int)header.arm7_rom_offset);
159        printf("0x34\t%-25s\t0x%X\n", "ARM7 entry address", (int)header.arm7_entry_address);
160        printf("0x38\t%-25s\t0x%X\n", "ARM7 RAM address", (int)header.arm7_ram_address);
161        printf("0x3C\t%-25s\t0x%X\n", "ARM7 code size", (int)header.arm7_size);
162        printf("0x40\t%-25s\t0x%X\n", "File name table offset", (int)header.fnt_offset);
163        printf("0x44\t%-25s\t0x%X\n", "File name table size", (int)header.fnt_size);
164        printf("0x48\t%-25s\t0x%X\n", "FAT offset", (int)header.fat_offset);
165        printf("0x4C\t%-25s\t0x%X\n", "FAT size", (int)header.fat_size);
166        printf("0x50\t%-25s\t0x%X\n", "ARM9 overlay offset", (int)header.arm9_overlay_offset);
167        printf("0x54\t%-25s\t0x%X\n", "ARM9 overlay size", (int)header.arm9_overlay_size);
168        printf("0x58\t%-25s\t0x%X\n", "ARM7 overlay offset", (int)header.arm7_overlay_offset);
169        printf("0x5C\t%-25s\t0x%X\n", "ARM7 overlay size", (int)header.arm7_overlay_size);
170        printf("0x60\t%-25s\t0x%08X\n", "ROM control info 1", (int)header.rom_control_info1);
171        printf("0x64\t%-25s\t0x%08X\n", "ROM control info 2", (int)header.rom_control_info2);
172        printf("0x68\t%-25s\t0x%X\n", "Icon/title offset", (int)header.banner_offset);
173        unsigned short secure_area_crc = CalcSecureAreaCRC((romType == ROMTYPE_NDSDUMPED));
174        const char *s1, *s2 = "";
175        if (romType == ROMTYPE_HOMEBREW) s1 = "-";
176        else if (secure_area_crc == header.secure_area_crc) s1 = "OK";
177        else
178        {
179                s1 = "INVALID";
180        }
181        switch (romType)
182        {
183                case ROMTYPE_HOMEBREW: s2 = "homebrew"; break;
184                case ROMTYPE_MULTIBOOT: s2 = "multiboot"; break;
185                case ROMTYPE_NDSDUMPED: s2 = "decrypted"; break;
186                case ROMTYPE_ENCRSECURE: s2 = "encrypted"; break;
187                case ROMTYPE_MASKROM: s2 = "mask ROM"; break;
188        }
189        printf("0x6C\t%-25s\t0x%04X (%s, %s)\n", "Secure area CRC", (int)header.secure_area_crc, s1, s2);
190        printf("0x6E\t%-25s\t0x%04X\n", "ROM control info 3", (int)header.rom_control_info3);
191        printf("0x70\t%-25s\t0x%X\n", "ARM9 ?", (int)header.offset_0x70);
192        printf("0x74\t%-25s\t0x%X\n", "ARM7 ?", (int)header.offset_0x74);
193        printf("0x78\t%-25s\t0x%08X\n", "Magic 1", (int)header.offset_0x78);
194        printf("0x7C\t%-25s\t0x%08X\n", "Magic 2", (int)header.offset_0x7C);
195        printf("0x80\t%-25s\t0x%08X\n", "Application end offset", (int)header.application_end_offset);
196        printf("0x84\t%-25s\t0x%08X\n", "ROM header size", (int)header.rom_header_size);
197        for (unsigned int i=0x88; i<0xC0; i+=4)
198        {
199                unsigned_int &x = ((unsigned_int *)&header)[i/4];
200                if (x != 0) printf("0x%02X\t%-25s\t0x%08X\n", i, "?", (int)x);
201        }
202        unsigned short logo_crc = CalcLogoCRC(header);
203        printf("0x15C\t%-25s\t0x%04X (%s)\n", "Logo CRC", (int)header.logo_crc, (logo_crc == header.logo_crc) ? "OK" : "INVALID");
204        unsigned short header_crc = CalcHeaderCRC(header);
205        printf("0x15E\t%-25s\t0x%04X (%s)\n", "Header CRC", (int)header.header_crc, (header_crc == header.header_crc) ? "OK" : "INVALID");
206        for (unsigned int i=0x160; i<length; i+=4)
207        {
208                unsigned_int &x = ((unsigned_int *)&header)[i/4];
209                if (x != 0) printf("0x%02X\t%-25s\t0x%08X\n", i, "?", (int)x);
210        }
211}
212
213/*
214 * HeaderSha1
215 */
216void HeaderSha1(FILE *fNDS, unsigned char *header_sha1, int romType)
217{
218        sha1_ctx m_sha1;
219        sha1_begin(&m_sha1);
220        unsigned char buf[32 + 0x200];
221        fseek(fNDS, 0x200, SEEK_SET);           // check for 32 bytes text + alternate header
222        fread(buf, 1, sizeof(buf), fNDS);
223        if (!memcmp(buf, "DS DOWNLOAD PLAY", 16))       // found?
224        {
225                sha1_hash(buf + 0x20, 0x160, &m_sha1);  // alternate header
226                if (verbose >= 2)
227                {
228                        printf("{ DS Download Play(TM) / Wireless MultiBoot header information:\n");
229                        ShowHeaderInfo(*(Header *)(buf + 0x20), romType, 0x160);
230                        printf("}\n");
231                }
232        }
233        else
234        {
235                fseek(fNDS, 0, SEEK_SET);
236                fread(buf, 1, sizeof(buf), fNDS);
237                sha1_hash(buf, 0x160, &m_sha1);
238        }
239        sha1_end(header_sha1, &m_sha1);
240}
241
242/*
243 * Arm9Sha1Multiboot
244 */
245void Arm9Sha1Multiboot(FILE *fNDS, unsigned char *arm9_sha1)
246{
247        sha1_ctx m_sha1;
248        sha1_begin(&m_sha1);
249        fseek(fNDS, header.arm9_rom_offset, SEEK_SET);
250        unsigned int len = header.arm9_size;
251        unsigned char *buf = new unsigned char [len];
252        fread(buf, 1, len, fNDS);
253        //printf("%u\n", len);
254        sha1_hash(buf, len, &m_sha1);
255        delete [] buf;
256        sha1_end(arm9_sha1, &m_sha1);
257}
258
259/*
260C:\NitroSDK\tools\bin>emuchild.exe -d AMFE.bin C:\NitroSDK\build\demos\mb\cloneboot\etc\libsyscall_child.bin AMFE.bi
261option -d: No ARG
262argc=3  optind=2
263004B0020 16777216 bytes  ReadFile 'AMFE.bin'
26400475200     2048 bytes  ReadFile 'C:\NitroSDK\build\demos\mb\cloneboot\etc\libsyscall_child.bin'
265004B0020 16777216 bytes  WriteFile 'AMFE.bi'
266
267
268    -a I_OFFSET  Default 0x4000. Location to insert syscall.
269    -A I_SIZE    Default 0x0800. Size to insert.
270    -c C_OFFSET  Default 0x5000. Location to clear romimage.
271    -C C_SIZE    Default 0x2000. Size to clear.
272    -d           Show debug messages (for test purpose)
273    -h           Show this  message
274
275*/
276
277/*
278 * Arm9Sha1ClearedOutArea
279 */
280void Arm9Sha1ClearedOutArea(FILE *fNDS, unsigned char *arm9_sha1)
281{
282        sha1_ctx m_sha1;
283        sha1_begin(&m_sha1);
284        fseek(fNDS, header.arm9_rom_offset, SEEK_SET);
285        unsigned int len = header.arm9_size;
286        unsigned char *buf = new unsigned char [len];
287
288        int len1 = (0x5000 - header.arm9_rom_offset);           // e.g. 0x5000 - 0x4000 = 0x1000
289        int len3 = header.arm9_size - (0x7000 - header.arm9_rom_offset);        // e.g. 0x10000 - (0x7000 - 0x4000) = 0xD000
290        int len2 = header.arm9_size - len1 - len3;                      // e.g. 0x10000 - 0x1000 - 0xD000 = 0x2000
291        if (len1 > 0) fread(buf, 1, len1, fNDS);
292        if (len2 > 0) { memset(buf + len1, 0, len2); fseek(fNDS, len2, SEEK_CUR); }             // gets cleared for security?
293        if (len3 > 0) fread(buf + len1 + len2, 1, len3, fNDS);
294//      printf("%X %X %X\n", len1, len2, len3);
295
296//              memset(buf, 0, 0x800);          // clear "secure area" too
297
298        sha1_hash(buf, len, &m_sha1);
299        delete [] buf;
300        sha1_end(arm9_sha1, &m_sha1);
301}
302
303/*
304 * Arm7Sha1
305 */
306void Arm7Sha1(FILE *fNDS, unsigned char *arm7_sha1)
307{
308        sha1_ctx m_sha1;
309        sha1_begin(&m_sha1);
310        fseek(fNDS, header.arm7_rom_offset, SEEK_SET);
311        unsigned int len = header.arm7_size;
312        unsigned char *buf = new unsigned char [len];
313        fread(buf, 1, len, fNDS);
314        //printf("%u\n", len);
315        sha1_hash(buf, len, &m_sha1);
316        delete [] buf;
317        sha1_end(arm7_sha1, &m_sha1);
318}
319
320/*
321 * CompareSha1WithList
322 */
323int CompareSha1WithList(unsigned char *arm7_sha1, const unsigned char *text, unsigned int textSize)
324{
325        while (1)
326        {
327                //printf("\n");
328                for (int i=0; i<SHA1_DIGEST_SIZE; i++)
329                {
330                        unsigned char b = 0;
331                        for (int n=0; n<2; n++)
332                        {
333                                //printf("%c", *text);
334                                if (!*text) return -1;
335                                b = b << 4 | ((*text > '9') ? ((*text - 'A') & 7) + 10 : *text - '0');
336                                text++;
337                        }
338                        //printf("%02X", b);
339                        if (b != arm7_sha1[i]) break; else if (i == 19) return 0;
340                }
341                while (*text && (*text >= ' ')) text++;         // line end
342                while (*text && (*text < ' ')) text++;          // new line
343        }
344}
345
346/*
347 * HashAndCompareWithList
348 * -1=error, 0=match, 1=no match
349 */
350int HashAndCompareWithList(char *filename, unsigned char sha1[])
351{
352        FILE *f = fopen(filename, "rb");
353        if (!f) return -1;
354        sha1_ctx m_sha1;
355        sha1_begin(&m_sha1);
356        unsigned char buf[1024];
357        unsigned int r;
358        do
359        {
360                r = fread(buf, 1, 1024, f);
361                sha1_hash(buf, r, &m_sha1);
362        } while (r > 0);
363        fclose(f);
364        sha1_end(sha1, &m_sha1);
365        if (CompareSha1WithList(sha1, arm7_sha1_homebrew, arm7_sha1_homebrew_size)) return 1;   // not yet in list
366        return 0;
367}
368
369/*
370 * strsepc
371 */
372char *strsepc(char **s, char d)
373{
374        char *r = *s;
375        for (char *p = *s; ; p++)
376        {
377                if (*p == 0) { *s = p; break; }
378                if (*p == d) { *s = p+1; *p = 0; break; }
379        }
380        return r;
381}
382
383/*
384 * RomListInfo
385 */
386void RomListInfo(unsigned int crc32_match)
387{
388        if (!romlistfilename) return;
389        FILE *fRomList = fopen(romlistfilename, "rt");
390        if (!fRomList) { fprintf(stderr, "Cannot open file '%s'.\n", romlistfilename); exit(1); }
391        char s[1024];
392        while (fgets(s, 1024, fRomList))        // empty, title, title, title, title, filename, CRC32
393        {
394                char *p = s;
395                if (strlen(strsepc(&p, '\xAC')) == 0)
396                {
397                        char *title = strsepc(&p, '\xAC');
398                        unsigned int index = strtoul(title, 0, 10);
399                        title += 7;
400                        char *b1 = strchr(title, '(');
401                        char *b2 = b1 ? strchr(b1+1, ')') : 0;
402                        char *b3 = b2 ? strchr(b2+1, '(') : 0;
403                        char *b4 = b3 ? strchr(b3+1, ')') : 0;
404                        char *group = 0;
405                        if (b1 + 2 == b2) if (b3 && b4) { *b3 = 0; *b4 = 0; group = b3+1; }             // remove release group name
406                        strsepc(&p, '\xAC'); strsepc(&p, '\xAC');
407                        strsepc(&p, '\xAC'); strsepc(&p, '\xAC');
408                        unsigned long crc32 = strtoul(strsepc(&p, '\xAC'), 0, 16);
409                        if (crc32 == crc32_match)
410                        {
411                                printf("Release index: \t%u\n", index);
412                                printf("Release title: \t%s\n", title);
413                                printf("Release group: \t%s\n", group ? group : "");
414                        }
415                        //for (int i=0; i<10; i++) printf("%d %s\n", i, strsepc(&p, '\xAC'));
416                }
417        }
418}
419
420/*
421 * ShowVerboseInfo
422 */
423void ShowVerboseInfo(FILE *fNDS, Header &header, int romType)
424{
425        // calculate SHA1 of ARM7 binary
426        unsigned char arm7_sha1[SHA1_DIGEST_SIZE];
427        Arm7Sha1(fNDS, arm7_sha1);
428
429        // find signature data
430        unsigned_int signature_id = 0;
431        fseek(fNDS, header.application_end_offset, SEEK_SET);
432        fread(&signature_id, sizeof(signature_id), 1, fNDS);
433        if (signature_id != 0x00016361)
434        {
435                fseek(fNDS, header.application_end_offset - 136, SEEK_SET);             // try again
436                fread(&signature_id, sizeof(signature_id), 1, fNDS);
437        }
438        if (signature_id == 0x00016361)
439        {
440                printf("\n");
441
442                unsigned char signature[128];
443                fread(signature, 1, sizeof(signature), fNDS);
444
445                unsigned char sha_parts[3*SHA1_DIGEST_SIZE + 4];
446                fread(sha_parts + 3*SHA1_DIGEST_SIZE, 4, 1, fNDS);              // some number
447               
448                //printf("%08X\n", *(unsigned int *)(sha_parts + 3*SHA1_DIGEST_SIZE));
449
450                unsigned char header_sha1[SHA1_DIGEST_SIZE];
451                HeaderSha1(fNDS, header_sha1, romType);
452                memcpy(sha_parts + 0*SHA1_DIGEST_SIZE, header_sha1, SHA1_DIGEST_SIZE);
453
454                unsigned char arm9_sha1[SHA1_DIGEST_SIZE];
455                if (romType == ROMTYPE_MULTIBOOT)
456                {
457                        Arm9Sha1Multiboot(fNDS, arm9_sha1);
458                }
459                else
460                {
461                        Arm9Sha1ClearedOutArea(fNDS, arm9_sha1);
462                }
463                memcpy(sha_parts + 1*SHA1_DIGEST_SIZE, arm9_sha1, SHA1_DIGEST_SIZE);
464
465                memcpy(sha_parts + 2*SHA1_DIGEST_SIZE, arm7_sha1, SHA1_DIGEST_SIZE);
466
467                unsigned char sha_final[SHA1_DIGEST_SIZE];
468                {
469                        sha1_ctx m_sha1;
470                        sha1_begin(&m_sha1);
471                        unsigned int len = sizeof(sha_parts);
472                        unsigned char *buf = sha_parts;
473                        sha1_hash(buf, len, &m_sha1);
474                        sha1_end(sha_final, &m_sha1);
475                }
476
477                // calculate SHA1 from signature
478                unsigned char sha1_from_sig[SHA1_DIGEST_SIZE];
479                {
480                        BigInt _signature;
481                        _signature.Set(signature, sizeof(signature));
482                        //printf("signature: "); _signature.print();
483
484                        BigInt _publicKey;
485                        _publicKey.Set(publicKeyNintendo, sizeof(publicKeyNintendo));
486                        //printf("public key: "); _publicKey.print();
487
488                        BigInt big_sha1;
489                        big_sha1.PowMod(_signature, _publicKey);
490                        //printf("big_sha1: "); big_sha1.print();
491                        big_sha1.Get(sha1_from_sig, sizeof(sha1_from_sig));
492                }
493               
494                bool ok = (memcmp(sha_final, sha1_from_sig, SHA1_DIGEST_SIZE) == 0);
495                printf("DS Download Play(TM) / Wireless MultiBoot signature: %s\n", ok ? "OK" : "INVALID");
496                if (!ok)
497                {
498                        printf("header hash:    \t"); for (int i=0; i<SHA1_DIGEST_SIZE; i++) printf("%02X", (sha_parts + 0*SHA1_DIGEST_SIZE)[i]); printf("\n");
499                        printf("ARM9 hash:      \t"); for (int i=0; i<SHA1_DIGEST_SIZE; i++) printf("%02X", (sha_parts + 1*SHA1_DIGEST_SIZE)[i]); printf("\n");
500                        printf("ARM7 hash:      \t"); for (int i=0; i<SHA1_DIGEST_SIZE; i++) printf("%02X", (sha_parts + 2*SHA1_DIGEST_SIZE)[i]); printf("\n");
501                        printf("combined hash:  \t"); for (int i=0; i<SHA1_DIGEST_SIZE; i++) printf("%02X", sha_final[i]); printf("\n");
502                        printf("signature hash: \t"); for (int i=0; i<SHA1_DIGEST_SIZE; i++) printf("%02X", sha1_from_sig[i]); printf("\n");
503                }
504        }
505       
506        // CRC32
507        {
508                unsigned char *buf = new unsigned char [0x10000];
509                fseek(fNDS, 0, SEEK_SET);
510                unsigned long crc32 = ~0;
511                int r;
512                while ((r = fread(buf, 1, 0x10000, fNDS)) > 0)
513                {
514                        crc32 = CalcCrc32(buf, r, crc32);
515                }
516                crc32 = ~crc32;
517                delete [] buf;
518
519                printf("\nFile CRC32:    \t%08X\n", (unsigned int)crc32);
520                RomListInfo(crc32);
521        }
522       
523        // ROM dumper 1.0 bad data
524        {
525                unsigned char buf[0x200];
526                fseek(fNDS, 0x7E00, SEEK_SET);
527                fread(buf, 1, 0x200, fNDS);
528                unsigned long crc32 = ~CalcCrc32(buf, 0x200);
529                printf("\nSMT dumper v1.0 corruption check: \t%s\n", (crc32 == 0x7E8B456F) ? "CORRUPTED" : "OK");
530        }
531
532        // Verify ARM7 SHA1 hash against known default binaries
533        int bKnownArm7 = 0;
534        {
535                printf("\nARM7 binary hash : \t"); for (int i=0; i<SHA1_DIGEST_SIZE; i++) printf("%02X", arm7_sha1[i]); printf("\n");
536
537                if (CompareSha1WithList(arm7_sha1, arm7_sha1_homebrew, arm7_sha1_homebrew_size) == 0)
538                {
539                        bKnownArm7 = 1; printf("ARM7 binary is homebrew verified.\n");
540                }
541                if (CompareSha1WithList(arm7_sha1, arm7_sha1_nintendo, arm7_sha1_nintendo_size) == 0)
542                {
543                        bKnownArm7 = 2; printf("ARM7 binary is Nintendo verified.\n");
544                }
545                if (!bKnownArm7) printf("WARNING! ARM7 binary is NOT verified!\n");
546        }
547
548        // check ARM7 RAM address
549        if (bKnownArm7 != 2)
550        if ((header.arm7_ram_address < 0x03000000) || (header.arm7_ram_address >= 0x04000000))
551        {
552                printf("\nWARNING! ARM7 RAM address does not point to shared memory!\n");
553        }
554
555        // check ARM7 entry address
556        if ((header.arm7_entry_address < header.arm7_ram_address) ||
557                (header.arm7_entry_address > header.arm7_ram_address + header.arm7_size))
558        {
559                printf("\nWARNING! ARM7 entry address points outside of ARM7 binary!\n");
560        }
561}
562
563/*
564 * ShowInfo
565 */
566void ShowInfo(char *ndsfilename)
567{
568        fNDS = fopen(ndsfilename, "rb");
569        if (!fNDS) { fprintf(stderr, "Cannot open file '%s'.\n", ndsfilename); exit(1); }
570        fread(&header, 512, 1, fNDS);
571
572        int romType = DetectRomType();
573
574        printf("Header information:\n");
575        ShowHeaderInfo(header, romType);
576
577        // banner info
578        if (header.banner_offset)
579        {
580                Banner banner;
581                fseek(fNDS, header.banner_offset, SEEK_SET);
582                if (fread(&banner, 1, sizeof(banner), fNDS))
583                {
584                        unsigned short banner_crc = CalcBannerCRC(banner);
585                        printf("\n");
586                        printf("Banner CRC:                     \t0x%04X (%s)\n", (int)banner.crc, (banner_crc == banner.crc) ? "OK" : "INVALID");
587       
588                        for (int language=1; language<=1; language++)
589                        {
590                                int line = 1;
591                                bool nextline = true;
592                                for (int i=0; i<128; i++)
593                                {
594                                        unsigned short c = banner.title[language][i];
595                                        if (c >= 128) c = '_';
596                                        if (c == 0x00) { printf("\n"); break; }
597                                        if (c == 0x0A)
598                                        {
599                                                nextline = true;
600                                        }
601                                        else
602                                        {
603                                                if (nextline)
604                                                {
605                                                        if (line != 1) printf("\n");
606                                                        printf("%s banner text, line %d:", bannerLanguages[language], line);
607                                                        for (unsigned int i=0; i<11 - strlen(bannerLanguages[language]); i++) putchar(' ');
608                                                        printf("\t");
609                                                        nextline = false;
610                                                        line++;
611                                                }
612                                                putchar(c);
613                                        }
614                                }
615                        }
616                }
617        }
618
619        // ARM9 footer
620        fseek(fNDS, header.arm9_rom_offset + header.arm9_size, SEEK_SET);
621        unsigned_int nitrocode;
622        if (fread(&nitrocode, sizeof(nitrocode), 1, fNDS) && (nitrocode == 0xDEC00621))
623        {
624                printf("\n");
625                printf("ARM9 footer found.\n");
626                unsigned_int x;
627                fread(&x, sizeof(x), 1, fNDS);
628                fread(&x, sizeof(x), 1, fNDS);
629        }
630
631        // show security CRCs
632        if (romType >= ROMTYPE_NDSDUMPED)
633        {
634                printf("\n");
635                unsigned short securitydata_crc = CalcSecurityDataCRC();
636                printf("Security data CRC (0x1000-0x2FFF)  0x%04X\n", (int)securitydata_crc);
637                unsigned short segment3_crc = CalcSegment3CRC();
638                printf("Segment3 CRC (0x3000-0x3FFF)       0x%04X (%s)\n", (int)segment3_crc, (segment3_crc == 0x0254) ? "OK" : "INVALID");
639        }
640
641        // more information
642        if (verbose >= 1)
643        {
644                ShowVerboseInfo(fNDS, header, romType);
645        }
646
647        fclose(fNDS);
648}
Note: See TracBrowser for help on using the repository browser.