LookupXRef_在重定位数据中查找所有引用 SymAddr 的地址

本文提供了一个查找模块内特定符号地址的所有引用位置的实现方法。通过遍历重定位块,找到指向该符号地址的所有指令地址,适用于Hook操作等场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 
// 在重定位数据中查找所有引用 SymAddr 的地址
// ex: mov eax, [g_hModule]       ; SymAddr 即 [] 中的数字,而要查找的是 [] 所在的“位置”
// 如果进行查找是个地址表或是函数地址,那进行 hook 操作将会更隐秘一些(一般都是和GetImageImpSym顺序使用 )

// BOOLEAN NTAPI LookupXRefCallback(PULONG RefAddr)
// {
//   // 返回 True 继续寻找,返回 False 停止寻找
//   printf("%08X --> %08X", RefAddr, RefAddr[0]);
//
//   return TRUE;
// }

ULONG NTAPI // 返回找到的引用个数
pLookupImageXRef(
   IN ULONG ImageBase, // 参考地址
   IN PIMAGE_DATA_DIRECTORY pBrDir,
   IN PIMAGE_BASE_RELOCATION pBr,
   IN ULONG SymAddr,
   IN LOOPUPXREF_CALLBACK LookupXRefCallback // 回调
   )
{
   ULONG nRefCount = 0;

   __try
   {
       ULONG Size = 0;
       while ( pBr->SizeOfBlock != 0 && Size < pBrDir->Size )
       {
           PWORD pRelItem = (PWORD)(pBr + 1);
           PIMAGE_BASE_RELOCATION pNextBr = (PIMAGE_BASE_RELOCATION)((ULONG)pBr + pBr->SizeOfBlock);

           while ( (ULONG)pRelItem < (ULONG)pNextBr )
           {
               if ( (pRelItem[0] >> 12) == 3 )
               {
                   PULONG RefAddr = (PULONG)(ImageBase + pBr->VirtualAddress + (pRelItem[0] & 0x0FFF));
                   if (
                       MmIsAddressValid(RefAddr) && // 验证内存是否有效
                       *RefAddr == SymAddr &&
                       LookupXRefCallback(RefAddr)
                       )
                   {
                       nRefCount++;
                   }
               }
              
               pRelItem++;
           }
          
           Size += pBr->SizeOfBlock;
           pBr = pNextBr;
       }
   }
   __except ( EXCEPTION_EXECUTE_HANDLER )
   {
       DbgPrint("pLookupImageXRef: Found a Exception!/n");
   }
  
   return nRefCount;
}

ULONG NTAPI
LookupImageXRef(
   IN ULONG ImageBase, // 有效地址
   IN ULONG SymAddr,
   IN LOOPUPXREF_CALLBACK LookupXRefCallback // 回调
   )
{
   if ( LookupXRefCallback != NULL )
   {
       PIMAGE_DATA_DIRECTORY pBrDir;
       PIMAGE_BASE_RELOCATION pBr;
      
       pBr = GetImageDirEntry(ImageBase, IMAGE_DIRECTORY_ENTRY_BASERELOC, NULL, &pBrDir);
       if ( pBr != NULL )
       {
           return pLookupImageXRef(ImageBase, pBrDir, pBr, SymAddr, LookupXRefCallback);
       }
   }

   return 0;
}

ULONG NTAPI
LookupFileXRef(
   IN PCWSTR pszFileName,
   IN ULONG ImageBase, // 参考基址
   IN ULONG SymAddr,
   IN LOOPUPXREF_CALLBACK LookupXRefCallback // 回调
)
{
   NTSTATUS Status;
   HANDLE FileHandle;
   OBJECT_ATTRIBUTES ObAttr;
   UNICODE_STRING usFileName;
   IO_STATUS_BLOCK IoStatus;
   LARGE_INTEGER FilePos;
   IMAGE_DOS_HEADER DosHeader;
   IMAGE_NT_HEADERS NtHeader;
   IMAGE_SECTION_HEADER SectHeader;
   IMAGE_DATA_DIRECTORY BrDir;
   PIMAGE_BASE_RELOCATION pBr;
   ULONG nSection, nRefCount;

   RtlInitUnicodeString(&usFileName, pszFileName);
   InitializeObjectAttributes(
       &ObAttr,
       &usFileName,
       OBJ_CASE_INSENSITIVE,
       NULL,
       NULL
       );
  
   Status = ZwOpenFile(
       &FileHandle,
       GENERIC_READ,
       &ObAttr,
       &IoStatus,
       FILE_SHARE_READ,
       0
       );
   if ( !NT_SUCCESS(Status) )
   {
       return 0;
   }
  
   //
   // 读出 Dos header
   FilePos.QuadPart = 0;
   Status = ZwReadFile(
       FileHandle,
       NULL,
       NULL,
       NULL,
       &IoStatus,
       &DosHeader,
       sizeof (DosHeader),
       &FilePos,
       NULL
       );
   if ( !NT_SUCCESS(Status) || DosHeader.e_magic != IMAGE_DOS_SIGNATURE )
   {
       ZwClose(FileHandle);
       return 0;
   }
  
   // 读出 nt header
   FilePos.LowPart = DosHeader.e_lfanew;
   Status = ZwReadFile(
       FileHandle,
       NULL,
       NULL,
       NULL,
       &IoStatus,
       &NtHeader,
       sizeof (NtHeader),
       &FilePos,
       NULL
       );
   if ( !NT_SUCCESS(Status) || NtHeader.Signature != IMAGE_NT_SIGNATURE )
   {
       ZwClose(FileHandle);
       return 0;
   }
  
   //
   // 验证重定位信息
   BrDir = NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
   if ( BrDir.VirtualAddress == 0 || BrDir.Size == 0 )
   {
       ZwClose(FileHandle);
       return 0;
   }
  
   //
   // 获取 重定位信息 的 raw
   FilePos.LowPart = DosHeader.e_lfanew + sizeof (NtHeader);
   FilePos.LowPart += NtHeader.FileHeader.SizeOfOptionalHeader - sizeof (IMAGE_OPTIONAL_HEADER);

   for ( nSection = 0; nSection < NtHeader.FileHeader.NumberOfSections; nSection++ )
   {
       const ULONG PointerSectionHeader = FilePos.LowPart;

       Status = ZwReadFile(
           FileHandle,
           NULL,
           NULL,
           NULL,
           &IoStatus,
           &SectHeader,
           sizeof (SectHeader),
           &FilePos,
           NULL
           );
       if ( !NT_SUCCESS(Status) )
       {
           ZwClose(FileHandle);
           return 0;
       }
      
   //   DbgPrint("Section Name: %s/n", SectHeader.Name);

#if 0
       if (
           BrDir.VirtualAddress >= SectHeader.VirtualAddress &&
           BrDir.VirtualAddress < (SectHeader.VirtualAddress + SectHeader.SizeOfRawData)
           )
#else
       if ( _stricmp(SectHeader.Name, ".reloc") == 0 )
#endif
       {
           FilePos.LowPart = BrDir.VirtualAddress - SectHeader.VirtualAddress   + SectHeader.PointerToRawData;
           break;
       }
      
       FilePos.LowPart = PointerSectionHeader + sizeof (SectHeader);
   }
  
   //
   // 无效的陈定位数据
   if ( nSection == NtHeader.FileHeader.NumberOfSections )
   {
       ZwClose(FileHandle);
       return 0;
   }

   //
   // 分配内存,存放从文件中读出的重定位信息
   pBr = ExAllocatePool(NonPagedPool, BrDir.Size);
   if ( NULL == pBr )
   {
       ZwClose(FileHandle);
       return 0;
   }
  
   //
   // 读取重定位信息到内存中
   Status = ZwReadFile(
       FileHandle,
       NULL,
       NULL,
       NULL,
       &IoStatus,
       pBr,
       BrDir.Size,
       &FilePos,
       NULL
       );
   ZwClose(FileHandle);

   if ( !NT_SUCCESS(Status) )
   {
       ExFreePool(pBr);
       return 0;
   }
  
   //
   // 开始进行查找
   nRefCount = pLookupImageXRef(ImageBase, &BrDir, pBr, SymAddr, LookupXRefCallback);
   ExFreePool(pBr);
  
   return nRefCount;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值