Providing seperate kernel32.dll to a process

Hello,

I’m developing process monitoring idea and I would like to hook accesses to kernel32.dll (and some other dll’s as well), I hook the physical pages of the dll (from hypervisor) but unfortunately my process is not the only one who uses the dll so it causes a lot of overhead.

I want to use my own kernel32.dll instance, I use pssetloadimagenotifyroutine to see all the images that load to my process. I tried to do some tricks using the copy-on-write system so it will rallocate new memory to the pages but it didn’t really work since it blocked me from writing to the image (bsod).

Also I saw that I get image_info struct from the pssetloadimagenotifyroutine callback but after some research it seems it doesn’t effect anything in the system if I modify it.

Is there a way to do it without massivelly interfere with the system code?

You need to change the virtual address range protection from PAGE_EXECUTE_READ to PAGE_EXECUTE_WRITECOPY. NtProtectVirtualMemory/ZwProtectVirtualMemory does this. The bad news it is not exported by the kernel, though it can be located by some “disassembling” technique “embedded” in a driver.

>The bad news it is not exported by the kernel, though it can be located by

some “disassembling” technique “embedded” in a driver.

It is exported but if it weren’t you could get the address simply by
downloading the symbols.

Not that I’m endorsing these plans, but perhaps you could get your process
to load another copy of kernel32.dll by means of a file-system filter.

//Daniel

No, it is not

dumpbin /EXPORTS c:\windows\system32\ntoskrnl.exe

1073 430 0049D0C0 NtOpenTransactionManager
1074 431 004A3C20 NtPrePrepareComplete
1075 432 004CAD90 NtPrePrepareEnlistment
1076 433 004A3CD0 NtPrepareComplete
1077 434 004CAE40 NtPrepareEnlistment
1078 435 004D1E20 NtPropagationComplete
1079 436 004A1C50 NtPropagationFailed
1080 437 0035D980 NtQueryDirectoryFile

I’ve managed to get the Zw version.

if (KeGetCurrentIrql() == PASSIVE_LEVEL) {
DbgPrint(“Passive level”);

UNICODE_STRING pText;
// Obtain address to ZwProtectVirtualMemory
RtlInitUnicodeString(&pText, L"ZwProtectVirtualMemory");
auto NtProtect = MmGetSystemRoutineAddress(&pText);
DbgPrint(“ZwProtectVirtualMemory: %p”, NtProtect);
}

I will try this solution and will reply.

I know I can do this with filesystem filter driver (I’ve already done it in the past with dokan) but it’s a little of overhead to use new driver for this purpose only.

>No, it is not

It is in mine, so they probably only started exporting this at some point.

dumpbin /EXPORTS c:\windows\system32\ntoskrnl.exe

2493 9B9 00149410 ZwPropagationFailed
2494 9BA 00147890 ZwProtectVirtualMemory
2495 9BB 00149430 ZwPulseEvent

//Daniel

> It is in mine

Missing in mine

1895 766 0006AA00 ZwOpenTransaction
1896 767 0006AA20 ZwOpenTransactionManager
1897 768 00069580 ZwPowerInformation
1898 769 0006AA60 ZwPrePrepareComplete
1899 76A 0006AA80 ZwPrePrepareEnlistment
1900 76B 0006AAA0 ZwPrepareComplete
1901 76C 0006AAC0 ZwPrepareEnlistment
1902 76D 0006AB40 ZwPropagationComplete
1903 76E 0006AB60 ZwPropagationFailed
1904 76F 0006AB80 ZwPulseEvent
1905 770 0006ABA0 ZwQueryBootEntryOrder

so they probably only started exporting this at some point.

Mine is Win7 x64

Hmm ok so i’m having some trouble with changing the protections, I’m using ZwProtectVirtualMemory (on windows 10 x64) the following way:

eStatus = ZwProtect(PsGetProcessId(process), &base_address, (PULONG)&page_size, PAGE_EXECUTE_WRITECOPY, &old_access);

The following return on kernel32.dll (and all the other dll’s):
eStatus = c0000008 (STATUS_INVALID_HANDLE)
The handle I pass seems to be correct (- it’s the pid of the process - checked)

the base_address is right (double checked with windbg)

the page_size variable I correct (check in windbg) and from type ULONGLONG.

Now, I changed the page_size variable type from ULONG to ULONGLONG because I thought it might changed in 64bit. If I use the ULONG type it return the error: STATUS_INVALID_PARAMETER_3

from checking reactos & ida - https://doxygen.reactos.org/d2/dfa/ntoskrnl_2mm_2ARM3_2virtual_8c.html#a2cab978ee136ac00a0c06b56aa9170ef

It doesn’t seems like it should be failed in this error - unless it gets 0 (or another check) in the size -> which I thought it happens because of the wrong size of ULONG so I used ULONGLONG instead.

Any idea what type of size I need to use & what can cause this errors?

It should be a valid handle for a process object or NtCurrentProcess() not a PID.
If you have a process object use ObOpenObjectByPointer to get a handle.

ObOpenObjectByPointer( Process,
OBJ_KERNEL_HANDLE,
NULL,
PROCESS_ALL_ACCESS,
*PsProcessType,
KernelMode,
&ProcessHandle );

It does work for ntdll.dll but does not work for kernel32.dll / wow64 / user32.dll / kernelbase.dll.

the return value is c0000045 which is STATUS_INVALID_PAGE_PROTECTION.

It also return in the old accesses 1 (NO_ACCESS) permission - although the function failed.

If PAGE_EXECUTE_WRITECOPY failed try PAGE_EXECUTE_READWRITE. It might happen you are trying to modify a private portion of the address space which is not backed by a mapped file so COW is not supported for it.

Unfortunately it doesn’t seems to work, I noticed that if you iterate the header of the dll (pe header) it have access of 2 (PAGE_READONLY), the code have 20 (PAGE_EXECUTE_READ) access, also trying to set the exisiting protection failed - works only for the pe header. the code keeps returning the same error.

So I couldn’t really figure a solution for this,

Is there a way to “reload” the same dll (to overwrite the existing one) to a process but allocating it on seperate memory?

Why couldn’t you change the protection of memory pages within a mapped binary ?

The loader does this to resolve a binary dependencies.

My guess is that you are trying to change the protection of different regions of pages within the mapped binary. These are pages that have different protections. You must first query the size of the region a page belongs to before changing its protection. See VirtualQuery documentation.



I just refuse to believe my own eyes - this is already a second hooking-related thread in less than a week, but still I don’t see any reaction from “TELL US YOUR NAME AND COMPANY… (etc)” folks in so far.t If things keep on going this way I would not be too surprised if those who
consider using Bo Branten’s Filedisk (or whatever it is called) are left unadvised about the possible legal ramifications of such a bold move…

Anton Bassov

If you’re going to hook kernel32.dll, why not hook from user mode? I’m assuming you have code in the memory space of the target process anyway since you need somewhere for those hooks to go.

VirtualProtect is definitely available in user mode and modifying kernel32 from the context of a user app will not negatively impact other processes.

xxxxx@hotmail.com wrote:


>
> I just refuse to believe my own eyes - this is already a second hooking-related thread in less than a week, but still I don’t see any reaction from “TELL US YOUR NAME AND COMPANY… (etc)” folks in so far.t If things keep on going this way I would not be too surprised if those who
> consider using Bo Branten’s Filedisk (or whatever it is called) are left unadvised about the possible legal ramifications of such a bold move…
>
>

+1 for totally unnecessary provocative post of the week.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

> +1 for totally unnecessary provocative post of the week.

Sorry, guys,but I just could not resist the temptation this time - as you must have noticed it yourself, these days I try my best to behave However,in some cases the temptation is just too strong to resist.
Let’s face it - a thread like that without a “strong reaction” from certain posters is highly unusual,don’t you think…

Anton Bassov

xxxxx@gmail.com wrote:

So I couldn’t really figure a solution for this,

Is there a way to “reload” the same dll (to overwrite the existing one) to a process but allocating it on seperate memory?

Do you recognize the inherent conflict in “overwrite the existing one”
and “allocating it on separate memory”?

Kernel32.dll is special. You can do hooking to redirect some of the
entry points, but you can’t reload it.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.