using System; using System.Collections.Generic; using System.Collections; using System.Text; using System.IO; namespace NBHDump { class NBHDumper { protected byte[] romtype = null; public int headerblock, signerblock; public int[] roms, romsaddr, romssize; public byte headerflag; public bool ArrayEquals(byte[] a, byte[] b) //Dear Microsoft: add a fucking Array compare function { if (a.Length != b.Length) return false; for (int i = 0; i < a.Length; i++) { if (a[i] != b[i]) return false; } return true; } protected int StreamtoInt(byte[] arr) { return (arr[0] + (arr[1] * 0x100) + (arr[2] * 0x10000) + (arr[3] * 0x1000000)); } protected FileStream f_nbh; public NBHDumper(string thenbh) { f_nbh = new FileStream(thenbh,FileMode.Open,FileAccess.Read); } byte[] headersig = new byte[7] {82, 48, 48, 48, 70, 70, 10}; protected int readheader() { byte[] retval = new byte[4]; f_nbh.Read(retval, 0, 4); return StreamtoInt(retval); } protected int[] readnbtypes() { romtype = new byte[4]; ArrayList arr = new ArrayList(); for(int i = 0; i < 32; i++) { f_nbh.Read(romtype,0,4); if (StreamtoInt(romtype) != 0) arr.Add(StreamtoInt(romtype)); } roms = new int[arr.Count]; arr.CopyTo(roms); return roms; } protected int[] readnbaddr() { byte[] romaddr = new byte[4]; ArrayList arr = new ArrayList(); for (int i = 0; i < 32; i++) { f_nbh.Read(romaddr, 0, 4); if (StreamtoInt(romaddr) != 0 && i < this.roms.Length) arr.Add(StreamtoInt(romaddr)+32); } romsaddr = new int[arr.Count]; arr.CopyTo(romsaddr); return romsaddr; } protected int[] readnbsize() { byte[] romsize = new byte[4]; ArrayList arr = new ArrayList(); for (int i = 0; i < 32; i++) { f_nbh.Read(romsize, 0, 4); if (StreamtoInt(romsize) != 0 && i < roms.Length) { arr.Add(StreamtoInt(romsize)); } } romssize = new int[arr.Count]; arr.CopyTo(romssize); return romssize; } public int[] romstemp, romssyze; public long[] sigspots = null; int[] getsigssize() { long remember = f_nbh.Position; romstemp = new int[romsaddr.Length]; romstemp = romsaddr; romssyze = new int[romssize.Length]; romssyze = romssize; ArrayList sigspts = new ArrayList(); f_nbh.Seek(23, SeekOrigin.Begin); int flag = 0; //long total = 0; byte[] block = new byte[4], sign = new byte[4]; int g = 0; while (flag != 2) { long place2 = f_nbh.Position; f_nbh.Read(block, 0, 4); f_nbh.Read(sign, 0, 4); flag = f_nbh.ReadByte(); f_nbh.Seek(StreamtoInt(block) + StreamtoInt(sign), SeekOrigin.Current); long place = f_nbh.Position; if (StreamtoInt(sign) == 128) { sigspts.Add(place); for (int i = 1; i < romstemp.Length; i++) { if (place2 < (romstemp[i] + romssyze[i]) && place2 > romstemp[i]) romssyze[i] += 137; if (place < romstemp[i]) romstemp[i] += 137; } } g++; } for(int i = 0;i < romssyze.Length;i++) romssyze[i] += romstemp[i]-1; if((romssyze[0]+1) != romstemp[1]) romssyze[0] = romstemp[1] - 1; f_nbh.Seek(remember, SeekOrigin.Begin); sigspots = new long[sigspts.Count]; sigspts.CopyTo(sigspots); return romstemp; } public string romtypetoname(int Romval) { if (Romval == 256) return "00_IPL.nb"; if (Romval == 512) return "01_SPL.nb"; if (Romval == 768) return "03_GSM.nb"; if (Romval == 1024) return "04_OS.nb"; if (Romval == 1536) return "05_MainSplash.nb"; if (Romval == 1537) return "06_SubSplash.nb"; if (Romval == 1792) return "07_ExtROM.nb"; return "Unknown.nb"; } public void donbjob() { long dss; byte[] writer; byte[] signat = new byte[4]; byte[] blocks = new byte[4]; FileStream f_nb; for (int i = 0; i < romstemp.Length; i++) { f_nb = new FileStream(romtypetoname(roms[i]),FileMode.OpenOrCreate,FileAccess.ReadWrite); Console.Out.WriteLine("Extracting: " +romtypetoname(roms[i])); f_nbh.Seek(romstemp[i], SeekOrigin.Begin); while(f_nbh.Position < romssyze[i]) { if ((f_nbh.Position + 65536) > romssyze[i]) { if((dss = SigbetweenFiles(((long)romssyze[i]))) != 0) { writer = new byte[((int)(dss - (f_nbh.Position + 128)))]; f_nbh.Read(writer, 0, ((int)(dss - (f_nbh.Position + 128)))); f_nb.Write(writer, 0, writer.Length/*((int)(dss - (f_nbh.Position + 128)))*/); f_nb.Flush(); } else { writer = new byte[((int)(romssyze[i]+1 - f_nbh.Position))]; f_nbh.Read(writer, 0, ((int)(romssyze[i]+1 - f_nbh.Position))); f_nb.Write(writer, 0, writer.Length/*((int)(romssyze[i]+1 - f_nbh.Position))*/); f_nb.Flush(); } } else if ((dss = SigbetweenFiles((f_nbh.Position + 65536))) != 0) { writer = new byte[((int)(dss - (f_nbh.Position+128)))]; f_nbh.Read(writer, 0, ((int)(dss - (f_nbh.Position+128)))); f_nb.Write(writer, 0, writer.Length/*((int)(dss - (f_nbh.Position + 128)))*/); f_nb.Flush(); } else { writer = new byte[65536]; f_nbh.Read(writer, 0, 65536); f_nb.Write(writer, 0, writer.Length); f_nb.Flush(); } f_nbh.Seek(137, SeekOrigin.Current); } f_nb.Flush(); f_nb.Close(); f_nb = null; } Console.Out.WriteLine("Done!"); } public long SigbetweenFiles(long val) { for (int i = 0; i < sigspots.Length; i++) { if (sigspots[i] > f_nbh.Position && sigspots[i] < val) return sigspots[i]; } return 0; } public void CloseFile() { f_nbh.Close(); } public void readheaders() //This is essentially the main part of the class { byte[] headercheck = new byte[7]; byte[] htcimage = new byte[32]; int headerflag; f_nbh.Read(headercheck, 0, 7); if(!ArrayEquals(headercheck,headersig)) errorcodes(2); f_nbh.Seek(23,SeekOrigin.Begin); headerblock = readheader(); signerblock = readheader(); headerflag = f_nbh.ReadByte(); f_nbh.Read(htcimage, 0, 32); Console.Out.WriteLine("ImageType: " + Encoding.UTF32.GetString(htcimage)); f_nbh.Read(htcimage, 0, 32); Console.Out.WriteLine("Device: " + Encoding.ASCII.GetString(htcimage)); readnbtypes(); //these bastards could be in this function but I moved them out for my benefit. readnbaddr(); readnbsize(); getsigssize(); donbjob(); } void errorcodes(int errors) { if (errors == 2) throw new Exception("Error: File is not an NBH"); } } }