mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-27 15:44:00 +08:00
(RCT): lookup image password in start.mjo game file.
This commit is contained in:
parent
6959cb7ebd
commit
a14c781ae3
@ -25,9 +25,11 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.Composition;
|
using System.ComponentModel.Composition;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
@ -286,10 +288,96 @@ namespace GameRes.Formats.Majiro
|
|||||||
|
|
||||||
private string QueryPassword ()
|
private string QueryPassword ()
|
||||||
{
|
{
|
||||||
|
if (VFS.IsVirtual)
|
||||||
|
{
|
||||||
|
var password = FindImageKey();
|
||||||
|
if (!string.IsNullOrEmpty (password))
|
||||||
|
return password;
|
||||||
|
}
|
||||||
var options = Query<RctOptions> (arcStrings.ArcImageEncrypted);
|
var options = Query<RctOptions> (arcStrings.ArcImageEncrypted);
|
||||||
return options.Password;
|
return options.Password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static readonly Lazy<ArchiveFormat> s_Majiro = new Lazy<ArchiveFormat> (() => FormatCatalog.Instance.ArcFormats.FirstOrDefault (x => x.Tag == "MAJIRO"));
|
||||||
|
|
||||||
|
private string FindImageKey ()
|
||||||
|
{
|
||||||
|
var arc_fs = VFS.Top as ArchiveFileSystem;
|
||||||
|
if (null == arc_fs)
|
||||||
|
return null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// look for "start.mjo" within "scenario.arc" archive
|
||||||
|
var src_name = arc_fs.Source.File.Name;
|
||||||
|
var scenario_arc_name = Path.Combine (Path.GetDirectoryName (src_name), "scenario.arc");
|
||||||
|
if (!File.Exists (scenario_arc_name))
|
||||||
|
return null;
|
||||||
|
byte[] script;
|
||||||
|
using (var file = new ArcView (scenario_arc_name))
|
||||||
|
using (var arc = s_Majiro.Value.TryOpen (file))
|
||||||
|
{
|
||||||
|
if (null == arc)
|
||||||
|
return null;
|
||||||
|
var start_mjo = arc.Dir.First (e => e.Name == "start.mjo");
|
||||||
|
using (var mjo = arc.OpenEntry (start_mjo))
|
||||||
|
{
|
||||||
|
script = new byte[mjo.Length];
|
||||||
|
mjo.Read (script, 0, script.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Binary.AsciiEqual (script, "MajiroObjX1.000"))
|
||||||
|
DecryptMjo (script);
|
||||||
|
else if (!Binary.AsciiEqual (script, "MjPlainBytecode"))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// locate key within start.mjo script
|
||||||
|
int n = script.ToInt32 (0x18);
|
||||||
|
for (int offset = 0x20 + n * 8; offset < script.Length - 4; ++offset)
|
||||||
|
{
|
||||||
|
offset = Array.IndexOf<byte> (script, 1, offset);
|
||||||
|
if (-1 == offset)
|
||||||
|
break;
|
||||||
|
if (8 != script[offset+1])
|
||||||
|
continue;
|
||||||
|
int str_length = script.ToUInt16 (offset+2);
|
||||||
|
if (0 == str_length || str_length + 12 > script.Length - offset
|
||||||
|
|| 0x0835 != script.ToUInt16 (offset+str_length+4)
|
||||||
|
|| 0x7A7B6ED4 != script.ToUInt32 (offset+str_length+6))
|
||||||
|
continue;
|
||||||
|
offset += 4;
|
||||||
|
int end = Array.IndexOf<byte> (script, 0, offset, str_length);
|
||||||
|
if (-1 != end)
|
||||||
|
str_length = end - offset;
|
||||||
|
var password = Encodings.cp932.GetString (script, offset, str_length);
|
||||||
|
Trace.WriteLine (string.Format ("Found key in start.mjo [{0}]", password), "[RCT]");
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { /* ignore errors */ }
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DecryptMjo (byte[] data)
|
||||||
|
{
|
||||||
|
int offset = 0x1C + 8 * data.ToInt32 (0x18);
|
||||||
|
if (offset < 0x1C || offset >= data.Length - 4)
|
||||||
|
return;
|
||||||
|
int count = data.ToInt32 (offset);
|
||||||
|
offset += 4;
|
||||||
|
if (count <= 0 || count > data.Length - offset)
|
||||||
|
return;
|
||||||
|
Debug.Assert (Crc32.Table.Length == 0x100);
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (uint* table = Crc32.Table)
|
||||||
|
{
|
||||||
|
byte* key = (byte*)table;
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
data[offset+i] ^= key[i & 0x3FF];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override ResourceOptions GetDefaultOptions ()
|
public override ResourceOptions GetDefaultOptions ()
|
||||||
{
|
{
|
||||||
return new RctOptions { Password = Settings.Default.RCTPassword };
|
return new RctOptions { Password = Settings.Default.RCTPassword };
|
||||||
|
Loading…
Reference in New Issue
Block a user