Shadow API技术

《深入浅出Windows API程序设计:核心编程篇》这本书介绍了Shadow API技术,此技术可以起到隐藏api调用的作用,从而显著增加调试和逆向的难度。

但是里面给的示例代码由于严重依赖于操作系统版本,不要说Win11,在部分Win10上都会出现崩溃,这很不利于学习。

所以我在Win11上重新进行了实现,分析崩溃原因时发现Win11上的MessageBoxW已经不再是直接call MessageBoxTimeOutW,而是直接call了一个位置:

复制代码
760B8840 8B FF                mov         edi,edi  
760B8842 55                   push        ebp  
760B8843 8B EC                mov         ebp,esp  
760B8845 83 3D 84 8C 0E 76 00 cmp         dword ptr ds:[760E8C84h],0  
760B884C 74 22                je          760B8870  
760B884E 64 A1 18 00 00 00    mov         eax,dword ptr fs:[00000018h]  
760B8854 BA 00 93 0E 76       mov         edx,760E9300h  
760B8859 8B 48 24             mov         ecx,dword ptr [eax+24h]  
760B885C 33 C0                xor         eax,eax  
760B885E F0 0F B1 0A          lock cmpxchg dword ptr [edx],ecx  
760B8862 85 C0                test        eax,eax  
760B8864 75 0A                jne         760B8870  
760B8866 C7 05 20 8D 0E 76 01 00 00 00 mov         dword ptr ds:[760E8D20h],1  
760B8870 6A FF                push        0FFFFFFFFh  
760B8872 6A 00                push        0  
760B8874 FF 75 14             push        dword ptr [ebp+14h]  
760B8877 FF 75 10             push        dword ptr [ebp+10h]  
760B887A FF 75 0C             push        dword ptr [ebp+0Ch]  
760B887D FF 75 08             push        dword ptr [ebp+8]  
760B8880 E8 0B FE FF FF       call        760B8690  ; 重点
760B8885 5D                   pop         ebp  
760B8886 C2 10 00             ret         10h

所以按照书中原来的思路是肯定不行的,需要自己手动修正新代码的偏移。

本人修复后的例子如下,同时也对代码风格进行了部分现代化(如积极使用using、nullptr、增加返回值检查):

cpp 复制代码
#include <windows.h>
#include "resource.h"

using PFN_MESSAGEBOXW = int (WINAPI *)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);

// 函数声明
INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
   DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, DialogProc, NULL);
   return 0;
}

INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   HMODULE hUser32 = NULL;
   PFN_MESSAGEBOXW pfnMessageBoxW = nullptr;
   static PFN_MESSAGEBOXW pfnNewMessageBoxW = nullptr;   // 分配内存空间存放MessageBoxW函数机器码
   BYTE bArr[74] = { 0 };                                // 存放MessageBoxW函数实现代码的缓冲区
   PBYTE pMessageBoxInnerCall = nullptr;
   PBYTE pMyMessageBoxInnerCall = nullptr;
   UINT_PTR uOffset = 0;

   switch (uMsg)
   {
   case WM_INITDIALOG:
      // 获取MessageBoxW函数的地址,并读取函数数据
      hUser32 = GetModuleHandle(TEXT("User32.dll"));
      if (!hUser32)
      {
          return TRUE;
      }
      pfnMessageBoxW = (PFN_MESSAGEBOXW)GetProcAddress(hUser32,
         "MessageBoxW");
      if (!pfnMessageBoxW)
      {
          return TRUE;
      }
      if (!ReadProcessMemory(GetCurrentProcess(), pfnMessageBoxW, bArr, sizeof(bArr), NULL))
      {
          return TRUE;
      }

      // 分配内存空间存放MessageBoxW函数,可读可写可执行
      pfnNewMessageBoxW = (PFN_MESSAGEBOXW)VirtualAlloc(NULL, sizeof(bArr), MEM_RESERVE | MEM_COMMIT,
         PAGE_EXECUTE_READWRITE);
      if (!pfnNewMessageBoxW)
      {
          return TRUE;
      }
      if (!WriteProcessMemory(GetCurrentProcess(), pfnNewMessageBoxW, bArr, sizeof(bArr), NULL))
      {
          return TRUE;
      }

      // 获取MessageBoxW中Call的位置,获取call指令中的偏移
      pMessageBoxInnerCall = (PBYTE)pfnMessageBoxW + 0x40;
      if (!ReadProcessMemory(GetCurrentProcess(), pMessageBoxInnerCall + 1, &uOffset, sizeof(uOffset), nullptr))
      {
          return TRUE;
      }
      uOffset += (UINT_PTR)pMessageBoxInnerCall;

      // 获取NewMessageBoxW中Call的位置,修正call指令中的偏移
      pMyMessageBoxInnerCall = (PBYTE)pfnNewMessageBoxW + 0x40;
      uOffset = uOffset - (UINT)pMyMessageBoxInnerCall;
      WriteProcessMemory(GetCurrentProcess(), pMyMessageBoxInnerCall + 1, &uOffset, sizeof(uOffset), nullptr);
      return TRUE;

   case WM_COMMAND:
      switch (LOWORD(wParam))
      {
      case IDC_BTN_OK:
         // 如果在调试器中对MessageBoxW函数下了int3断点,有可能第一个字节被修改为0xCC
         if (*(LPBYTE)pfnNewMessageBoxW == 0xCC)
            *(LPBYTE)pfnNewMessageBoxW = 0x8B;
         pfnNewMessageBoxW(hwndDlg, TEXT("内容"), TEXT("标题"), MB_OK);
         break;

      case IDCANCEL:
         EndDialog(hwndDlg, 0);
         break;
      }
      return TRUE;
   }

   return FALSE;
}

上面的代码在Win11 22H2自测通过,Debug版和Release版都可以,Debug版的区别就是MessageBoxW函数短一点,但是关键的call偏移没有变。

相关推荐
ShineWinsu14 分钟前
对于C++:继承的解析—上
开发语言·数据结构·c++·算法·面试·笔试·继承
码农阿豪35 分钟前
Nacos 日志与 Raft 数据清理指南:如何安全释放磁盘空间
java·安全·nacos
国科安芯37 分钟前
芯片抗单粒子性能研究及其在商业卫星测传一体机中的应用
嵌入式硬件·安全·fpga开发·性能优化·硬件架构
黑果魏叔37 分钟前
手滑点错更新也不怕!超详细 Mac 系统更新屏蔽指南(附安全恢复方案)
安全·macos
绿蕉38 分钟前
飞机与高铁,谁更安全?——基于中国出行死亡数据的深度对比分析
安全·飞机·高铁
左手厨刀右手茼蒿42 分钟前
Flutter for OpenHarmony: Flutter 三方库 hashlib 为鸿蒙应用提供军用级加密哈希算法支持(安全数据完整性卫士)
安全·flutter·华为·c#·哈希算法·linq·harmonyos
星河耀银海43 分钟前
人工智能大模型的安全与隐私保护:技术防御与合规实践
人工智能·安全·ai·隐私
王码码203543 分钟前
Flutter for OpenHarmony: Flutter 三方库 cryptography 在鸿蒙上实现金融级现代加解密(高性能安全库)
android·安全·flutter·华为·金融·harmonyos
消失的旧时光-19431 小时前
C++ 多线程与并发系统取向(二)—— 资源保护:std::mutex 与 RAII(类比 Java synchronized)
java·开发语言·c++·并发
抓饼先生3 小时前
iceoryx编译和验证
linux·c++·零拷贝·iceoryx