Effect of changing page protection inside the code section of a DLL? - windows

I want to change the protection for the memory pages of a hole function inside a Dll to be no more executable.
Does this affect other processes which mapped the same dll into virtual address space?

TL;DR: No, it doesn't.
The NX bit works at the virtual/page level. Each process has their own virtual address space, and cannot directly affect another process' address space (barring shared memory).
Different processes can share mapped pages of a DLL. If one process alters a page, copy-on-write kicks in and that process gets a unique copy of the page, the other processes' view(s) of the DLL are unaffected.
For more information on NX, see Intel® 64 and IA-32 Architectures
Software Developer’s Manual (Volume 3A linked, 7 volumes total).
Also, here is an older but still relevant Microsoft article on copy-on-write protection.

Related

Does the existence of PAGE_EXECUTE_READWRITE as an option in VirtualAlloc mean that the W^X is only facilitated in Windows by DEP?

W^X ("write xor execute", pronounced W xor X) is a security feature in operating systems and virtual machines. It is a memory protection policy whereby every page in a process's or kernel's address space may be either writable or executable, but not both.
My basic perspective on why this is a good security feature is that the owner of the system theoretically has an opportunity to, within the kernel, or specifically within the VirtualAlloc function, to hook some analysis function to perform some security validation before allowing newly written code to be executed on the machine.
I was already familiar with DEP, but only just now realizing it has something to do with W^X in Windows:
Executable space protection on Windows is called "Data Execution Prevention" (DEP).
Under Windows XP or Server 2003 NX protection was used on critical Windows services exclusively by default. If the x86 processor supported this feature in hardware, then the NX features were turned on automatically in Windows XP/Server 2003 by default. If the feature was not supported by the x86 processor, then no protection was given.
Early implementations of DEP provided no address space layout randomization (ASLR), which allowed potential return-to-libc attacks that could have been feasibly used to disable DEP during an attack.
It was my impression that W^X applied to Windows in general, without requiring configuration of the process. But I just noticed that VirtualProtect allows the option PAGE_EXECUTE_READWRITE, which is documented as:
Enables execute, read-only, or read/write access to the committed region of pages.
This seems to entirely defy the concept of W^X. So is W^X not an enforced security policy on Windows, except when DEP is enabled?
If you turn DEP off, W^X is not enforced. When DEP is on, W^X is enforced by all memory pages that ask for it (when the hardware supports it). It is bit 63 in the page table on x86, known as the NX bit.
Now the question becomes, when is this bit set?
The PE header has a bit indicating if DEP/W^X is supported (IMAGE_DLLCHARACTERISTICS_NX_COMPAT) and if so, the code sections in the file without the write attribute gets the NX bit set when that code is mapped into memory.
For memory dynamically allocated at run-time, the developer gets to choose. PAGE_EXECUTE_READWRITE does not get the NX bit set on purpose. This is useful if they have legacy code that dynamically alters executable code while still having the DEP bit set on the PE so the majority of their code is W^X.
Early x86 CPUs had no support for pages without eXec permission. In legacy 32-bit x86 page tables, there was only a bit for write permission, the R/W bit. (Read permission is always implicit in the page being valid, whether the page is writeable or not). The PAE format for page-table entries, which x86-64 also uses, added an NX bit ("no exec"), aka XD (eXecute Disable).
An OS still had to decide which pages to make non-executable.
Windows seems to use DEP to describe the feature of actually mapping logical page permissions to the hardware page tables, to be enforced by the CPU.
Some programs written in the bad old days when every readable page was executable may have been sloppy about telling the OS that they wanted a page to be executable. Especially ones that only targeted 32-bit x86. This is what Windows caters for by requiring executables to opt in to DEP, to indicate that they're aware of and compatible with not having exec permission for pages that aren't explicitly marked that way.
Some OSes, notably OpenBSD, truly enforce W^X. For example, mmap(..., PROT_WRITE | PROT_EXEC, ...) will return an error on OpenBSD. Their mmap(2) man page documents that such an mmap or mprotect system call will return
[ENOTSUP] The accesses requested in the prot argument are not allowed. In particular, PROT_WRITE | PROT_EXEC mappings are not permitted unless the filesystem is mounted wxallowed and the process is link-time tagged with wxneeded. (See also kern.wxabort in sysctl(2) for a method to diagnose failure).
Most other OSes (including Linux and Windows) allow user-space to create pages that are writeable and executable at the same time. But the standard toolchains and dynamic linking mechanisms aim for W^X compliance by default, if you don't use any options like gcc -zexecstack that will get the OS to create a process image with some R|W|X pages.
Older 32-bit x86 Linux for example used to use PLT entries (dynamic linking stubs) with jmp rel32 direct jumps, and rewrite the machine code to have the right displacement to reach wherever the shared library got loaded in memory. But these days, the PLT code uses indirect jumps (through the GOT = global offset table), so the executable PLT code can be in read-only page(s).
Changes like this have weeded out any need for write+exec pages in a normal process built with the standard tools.
But on Windows, MacOS, and Linux, W^X is not enforced by the OS. System calls like Windows VirtualAlloc / VirtualProtect and their POSIX equivalents mmap / mprotect will work just fine.
#Ander's answer says DEP does not enforce W^X, just gets the OS to respect the exec permission settings in the executable when creating the initial mappings for .text / .data / .bss and stack space, and stuff like that during process startup.

Does Windows map DLLs to the same virtual address in different processes?

Say two processes are using Kernel32.dll, does Windows map the DLLs to the same virtual address space in both processes? If not, how does paging mechanism end up using the same physical address where the DLL is in fact loaded for both processes? I tried finding this info in the windows internals book but didn't find anything
TL;DR: No, it might be loaded somewhere else in another process.
Ntdll and Kernel32 are special and always load at the same address so it is better to focus on something else, Shell32 for example.
A dll has what is known as a preferred base address and this is stored in the PE header (ImageBase). The loader will first attempt to load the dll at this address. If that address range is free then loading will succeed with no extra work required.
If the address is not free then the loader has to load it somewhere else. Loading at a different address usually requires relocation information and if this was removed during linking (/FIXED) then loading will fail! If there was space somewhere else to load the dll, the loader will use the relocation information to patch the given locations in the dll with the new base address. Because dlls are loaded as copy-on-write, this will cause extra memory usage compared to loading at the preferred address since each memory page that needed a patch is now a private copy in the process. This means that the answer to your question is no, a dll might not load at the same address in a different process if that process already has something else loaded there.
So far I have only talked about the loader. The loader is implemented in Ntdll as normal usermode code and is not involved with how a file mapped into memory actually works. Memory mapped files (known as Sections internally in NT) is a co-operation between the operating system kernel and the CPU hardware. This is a whole topic in of itself but the important thing to know is that physical memory and the page/swap file mechanism is completely disconnected from how a usermode process accesses its virtual memory pages. The kernel can map a physical memory page to zero, one, or multiple places in a processes virtual memory and the CPU will automatically translate when a virtual page is accessed by the process.
As a final note, ASLR does complicate things a little bit but the "offset" only changes on reboot and should not have an impact on this specific question in current implementations. In theory Windows could change this in the future and always load things at different addresses in different processes but this is unlikely to happen because of the copy-on-write downsides.

Is the same DLL guaranteed to be mapped to the same virtual address in every process using it?

I'm studying Windows system internals and the question is just a guess.
I learn that DLL is a form of shared libraries, so at least the code section of the same DLL is shared between processes using it. (By adding the same page entries into the page table of these processes) The code section usually has something like jump tables, which need to be relocated (i.e. write the run-time virtual address to fix the pointer) before it's ready to be executed.
Assume that the same DLL aa.dll is mapped in two different processes at different virtual addresses. (e.g. a.exe 0x00400000 b.exe 0x00410000) The same pointer (at .text+0x100) will be fixed into different addresses. (e.g. a.exe 0x00400100 b.exe 0x004100100). So we have to make a copy of the code section and change it to adapt one process. Then how can the code section be shared?
Am I right?
Answering my own question. The first time a DLL is loaded, Windows would try to load it at the Preferred address which would not require relocation (i.e. fixing addresses due to the fact that code segment is located at x). If it cannot be loaded at the preferred address, it would be allocated virtual pages at a free address backed up by the DLL file itself (not swap file) but marked as Copy-On-Write. Now Windows has to go and fix up the assembly code using the relocation table. Hopefully only a small percentage of code needs to be fixed up and each code segment that is changed would be copied on write and put into physical memory somewhere.
Each time a process cannot load a DLL at the preferred address, I believe this process would happen. This is why sometimes popular DLLs need to be rebased so that their preferred addresses don't conflict.

Does visual studio show virtual or physical address while debugging?

Image demonstrating the memory window while debugging
When using the memory window in visual studio, do we see the virtual address of that process or the physical address of RAM?
User-level code always sees virtual addresses. It has no way to know what physical address (if any!) presently corresponds to one of these addresses. "Virtual" is the only world that it lives in, and the only one that it ever knows. For all of a program's intents and purposes, "virtual is reality."
To clarify: all operating systems (except MS-DOS and the like ...) run user programs in a virtual memory space. Each program has its own perception of what "location $12345678 contains," and each program's perception is, for it, correct. Each program can have a different number there, and can change it at its own pleasure.
They can do this because none of them actually know:
Where, in physical memory, "their 'location $12345678'" actually resides. (If it does ... and quite-possibly it doesn't!)
What is in physical address $12345678.
The operating system maintains virtual memory for each process, using a combination of physical-RAM and (if necessary) page-file and/or swap-file space. Information that is actively being used by a process is made available to it "on demand," at a physical RAM-location that is both unknown to it and unknowable by it. Information that has not recently been used is eventually "stolen" from physical RAM and moved to external storage ... until it is referenced again, triggering what is known as a "page fault."
The memory view that is given to you by a debugger is the memory view that is perceived by and that is correct for the program being debugged: virtual addresses, in the process's virtual memory.

Microsoft's ASLR is weird

I watched a ASLRed dll images's based address for 32bit Process.
It's not a fully randomization. It just randomizated 1/2 probability.
For example, once I load a dll then the image is loaded on 0x12345678.
And I load the image again, the image is loaded on 0x23456789.(Base address is changed!)
But I load the image again
0x12345678
0x23456789
0x12345678
0x23456789
...
Why they did implement like this?
Is it for a crash report's frequency?(For getting same crash addresses of re-deployed dlls)
This is by design. Normally, Windows selects a preferred base address for an ASLR DLL when the DLL is first loaded, and then it keeps using that address until the system is rebooted. That way the DLL will be mapped at the same address in every process that loads it, allowing code pages to be shared.
However, if a DLL has been unloaded from every process, the system may sometimes select a different base address the next time the DLL is loaded. It does this to reduce virtual address space fragmentation, not for security reasons. This is what seems to be happening in your case.
It's documented as being at one of 1 of 256 possible starting addresses.
But i didn't think it even applied to a process, but to shared DLL's.
ASLR: is not on by default for process images. It's an opt-in thing, for compatiblity.(3)
Address Space Layout Randomization
(ASLR)
ASLR moves executable images into
random locations when a system boots,
making it harder for exploit code to
operate predictably. For a component
to support ASLR, all components that
it loads must also support ASLR. For
example, if A.exe consumes B.dll and
C.dll, all three must support ASLR. By
default, Windows Vista and later will
randomize system DLLs and EXEs, but
DLLs and EXEs created by ISVs must opt
in to support ASLR using the
/DYNAMICBASE linker option.
ASLR also randomizes heap and stack
memory:
When an application creates a heap in
Windows Vista and later, the heap
manager will create that heap at a
random location to help reduce the
chance that an attempt to exploit a
heap-based buffer overrun succeeds.
Heap randomization is enabled by
default for all applications running
on Windows Vista and later.
When a
thread starts in a process linked with
/DYNAMICBASE, Windows Vista and later
moves the thread's stack to a random
location to help reduce the chance
that a stack-based buffer overrun
exploit will succeed.
Had installed new Win8 RC x64 yesterday.
Watch out!
Kernel32.dll (64-bit version) have different base address in different processes (in single session, of course). Only ntdll.dll base address remains constant. I had to change the code, you can no longer rely on the permanent address Loadlibrary.

Resources