5

I'm studying protection techniques and I've got a doubt about how ASLR works for a program in a Windows environment.

As far as I know ASLR works by randomizing part of the imagebase address when loading the module into memory so that exploits cannot rely on hardcoded addresses.

My question is: suppose that a program uses the module "kernel32.dll" and loads it into its address space. There are probably CALL instructions inside that program like

...
CALL some_address_inside_kernel32.dll
...
...

how does the program know where to jump to if kernel32.dll function addresses are no longer reliable? Does the loader intervene in this process?

2 Answers 2

9

You do not call functions inside the kernel. The kernel resides in another privilege level; its memory pages are not accessible from normal code. To jump into kernel code, application code performs a system call which entails using a specific doorway which handles the temporary privilege escalation. On a 32-bit x86 system running Linux, this is done with int 0x80: a software-triggered interrupt. The system call parameters are provided by the caller in some specific CPU registers; in particular, the %eax register contains the symbolic identifier for the system call which the application wants to perform. The interruption handler (within the kernel) looks at the CPU registers to know what the application wants the kernel to do (whether the system call is granted is yet another issue).

There is no ASLR for system calls; this is not a relevant concept here. ASLR is for DLL. A DLL is a piece of application code which is loaded into the application address space and is accessible to the application under its normal privileges; in particular, the application code can "jump" into the DLL code with a normal "jump" opcode (a function call is nothing else than a glorified jump).

Since the actual address at which the DLL will be loaded is known only when the DLL is actually loaded, application code follows special conventions so that its jump opcodes can be dynamically adjusted to point to wherever the DLL happens to be loaded. This dynamic adjustment is performed by the dynamic linker. This linker uses relocation tables to perform its job: an entry in such a table describes an opcode which needs to be adjusted, and the name of the function which the opcode tries to reach. When the DLL is loaded (by the dynamic linker), the emplacement in memory of that function is known, and the jump opcodes described in the relocation tables are adjusted.

As you see, the whole concept of DLL allows for the DLL to be loaded at an arbitrary emplacement in RAM; that emplacement may differ upon successive executions of the application. The actual emplacement depends upon where there is a sufficiently large "hole" of free memory to do the loading, so it can change depending on what the application does, how much memory it allocates previously, and so on. DLL loading "naturally" implies non-fixed loading addresses. ASLR is just voluntary moving around of DLL: the dynamic linker chooses a random (free) loading address on purpose. This is (almost) completely transparent for the applications.

3
  • Additional question for clarity - Is there any type of ASLR-like security mechanism for the kernel itself?
    – JZeolla
    Jan 18, 2013 at 19:17
  • 1
    Not to my knowledge. ASLR is a kind of hide-and-seek game meant to cope with buffer overflows: the application crashes, instead of leading to a remote shell. Buffer overflows in the kernel are considered severe enough by themselves to warrant more thorough fixes, i.e. prevent the overflow, instead of trying to live with the overflow having occurred. Jan 18, 2013 at 19:22
  • 1
    @JZeolla There is KASLR, but it is ASLR in name only. It provides very limited protection (and has been frequently criticized as security theater) due to the triviality of infoleaks. All it does is load the base of the kernel at a random offset once at boot, making all addresses moved by that same offset. The leak of a single address for a known function leaks that offset, which is not uncommon.
    – forest
    Jun 27, 2018 at 4:53
4

how does the program know where to jump to if kernel32.dll function addresses are no longer reliable? Does the loader intervene in this process?

The bear has given you the general overview of ASLR. There are a number of points specific to Windows that you need to take away, however:

  • Actually, DLLs have always had to cope with relocation. They contain a preferred base address within the address space, to the point that one previous optimisation step in developing win32 apps as to rebase your DLLs because the cost of relocating many DLLs on application launch slowed things down, since loading in many DLLs caused a lot of collisions.
  • This is in contrast to Unix's PIC approach, see wikipedia.
  • When a DLL is loaded it remains in memory until the last handle to it is closed. Given it would be inefficient to map a DLL to a unique address location per process, this means that once loaded, common system DLLs such as kernel32.dll are present at the same address in all applications. You can read more about the internals of ASLR from the excellent answers here. As such, whilst it might be hard to predict addresses in kernel32.dll across reboots, once found for a given boot, the address does not change.
  • On Windows Architecture, kernel32.dll is in fact a user mode helper library. As Thomas rightly says, system calls are needed to get to kernel mode. These in fact happen in ntdll.dll (Yes, another DLL) which wraps various Nt prefixed functions into system calls, packages them off and fires them up to the kernel.
  • Kernel drivers are loaded non-deterministically - the kernel does have ASLR. See this osr thread and this presentation. As I understand it, the windows boot managar loads ntoskrnl and hal.dll at random locations for you. Drivers since Server 2008 certainly always load non-deterministically.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .