Closed Jack-McDowell closed 3 years ago
I think this is the main issue to solve here:
When scanning the vmmem process, it appears a valid handle is being granted, even though the handle doesn't have the access requested.
Unfortunately nowadays I am extremely busy (working almost non-stop to meet some close deadlines) and I cannot dedicate much time to this. Also I cannot reproduce it in my current environment. Is it something very urgent for you? Can you provide more details, including screenshots, that could help me in troubleshooting? As much details as possible, but mostly I am interested in:
I believe there will be some possibility to determine that we cannot read the workingset at all, and this is the direction of bugfixing here.
I went with a check for whether the process name is vmmem. It's not an ideal solution, but at least it's not an urgent issue. I can try to see if I can diagnose the issue. I'll add more info as I find it
ok, as a temporary workaround - maybe not the name of the process, because it can be spoofed. but the path to the image that is mapped.
The error being returned by VirtualQueryEx
is ERROR_BAD_LENGTH
.
My access mask on the handle is 0x1410 (corresponding to Query information and VM read).
Using process hacker's kernel driver, I was able to peek at the memory of vmmem
. It appears that the only usermode memory section is 0xFFFF0000 bytes of reserved (but uncommitted) starting at address 0x10000.
As a side note, vmmem appears to be a process that mostly is used for representing the resources used by Hyper-V in running other VMs. I'm wondering if this is a result of the WinAPI not interacting well with virtualization yet...
Also - vmmem
has no mapped image. I think it's a pico process. All it has is its name.
https://devblogs.microsoft.com/oldnewthing/20180717-00/?p=99265
hmm, it seems a tough case, and it will need time and many tests to find a proper solution, which will not break other things at the same time. Maybe some redesigning of the workingset scan will be required. I will take care of this after I am done with my deadlines, but for now it unfortunately has to wait.
Basing on what you wrote, and assuming things are the way I understood, I tried to make a workaround in a new branch: https://github.com/hasherezade/pe-sieve/tree/issue_68
Please let me know if it works.
You said:
the start_va is incremented by one page size and an error message is printed.
Which error message is printed then? Isn't it this one? https://github.com/hasherezade/pe-sieve/blob/a7bfff9562c3d58f37233cc76fdd2ee0c21c8470/utils/workingset_enum.cpp#L37-L41
The error being returned by VirtualQueryEx is ERROR_BAD_LENGTH.
So, if as you said error == ERROR_BAD_LENGTH
, yet the above message is printed, it means: out != sizeof(page_info)
. I based my idea for the fix on this assumption.
Oh, my bad, I saw that was the error message being issued, and my brain went ERROR_BAD_LENGTH
. The correct error is ERROR_PARTIAL_COPY
, "Only part of a ReadProcessMemory or WriteProcessMemory request was completed."
The handle lying about its access may also have been a premature assumption I made. I'd seen it before when something I'd written was trying to read lsaiso, so I jumped to conclusions a bit here.
After playing around a bit with the debugger, it looks like the MEMORY_BASIC_INFORMATION
struct actually holds the correct data. For some reason, it's just giving that error, and pe-sieve is adding PAGE_SIZE
instead of page_info.RegionSize
. The fix should be pretty easy. Just change
if (out != sizeof(page_info) || error != ERROR_BAD_LENGTH) {
to
if (error != ERROR_PARTIAL_COPY && (out != sizeof(page_info) || error != ERROR_BAD_LENGTH)) {
Sorry about the confusion!
ok, maybe this will help then: https://github.com/hasherezade/pe-sieve/tree/issue_68a
That works! Thank you for fixing it so quickly!
oh, no. I merged a wrong branch... just a moment...
ok, should be fine now. I reworked some things, so please let me know if everything works fine. and feel free to close the issue after the passed tests.
All good now!
When scanning the vmmem process, it appears a valid handle is being granted, even though the handle doesn't have the access requested.
In
workingset_enum.cpp
, this is extremely problematic, since the entire usermode address space is enumerated. If theVirtualQuery
fails (and it does), thestart_va
is incremented by one page size and an error message is printed. While adequate for expected scenarios, this process of iterating the entire address space one page at a time, printing out an error with each page is extremely slow. For all intents and purposes, this is a scan that will never actually finish.Unfortunately, I don't think the trivial check of "is the process named vmmem" is a viable solution; what's to stop a piece of malware from calling itself vmmem?
While this is not specifically related to the problem here, it appears that this is also writing to standard error even in quiet mode rather than just reporting an error in the scan report.