diff --git a/BW Entralink Forest tool/MainForm.Designer.cs b/BW Entralink Forest tool/MainForm.Designer.cs index 9e1fefa..4386852 100644 --- a/BW Entralink Forest tool/MainForm.Designer.cs +++ b/BW Entralink Forest tool/MainForm.Designer.cs @@ -18,6 +18,7 @@ partial class MainForm private System.Windows.Forms.TextBox savegamename; private System.Windows.Forms.Button dump_but; private System.Windows.Forms.Button inject_but; + private System.Windows.Forms.Button dump_dec_but; /// /// Disposes resources used by the form. @@ -44,6 +45,7 @@ private void InitializeComponent() this.savegamename = new System.Windows.Forms.TextBox(); this.dump_but = new System.Windows.Forms.Button(); this.inject_but = new System.Windows.Forms.Button(); + this.dump_dec_but = new System.Windows.Forms.Button(); this.SuspendLayout(); // // loadsave @@ -86,11 +88,23 @@ private void InitializeComponent() this.inject_but.UseVisualStyleBackColor = true; this.inject_but.Click += new System.EventHandler(this.Inject_butClick); // + // dump_dec_but + // + this.dump_dec_but.Enabled = false; + this.dump_dec_but.Location = new System.Drawing.Point(13, 97); + this.dump_dec_but.Name = "dump_dec_but"; + this.dump_dec_but.Size = new System.Drawing.Size(161, 36); + this.dump_dec_but.TabIndex = 5; + this.dump_dec_but.Text = "Dump Entralink Forest Data (decrypted)"; + this.dump_dec_but.UseVisualStyleBackColor = true; + this.dump_dec_but.Click += new System.EventHandler(this.Dump_dec_butClick); + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(354, 95); + this.ClientSize = new System.Drawing.Size(354, 136); + this.Controls.Add(this.dump_dec_but); this.Controls.Add(this.savegamename); this.Controls.Add(this.dump_but); this.Controls.Add(this.loadsave); diff --git a/BW Entralink Forest tool/MainForm.cs b/BW Entralink Forest tool/MainForm.cs index 0108a31..9d70099 100644 --- a/BW Entralink Forest tool/MainForm.cs +++ b/BW Entralink Forest tool/MainForm.cs @@ -16,6 +16,23 @@ using System.Windows.Forms; using System.IO; +/* +Kaphotics info about forest data: + +0x850 bytes of data +u16 update counter +u16 checksum + +checksum: crc-ccitt (16 bit) over the 0x850 range +encryption seed: last 4 bytes of the 0x850 bytes (the only thing that isn't encrypted!) +encryption method: 32bit lcrng, same used for Pokemon encryption, xor (result >> 16). + +The internal structure should be pretty easy to figure out if you just compare it to PokeStock's display. Something like u16 Species, u16 Move. +A species' level is static, determined by a table stored in the ROM (NARC file) afaik. + +The one save file I checked had it at 0x22A00, must have been B2W2 (not BW). + +*/ namespace BW_Entralink_Forest_tool { @@ -38,6 +55,7 @@ public MainForm() string forestfile; byte[] savebuffer = new byte[524288]; byte[] forestbuffer = new byte[2304]; + byte[] forestbuffer_dec = new byte[2304]; //adapted from Gocario's PHBank (www.github.com/gocario/phbank) byte[] ccitt16(byte[] data) @@ -61,6 +79,33 @@ byte[] ccitt16(byte[] data) return BitConverter.GetBytes(crc); } + UInt32 LCRNG(UInt32 seed) + // -------------------------------------------------- + { + UInt32 a = 0x41c64e6d; + UInt32 c = 0x00006073; + return (UInt32)(((UInt64)seed * (UInt64)a + (UInt64)c)&0x00000000FFFFFFFF); + } + void decryptForest() + // -------------------------------------------------- + { + Array.Copy(forestbuffer, forestbuffer_dec, 2304); + + UInt32 pv = BitConverter.ToUInt32(forestbuffer_dec, 0x84C); + byte sv = (byte)((((pv & 0x3e000) >> 0xd) % 24)&0x000000FF); + + UInt32 seed = pv; + UInt16 tmp; + + for (Int32 i = 0x0; i < 0x850; i += 0x2) + { + tmp = BitConverter.ToUInt16(forestbuffer_dec, i); + + seed = LCRNG(seed); + tmp ^= (UInt16)((seed >> 16)&0x0000FFFF); + Array.Copy(BitConverter.GetBytes(tmp), 0, forestbuffer_dec, i, 2); + } + } /// /// Reads data into a complete array, throwing an EndOfStreamException @@ -124,6 +169,20 @@ private void PDR_save_data() saveFile.Write(savebuffer, 0, savebuffer.Length); saveFile.Close(); MessageBox.Show("File Saved.", "Save file"); + } + } + private void PDR_save_decforest_data() + { SaveFileDialog saveFD = new SaveFileDialog(); + //saveFD.InitialDirectory = "c:\\"; + saveFD.Filter = "Entralink Forest Decrypted Data|*.efdd|All Files (*.*)|*.*"; + if (saveFD.ShowDialog() == DialogResult.OK) + { + System.IO.FileStream saveFile; + saveFile = new FileStream(saveFD.FileName, FileMode.Create); + //Write file + saveFile.Write(forestbuffer_dec, 0, forestbuffer_dec.Length); + saveFile.Close(); + MessageBox.Show("File Saved.", "Save file"); } } private void PDR_dump_forest_data() @@ -141,19 +200,6 @@ private void PDR_dump_forest_data() MessageBox.Show("Entralink forest data dumped to:\r"+saveFD.FileName+".", "Dump Entralink Forest Data"); } } - private void PDR_read_forest_data() - { - System.IO.FileStream saveFile; - saveFile = new FileStream(forestfile, FileMode.Open); - if (saveFile.Length != 0x900){ - //forestfile = ""; - MessageBox.Show("Invalid file length", "Error"); - return; - } - ReadWholeArray(saveFile, forestbuffer); - saveFile.Close(); - PDR_injectNsave(); - } private void PDR_get_forest_data() { OpenFileDialog openFD = new OpenFileDialog(); @@ -168,6 +214,18 @@ private void PDR_get_forest_data() } } + private void PDR_read_forest_data() + { + System.IO.FileStream forestFile; + forestFile = new FileStream(forestfile, FileMode.Open); + if (forestFile.Length != 0x900){ + //forestfile = ""; + MessageBox.Show("Invalid file length", "Error"); + return; + } + ReadWholeArray(forestFile, forestbuffer); + forestFile.Close(); + } private void PDR_injectNsave() { //Put new forest in both save file slots @@ -213,9 +271,11 @@ void SavegamenameTextChanged(object sender, EventArgs e) { if (savegamename.Text.Length > 0){ dump_but.Enabled = true; + dump_dec_but.Enabled = true; inject_but.Enabled = true; }else{ dump_but.Enabled = false; + dump_dec_but.Enabled = false; inject_but.Enabled = false; } @@ -223,6 +283,14 @@ void SavegamenameTextChanged(object sender, EventArgs e) void Inject_butClick(object sender, EventArgs e) { PDR_get_forest_data(); + PDR_injectNsave(); + } + void Dump_dec_butClick(object sender, EventArgs e) + { + //Copy forest to buffer + Array.Copy(savebuffer, 0x22C00, forestbuffer, 0, 0x900); + decryptForest(); + PDR_save_decforest_data(); } }