“Pirate” Google Chrome on Microsoft Windows 7 a year later. And MS EDGE, Opera, Brave joined them. Full version

VMProtect Ultimate was unable to control the growing codebase of the Chrome browser

file size chrome.dll depending on browser version/bit size/Windows compatibility

Let each reader draw his own conclusions from the diagram. For myself, I just noted the fact of the absence of 110 versions of any tangible improvements in terms of compactness of the browser code base (what was the point of removing support for Windows 7 then???).

Technical part.

If the reader still reaches the specified location, having mastered everything that is written above, then he will understand perfectly well that patching the browser in binary code quite simple. Based on the size of chrome.dll – nothing at the junction 109-110 Chrome versions have not changed fundamentally. DXGI with DXDVA and DirectX 9 with 11 have not gone away – the page redner will work physically. Sandbox will work (although a little later). If something affects, then some “small things” such as advanced power management capabilities, as well as purely specific auxiliary functions of Windows 8-10. We immediately throw AppX overboard.

As you remember from the first part, I wanted to create a current one at that time, 114 version in one evening without unnecessary problems (like “on your knees”). The first step was to find out whether many new WinAPIs had been added to chrome.exe && chrome_elf.dll && chrome.dll.

Dependency Walker runs on Brave.exe (chrome.exe).  In the left list is a table for importing a PE COFF file with system dll libraries, the right part is the missing WinAPI in Windows 7.

Dependency Walker runs on Brave.exe (chrome.exe). In the left list is a table for importing a PE COFF file with system dll libraries, the right part is the missing WinAPI in Windows 7.

Using Dependency Walker I quickly put up a small list of the missing WinAPIs, as well as a couple of system dlls. Having gone through their new functionality, it became obvious that they can be easilyNOP‘ in assembly code, and in the CPU general purpose register RAX/EAX return either an error or a success depending on the function in which they are used.

Replacing the line GetProcessMitigationPolicy (27) with a short plug Beep (5) in kernel32.dll

String replacement GetProcessMitigationPolicy (27) for a short plug Beep (5) in kernel32.dll

NOP’il calls in binary code are good, but there was still a PE COFF import table – in it ACSII Constant strings contain the names of missing WinAPIs and the Windows loader will try to find them. But they are no longer used in our patched code! It’s a small matter – given the fact that we should not go beyond the original ASCII string (“GetProcessMitigationPolicy” – 27 characters), you need to choose a short and safe version of the WinAPI name, which has been present since Windows XP. For kernel32.dll there is nothing simpler – Beep. WinAPI names are selected in a similar way for a couple of other DLLs.

DiscardSystemPagesInternal() in chromium/base/allocator/partition_allocator/src/partition_alloc/page_allocator_internals_win.h

DiscardSystemPagesInternal() in chromium/base/allocator/partition_allocator/src/partition_alloc/page_allocator_internals_win.h

From the list above, WinAPI stood apart DiscardVirtualMemory – right in the browser code for it there was a complete analogue of the call through the good old VirtualAlloc. Literally while writing these lines, I turned to the chromium source code to find out the details. The details made me smile widely – the comments in the source code read:

// DiscardVirtualMemory is buggy in Win10 SP0, so fall back to MEM_RESET on
// failure.

buggy And Win10 – So, reminded permanent news, which “game” was not even in the early builds of the “seven”. Anyway! Not about that now. The point is different – for some new WinAPI functions there are standard analogueseven if they work a little slower (Use DiscardVirtualMemory when available because it releases faster than MEM_RESET). Will this be useful to us? Definitely!

Windows 7 SP2

Windows 7 SP2

Of the missing dlls, the only thing to mention is API-MS-WIN-SHCORE-SCALING-L1-1-1.dllin which it was necessary to rewrite the scaling procedure for windows/monitors for Windows 7. GetDeviceCaps and payment via DPI – yes, it will even work on Windows XP.

Browser logs

After work on the missing WinAPIs and dlls was completed, the first attempt followed to launch the Chrome 114 browser in Windows 7. Call chrome.exe — visually there are no errors, the window title appears for just a second and immediately disappears, i.e. It seemed like it started up and immediately crashed. Clear! Browser logs needed: --enable-logging --v=7 Stop! What about the sandbox (SANDBOX) – it doesn’t seem to be functioning. Having rummaged around in the debugger, I quickly came to the conclusion that I would have to tinker with the sandbox for quite a long time (obviously more than one evening), since the code was unfamiliar to me, and I didn’t quite clearly imagine the technology itself (ReadProcessMemory/WriteProcessMemoryshared sections and other tricks with ntdll I’ve seen enough breaking SecuROM and the like). We add as an argument --no-sandboxwe launch our “balalaika” again and get into %LOCALAPPDATA%\Google\Chrome\User Data to view chrome_debug.log V Notepad++ or 010 Editor.

I’ll say right away that the problem with browser logs is that the necessary information may simply not be there. The browser becomes on instructions ud2, if you’re lucky, the system will catch the exception and highlight the right place, in the worst case scenario, one of the processes ends abnormally… why did it end? Why did it end? How did it end? What actually happened? Who knows! With the latter, the solution was found when I remembered the existence GetExitCodeProcess (there must be a challenge before it CreateProcessW or CreateProcessAsUserW for sandbox). But this is the ending, what about the beginning? --wait-for-debugger-children I didn’t like it because the RPC timings are “scrambled” and the result is complete nonsense. Looking ahead, I used an already proven version with MessageBox and DllMain()only in your own KERNEL64.DLL in order to humanly join one of the two necessary processes (gpu or render).

The actual case being described is the following compatibility error with Windows 7, for which there was only a mention in the logs:

[6264:4924:0701/003015.755:FATAL:gpu_data_manager_impl_private.cc(431)] GPU process isn’t usable. Goodbye.

Well, very informative and incredibly useful! Without achieving the root cause of Goodbye in the head process chrome.exe, I had to spend several hours to debug it properly --type=gpu-process. Only then did I realize that after creating some table of open handles (HANDLE), they are validated (GetHandleVerifier), which fails on shared sections. In Chrome 114 the fix looked traditional NOP. Only a couple of months later, when fixing the sandbox, I more consciously understood the essence of the error (a piece with the condition if thrown into 110 versions):

// static
PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode,
                                                              size_t size) {
  // TODO(crbug.com/210609): NaCl forces us to round up 64k here, wasting 32k
  // per mapping on average.
  static const size_t kSectionSize = 65536;
...
	
  std::u16string name;
  if (win::GetVersion() < win::Version::WIN8_1) {
    // Windows < 8.1 ignores DACLs on certain unnamed objects (like shared
    // sections). So, we generate a random name when we need to enforce
    // read-only.
	/*
	Windows < 8.1 игнорирует DACL для некоторых неименованных объектов (like shared sections). 
	Поэтому мы генерируем случайное имя, когда нам нужно обеспечить только для чтения.
	*/
    uint64_t rand_values[4];
    RandBytes(&rand_values, sizeof(rand_values));
    name = ASCIIToUTF16(StringPrintf("CrSharedMem_%016llx%016llx%016llx%016llx",
                                     rand_values[0], rand_values[1],
                                     rand_values[2], rand_values[3]));
    DCHECK(!name.empty());
  }

However, even after the life-giving “repair” NOP‘ami functional GetHandleVerifierthe browser stubbornly did not want to start, so we scroll through the error log further by keyword ERROR.

[1380:3396:0127/174930.071:ERROR:check.cc(297)] Check failed: false. NOTREACHED log messages are omitted in official builds. Sorry!

My intuition immediately told me that I didn’t like the Windows version. 7, however, Chrome will definitely not crash because of such nonsense. Just in case, I apologize for the expression, I shut my mouth about the Windows version checking function and ran further down the list.

DNS registry watch failed to start

IN RegNotifyChangeKeyValue starting from Windows 8 added a flag REG_NOTIFY_THREAD_AGNOSTIC. But the watcher’s registry.cc doesn’t know that we are in the “seven”. We cut out the underperforming flag by correcting the byte 01 on 00 and lo and behold! There were no errors.

After all these edits the stack ERROR exhausted, but not even close to seeing at least the initial browser tab. It was possible to establish that render The browser process crashed with error C0000005 (ACCESS_VIOLATION) – that’s just chrome_debug.log was silent.

Microsoft DirectX 12. IID_IDWriteFactory3.

Oddly enough, it turned out to be even easier to read the logs here. x64dbg caught in chrome.dll the place where the access exception occurred. The browser tried to call some function, but instead of the FARPROC address there was a zero (NULL). After reconnaissance stack call and the ACCESS_VIOLATION surroundings, we managed to trophy the lines “DWriteFontProxyImpl::InitializeDirectWrite”, “dwrite,fonts”. Fun fact was using IDAPro instead of open source chromium (there were some concerns that the code might not match or simply might not be in the open repository):

 v3 = "DWriteFontProxyImpl::InitializeDirectWrite";
    (**v8)(v8, &IDWriteFactory2, a1 + 0x20);
      v10 = (a1 + 0x28);
      v11 = *(a1 + 24);
      v12 = *(a1 + 40);
      if ( v12 )
      {
        *v10 = 0i64;
        (*(*v12 + 16i64))(v12);
      }
      (**v11)(v11, &IDWriteFactory3, a1 + 0x28);

As a result, using IDAPro, I pulled out three interfaces (IIDs) that the DirectX device created by the browser tries to call:

  1. {B859EE5A-D838-4B5B-A2E8-1ADC7D93DB48} IID_DWriteFactory

  2. {0439FC60-CA44-4994-8DEE-3A9AF7B732EC} IID_DWriteFactory2

  3. {9A1B41C3-D3BB-466A-87FC-FE67556A3B65} IID_IDWriteFactory3

Of the three only IID_DWriteFactory available on Windows 7 (DirectX 11). The exception occurs at IID_IDWriteFactory3, which appeared in Windows 10 (DirectX 12). Without thinking twice, we change {9A1B41C3-D3BB-466A-87FC-FE67556A3B65} on {B859EE5A-D838-4B5B-A2E8-1ADC7D93DB48} (it’s noteworthy that just a couple of weeks ago a different path emerged with crutches from Microsoft itself). For our case, it is important to understand one nuance – depending on inheritance IID_IDWriteFactory3 (inherited from IID_IDWriteFactory2which is inherited from IID_IDWriteFactorywhich is inherited from IID_IUknown), there is a possibility of running into a lack of implementation of its methods in IID_IDWriteFactory and get a new series ACCESS_VIOLATION. However, even this edit was enough to launch Chrome 114 on Windows 7 followed by surfing the vastness of the World Wide Web.

Bridged DLLs

After the success of Chrome 114, inspired Windows users crawled out from under the tiles and started writing 8, demanding justice from Google and towards them. Actually, from the very beginning I understood perfectly well what the concept wasNOPFind the missing WinAPI calls and add them to the universal import table Beep the idea is so-so and is only suitable as a quick temporary solution “on the knee”. The appeal from the tilers aggravated the problem – the number of missing WinAPIs between Windows 8 and 10 could be counted on the fingers of one hand. The G8 had mitigations, AppX, and fresh DirectX 11.1 features for texture mapping – there was NO reason AT ALL to cut out browser support for 8/8.1. Due to the fact that, unlike supermium We can only edit the browser binary code in .exe/.dll to a limited extent; the solution suggested itself: proxy the missing WinAPIs and, depending on their presence in the original DLLs, directly call the ready-made implementation. I will not go into detail here, since the finished implementation Bridged DLLs open in its own separate repository.

Google LLC’s response

Officially it was not there. The Google engineer also tried his best to make it clear that he was neutral to “all the bacchanalia that is happening.”

However, loading the following into the debugger 117 version, I realized that there is a reaction.

GetProcessPrng in chromium/base/rand_util_win.cc

GetProcessPrng in chromium/base/rand_util_win.cc

ProcessPrng appeared in the export table bcryptprimitives.dll only with Windows 10. Oh well, maybe she’s really cooler than usual rand()/srand() (although all paths go to KUSER_SHARED_DATA). Not the point.

I was “puzzled” by three things related to ProcessPrng:

  1. The described piece of code was shoved into absolutely everything .exe/.dll browser and it is called constantly. Is this really necessary? chrome_proxy.exe, elevation_service.exe, notification_helper.exe or chrome_pwa_launcher.exe? Stack guard without GetProcessPrng() works initially.

  2. The implementation itself looks strange, to put it mildly. What’s the point of using dynamic loading? LoadLibraryW/GetProcAddress? After all, you yourself already abandoned support for Windows 7/8/8.1 a year ago – link to the main import table of the PE COFF file or DELAY_IMPORT_TABLEas is done in all other code everywhere and call without 100200 byte of extra code. Why can’t we go further using LoadLibraryExW with a flag LOAD_LIBRARY_SEARCH_SYSTEM32 for greater security?

  3. LPCWSTR name for LoadLibraryW This two UNICODE strings: “bcryptprimitives.dll” and “bcryptprimitives” (pick one). A piece of code is duplicated twice. For what?

    Yes, the words about the need to control the code base were spoken by a Google engineer.

Differences between Chrome, MS Edge, Opera and BRAVE

Importing native functions from ntdll - how do you like this, Google Chrome?

Importing native functions from ntdll – how do you like this, Google Chrome?

MS EDGE is technically much more advanced (Incredible!They immediately import native ntdll functions in the msedge.dll table) than everyone else. This is due to the fact that Microsoft knows its brainchild (Windows) better and more subtly. In addition to the one mentioned in the previous paragraph ProcessPrng in MS EDGE you additionally need to patch a similar piece of code, only with RtlGetDeviceFamilyInfoEnum (ntdll.dll) – for Windows 7 we simply return zero 0. And again, the suspicion is that dynamic loading was inserted on purpose, like a cheap stick in the wheels. PDF viewing works a little differently in the sandbox.

MS EDGE, Opera and BRAVE Not use code that sends various statistics to Google servers – the previously mentioned service call BITS with all sorts of http://edgedl.me.gvt1.com none of them had it.

Otherwise, everyone adds their own individual functionality to the open source Chromium.

Differences between x64 and x86 versions of the browser

For x86 (32 bit version) you need to additionally edit the functionality of the sandbox. Explain this difference lengths assembly code for low-level native functions like NtOpenFile on Windows 7 and Windows 10.
This is ntdll.NtOpenFile for Windows 7 (+15 is 21 bytes in decimal number system):

$ ==>    | B8 30000000      | mov eax,30                               | NtOpenFile
$+5      | 33C9             | xor ecx,ecx                              |
$+7      | 8D5424 04        | lea edx,dword ptr ss:[esp+4]             |
$+B      | 64:FF15 C0000000 | call dword ptr fs:[C0]                   | [dword ptr fs:[000000C0]]
$+12     | 83C4 04          | add esp,4                                |
$+15     | C2 1800          | ret 18                                   |

This is ntdll.NtOpenFile for Windows 10 (+C is 12 bytes in decimal number system):

$ ==> | B8 33000000              | mov eax,33              | NtOpenFile
$+5   | BA 408AA877              | mov edx,ntdll.77A88A40  | 77A88A40:
$+A   | FFD2                     | call edx                |
$+C   | C2 1800                  | ret 18                  |

In the case of “seven”, the length of ntdll.NtOpenFile (and all other Nts that are used by the sandbox) is 9 byte more.

ServiceResolverThunk::SaveOriginalFunction ASSEMBLY

ServiceResolverThunk::SaveOriginalFunction ASSEMBLY

Why am I saying this? After 110 sandbox browser version reads (ReadProcessMemory) in the created children process there is a fixed number of bytes, which is equal to 16. In the case of Windows 7, a piece of assembly code ntdll.NtOpenFile of size 5 byte(2116) is lost when reading, which leads to fatal consequences in the children process. This misunderstanding is happening somewhere in the area chromium/sandbox/win/src/service_resolver_32.cc. If the dear reader believes that in binary form, correct the implementation ServiceResolverThunk::SaveOriginalFunction much more difficult than recompiling in the same supermium – this is a fallacy. We expand the stack instead 16 read the byte immediately 32 bytes, we interrupt pointers to local variables, force memcpy copy a larger (twice) amount of data. Well, see for yourself in the attached picture from the x64dbg debugger.

Brave Software

I noticed the presence of Brave among the participants. I understand, we will sound a little strange, but why don’t you go against the established rules once (release at least one modern version for Windows 7 in 2024), because users appreciate this approach.

inc eax

Brief instructions on Google's work after the end of support for WIndows 7

Brief instructions Google’s work after the end of WIndows support 7

Yes, I know perfectly well that they exist https://github.com/win32ss/supermium With https://github.com/ungoogled-software/ungoogled-chromium And I warmly support the guys.

The presence of such projects once again reminds us that Google has curtailed “somewhere in the wrong place” with Manifest V3 and “other joys”, which are repeatedly mentioned in the links at the very beginning of this long text with pictures. Every increment majorThe ‑version of the Google browser does not bring any tangible innovations, so it is perceived as another “Advertising release”. After analyzing all the information received, perhaps one of the readers will have the thought: “Are such huge corporations in demand today in 2024, if we (end users) are already creating comfortable working conditions for them?” or “How is it that large corporations themselves create the ground for the growth of piracy?”

THANK YOU FOR YOUR ATTENTION!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *