Exemplo n.º 1
0
/*
 * Hook
 * Append own ARM7 code without affecting CRC32 of the file and patchability
 * This could be used for trainers
 */
void Hook(char *ndsfilename, char *arm7filename)
{
	fNDS = fopen(ndsfilename, "r+b");
	if (!fNDS) { fprintf(stderr, "Cannot open file '%s'.\n", ndsfilename); exit(1); }
	fseek(fNDS, 0, SEEK_SET);
	fread(&header, 512, 1, fNDS);

	// load additional ARM7 code
	FILE *fARM7 = fopen(arm7filename, "rb");
	if (!fARM7) { fprintf(stderr, "Cannot open file '%s'.\n", arm7filename); exit(1); }
	fseek(fARM7, 0, SEEK_END);
	unsigned int add_arm7_size = (ftell(fARM7) + 3) &~ 3;
	unsigned char *add_arm7 = new unsigned char [add_arm7_size];
	fseek(fARM7, 0, SEEK_SET);
	fread(add_arm7, 1, add_arm7_size, fARM7);
	fclose(fARM7);

	// restore backup of original header if found
	if (header.offset_0x160)
	{
		fseek(fNDS, header.offset_0x78, SEEK_SET);
		Header originalHeader;
		fread(&originalHeader, 512, 1, fNDS);
		if (*(unsigned int *)header.gamecode == *(unsigned int *)originalHeader.gamecode) header = originalHeader;
	}

	// calculate new offsets
	unsigned int new_arm7_offset = (header.application_end_offset + 0x100 + 0x1FF) &~ 0x1FF;
	unsigned int add_arm7_offset = new_arm7_offset + header.arm7_size;
	unsigned int header_backup_offset = add_arm7_offset + add_arm7_size;
	unsigned int new_application_end_offset = header_backup_offset + 0x200;

	// read original ARM7 code
	unsigned char *arm7 = new unsigned char [header.arm7_size];
	fseek(fNDS, header.arm7_rom_offset, SEEK_SET);
	fread(arm7, 1, header.arm7_size, fNDS);

	// write original header, original ARM7 code and append own ARM7 code
	//fseek(fNDS, new_arm7_offset, SEEK_SET);
	//fwrite(arm7, 1, header.arm7_size, fNDS);
	FFixCrc32(fNDS, new_arm7_offset, arm7, header.arm7_size);
	//fseek(fNDS, add_arm7_offset, SEEK_SET);
	//fwrite(add_arm7, 1, add_arm7_size, fNDS);
	FFixCrc32(fNDS, add_arm7_offset, add_arm7, add_arm7_size);
	//fseek(fNDS, header_backup_offset, SEEK_SET);
	//fwrite(&header, 1, 0x200, fNDS);
	FFixCrc32(fNDS, header_backup_offset, (unsigned char *)&header, 0x200);

	// write new header information
	header.offset_0x78 = header_backup_offset;		// ROM offset of header backup
	header.offset_0x7C = header.arm7_ram_address + header.arm7_size + add_arm7_size;		// RAM location of header backup
	header.arm7_entry_address = header.arm7_entry_address + header.arm7_size;
	header.arm9_entry_address = 0x027FFE18;
	*(unsigned_int *)(header.reserved1 + 3) = 0xE59FF004;
	header.arm7_rom_offset = new_arm7_offset;
	header.arm7_size = header.arm7_size + add_arm7_size + 0x200;		// also load our code and the original header into memory
	header.application_end_offset = new_application_end_offset;
	header.header_crc = CalcHeaderCRC(header);
	//fseek(fNDS, 0, SEEK_SET);
	//fwrite(&header, 1, 0x200, fNDS);
	FFixCrc32(fNDS, 0, (unsigned char *)&header, 0x200, header.application_end_offset);

	fclose(fNDS);
}
Exemplo n.º 2
0
/*
 * Create
 */
void Create()
{
	fNDS = fopen(ndsfilename, "wb");
	if (!fNDS) { fprintf(stderr, "Cannot open file '%s'.\n", ndsfilename); exit(1); }

	bool bSecureSyscalls = false;
	char *headerfilename = (headerfilename_or_size && (strtoul(headerfilename_or_size,0,0) == 0)) ? headerfilename_or_size : 0;
	u32 headersize = headerfilename_or_size ? strtoul(headerfilename_or_size,0,0) : 0x200;

	// initial header data
	if (headerfilename)
	{
		// header template
		FILE *fi = fopen(headerfilename, "rb");
		if (!fi) { fprintf(stderr, "Cannot open file '%s'.\n", headerfilename); exit(1); }
		fread(&header, 1, 0x200, fi);
		fclose(fi);

		if ((header.arm9_ram_address + 0x800 == header.arm9_entry_address) || (header.rom_header_size > 0x200))
		{
			bSecureSyscalls = true;
		}
	}
	else	// set header default values
	{
		// clear header
		memset(&header, 0, sizeof(header));
		memcpy(header.gamecode, "####", 4);

		if ((arm9RamAddress + 0x800 == arm9Entry) || (headersize > 0x200))
		{
			bSecureSyscalls = true;
		}
		else
		{
			header.reserved2 = 0x04;		// autostart
			*(unsigned_int *)(((unsigned char *)&header) + 0x0) = 0xEA00002E;		// for PassMe's that start @ 0x08000000
		}
		*(unsigned_int *)(((unsigned char *)&header) + 0x60) = 1<<22 | latency2<<16 | 1<<14 | 1<<13 | latency1;	// ROM control info 1
		*(unsigned_int *)(((unsigned char *)&header) + 0x64) = 1<<29 | latency2<<16 | latency1;	// ROM control info 2
		*(unsigned_short *)(((unsigned char *)&header) + 0x6E) = 0x051E;	// ROM control info 3
	}
	if (headersize) header.rom_header_size = headersize;
	if (header.rom_header_size == 0) header.rom_header_size = bSecureSyscalls ? 0x4000 : 0x200;

	// load a logo
	if (logofilename)
	{
		char *p = strrchr(logofilename, '.');
		if (!strcmp(p, ".bmp"))
		{
			CRaster raster;
			if (raster.LoadBMP(logofilename) < 0) exit(1);
			unsigned char white = (raster.palette[0].rgbGreen >= 128) ? 0 : 1;
			if (LogoConvert(raster.raster, header.logo, white) < 0) exit(1);
		}
		else
		{
			FILE *fi = fopen(logofilename, "rb");
			if (!fi) { fprintf(stderr, "Cannot open file '%s'.\n", logofilename); exit(1); }
			fread(&header.logo, 1, 156, fi);
			fclose(fi);
		}
	}
	else if (bSecureSyscalls)	// use Nintendo logo
	{
		memcpy(((unsigned char *)&header) + 0xC0, nintendo_logo, sizeof(nintendo_logo));
	}
	else	// add small NDS loader
	{
		if (loadme_size != 156) { fprintf(stderr, "loadme size error\n"); exit(1); }
		memcpy(header.logo, loadme, loadme_size);		// self-contained NDS loader for *Me GBA cartridge boot
		memcpy(&header.offset_0xA0, "SRAM_V110", 9);		// allow GBA cartridge SRAM backup
		memcpy(&header.offset_0xAC, "PASS01\x96", 7);		// automatically start with FlashMe, make it look more like a GBA rom
	}

	// override default title/game/maker codes
	if (title) strncpy(header.title, title, 12);
	if (gamecode) strncpy(header.gamecode, gamecode, 4);
	if (makercode) strncpy((char *)header.makercode, makercode, 2);

	// --------------------------

	fseek(fNDS, header.rom_header_size, SEEK_SET);

	// ARM9 binary
	if (arm9filename)
	{
		header.arm9_rom_offset = (ftell(fNDS) + arm9_align) &~ arm9_align;
		fseek(fNDS, header.arm9_rom_offset, SEEK_SET);

		unsigned int entry_address = arm9Entry ? arm9Entry : (unsigned int)header.arm9_entry_address;		// template
		unsigned int ram_address = arm9RamAddress ? arm9RamAddress : (unsigned int)header.arm9_ram_address;		// template
		if (!ram_address && entry_address) ram_address = entry_address;
		if (!entry_address && ram_address) entry_address = ram_address;
		if (!ram_address) { ram_address = entry_address = 0x02000000; }

		// add dummy area for secure syscalls
		header.arm9_size = 0;
		if (bSecureSyscalls)
		{
			unsigned_int x;
			FILE *fARM9 = fopen(arm9filename, "rb");
			if (fARM9)
			{
				fread(&x, sizeof(x), 1, fARM9);
				fclose(fARM9);
				if (x != 0xE7FFDEFF)	// not already exist?
				{
					x = 0xE7FFDEFF;
					for (int i=0; i<0x800/4; i++) fwrite(&x, sizeof(x), 1, fNDS);
					header.arm9_size = 0x800;
				}
			}
		}

		unsigned int size = 0;


		if (HasElfExtension(arm9filename) || HasElfHeader(arm9filename) )
			CopyFromElf(arm9filename, &entry_address, &ram_address, &size);
		else
			CopyFromBin(arm9filename, 0, &size);
		header.arm9_entry_address = entry_address;
		header.arm9_ram_address = ram_address;
		header.arm9_size = header.arm9_size + ((size + 3) &~ 3);
	}
	else
	{
		fprintf(stderr, "ARM9 binary file required.\n");
		exit(1);
	}

	// ARM9 overlay table
	if (arm9ovltablefilename)
	{
		unsigned_int x1 = 0xDEC00621; fwrite(&x1, sizeof(x1), 1, fNDS);		// 0x2106c0de magic
		unsigned_int x2 = 0x00000AD8; fwrite(&x2, sizeof(x2), 1, fNDS);		// ???
		unsigned_int x3 = 0x00000000; fwrite(&x3, sizeof(x3), 1, fNDS);		// ???

		header.arm9_overlay_offset = ftell(fNDS);		// do not align
		fseek(fNDS, header.arm9_overlay_offset, SEEK_SET);
		unsigned int size = 0;
		CopyFromBin(arm9ovltablefilename, &size);
		header.arm9_overlay_size = size;
		overlay_files += size / sizeof(OverlayEntry);
		if (!size) header.arm9_overlay_offset = 0;
	}

	// COULD BE HERE: ARM9 overlay files, no padding before or between. end is padded with 0xFF's and then followed by ARM7 binary
	// fseek(fNDS, 1388772, SEEK_CUR);		// test for ASME

	// ARM7 binary
	header.arm7_rom_offset = (ftell(fNDS) + arm7_align) &~ arm7_align;
	fseek(fNDS, header.arm7_rom_offset, SEEK_SET);

	char *devkitProPATH;
	devkitProPATH = getenv("DEVKITPRO");

	#ifdef __WIN32__
	// convert to standard windows path
	if ( devkitProPATH && devkitProPATH[0] == '/' ) {
		devkitProPATH[0] = devkitProPATH[1];
		devkitProPATH[1] = ':';
	}
	#endif

	if ( !arm7filename) {
		char arm7PathName[MAXPATHLEN];

		if (!devkitProPATH) {
			fprintf(stderr,"No arm7 specified and DEVKITPRO missing from environment!\n");
			exit(1);
		}

		strcpy(arm7PathName,devkitProPATH);
		strcat(arm7PathName,"/libnds/default.elf");
		arm7filename = arm7PathName;
	}

	unsigned int entry_address = arm7Entry ? arm7Entry : (unsigned int)header.arm7_entry_address;		// template
	unsigned int ram_address = arm7RamAddress ? arm7RamAddress : (unsigned int)header.arm7_ram_address;		// template
	if (!ram_address && entry_address) ram_address = entry_address;
	if (!entry_address && ram_address) entry_address = ram_address;
	if (!ram_address) { ram_address = entry_address = 0x037f8000; }

	unsigned int size = 0;

	if (HasElfExtension(arm7filename))
		CopyFromElf(arm7filename, &entry_address, &ram_address, &size);
	else
		CopyFromBin(arm7filename, &size);

	header.arm7_entry_address = entry_address;
	header.arm7_ram_address = ram_address;
	header.arm7_size = ((size + 3) &~ 3);

	// ARM7 overlay table
	if (arm7ovltablefilename)
	{
		header.arm7_overlay_offset = ftell(fNDS);		// do not align
		fseek(fNDS, header.arm7_overlay_offset, SEEK_SET);
		unsigned int size = 0;
		CopyFromBin(arm7ovltablefilename, &size);
		header.arm7_overlay_size = size;
		overlay_files += size / sizeof(OverlayEntry);
		if (!size) header.arm7_overlay_offset = 0;
	}

	// COULD BE HERE: probably ARM7 overlay files, just like for ARM9
	//

	if (overlay_files && !overlaydir)
	{
		fprintf(stderr, "Overlay directory required!.\n");
		exit(1);
	}

	// filesystem
	//if (filerootdir || overlaydir)
	{
		// read directory structure
		free_file_id = overlay_files;
		free_dir_id++;
		directory_count++;
		TreeNode *filetree;
		if (filerootdir)
			filetree = ReadDirectory(new TreeNode(), filerootdir);
		else
			filetree = new TreeNode();		// dummy root node 0xF000

		// calculate offsets required for FNT and FAT
		_entry_start = 8*directory_count;		// names come after directory structs
		header.fnt_offset = (ftell(fNDS) + fnt_align) &~ fnt_align;
		header.fnt_size =
			_entry_start +		// directory structs
			total_name_size +	// total number of name characters for dirs and files
			directory_count*4 +	// directory: name length (1), dir id (2), end-character (1)
			file_count*1 +		// files: name length (1)
			- 3;				// root directory only has an end-character
		file_count += overlay_files;		// didn't take overlay files into FNT size, but have to be calculated into FAT size
		header.fat_offset = (header.fnt_offset + header.fnt_size + fat_align) &~ fat_align;
		header.fat_size = file_count * 8;		// each entry contains top & bottom offset

		// banner after FNT/FAT
		if (bannerfilename)
		{
			header.banner_offset = (header.fat_offset + header.fat_size + banner_align) &~ banner_align;
			file_top = header.banner_offset + 0x840;
			fseek(fNDS, header.banner_offset, SEEK_SET);
			if (bannertype == BANNER_IMAGE)
			{
				char * Ext = strrchr(bannerfilename, '.');
				if (Ext && strcasecmp(Ext, ".bmp") == 0)
					IconFromBMP();
				else if (Ext && strcasecmp(Ext, ".grf") == 0)
					IconFromGRF();
				else
				{
					fprintf(stderr,
						"Banner File Error: Unknown extension '%s'!\n", Ext);
					exit(1);
				}
			}
			else
			{
				CopyFromBin(bannerfilename, 0);
			}
		}
		else
		{
			file_top = header.fat_offset + header.fat_size;
			header.banner_offset = 0;
		}

		file_end = file_top;	// no file data as yet

		// add (hidden) overlay files
		for (unsigned int i=0; i<overlay_files; i++)
		{
			char s[32]; sprintf(s, OVERLAY_FMT, i/*free_file_id*/);
			AddFile(overlaydir, "/", s, i/*free_file_id*/);
			//free_file_id++;		// incremented up to overlay_files
		}

		// add all other (visible) files
		AddDirectory(filetree, "/", 0xF000, directory_count);
		fseek(fNDS, file_end, SEEK_SET);

		if (verbose)
		{
			printf("%u directories.\n", directory_count);
			printf("%u normal files.\n", file_count - overlay_files);
			printf("%u overlay files.\n", overlay_files);
		}
	}

	// --------------------------

	// align file size
	unsigned int newfilesize = file_end;	//ftell(fNDS);
	newfilesize = (newfilesize + 3) & ~3;	// align to 4 bytes
	header.application_end_offset = newfilesize;
	if (newfilesize != file_end ) {
		fseek(fNDS, newfilesize-1, SEEK_SET);
		fputc(0, fNDS);
	}
	// calculate device capacity
	newfilesize |= newfilesize >> 16; newfilesize |= newfilesize >> 8;
	newfilesize |= newfilesize >> 4; newfilesize |= newfilesize >> 2;
	newfilesize |= newfilesize >> 1; newfilesize++;
	if (newfilesize <= 128*1024) newfilesize = 128*1024;
	int devcap = -18;
	unsigned int x = newfilesize;
	while (x != 0) { x >>= 1; devcap++; }
	header.devicecap = (devcap < 0) ? 0 : devcap;

	// fix up header CRCs and write header
	header.logo_crc = CalcLogoCRC(header);
	header.header_crc = CalcHeaderCRC(header);
	fseek(fNDS, 0, SEEK_SET);
	fwrite(&header, 0x200, 1, fNDS);

	fclose(fNDS);
}