Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

UEFI Bootkit with user-mode communication

NotificationsYou must be signed in to change notification settings

3a1/Calypso

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Calypso

Calypso

A lightweight UEFI Bootkit with user-mode communication

General

  • Written in C++ and assembly
  • Compiled binary is just 7 KB in size
  • Usermode communication
  • KPP Safe (Kernel Patch Guard)
  • EDK2 library reduced to minimal (only the necessary)

Features

  • Read/Write Kernel Memory
  • Read/Write Process Memory (MMU translation)
  • Kill Protected Process
  • Process Privilege Escalation (LPE)

You can probably build any feature you want since you can directly call any exported function fromntoskrnl.exe.The bootkit is designed to work onWindows 10 22H2. However, the offsets are hardcoded, so to make it work on other versions, you’ll need to update the offsets accordingly.

Workflow

Calypso

UefiMain

InUefiMain, the bootkit perfoms two main tasks.One is to save originalExitBootServices address to restore it later and place anExitBootServices hook to redirect calls toExitBootServicesWrapper.Second is to create aSetVirtualAddressMap event which we will explain later why it is needed.

ExitBootServices Wrapper (asm)

InExitBootServicesWrapper the goal is to retrieve the return address from theRSP register.Once the return address is obtained, execution is passed to theExitBootServicesHook.This is why we can't use theExitBootServices event - in an event we cannot access the return address.

ExitBootServices Hook

InExitBootServicesHook the goal is to locatewinload.efi base. SinceExitBootServices is called fromwinload.efi,and we have its return address, we know it points to a location somewhere insidewinload.efi.Executable images are always loaded at the start of a memory page (0x1000), so the base address will always end with three zeros.Additionally, all executable images have a DOS header at the beggining, which starts with a specific magic value.With this knowledge, we can iterate backward through memory, page by page, reading the first bytes of each page andchecking for the DOS magic value to identify the base address.

The next step is to locate theOslArchTransferToKernel address.Why do we needOslArchTransferToKernel? This function is called whenwinload.efi exits, and it passestheLoaderBlock address. In theLoaderBlock structure, we can find theLoadOrderListHead list,which contains the address ofntoskrnl.exe. To avhieve this, we use a simple pattern scan to identify theOslArchTransferToKernel address and hook it.

SetVirtualAddressMap Event

Remember the event we created inUefiMain? Now is the time for it to start.The purpose of this event is to convert address of our function hook from physical to virtual.Up to this point, the system operates only in physical memory without virtual address space.I'll provide more details in the next stage.

OslArchTransferToKernel Hook

At this point, we have theLoaderBlock address, and we traverse theLIST_ENTRY structure to locate thentoskrnl.exe base.Once we have thentoskrnl.exe base, the next step is to decide which function in the OS kernel to hook.

I choose theNtUnloadKey function for couple of reasons.

First, we need to keep in mind that we aim to establish communication between user-mode and the UEFI driver.For this purpose, our kernel function needs to be executed as a syscall from thentdll.dll user-mode library.

As I mentioned, i chose this function for several reasons, with the second and primary one that it is just wrapper forCmUnloadKey function.What does this means?As you might know, Windows has a security feature calledKernel Patch Guard (KPP).The purpose of KPP is to scan kernel memory for changes and trigger a blue screen if any are detected.We bypass this feature by patching the OS kernel before it gets executed, so PatchGuard compares the alreadypatchedntosrknl with the one in memory for any changes (believing that the patched one is the correct version).However, the problem that when hooking a function with a trampoline, the hooked function first jumps to the hook, performsits work, restores the modified bytes, calls the original function again and then re-applies the trampoline jump before returning.With KPP in place, we can't unhook the function because modifying the OS kernel at runtime would trigger KPP.

Here's where it gets complicated, we can't directly call the original function. Instead, we need to find a way to replacethe functionality of the original function. A function that acts as a wrapper to another function is ideal in this case.By calling this wrapper function inside our kernel hook, it will effectively replace the original function's functionality.Of course, we could just hook it without saving the original functionallity, but if function is important and called by the OS,we need to ensure it still performs as expected.

The next stage in this hook is to locate the function that callsNtUnloadKey and its original call toCmUnloadKey.Once we have identified this, we proceed by hookingNtUnloadKey.

Here's the tricky part, we can't directly hook it here because we're are dealing with physical memory addresses.Our localNtUnloadKeyHook address is physical, and when the system completes the boot process, it will translate to virtualaddresses, making that our hook won't work. This is whereSetVirtualAddressMap event comes in. Inside it, we can translateout local function hook into a virtual memory address, ensuring that the hook will work after OS will translate into virtual memory space.

NtUnloadKey Hook

In this function we simply check if the passed parameter is our command structure, if it's not, we return toCmUnloadKey,mimicking the behavior of the original function. If it is our command, we pass the execution to thedispatcher.

Usermode

As we remember, theNtUnloadKey function fromntdll.dll is a syscall to theNtUnloadKey insidentoskrnl.exe.So, Usermode can interact with ourNtUnloadKey hook placed insidentoskrnl.exe by calling theNtUnloadKey fromntdll.dll.Overall in usermode is nothing fancy, usermode is very simple and gets its job done.

Usage

You can check usage onYoutube.

Credits

This project is inspired by and builds upon the following repositories:

About

UEFI Bootkit with user-mode communication

Topics

Resources

Stars

Watchers

Forks

Languages


[8]ページ先頭

©2009-2025 Movatter.jp