[转载]一份LoadImage()函数代码,可以实现基本的重载内核

这里实现一个 LoadImage() 函数,用来加载目标 image 文件。如下面的用法:

 1         ... ...
 2 
 3 
 4          RtlInitUnicodeString(&ImageFile, L"\\??\\C:\\windows\\system32\\ntkrnlpa.exe"); // 目标文件为 ntkrnlpa.exe
 5          LoadImage(&ImageFile, &ImageBase);                                              // 加载目标 image, ImageBase 返回 image 基址
 6 
 7 
 8         ... ...
 9 
10 
11          ExFreePoolWithTag(ImageBase, 'fubi');                                           // 最后释放 Image 占用内存

 

LoadImage() 内部实现了基址重定位以及导入符号绑定操作。

 

  1 BOOLEAN LoadImage(
  2          IN PUNICODE_STRING ImageFile,
  3          OUT PVOID *OutImageBase          
  4          )
  5 /*++
  6         LoadImage():
  7                 加载目标映像文件到目标 buffer 中。
  8         input:
  9                 ImageFile - 提供目标映像文件名。
 10                 ImageBase - 提供输出的目标 buffer,这个 buffer 必须能装下映像文件。
 11                             函数内部分配 buffer,并返回 buffer 给 caller。当失败时返回 NULL。
 12                             ImageBase 使用 ExAllocatePoolWithTag() 分配,caller 需要使用
 13                             ExFreePoolWithTag() 来释放,Tag = 'fubi'。
 14         output:
 15                 TRUE - 成功, 否则返回 FALSE 指示失败,OutImageBase 返回 NULL。
 16 --*/
 17 {
 18          NTSTATUS Status;
 19          OBJECT_ATTRIBUTES ObjAttributes;
 20          HANDLE FileHandle;
 21          IO_STATUS_BLOCK IoStatusBlock;
 22          LARGE_INTEGER Offset;
 23          
 24          IMAGE_DOS_HEADER DosHeader;                             // DOS header
 25          IMAGE_NT_HEADERS NtHeader;                              // NT header
 26          PIMAGE_SECTION_HEADER SectionHeader;                    // section header
 27          PIMAGE_BASE_RELOCATION BaseRelocation;                  // base relocation
 28          PIMAGE_BASE_RELOCATION BaseRelocationTop;               // base relocation 区域顶部
 29         PBASE_RELOCATION_ENTRY BaseRelocEntry;                  // base relocation entry
 30          PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;              // image import descriptor 区域
 31         PIMPORT_LOOKUP_TABLE_ENTRY LookupTableEntry;            // 符号查找表项
 32         
 33          IMAGE_IMPORT_MAINTAIN_TABLE ImportMaintainTable = { 0, NULL, { 0 } };
 34              
 35              
 36          ULONG BaseRelocationSize;                               // 重定位区域 size
 37          PULONG_PTR RelocationAddress;                           // 需要重定位的地址
 38         ULONG_PTR RelocationValue;                              // 需要重定位的值
 39         PULONG_PTR BoundSymbolAddress;                          // 需要绑定符号的地址
 40         PCHAR Symbol;                                           // 通用符号名地址
 41             
 42          PVOID OriginalImageBase = NULL;
 43          PVOID ImageBase = NULL;
 44          PVOID ImageSection = NULL;
 45          ULONG NumberOfSections;
 46          ULONG SectionOffset;                    
 47          ULONG Index = 0;
 48          BOOLEAN Result = TRUE;
 49 
 50          *OutImageBase = NULL;                                   // 初始设置 OutImageBase
 51          
 52          InitializeObjectAttributes(
 53                          &ObjAttributes,
 54                          ImageFile,
 55                          OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
 56                          NULL,
 57                          NULL);
 58          
 59         //
 60          // 打开映像文件
 61         //
 62          Status = ZwCreateFile(
 63                          &FileHandle,
 64                          FILE_ALL_ACCESS, 
 65                          &ObjAttributes,
 66                          &IoStatusBlock,
 67                          NULL,
 68                          FILE_ATTRIBUTE_NORMAL,
 69                          FILE_SHARE_READ,
 70                          FILE_OPEN,
 71                          FILE_NON_DIRECTORY_FILE,
 72                          NULL,
 73                          0);
 74          
 75          if (NT_SUCCESS(Status) == FALSE)
 76          {
 77                  KdPrint(("failure to open image file"));
 78                  return FALSE;
 79          }
 80          
 81         //
 82          // 读取文件内容:
 83         // 1. DOS header
 84          // 2. NT header
 85          // 3. Section header
 86          //
 87          Offset.QuadPart = 0;
 88          Status = ZwReadFile(
 89                          FileHandle,
 90                          NULL,
 91                          NULL,
 92                          NULL,
 93                          &IoStatusBlock,
 94                          &DosHeader,                             // DOS 头部
 95                         sizeof(IMAGE_DOS_HEADER),
 96                          &Offset,
 97                          NULL);                
 98          
 99          if (NT_SUCCESS(Status) == FALSE)
100          {
101                  KdPrint(("failure to read image file"));
102                  ZwClose(FileHandle);
103                  return FALSE;
104          }
105          
106         //
107          // 读取 NT header
108          //
109          Offset.QuadPart = DosHeader.e_lfanew;
110          Status = ZwReadFile(
111                          FileHandle,
112                          NULL,
113                          NULL,
114                          NULL,
115                          &IoStatusBlock,
116                          &NtHeader,                              // NT 头部
117                         sizeof(IMAGE_NT_HEADERS),
118                          &Offset,
119                          NULL);                
120          
121          if (NT_SUCCESS(Status) == FALSE)
122          {
123                  KdPrint(("failure to read image file"));
124                  ZwClose(FileHandle);
125                  return FALSE;
126          }
127 
128 
129         
130         //
131          // 根据映像文件大小分配 pool
132          //
133          ImageBase = ExAllocatePoolWithTag(
134                                  NonPagedPool,                           // non-paged
135                                  NtHeader.OptionalHeader.SizeOfImage,    // pool size = SizeOfImage
136                                  'fubi');                                // 'ibuf'
137          if (ImageBase == NULL)
138          {
139                  KdPrint(("failure to allocate image pool"));
140                  ZwClose(FileHandle);
141                  return FALSE;
142          }
143          
144         //
145          // 定位 section table
146          //
147          NumberOfSections = NtHeader.FileHeader.NumberOfSections;
148          SectionOffset = DosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS);
149          SectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)ImageBase + SectionOffset);
150 
151 
152         //
153          // 读取 section header
154          //
155          Offset.QuadPart = SectionOffset;
156          Status = ZwReadFile(
157                          FileHandle,
158                          NULL,
159                          NULL,
160                          NULL,
161                          &IoStatusBlock,
162                          SectionHeader,
163                          NumberOfSections * sizeof(IMAGE_SECTION_HEADER),
164                          &Offset,
165                          NULL);       
166          
167          if (NT_SUCCESS(Status) == FALSE)
168          {
169                  KdPrint(("failure to read image file"));
170                  ZwClose(FileHandle);
171                  return FALSE;
172          }
173                  
174          
175         //
176          // 下面加载映像的每个 section
177          //
178          for (Index = 0; Index < NumberOfSections; Index++)
179          {
180                 //
181                  // 如果 SizeOfRawData = 0 时,跳过 section
182                  //
183                  if (SectionHeader[Index].SizeOfRawData == 0)
184                  {
185                          continue;
186                  }
187                  
188                 //
189                  // 从文件的 PointerToRawData 偏移量里读取内容到 ImageBase + RAV 地址
190                 // size 为 SizeOfRawData
191                  //
192                  Offset.QuadPart = SectionHeader[Index].PointerToRawData;
193                  ImageSection = (PVOID)((ULONG_PTR)ImageBase + SectionHeader[Index].VirtualAddress);
194                  Status = ZwReadFile(
195                                  FileHandle,
196                                  NULL,
197                                  NULL,
198                                  NULL,
199                                  &IoStatusBlock,
200                                  ImageSection,
201                                  SectionHeader[Index].SizeOfRawData,
202                                  &Offset,
203                                  NULL);  
204                   
205                  if (NT_SUCCESS(Status) == FALSE)
206                  {
207                          KdPrint(("failure to read image file"));
208                          ZwClose(FileHandle);
209                          return FALSE;
210                  }
211          }
212 
213 
214         //
215          // 复制 DOS header 和 NT header 到 Image 区域
216         //
217          RtlCopyMemory(ImageBase, &DosHeader, sizeof(DosHeader));
218          RtlCopyMemory((PVOID)((ULONG_PTR)ImageBase + (ULONG_PTR)DosHeader.e_lfanew), &NtHeader, sizeof(NtHeader));
219 
220 
221         //
222          // 下面进行 base 重定位
223         //
224                  
225          //
226          // 找到 IMAGE_BASE_RELOCATION 表区域
227         //
228          BaseRelocation = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase + 
229                          (ULONG_PTR)NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);        
230          BaseRelocationSize = NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
231          BaseRelocationTop = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)BaseRelocation + BaseRelocationSize - 1);
232          OriginalImageBase = NtHeader.OptionalHeader.ImageBase;                          // 映像文件的原始 ImageBase 值
233     
234          while (BaseRelocation < BaseRelocationTop)
235          {
236                 //
237                  // 对每一个 IMAGE_BASE_RELOCATION 表区域内的 entry 进行调整
238                 //   
239                  for (BaseRelocEntry = (PBASE_RELOCATION_ENTRY)((ULONG_PTR)BaseRelocation + 8);
240                          (ULONG_PTR)BaseRelocEntry < ((ULONG_PTR)BaseRelocation + BaseRelocation->SizeOfBlock);
241                          BaseRelocEntry++)
242                  {   
243                          switch (BaseRelocEntry->Type)
244                          {
245                          case IMAGE_REL_BASED_HIGHLOW:
246                                  //
247                                  // 找到需要进行重定位的地址
248                                 //
249                                  RelocationAddress = (PULONG_PTR)((ULONG_PTR)ImageBase 
250                                                          + BaseRelocation->VirtualAddress 
251                                                          + (ULONG_PTR)BaseRelocEntry->Offset);
252                                  //
253                                  // 读取原值进行调整
254                                 //
255                                  RelocationValue = *RelocationAddress;
256                                  *RelocationAddress = RelocationValue - (ULONG_PTR)OriginalImageBase + (ULONG_PTR)ImageBase;
257                                  break;
258                          case IMAGE_REL_BASED_DIR64:
259                                  break;
260                          }
261                  }
262                  
263                  //
264                  // 指向下一个 IMAGE_BASE_RELOCATION 表区域
265                 //
266                  BaseRelocation = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)BaseRelocation + BaseRelocation->SizeOfBlock);
267          }
268          
269         //
270          // 下面进行导入符号的绑定
271         //
272          
273          ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)ImageBase +
274                          (ULONG_PTR)NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
275          
276         //
277         // 得到 image 的所有导入模块及基址
278         //
279          Result = InitImportMaintainTable(&ImportMaintainTable, ImageBase, ImportDescriptor);
280          
281         //
282         // 进行导入符号绑定处理
283         //
284          if (Result == TRUE)
285                  Result = ProcessImportMaintainTable(&ImportMaintainTable);
286 
287          
288          ZwClose(FileHandle);        
289          *OutImageBase = ImageBase;              // 返回 image buffer
290          
291          return TRUE;
292  }
View Code

 

InitImportMaintainTable() 函数用来生成初始化的 IMAGE_IMPORT_MAINTAIN_TABLE 结构,它的定义如下:

 

 1 //
 2 // 预定义 image 导入模块的最大数量
 3 //
 4  #define IMPORT_MODULE_MAX_NUMBER                                100
 5 
 6 
 7 //
 8 // image 所引用的模块表
 9 //
10 typedef struct _IMAGE_REFERENCE_MODULE_TABLE
11  {
12          PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;      // 导入模块信息
13         PVOID ModuleBase;                               // 模块基址
14 } IMAGE_REFERENCE_MODULE_TABLE, *PIMAGE_REFERENCE_MODULE_TABLE;
15    
16 
17 
18 //
19 // image 导入维护表
20 //
21 typedef struct _IMAGE_IMPORT_MAINTAIN_TABLE
22  {
23          ULONG NumberOfReferenceModules;                 // 引用模块的数量
24         PVOID ImageBase;                                // image 模块的基址
25         
26          //
27         // 预定义导入 IMPORT_MODULE_MAX_NUMBER 模块
28         //
29          IMAGE_REFERENCE_MODULE_TABLE Entry[IMPORT_MODULE_MAX_NUMBER];
30          
31  } IMAGE_IMPORT_MAINTAIN_TABLE, *PIMAGE_IMPORT_MAINTAIN_TABLE;
View Code

 

IMAGE_IMPORT_MAINTAIN_TABLE 结构用来处理 image 导入符号的绑定,这项工作由 ProcessImportMaintainTable() 函数负责。ProcessImportMaintainTable() 调用 GetAddressOfExportSymbol() 函数得到符号在引用模块的导出地址值。

下面是 InitImportMaintainTable(),ProcessImportMaintainTable(),GetAddressOfExportSymbol() 以及 SerachBinaryForSymbol() 函数的实现:

 

  1 BOOLEAN InitImportMaintainTable(
  2          INOUT PIMAGE_IMPORT_MAINTAIN_TABLE ImportMaintainTable,
  3          IN PVOID ImageBase,
  4          IN PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
  5          )
  6 /*++
  7         InitImportMaintainTable():
  8                 根据提供的 image 导入描述符表初始化 ImportMaintainTable。
  9         input:
 10                 ImportMaintainTable - image 导入维护表。
 11                 ImageBase - image 基址
 12                 ImportDescriptor - image 的导入描述符表。
 13         output:
 14                 成功返回 TRUE,否则返回 FALSE。
 15 --*/
 16  {
 17          PIMAGE_REFERENCE_MODULE_TABLE ReferenceModuleTable = ImportMaintainTable->Entry;
 18          ULONG NumberOfModules = 0;
 19          NTSTATUS Status;
 20          ULONG RequiredLength;
 21          PLIST_ENTRY Next;
 22          PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
 23          PKLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
 24          ANSI_STRING AnsiString;
 25          
 26          PCHAR ModuleName;
 27          ULONG Index;
 28          ULONG Result = 0;
 29          
 30                      
 31          while(!IS_NULL_IMAGE_IMPORT_DESCRIPTOR(*ImportDescriptor))
 32          {
 33                  //
 34                 // 查找对应的导入文件模块
 35                 //            
 36                  ReferenceModuleTable->ImportDescriptor = ImportDescriptor;
 37                  ImportDescriptor++;
 38                  ReferenceModuleTable++;
 39                  NumberOfModules++;
 40          }
 41                  
 42          ImportMaintainTable->NumberOfReferenceModules = NumberOfModules;                // image 引用的模块数
 43         ImportMaintainTable->ImageBase = ImageBase;                                     // image 基址
 44 
 45 
 46         //
 47         // 遍历 PsLoadedModuleList 列表,从已加载的模块里找到 image 所引用模块的基址
 48         // 注意:
 49         //      这里保留未实现未加载的模块!
 50         //
 51          for (Next = PsLoadedModuleListPointer->Flink;
 52                  Next != PsLoadedModuleListPointer; Next = Next->Flink)
 53          {
 54                  LdrDataTableEntry = CONTAINING_RECORD(Next,
 55                                                  KLDR_DATA_TABLE_ENTRY,
 56                                                  InLoadOrderLinks
 57                                                  );
 58                  //
 59                 // 匹配 image 导入模块名字
 60                 //
 61                  for (Index = 0; Index < ImportMaintainTable->NumberOfReferenceModules; Index++)
 62                  {
 63                          //
 64                         // 检查模块名,相等则找到引用模块的 Base 值
 65                         //
 66                          ModuleName = (PCHAR)((ULONG_PTR)ImageBase +
 67                                          ImportMaintainTable->Entry[Index].ImportDescriptor->Name);
 68                          
 69                          //
 70                         // 说明:
 71                         //      1)加载模块链中的模块名字是 UNICODE 字符串,而 image 导入模块名字是 ANSI 字符串。
 72                         //      2)需要在 UNICODE 串与 ANSI 串之间进行对比。模块名字是忽略大小写的,因此,使用 TRUE 参数。
 73                         //
 74                          if (CompareAnsiCharToUnicodeChar(
 75                                                  LdrDataTableEntry->BaseDllName.Buffer,          // 需要对比的模块名
 76                                                 ModuleName,                                     // image 所引用的模块名
 77                                                 TRUE) == 0)
 78                          {
 79                                  ImportMaintainTable->Entry[Index].ModuleBase = LdrDataTableEntry->DllBase;                                
 80                                  Result++;
 81                          }
 82                  }
 83          }
 84          
 85          if (Result == ImportMaintainTable->NumberOfReferenceModules)
 86              return TRUE;
 87          
 88          return FALSE;        
 89  }
 90 
 91 
 92 
 93 
 94   
 95 
 96 
 97 
 98 
 99  BOOLEAN ProcessImportMaintainTable(
100          IN PIMAGE_IMPORT_MAINTAIN_TABLE ImportMaintainTable
101          )
102 /*++
103         ProcessImportMaintainTable():
104                 根据导入维护表处理 image 导入符号的重定位
105         input:
106                 ImportMainTainTable - image 导入维护表
107         output:
108                 成功时返回 TURE,否则返回 FALSE
109 --*/
110  {
111          PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
112          ULONG NumberOfReferenceModules = ImportMaintainTable->NumberOfReferenceModules;
113          PVOID ImageBase = ImportMaintainTable->ImageBase;
114          ULONG ModuleIndex, Index;
115          PCHAR SymbolName;        
116          PVOID SymbolAddress;       
117          
118          PIMPORT_LOOKUP_TABLE_ENTRY ImportLookupTable;
119          PIMPORT_ADDRESS_TABLE_ENTRY ImportAddressTable;
120          PIMAGE_IMPORT_BY_NAME HitNameTable;
121              
122          for (ModuleIndex = 0; ModuleIndex < NumberOfReferenceModules; ModuleIndex++)
123          {
124                  //
125                 // 说明:
126                 //      1)从 import descriptor 里得到 import lookup table 与 import address table
127                 //      2)import descriptor 的 OrignalFirstThunk 指向 import lookup table
128                 //      3)import descriptor 的 FirstThunk 指向 import address table
129                 //      4)用 import lookup table entry 指向的 IMPORT_BY_NAME table entry 在引用模块里查找符号地址。
130                 //
131                  ImportDescriptor = ImportMaintainTable->Entry[ModuleIndex].ImportDescriptor;
132                  ImportLookupTable = (PIMPORT_LOOKUP_TABLE_ENTRY)
133                                  ((ULONG_PTR)ImageBase + ImportDescriptor->OriginalFirstThunk);
134                  ImportAddressTable = (PIMPORT_ADDRESS_TABLE_ENTRY)
135                                  ((ULONG_PTR)ImageBase + ImportDescriptor->FirstThunk);
136                  
137                  for (Index = 0; ImportLookupTable[Index].NameTable != 0; Index++)
138                  {
139                          HitNameTable = (PIMAGE_IMPORT_BY_NAME)
140                                          ((ULONG_PTR)ImageBase + ImportLookupTable[Index].NameTable);
141                          SymbolName = (PCHAR)HitNameTable->Name;
142                          
143                          //
144                         // 在引用的模块里查找符号的地址,SymbolAddress 返回地址值
145                         // SymbolAddress = NULL 时,表明查找失败。
146                         //
147                          SymbolAddress = GetAddressOfExportSymbol(
148                                                  ImportMaintainTable->Entry[ModuleIndex].ModuleBase,
149                                                  SymbolName);
150                          
151                          if (SymbolAddress == NULL)
152                          {
153                                  return FALSE;
154                          }
155                          
156                          //
157                         // 将符号的真实地址绑定到 import address table entry 里。
158                         //
159                          ImportAddressTable[Index].AddressOfSymbol = (ULONG_PTR)SymbolAddress;
160                  }
161          }
162          
163          return TRUE;
164  }
165 
166 
167 
168 
169  PVOID GetAddressOfExportSymbol(
170          IN PVOID ModuleBase,
171          IN PCHAR SymbolName
172          )
173 /*++
174         GetAddressOfExportSymbol():
175                 从引用模块里找到符号的导出地址值
176         input:
177                 ModuleBase - 模块的基址
178                 SymbolName - 符号名
179         output:
180                 成功时返回符号地址,否则返回 NULL
181 --*/
182  {
183          PIMAGE_NT_HEADERS NtHeader;                             // 模块 NT 头
184         PIMAGE_EXPORT_DIRECTORY ExportDirectory;                // 导出目录表            
185          
186          PULONG ExportAddressTable;                              // 导出地址表
187         PULONG ExportNamePointerTable;                          // 导出名字指针表
188         PUSHORT ExportNameOrdinalTable;                         // 导出名字序数表
189         ULONG OrdinalBase;                                      // 导出序数基值
190         PCHAR ExportName;                                       // 导出的符号名字
191             
192          ULONG NumberOfFunctions;                                // 导出地址表 entries 数量
193         ULONG NumberOfNames;                                    // 导出名字指针表 entries 数量
194 
195 
196         PVOID SymbolAddress = NULL;
197          PULONG NamePointer;
198          LONG Index;
199          
200          NtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)ModuleBase + 
201                                  (ULONG_PTR)((PIMAGE_DOS_HEADER)ModuleBase)->e_lfanew);        
202          ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((ULONG_PTR)ModuleBase +
203                          (ULONG_PTR)(NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress));
204                                  
205          //
206         // 获取导出表格
207         //
208          ExportAddressTable = (PULONG)((ULONG_PTR)ModuleBase +
209                                  (ULONG_PTR)(ExportDirectory->AddressOfFunctions));
210          ExportNamePointerTable = (PULONG)((ULONG_PTR)ModuleBase +
211                                  (ULONG_PTR)(ExportDirectory->AddressOfNames));
212          ExportNameOrdinalTable = (PUSHORT)((ULONG_PTR)ModuleBase +
213                                  (ULONG_PTR)(ExportDirectory->AddressOfNameOrdinals));       
214 
215 
216          NumberOfFunctions = ExportDirectory->NumberOfFunctions;
217          NumberOfNames = ExportDirectory->NumberOfNames;
218          OrdinalBase = ExportDirectory->Base;
219              
220          //
221         // 查找符号算法:
222         // 1) 使用二分查找法,在 name pointer table 里找到匹配的符号名,得到一个 name index 值。
223         // 2)将 name index 作为 name ordinal table 的 index 值,获得一个 oridnal 值。
224         // 3)将 ordinal - OrdinalBase 作为 index 值,在 export address table 里找到最终的符号地址。
225         //
226          NamePointer = SerachBinaryForSymbol(ExportNamePointerTable,             // Begin
227                          ExportNamePointerTable + (NumberOfNames - 1),           // End
228                          NumberOfNames,                                          // Count
229                          SymbolName,                                             // SourceString
230                          ModuleBase);                                            // Base of module
231          
232          if (NamePointer == NULL)
233                  return NULL;
234          
235         //
236         // 说明:
237         //      1) NamePointer 返回 Begin 到 End 间匹配元素的地址值,NamePointe - Begin 得到 index 值。
238         //      2)用这个 index 值在 name ordinal table 里找到对应的 ordinal 值。
239         //      3)用这个 ordinal 值在 export address table 里找到符号的真实地址。
240         //
241         // 注意:
242         //      在 microsoft PE 文件档里,明确指出从 name pointer table 里得到的 index 值需要减去 Ordinal Base 值,
243         //      但是经过测试,实际上并不需要减去 ordinal base 值。也就是:
244         //      Index = (ULONG)ExportNameOrdinalTable[Index] - OrdinalBase;     // 这个是错误
245         //      而是:Index = (ULONG)ExportNameOrdinalTable[Index];             // 不能减 ordinal base,否则计算错误。
246         //
247          
248          Index = NamePointer - ExportNamePointerTable;
249          //
250         //Index = (ULONG)ExportNameOrdinalTable[Index] - OrdinalBase;           // 减 ordinal base 值计算有误。
251         //
252          Index = (ULONG)ExportNameOrdinalTable[Index];                           // 实际中不需要减 ordinal base
253          SymbolAddress = (PVOID)((ULONG_PTR)ModuleBase + ExportAddressTable[Index]);
254              
255          return SymbolAddress;
256  }
257 
258 
259 
260 
261  PULONG SerachBinaryForSymbol(
262          IN PULONG Begin,
263          IN PULONG End,
264          IN ULONG Count,
265          IN PCHAR SourceString,
266          IN PVOID ImageBase
267          )
268 /*++
269         SerachBinaryForSymbol():
270                 在一个区域内使用二分查找匹配的符号名,返回匹配的元素值。
271                 Begin 与 End 指定一个查找区间。
272         input:
273                 Begin - 查找数组的起始点
274                 End - 查找数组的结束点
275                 Count - 元素个数
276                 SourceString - 源串
277         output:
278                 成功时返回匹配元素地址,失败时返回 NULL
279 --*/
280  {
281          PCHAR DestString;
282          ULONG Index = 0;
283          LONG Result;
284              
285          if (Begin > End)
286                  return NULL;
287          
288          Index = Count / 2;
289          DestString = (PCHAR)((ULONG_PTR)ImageBase + (ULONG_PTR)Begin[Index]);
290          
291          //
292         // 说明:
293         //      1)导入符号(源串)与导出符号(目标串)是 ANSI char 字符串。因此,需要进行 ANSI char 字符串对比。
294         //      2)需要区分字符的大小写。因此,使用 FALSE 参数。
295         //
296          Result = CompareAnsiChar(DestString, SourceString, FALSE);
297              
298          if (Result == 0)
299              return (Begin + Index);                     // 如果匹配,则返回元素地址值。
300                
301          if (Result < 0)
302              Begin = Begin + (Index + 1);                // 源串大于目标串,则在区间上半部分继续查找
303         else
304              End = Begin + (Index - 1);                  // 源串小于目标串,由在区间下半部分继续查找
305         
306          Count =  Count - Index - 1;
307          
308          return SerachBinaryForSymbol(Begin, End, Count, SourceString, ImageBase);
309  }
View Code


使用 LoadImage() 加载 ntkrnlpa.exe 模块后,可以在 windbg 调试验证结果:

上图显示的 ImageBase 值为 0x87176000,这是 ntkrnlpa.exe 加载的基址。我们随便找一个 NT 模块的函数。例如:nt!HalAllocateCommonBuffer 函数,它使用了导入的 HAL 模块 HalAllocateCommonBuffer() 函数。

下面观察我们加载的 ntkrnlpa.exe 模块情况如何:它加载的基址在 0x87176000 里。

这个反汇编结果显示,函数是一样的。说明我们模块的基址重定位正确!下面我们参观一下导入函数绑定是否正确。图中从 0x871770e8 处读取 HalAllocateCommonBuffer 函数地址。

图中说明我们的导入符号绑定是正确的!注意:这个测试在 windows 2003 下进行,没有测试其它平台。WIN 64 平台下没有测试。

转载于:https://www.cnblogs.com/Acg-Check/p/4268454.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值