using System; using System.Collections.Generic; using System.Text; using System.IO; namespace nbhgen { public class NBH { /* some small byte helpers i used while reving it */ public class ByteHelpers { public static string ByteArrayToString(byte[] b_in) { string temp = ""; foreach (byte b in b_in) temp += (char)b; return temp; } public static string ByteArrayToHexString(byte[] b_in) { string temp = ""; foreach (byte b in b_in) temp += string.Format("{0:x2} ", b); return temp; } public static int LongIntToDecimal(byte[] b_in) { return b_in[0] + b_in[1] * 256 + b_in[2] * 65536 + b_in[3] * 16777216; } } public class NBHRom { public class NBHBlock { public byte[] b_blocksize; public byte[] b_signaturesize; public int b_flag; public byte[] b_block; public byte[] b_signature; private FileStream fs_nbhstream; public NBHBlock(FileStream nbh) { fs_nbhstream = nbh; b_blocksize = new byte[4]; b_signaturesize = new byte[4]; b_flag = new byte(); } public void ReadBlock() { /* * block: * * [ 4byte blocksize ][4byte signature][1byte flag][ x-bytes block][ x-bytes signature] * the last block has flag == 2, and only contains a signature, probably for the whole file. */ fs_nbhstream.Read(b_blocksize, 0, 4); fs_nbhstream.Read(b_signaturesize, 0, 4); b_flag = fs_nbhstream.ReadByte(); int blocksize = ByteHelpers.LongIntToDecimal(b_blocksize); int signaturesize = ByteHelpers.LongIntToDecimal(b_blocksize); /* Console.WriteLine("blocksize: {0} signaturesize: {1} flag: {2}", blocksize, signaturesize, b_flag); */ b_block = new byte[blocksize]; fs_nbhstream.Read(b_block, 0, blocksize); b_signature = new byte[signaturesize]; fs_nbhstream.Read(b_signature, 0, signaturesize); } } public delegate void debugPrint(string function, params object[] arg); debugPrint DebugPrint; string s_fileIn; public NBHRom ( string s_filein, debugPrint debugprint ) { s_fileIn = s_filein; DebugPrint = debugprint; } /* convert a rom to the rbh format, the rbh format is the nbh format without the signatures and the block headers */ public void ConvertToRBH( string s_fileout ) { FileStream nbh = new FileStream( s_fileIn, FileMode.Open, FileAccess.Read); byte[] b_headercode = new byte[23]; /* according to xda-dev wiki 7bytes filetype+16 bytes garbage */ nbh.Read(b_headercode, 0, b_headercode.Length); DebugPrint("headercode: {0}", ByteHelpers.ByteArrayToString(b_headercode)); FileStream rnbout = new FileStream(s_fileout, FileMode.Create, FileAccess.Write); /* write the raw RNB format */ NBHBlock nbhblock = new NBHBlock(nbh); do { nbhblock.ReadBlock(); rnbout.Write(nbhblock.b_block, 0, nbhblock.b_block.Length); } while (nbhblock.b_flag != 2); /* flag 2 = last block */ rnbout.Close(); nbh.Close(); } } public class NBRom { /* image types, also used for filenames */ public enum NBImageType { IPL = 0x100, SPL = 0x200, Radio = 0x300, Windows = 0x400, PrimarySplash = 0x600, SecondarySplash = 0x601, ExtendedRom = 0x700 } public NBImageType ImageType; public long offset; public long length; public NBRom(int i_type) { ImageType = (NBImageType)i_type; } } public class RNBRom { public string s_cid; public string s_language; public string s_version; public string s_device; public string s_imagetype; FileStream fs_rbh; List nbr_list; public delegate void debugPrint(string function, params object[] arg); debugPrint DebugPrint; public RNBRom(debugPrint myprint) { DebugPrint = myprint; nbr_list = new List(); } public void LoadRom(string s_filename) { if (fs_rbh != null) throw new IOException("please close first romhandle prior to opening another with the same object"); fs_rbh = new FileStream(s_filename, FileMode.Open, FileAccess.Read); /* read rom type */ byte[] b_imagetype = new byte[32]; fs_rbh.Read(b_imagetype, 0, b_imagetype.Length); s_imagetype = System.Text.Encoding.UTF32.GetString(b_imagetype); DebugPrint("imagetype: {0}", s_imagetype); /* read device type */ fs_rbh.Read(b_imagetype, 0, b_imagetype.Length); s_device = System.Text.Encoding.ASCII.GetString(b_imagetype); DebugPrint("devicetype: {0}", s_device); /* read rom types */ byte[] b_romtype = new byte[4]; for (int i = 0; i < 128; i += 4) { fs_rbh.Read(b_romtype, 0, b_romtype.Length); int i_romtype = ByteHelpers.LongIntToDecimal(b_romtype); if (i_romtype != 0) { NBRom nbr_rom = new NBRom(i_romtype); nbr_list.Add(nbr_rom); DebugPrint("found rom: {0} (0x{1:x2})", nbr_rom.ImageType, (int)nbr_rom.ImageType); } } DebugPrint("numer of roms in nbh: {0}", nbr_list.Count); /* read rom offests */ byte[] b_romoffset = new byte[4]; for (int i = 0; i < 128; i += 4) { fs_rbh.Read(b_romoffset, 0, b_romoffset.Length); int i_offset = ByteHelpers.LongIntToDecimal(b_romoffset); int rom_no = i / 4; if (i_offset != 0 && rom_no < nbr_list.Count) { nbr_list[rom_no].offset = i_offset; DebugPrint("found offset: {0} (0x{1:x2})", nbr_list[rom_no].ImageType, (int)nbr_list[rom_no].offset); } } /* read rom lengths */ byte[] b_romlength = new byte[4]; for (int i = 0; i < 128; i += 4) { fs_rbh.Read(b_romlength, 0, b_romlength.Length); int i_length = ByteHelpers.LongIntToDecimal(b_romlength); int rom_no = i / 4; if (i_length != 0 && rom_no < nbr_list.Count) { nbr_list[rom_no].length = i_length; DebugPrint("found length: {0} (0x{1:x2})", nbr_list[rom_no].ImageType, (int)nbr_list[rom_no].length); } } } public void CloseRom() { nbr_list = new List(); fs_rbh.Close(); fs_rbh = null; } public void ExtractNBH(string s_outdir) { if (fs_rbh == null) throw new Exception("no filehandle to rbh rom"); if (nbr_list.Count == 0) throw new Exception("please load the rom prior to extracting it"); if (s_outdir.EndsWith("\\") == false ) s_outdir += "\\"; for (int i = 0; i < nbr_list.Count; i++) { FileStream fs_out = new FileStream(s_outdir + nbr_list[i].ImageType + ".nb", FileMode.Create, FileAccess.Write); fs_rbh.Seek(nbr_list[i].offset, SeekOrigin.Begin); int peeksize = 1024; for (long bytesleft = nbr_list[i].length; bytesleft >= 0; bytesleft -= peeksize) { byte[] bytes; if (bytesleft < peeksize) { bytes = new byte[bytesleft]; fs_rbh.Read(bytes, 0, bytes.Length); fs_out.Write(bytes, 0, bytes.Length); break; } bytes = new byte[peeksize]; fs_rbh.Read(bytes, 0, bytes.Length); fs_out.Write(bytes, 0, bytes.Length); } fs_out.Close(); } } } } class Program { static void Main(string[] args) { #if false /* do this */ NBH.NBHRom nbhrom = new NBH.NBHRom("..\\rom\\Ruu_signed.nbh", Console.WriteLine); nbhrom.ConvertToRBH("ruu.bin"); #else /* then this */ NBH.RNBRom rnbrom = new NBH.RNBRom(Console.WriteLine); rnbrom.LoadRom("..\\rom\\ruu.bin"); rnbrom.ExtractNBH("..\\rom"); rnbrom.CloseRom(); #endif } } }