On Wed, Dec 18, 2019 at 4:24 PM Ken Thomases ken@codeweavers.com wrote:
I wonder if it wouldn't be good enough to just use the current page protection. If a page allows access, you have to assume another thread could access it at any time. So, we could just pretend one has.
It is not true that you have to assume another thread could access it at any time. If a thread allocates a page of memory, and does not share the pointer to that memory, then it should be able to assume no other threads will access it. When this assumption breaks on Windows, it is usually because of anti-virus or similar programs and that is why these are not supported by some anti-cheat systems.
NOACCESS or GUARD -> invalid anything else -> valid
Do you happen to know if that would satisfy League of Legends?
I did some more research and found some public research that discusses this anti-debugging technique (e.g. http://everdox.blogspot.com/2013/03/utilizing-paged-virtual-memory-as-anti.h...). And to quote the blog of someone involved with League of Legends:
"Our trick relies on the fact that Windows, as an optimization, will not commit virtual memory to physical RAM unless it absolutely needs it. [...] So, we can detect the memory read on this adjacent page by inspecting the corresponding PTE (Page Table Entry) using the QueryWorkingSetEx API. If the page is resident in our process' working set (e.g. mapped into our process by the debugger), the Valid bit in the _PSAPI_WORKING_SET_EX_BLOCK will be set."
However, I agree that we can probably relax the semantics that I described previously. I will still use /proc/pid/pagemaps to determine if a page has been accessed (if not then it is "Invalid"). I will ignore the complex case of modifying the page protections to NOACCESS and back. I'm hoping this will be sufficient for both bug 45667 and bug 48268.
-Andrew