implemented key extraction from executable resources for encrypted INT archives.

This commit is contained in:
morkt
2015-11-20 01:01:25 +04:00
parent 5a5c10d91a
commit 33e83b196d
7 changed files with 276 additions and 24 deletions

View File

@@ -27,9 +27,9 @@ using System;
using System.IO;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Collections.Generic;
using System.Diagnostics;
using Simias.Encryption;
using System.Runtime.InteropServices;
using GameRes.Formats.Strings;
@@ -346,5 +346,82 @@ namespace GameRes.Formats.CatSystem
}
}
}
/// <summary>
/// Parse certain executable resources for encryption passphrase.
/// Returns null if no passphrase found.
/// </summary>
public static string GetPassFromExe (string filename)
{
var exe = NativeMethods.LoadLibraryEx (filename, IntPtr.Zero, 0x20); // LOAD_LIBRARY_AS_IMAGE_RESOURCE
if (IntPtr.Zero == exe)
throw new Win32Exception (Marshal.GetLastWin32Error());
try
{
var code = GetResource (exe, "DATA", "V_CODE2");
if (null == code || code.Length < 8)
return null;
var key = GetResource (exe, "KEY", "KEY_CODE");
if (null != key)
{
for (int i = 0; i < key.Length; ++i)
key[i] ^= 0xCD;
}
else
{
key = Encoding.ASCII.GetBytes ("windmill");
}
var blowfish = new Blowfish (key);
blowfish.Decipher (code, code.Length/8*8);
int length = Array.IndexOf<byte> (code, 0);
if (-1 == length)
length = code.Length;
return Encodings.cp932.GetString (code, 0, length);
}
finally
{
NativeMethods.FreeLibrary (exe);
}
}
static byte[] GetResource (IntPtr exe, string name, string type)
{
var res = NativeMethods.FindResource (exe, name, type);
if (IntPtr.Zero == res)
return null;
var glob = NativeMethods.LoadResource (exe, res);
if (IntPtr.Zero == glob)
return null;
uint size = NativeMethods.SizeofResource (exe, res);
var src = NativeMethods.LockResource (glob);
if (IntPtr.Zero == src)
return null;
var dst = new byte[size];
Marshal.Copy (src, dst, 0, dst.Length);
return dst;
}
}
static internal class NativeMethods
{
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static internal extern IntPtr LoadLibraryEx (string lpFileName, IntPtr hReservedNull, uint dwFlags);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static internal extern bool FreeLibrary (IntPtr hModule);
[DllImport( "kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static internal extern IntPtr FindResource (IntPtr hModule, string lpName, string lpType);
[DllImport("Kernel32.dll", SetLastError = true)]
static internal extern IntPtr LoadResource (IntPtr hModule, IntPtr hResource);
[DllImport("Kernel32.dll", SetLastError = true)]
static internal extern uint SizeofResource (IntPtr hModule, IntPtr hResource);
[DllImport("kernel32.dll")]
static internal extern IntPtr LockResource (IntPtr hResData);
}
}

View File

@@ -1,10 +1,21 @@
<Grid x:Class="GameRes.Formats.GUI.WidgetINT"
<StackPanel x:Class="GameRes.Formats.GUI.WidgetINT"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:GameRes.Formats.Strings"
xmlns:fmt="clr-namespace:GameRes.Formats.CatSystem"
xmlns:local="clr-namespace:GameRes.Formats.GUI"
MaxWidth="260">
MaxWidth="280" Orientation="Vertical">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Name="ExeMessage" Grid.Column="0" Text="{x:Static s:arcStrings.INTMessage1}" TextWrapping="Wrap" Margin="0,0,10,10"/>
<Button Content="{x:Static s:arcStrings.INTExeButton}" Grid.Column="1" Grid.Row="0" Width="75" Height="25"
HorizontalAlignment="Left" Margin="0,0,0,10" Click="Check_Click"/>
</Grid>
<TextBlock Grid.Column="0" Text="{x:Static s:arcStrings.INTMessage2}" Margin="0,0,0,10" TextWrapping="Wrap"/>
<Grid>
<Grid.Resources>
<local:KeyConverter x:Key="keyConverter"/>
<Style TargetType="{x:Type TextBox}">
@@ -21,13 +32,13 @@
<ColumnDefinition MinWidth="130" Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="{x:Static s:arcStrings.INTLabelNumericKey}" Target="{Binding ElementName=Passkey}"
Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right"/>
<TextBox Name="Passkey" Grid.Column="1" Grid.Row="0" Margin="0,3,0,3">
Grid.Column="0" Grid.Row="2" HorizontalAlignment="Right"/>
<TextBox Name="Passkey" Grid.Column="1" Grid.Row="2" Margin="0,3,0,3">
<TextBox.Text>
<Binding Path="Key" Converter="{StaticResource keyConverter}" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
@@ -51,9 +62,10 @@
<TextBox Name="Passphrase" Grid.Column="1" Grid.Row="1" Margin="0,3,0,3"
Text="{Binding Path=Password}"/>
<Label Content="{x:Static s:arcStrings.LabelScheme}" Target="{Binding ElementName=EncScheme}"
Grid.Column="0" Grid.Row="2" HorizontalAlignment="Right"/>
<ComboBox Name="EncScheme" Grid.Column="1" Grid.Row="2" Margin="0,3,0,0"
Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right"/>
<ComboBox Name="EncScheme" Grid.Column="1" Grid.Row="0" Margin="0,3,0,0"
ItemsSource="{Binding Source={x:Static fmt:IntOpener.KnownSchemes}, Path=Keys, Mode=OneWay}"
Width="{Binding ElementName=Passkey, Path=ActualWidth}"
SelectedValue="{Binding Path=Scheme}"/>
</Grid>
</StackPanel>

View File

@@ -1,15 +1,42 @@
using System;
//! \brief Code-behind for INT encryption query widget.
//
// Copyright (C) 2014-2015 by morkt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
using System;
using System.Globalization;
using System.Windows.Controls;
using System.Windows.Data;
using GameRes.Formats.CatSystem;
using GameRes.Formats.Strings;
using Microsoft.Win32;
using System.Windows;
using System.IO;
namespace GameRes.Formats.GUI
{
/// <summary>
/// Interaction logic for WidgetINT.xaml
/// </summary>
public partial class WidgetINT : Grid
public partial class WidgetINT : StackPanel
{
public WidgetINT ()
{
@@ -51,6 +78,36 @@ namespace GameRes.Formats.GUI
}
}
}
private void Check_Click (object sender, System.Windows.RoutedEventArgs e)
{
var dlg = new OpenFileDialog {
CheckFileExists = true,
CheckPathExists = true,
Multiselect = false,
Title = arcStrings.INTChooseExe,
Filter = arcStrings.INTExeFiles+"|*.exe",
FilterIndex = 1,
InitialDirectory = Directory.GetCurrentDirectory(),
};
if (!dlg.ShowDialog (Window.GetWindow (this)).Value)
return;
try
{
var pass = IntOpener.GetPassFromExe (dlg.FileName);
if (null != pass)
{
this.ExeMessage.Text = arcStrings.INTMessage1;
Passphrase.Text = pass;
}
else
this.ExeMessage.Text = string.Format (arcStrings.INTKeyNotFound, Path.GetFileName (dlg.FileName));
}
catch (Exception X)
{
this.ExeMessage.Text = X.Message;
}
}
}
[ValueConversion(typeof(uint?), typeof(string))]