Process Hacker
mapimg.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * mapped image
4  *
5  * Copyright (C) 2010 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 /*
24  * This file contains functions to load and retrieve information for
25  * image files (exe, dll). The file format for image files is explained
26  * in the PE/COFF specification located at:
27  *
28  * http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
29  */
30 
31 #include <ph.h>
32 #include <delayimp.h>
33 
35  _In_ PPH_MAPPED_IMAGE MappedImage,
36  _In_ PVOID Address,
37  _In_ SIZE_T Length
38  );
39 
41  _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,
42  _In_ PSTR Name
43  );
44 
46  _Out_ PPH_MAPPED_IMAGE MappedImage,
47  _In_ PVOID ViewBase,
48  _In_ SIZE_T Size
49  )
50 {
51  PIMAGE_DOS_HEADER dosHeader;
52  ULONG ntHeadersOffset;
53 
54  MappedImage->ViewBase = ViewBase;
55  MappedImage->Size = Size;
56 
57  dosHeader = (PIMAGE_DOS_HEADER)ViewBase;
58 
59  __try
60  {
61  PhpMappedImageProbe(MappedImage, dosHeader, sizeof(IMAGE_DOS_HEADER));
62  }
63  __except (EXCEPTION_EXECUTE_HANDLER)
64  {
65  return GetExceptionCode();
66  }
67 
68  // Check the initial MZ.
69 
70  if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
71  return STATUS_INVALID_IMAGE_NOT_MZ;
72 
73  // Get a pointer to the NT headers and probe it.
74 
75  ntHeadersOffset = (ULONG)dosHeader->e_lfanew;
76 
77  if (ntHeadersOffset == 0)
78  return STATUS_INVALID_IMAGE_FORMAT;
79  if (ntHeadersOffset >= 0x10000000 || ntHeadersOffset >= Size)
80  return STATUS_INVALID_IMAGE_FORMAT;
81 
82  MappedImage->NtHeaders = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(ViewBase, ntHeadersOffset);
83 
84  __try
85  {
87  MappedImage,
88  MappedImage->NtHeaders,
89  FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader)
90  );
92  MappedImage,
93  MappedImage->NtHeaders,
94  FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
95  MappedImage->NtHeaders->FileHeader.SizeOfOptionalHeader +
96  MappedImage->NtHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
97  );
98  }
99  __except (EXCEPTION_EXECUTE_HANDLER)
100  {
101  return GetExceptionCode();
102  }
103 
104  // Check the signature and verify the magic.
105 
106  if (MappedImage->NtHeaders->Signature != IMAGE_NT_SIGNATURE)
107  return STATUS_INVALID_IMAGE_FORMAT;
108 
109  MappedImage->Magic = MappedImage->NtHeaders->OptionalHeader.Magic;
110 
111  if (
112  MappedImage->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
113  MappedImage->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC
114  )
115  return STATUS_INVALID_IMAGE_FORMAT;
116 
117  // Get a pointer to the first section.
118 
119  MappedImage->NumberOfSections = MappedImage->NtHeaders->FileHeader.NumberOfSections;
120 
121  MappedImage->Sections = (PIMAGE_SECTION_HEADER)(
122  ((PCHAR)&MappedImage->NtHeaders->OptionalHeader) +
123  MappedImage->NtHeaders->FileHeader.SizeOfOptionalHeader
124  );
125 
126  return STATUS_SUCCESS;
127 }
128 
130  _In_opt_ PWSTR FileName,
131  _In_opt_ HANDLE FileHandle,
132  _In_ BOOLEAN ReadOnly,
133  _Out_ PPH_MAPPED_IMAGE MappedImage
134  )
135 {
136  NTSTATUS status;
137 
138  status = PhMapViewOfEntireFile(
139  FileName,
140  FileHandle,
141  ReadOnly,
142  &MappedImage->ViewBase,
143  &MappedImage->Size
144  );
145 
146  if (NT_SUCCESS(status))
147  {
148  status = PhInitializeMappedImage(
149  MappedImage,
150  MappedImage->ViewBase,
151  MappedImage->Size
152  );
153 
154  if (!NT_SUCCESS(status))
155  {
156  NtUnmapViewOfSection(NtCurrentProcess(), MappedImage->ViewBase);
157  }
158  }
159 
160  return status;
161 }
162 
164  _Inout_ PPH_MAPPED_IMAGE MappedImage
165  )
166 {
167  return NtUnmapViewOfSection(
168  NtCurrentProcess(),
169  MappedImage->ViewBase
170  );
171 }
172 
174  _In_opt_ PWSTR FileName,
175  _In_opt_ HANDLE FileHandle,
176  _In_ BOOLEAN ReadOnly,
177  _Out_ PVOID *ViewBase,
178  _Out_ PSIZE_T Size
179  )
180 {
181  NTSTATUS status;
182  BOOLEAN openedFile = FALSE;
183  LARGE_INTEGER size;
184  HANDLE sectionHandle = NULL;
185  SIZE_T viewSize;
186  PVOID viewBase;
187 
188  if (!FileName && !FileHandle)
189  return STATUS_INVALID_PARAMETER_MIX;
190 
191  // Open the file if we weren't supplied a file handle.
192  if (!FileHandle)
193  {
194  status = PhCreateFileWin32(
195  &FileHandle,
196  FileName,
197  ((FILE_EXECUTE | FILE_READ_ATTRIBUTES | FILE_READ_DATA) |
198  (!ReadOnly ? (FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA) : 0)) | SYNCHRONIZE,
199  0,
200  FILE_SHARE_READ,
201  FILE_OPEN,
203  );
204 
205  if (!NT_SUCCESS(status))
206  return status;
207 
208  openedFile = TRUE;
209  }
210 
211  // Get the file size and create the section.
212 
213  status = PhGetFileSize(FileHandle, &size);
214 
215  if (!NT_SUCCESS(status))
216  goto CleanupExit;
217 
218  status = NtCreateSection(
219  &sectionHandle,
220  SECTION_ALL_ACCESS,
221  NULL,
222  &size,
223  ReadOnly ? PAGE_EXECUTE_READ : PAGE_EXECUTE_READWRITE,
224  SEC_COMMIT,
225  FileHandle
226  );
227 
228  if (!NT_SUCCESS(status))
229  goto CleanupExit;
230 
231  // Map the section.
232 
233  viewSize = (SIZE_T)size.QuadPart;
234  viewBase = NULL;
235 
236  status = NtMapViewOfSection(
237  sectionHandle,
238  NtCurrentProcess(),
239  &viewBase,
240  0,
241  0,
242  NULL,
243  &viewSize,
244  ViewShare,
245  0,
246  ReadOnly ? PAGE_EXECUTE_READ : PAGE_EXECUTE_READWRITE
247  );
248 
249  if (!NT_SUCCESS(status))
250  goto CleanupExit;
251 
252  *ViewBase = viewBase;
253  *Size = (SIZE_T)size.QuadPart;
254 
255 CleanupExit:
256  if (sectionHandle)
257  NtClose(sectionHandle);
258  if (openedFile)
259  NtClose(FileHandle);
260 
261  return status;
262 }
263 
265  _In_ PPH_MAPPED_IMAGE MappedImage,
266  _In_ PVOID Address,
267  _In_ SIZE_T Length
268  )
269 {
270  PhProbeAddress(Address, Length, MappedImage->ViewBase, MappedImage->Size, 1);
271 }
272 
273 PIMAGE_SECTION_HEADER PhMappedImageRvaToSection(
274  _In_ PPH_MAPPED_IMAGE MappedImage,
275  _In_ ULONG Rva
276  )
277 {
278  ULONG i;
279 
280  for (i = 0; i < MappedImage->NumberOfSections; i++)
281  {
282  if (
283  (Rva >= MappedImage->Sections[i].VirtualAddress) &&
284  (Rva < MappedImage->Sections[i].VirtualAddress + MappedImage->Sections[i].SizeOfRawData)
285  )
286  {
287  return &MappedImage->Sections[i];
288  }
289  }
290 
291  return NULL;
292 }
293 
295  _In_ PPH_MAPPED_IMAGE MappedImage,
296  _In_ ULONG Rva,
297  _Out_opt_ PIMAGE_SECTION_HEADER *Section
298  )
299 {
300  PIMAGE_SECTION_HEADER section;
301 
302  section = PhMappedImageRvaToSection(MappedImage, Rva);
303 
304  if (!section)
305  return NULL;
306 
307  if (Section)
308  *Section = section;
309 
310  return (PVOID)(
311  (ULONG_PTR)MappedImage->ViewBase +
312  (Rva - section->VirtualAddress) +
313  section->PointerToRawData
314  );
315 }
316 
318  _In_ PIMAGE_SECTION_HEADER Section,
319  _Out_writes_opt_z_(Count) PSTR Buffer,
320  _In_ ULONG Count,
321  _Out_opt_ PULONG ReturnCount
322  )
323 {
324  BOOLEAN result;
325  SIZE_T returnCount;
326 
327  result = PhCopyBytesZ(
328  Section->Name,
329  IMAGE_SIZEOF_SHORT_NAME,
330  Buffer,
331  Count,
332  &returnCount
333  );
334 
335  if (ReturnCount)
336  *ReturnCount = (ULONG)returnCount;
337 
338  return result;
339 }
340 
342  _In_ PPH_MAPPED_IMAGE MappedImage,
343  _In_ ULONG Index,
344  _Out_ PIMAGE_DATA_DIRECTORY *Entry
345  )
346 {
347  if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
348  {
349  PIMAGE_OPTIONAL_HEADER32 optionalHeader;
350 
351  optionalHeader = (PIMAGE_OPTIONAL_HEADER32)&MappedImage->NtHeaders->OptionalHeader;
352 
353  if (Index >= optionalHeader->NumberOfRvaAndSizes)
354  return STATUS_INVALID_PARAMETER_2;
355 
356  *Entry = &optionalHeader->DataDirectory[Index];
357  }
358  else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
359  {
360  PIMAGE_OPTIONAL_HEADER64 optionalHeader;
361 
362  optionalHeader = (PIMAGE_OPTIONAL_HEADER64)&MappedImage->NtHeaders->OptionalHeader;
363 
364  if (Index >= optionalHeader->NumberOfRvaAndSizes)
365  return STATUS_INVALID_PARAMETER_2;
366 
367  *Entry = &optionalHeader->DataDirectory[Index];
368  }
369  else
370  {
371  return STATUS_INVALID_PARAMETER;
372  }
373 
374  return STATUS_SUCCESS;
375 }
376 
377 FORCEINLINE NTSTATUS PhpGetMappedImageLoadConfig(
378  _In_ PPH_MAPPED_IMAGE MappedImage,
379  _In_ USHORT Magic,
380  _In_ ULONG ProbeLength,
381  _Out_ PVOID *LoadConfig
382  )
383 {
384  NTSTATUS status;
385  PIMAGE_DATA_DIRECTORY entry;
386  PVOID loadConfig;
387 
388  if (MappedImage->Magic != Magic)
389  return STATUS_INVALID_PARAMETER;
390 
391  status = PhGetMappedImageDataEntry(MappedImage, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &entry);
392 
393  if (!NT_SUCCESS(status))
394  return status;
395 
396  loadConfig = PhMappedImageRvaToVa(MappedImage, entry->VirtualAddress, NULL);
397 
398  if (!loadConfig)
399  return STATUS_INVALID_PARAMETER;
400 
401  __try
402  {
403  PhpMappedImageProbe(MappedImage, loadConfig, ProbeLength);
404  }
405  __except (EXCEPTION_EXECUTE_HANDLER)
406  {
407  return GetExceptionCode();
408  }
409 
410  *LoadConfig = loadConfig;
411 
412  return STATUS_SUCCESS;
413 }
414 
416  _In_ PPH_MAPPED_IMAGE MappedImage,
417  _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY32 *LoadConfig
418  )
419 {
421  MappedImage,
422  IMAGE_NT_OPTIONAL_HDR32_MAGIC,
423  sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32),
424  LoadConfig
425  );
426 }
427 
429  _In_ PPH_MAPPED_IMAGE MappedImage,
430  _Out_ PIMAGE_LOAD_CONFIG_DIRECTORY64 *LoadConfig
431  )
432 {
434  MappedImage,
435  IMAGE_NT_OPTIONAL_HDR64_MAGIC,
436  sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64),
437  LoadConfig
438  );
439 }
440 
442  _In_ HANDLE ProcessHandle,
443  _In_ PVOID ViewBase,
444  _Out_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage
445  )
446 {
447  NTSTATUS status;
448  IMAGE_DOS_HEADER dosHeader;
449  ULONG ntHeadersOffset;
450  IMAGE_NT_HEADERS32 ntHeaders;
451  ULONG ntHeadersSize;
452 
453  RemoteMappedImage->ViewBase = ViewBase;
454 
455  status = PhReadVirtualMemory(
456  ProcessHandle,
457  ViewBase,
458  &dosHeader,
459  sizeof(IMAGE_DOS_HEADER),
460  NULL
461  );
462 
463  if (!NT_SUCCESS(status))
464  return status;
465 
466  // Check the initial MZ.
467 
468  if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE)
469  return STATUS_INVALID_IMAGE_NOT_MZ;
470 
471  // Get a pointer to the NT headers and read it in for some basic information.
472 
473  ntHeadersOffset = (ULONG)dosHeader.e_lfanew;
474 
475  if (ntHeadersOffset == 0 || ntHeadersOffset >= 0x10000000)
476  return STATUS_INVALID_IMAGE_FORMAT;
477 
478  status = PhReadVirtualMemory(
479  ProcessHandle,
480  PTR_ADD_OFFSET(ViewBase, ntHeadersOffset),
481  &ntHeaders,
482  sizeof(IMAGE_NT_HEADERS32),
483  NULL
484  );
485 
486  if (!NT_SUCCESS(status))
487  return status;
488 
489  // Check the signature and verify the magic.
490 
491  if (ntHeaders.Signature != IMAGE_NT_SIGNATURE)
492  return STATUS_INVALID_IMAGE_FORMAT;
493 
494  RemoteMappedImage->Magic = ntHeaders.OptionalHeader.Magic;
495 
496  if (
497  RemoteMappedImage->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
498  RemoteMappedImage->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC
499  )
500  return STATUS_INVALID_IMAGE_FORMAT;
501 
502  // Get the real size and read in the whole thing.
503 
504  RemoteMappedImage->NumberOfSections = ntHeaders.FileHeader.NumberOfSections;
505  ntHeadersSize = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
506  ntHeaders.FileHeader.SizeOfOptionalHeader +
507  RemoteMappedImage->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
508 
509  if (ntHeadersSize > 1024 * 1024) // 1 MB
510  return STATUS_INVALID_IMAGE_FORMAT;
511 
512  RemoteMappedImage->NtHeaders = PhAllocate(ntHeadersSize);
513 
514  status = PhReadVirtualMemory(
515  ProcessHandle,
516  PTR_ADD_OFFSET(ViewBase, ntHeadersOffset),
517  RemoteMappedImage->NtHeaders,
518  ntHeadersSize,
519  NULL
520  );
521 
522  if (!NT_SUCCESS(status))
523  {
524  PhFree(RemoteMappedImage->NtHeaders);
525  return status;
526  }
527 
528  RemoteMappedImage->Sections = (PIMAGE_SECTION_HEADER)(
529  (PCHAR)RemoteMappedImage->NtHeaders +
530  FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + ntHeaders.FileHeader.SizeOfOptionalHeader
531  );
532 
533  return STATUS_SUCCESS;
534 }
535 
537  _Inout_ PPH_REMOTE_MAPPED_IMAGE RemoteMappedImage
538  )
539 {
540  PhFree(RemoteMappedImage->NtHeaders);
541 
542  return STATUS_SUCCESS;
543 }
544 
546  _Out_ PPH_MAPPED_IMAGE_EXPORTS Exports,
547  _In_ PPH_MAPPED_IMAGE MappedImage
548  )
549 {
550  NTSTATUS status;
551  PIMAGE_EXPORT_DIRECTORY exportDirectory;
552 
553  Exports->MappedImage = MappedImage;
554 
555  // Get a pointer to the export directory.
556 
557  status = PhGetMappedImageDataEntry(
558  MappedImage,
559  IMAGE_DIRECTORY_ENTRY_EXPORT,
560  &Exports->DataDirectory
561  );
562 
563  if (!NT_SUCCESS(status))
564  return status;
565 
566  exportDirectory = PhMappedImageRvaToVa(
567  MappedImage,
568  Exports->DataDirectory->VirtualAddress,
569  NULL
570  );
571 
572  if (!exportDirectory)
573  return STATUS_INVALID_PARAMETER;
574 
575  __try
576  {
577  PhpMappedImageProbe(MappedImage, exportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY));
578  }
579  __except (EXCEPTION_EXECUTE_HANDLER)
580  {
581  return GetExceptionCode();
582  }
583 
584  Exports->ExportDirectory = exportDirectory;
585  Exports->NumberOfEntries = exportDirectory->NumberOfFunctions;
586 
587  // Get pointers to the various tables and probe them.
588 
589  Exports->AddressTable = (PULONG)PhMappedImageRvaToVa(
590  MappedImage,
591  exportDirectory->AddressOfFunctions,
592  NULL
593  );
594  Exports->NamePointerTable = (PULONG)PhMappedImageRvaToVa(
595  MappedImage,
596  exportDirectory->AddressOfNames,
597  NULL
598  );
599  Exports->OrdinalTable = (PUSHORT)PhMappedImageRvaToVa(
600  MappedImage,
601  exportDirectory->AddressOfNameOrdinals,
602  NULL
603  );
604 
605  if (
606  !Exports->AddressTable ||
607  !Exports->NamePointerTable ||
608  !Exports->OrdinalTable
609  )
610  return STATUS_INVALID_PARAMETER;
611 
612  __try
613  {
615  MappedImage,
616  Exports->AddressTable,
617  exportDirectory->NumberOfFunctions * sizeof(ULONG)
618  );
620  MappedImage,
621  Exports->NamePointerTable,
622  exportDirectory->NumberOfNames * sizeof(ULONG)
623  );
625  MappedImage,
626  Exports->OrdinalTable,
627  exportDirectory->NumberOfFunctions * sizeof(USHORT)
628  );
629  }
630  __except (EXCEPTION_EXECUTE_HANDLER)
631  {
632  return GetExceptionCode();
633  }
634 
635  // The ordinal and name tables are parallel.
636  // Getting an index into the name table (e.g. by doing a binary
637  // search) and indexing into the ordinal table will produce the
638  // ordinal for that name, *unbiased* (unlike in the specification).
639  // The unbiased ordinal is an index into the address table.
640 
641  return STATUS_SUCCESS;
642 }
643 
645  _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,
646  _In_ ULONG Index,
648  )
649 {
650  PSTR name;
651 
652  if (Index >= Exports->ExportDirectory->NumberOfFunctions)
653  return STATUS_PROCEDURE_NOT_FOUND;
654 
655  Entry->Ordinal = Exports->OrdinalTable[Index] + (USHORT)Exports->ExportDirectory->Base;
656 
657  if (Index < Exports->ExportDirectory->NumberOfNames)
658  {
659  name = PhMappedImageRvaToVa(
660  Exports->MappedImage,
661  Exports->NamePointerTable[Index],
662  NULL
663  );
664 
665  if (!name)
666  return STATUS_INVALID_PARAMETER;
667 
668  // TODO: Probe the name.
669 
670  Entry->Name = name;
671  }
672  else
673  {
674  Entry->Name = NULL;
675  }
676 
677  return STATUS_SUCCESS;
678 }
679 
681  _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,
682  _In_opt_ PSTR Name,
683  _In_opt_ USHORT Ordinal,
684  _Out_ PPH_MAPPED_IMAGE_EXPORT_FUNCTION Function
685  )
686 {
687  ULONG rva;
688 
689  if (Name)
690  {
691  ULONG index;
692 
693  index = PhpLookupMappedImageExportName(Exports, Name);
694 
695  if (index == -1)
696  return STATUS_PROCEDURE_NOT_FOUND;
697 
698  Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base;
699  }
700 
701  Ordinal -= (USHORT)Exports->ExportDirectory->Base;
702 
703  if (Ordinal >= Exports->ExportDirectory->NumberOfFunctions)
704  return STATUS_PROCEDURE_NOT_FOUND;
705 
706  rva = Exports->AddressTable[Ordinal];
707 
708  if (
709  (rva >= Exports->DataDirectory->VirtualAddress) &&
710  (rva < Exports->DataDirectory->VirtualAddress + Exports->DataDirectory->Size)
711  )
712  {
713  // This is a forwarder RVA.
714 
715  Function->ForwardedName = PhMappedImageRvaToVa(
716  Exports->MappedImage,
717  rva,
718  NULL
719  );
720 
721  if (!Function->ForwardedName)
722  return STATUS_INVALID_PARAMETER;
723 
724  // TODO: Probe the name.
725 
726  Function->Function = NULL;
727  }
728  else
729  {
730  Function->Function = PhMappedImageRvaToVa(
731  Exports->MappedImage,
732  rva,
733  NULL
734  );
735  Function->ForwardedName = NULL;
736  }
737 
738  return STATUS_SUCCESS;
739 }
740 
742  _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,
743  _In_opt_ PSTR Name,
744  _In_opt_ USHORT Ordinal,
745  _In_ PVOID RemoteBase,
746  _Out_ PVOID *Function
747  )
748 {
749  ULONG rva;
750 
751  if (Name)
752  {
753  ULONG index;
754 
755  index = PhpLookupMappedImageExportName(Exports, Name);
756 
757  if (index == -1)
758  return STATUS_PROCEDURE_NOT_FOUND;
759 
760  Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base;
761  }
762 
763  Ordinal -= (USHORT)Exports->ExportDirectory->Base;
764 
765  if (Ordinal >= Exports->ExportDirectory->NumberOfFunctions)
766  return STATUS_PROCEDURE_NOT_FOUND;
767 
768  rva = Exports->AddressTable[Ordinal];
769 
770  if (
771  (rva >= Exports->DataDirectory->VirtualAddress) &&
772  (rva < Exports->DataDirectory->VirtualAddress + Exports->DataDirectory->Size)
773  )
774  {
775  // This is a forwarder RVA. Not supported for remote lookup.
776  return STATUS_NOT_SUPPORTED;
777  }
778  else
779  {
780  *Function = PTR_ADD_OFFSET(RemoteBase, rva);
781  }
782 
783  return STATUS_SUCCESS;
784 }
785 
787  _In_ PPH_MAPPED_IMAGE_EXPORTS Exports,
788  _In_ PSTR Name
789  )
790 {
791  LONG low;
792  LONG high;
793  LONG i;
794 
795  if (Exports->ExportDirectory->NumberOfNames == 0)
796  return -1;
797 
798  low = 0;
799  high = Exports->ExportDirectory->NumberOfNames - 1;
800 
801  do
802  {
803  PSTR name;
804  INT comparison;
805 
806  i = (low + high) / 2;
807 
808  name = PhMappedImageRvaToVa(
809  Exports->MappedImage,
810  Exports->NamePointerTable[i],
811  NULL
812  );
813 
814  if (!name)
815  return -1;
816 
817  // TODO: Probe the name.
818 
819  comparison = strcmp(Name, name);
820 
821  if (comparison == 0)
822  return i;
823  else if (comparison < 0)
824  high = i - 1;
825  else
826  low = i + 1;
827  } while (low <= high);
828 
829  return -1;
830 }
831 
833  _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports,
834  _In_ PPH_MAPPED_IMAGE MappedImage
835  )
836 {
837  NTSTATUS status;
838  PIMAGE_DATA_DIRECTORY dataDirectory;
839  PIMAGE_IMPORT_DESCRIPTOR descriptor;
840  ULONG i;
841 
842  Imports->MappedImage = MappedImage;
843  Imports->Flags = 0;
844 
845  status = PhGetMappedImageDataEntry(
846  MappedImage,
847  IMAGE_DIRECTORY_ENTRY_IMPORT,
848  &dataDirectory
849  );
850 
851  if (!NT_SUCCESS(status))
852  return status;
853 
854  descriptor = PhMappedImageRvaToVa(
855  MappedImage,
856  dataDirectory->VirtualAddress,
857  NULL
858  );
859 
860  if (!descriptor)
861  return STATUS_INVALID_PARAMETER;
862 
863  Imports->DescriptorTable = descriptor;
864 
865  // Do a scan to determine how many import descriptors there are.
866 
867  i = 0;
868 
869  __try
870  {
871  while (TRUE)
872  {
873  PhpMappedImageProbe(MappedImage, descriptor, sizeof(IMAGE_IMPORT_DESCRIPTOR));
874 
875  if (descriptor->OriginalFirstThunk == 0 && descriptor->FirstThunk == 0)
876  break;
877 
878  descriptor++;
879  i++;
880  }
881  }
882  __except (EXCEPTION_EXECUTE_HANDLER)
883  {
884  return GetExceptionCode();
885  }
886 
887  Imports->NumberOfDlls = i;
888 
889  return STATUS_SUCCESS;
890 }
891 
893  _In_ PPH_MAPPED_IMAGE_IMPORTS Imports,
894  _In_ ULONG Index,
895  _Out_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll
896  )
897 {
898  ULONG i;
899 
900  if (Index >= Imports->NumberOfDlls)
901  return STATUS_INVALID_PARAMETER_2;
902 
903  ImportDll->MappedImage = Imports->MappedImage;
904  ImportDll->Flags = Imports->Flags;
905 
906  if (!(ImportDll->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS))
907  {
908  ImportDll->Descriptor = &Imports->DescriptorTable[Index];
909 
910  ImportDll->Name = PhMappedImageRvaToVa(
911  ImportDll->MappedImage,
912  ImportDll->Descriptor->Name,
913  NULL
914  );
915 
916  if (!ImportDll->Name)
917  return STATUS_INVALID_PARAMETER;
918 
919  // TODO: Probe the name.
920 
921  if (ImportDll->Descriptor->OriginalFirstThunk)
922  {
923  ImportDll->LookupTable = PhMappedImageRvaToVa(
924  ImportDll->MappedImage,
925  ImportDll->Descriptor->OriginalFirstThunk,
926  NULL
927  );
928  }
929  else
930  {
931  ImportDll->LookupTable = PhMappedImageRvaToVa(
932  ImportDll->MappedImage,
933  ImportDll->Descriptor->FirstThunk,
934  NULL
935  );
936  }
937  }
938  else
939  {
940  ImportDll->DelayDescriptor = &((PImgDelayDescr)Imports->DelayDescriptorTable)[Index];
941 
942  ImportDll->Name = PhMappedImageRvaToVa(
943  ImportDll->MappedImage,
944  ((PImgDelayDescr)ImportDll->DelayDescriptor)->rvaDLLName,
945  NULL
946  );
947 
948  if (!ImportDll->Name)
949  return STATUS_INVALID_PARAMETER;
950 
951  // TODO: Probe the name.
952 
953  ImportDll->LookupTable = PhMappedImageRvaToVa(
954  ImportDll->MappedImage,
955  ((PImgDelayDescr)ImportDll->DelayDescriptor)->rvaINT,
956  NULL
957  );
958  }
959 
960  if (!ImportDll->LookupTable)
961  return STATUS_INVALID_PARAMETER;
962 
963  // Do a scan to determine how many entries there are.
964 
965  i = 0;
966 
967  if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
968  {
969  PULONG entry;
970 
971  entry = (PULONG)ImportDll->LookupTable;
972 
973  __try
974  {
975  while (TRUE)
976  {
978  ImportDll->MappedImage,
979  entry,
980  sizeof(ULONG)
981  );
982 
983  if (*entry == 0)
984  break;
985 
986  entry++;
987  i++;
988  }
989  }
990  __except (EXCEPTION_EXECUTE_HANDLER)
991  {
992  return GetExceptionCode();
993  }
994  }
995  else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
996  {
997  PULONG64 entry;
998 
999  entry = (PULONG64)ImportDll->LookupTable;
1000 
1001  __try
1002  {
1003  while (TRUE)
1004  {
1006  ImportDll->MappedImage,
1007  entry,
1008  sizeof(ULONG64)
1009  );
1010 
1011  if (*entry == 0)
1012  break;
1013 
1014  entry++;
1015  i++;
1016  }
1017  }
1018  __except (EXCEPTION_EXECUTE_HANDLER)
1019  {
1020  return GetExceptionCode();
1021  }
1022  }
1023  else
1024  {
1025  return STATUS_INVALID_PARAMETER;
1026  }
1027 
1028  ImportDll->NumberOfEntries = i;
1029 
1030  return STATUS_SUCCESS;
1031 }
1032 
1034  _In_ PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll,
1035  _In_ ULONG Index,
1036  _Out_ PPH_MAPPED_IMAGE_IMPORT_ENTRY Entry
1037  )
1038 {
1039  PIMAGE_IMPORT_BY_NAME importByName;
1040 
1041  if (Index >= ImportDll->NumberOfEntries)
1042  return STATUS_INVALID_PARAMETER_2;
1043 
1044  if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
1045  {
1046  ULONG entry;
1047 
1048  entry = ((PULONG)ImportDll->LookupTable)[Index];
1049 
1050  // Is this entry using an ordinal?
1051  if (entry & IMAGE_ORDINAL_FLAG32)
1052  {
1053  Entry->Name = NULL;
1054  Entry->Ordinal = (USHORT)IMAGE_ORDINAL32(entry);
1055 
1056  return STATUS_SUCCESS;
1057  }
1058  else
1059  {
1060  importByName = PhMappedImageRvaToVa(
1061  ImportDll->MappedImage,
1062  entry,
1063  NULL
1064  );
1065  }
1066  }
1067  else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
1068  {
1069  ULONG64 entry;
1070 
1071  entry = ((PULONG64)ImportDll->LookupTable)[Index];
1072 
1073  // Is this entry using an ordinal?
1074  if (entry & IMAGE_ORDINAL_FLAG64)
1075  {
1076  Entry->Name = NULL;
1077  Entry->Ordinal = (USHORT)IMAGE_ORDINAL64(entry);
1078 
1079  return STATUS_SUCCESS;
1080  }
1081  else
1082  {
1083  importByName = PhMappedImageRvaToVa(
1084  ImportDll->MappedImage,
1085  (ULONG)entry,
1086  NULL
1087  );
1088  }
1089  }
1090  else
1091  {
1092  return STATUS_INVALID_PARAMETER;
1093  }
1094 
1095  if (!importByName)
1096  return STATUS_INVALID_PARAMETER;
1097 
1098  __try
1099  {
1101  ImportDll->MappedImage,
1102  importByName,
1103  sizeof(IMAGE_IMPORT_BY_NAME)
1104  );
1105  }
1106  __except (EXCEPTION_EXECUTE_HANDLER)
1107  {
1108  return GetExceptionCode();
1109  }
1110 
1111  Entry->Name = (PSTR)importByName->Name;
1112  Entry->NameHint = importByName->Hint;
1113 
1114  // TODO: Probe the name.
1115 
1116  return STATUS_SUCCESS;
1117 }
1118 
1120  _Out_ PPH_MAPPED_IMAGE_IMPORTS Imports,
1121  _In_ PPH_MAPPED_IMAGE MappedImage
1122  )
1123 {
1124  NTSTATUS status;
1125  PIMAGE_DATA_DIRECTORY dataDirectory;
1126  PImgDelayDescr descriptor;
1127  ULONG i;
1128 
1129  Imports->MappedImage = MappedImage;
1130  Imports->Flags = PH_MAPPED_IMAGE_DELAY_IMPORTS;
1131 
1132  status = PhGetMappedImageDataEntry(
1133  MappedImage,
1134  IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,
1135  &dataDirectory
1136  );
1137 
1138  if (!NT_SUCCESS(status))
1139  return status;
1140 
1141  descriptor = PhMappedImageRvaToVa(
1142  MappedImage,
1143  dataDirectory->VirtualAddress,
1144  NULL
1145  );
1146 
1147  if (!descriptor)
1148  return STATUS_INVALID_PARAMETER;
1149 
1150  Imports->DelayDescriptorTable = descriptor;
1151 
1152  // Do a scan to determine how many import descriptors there are.
1153 
1154  i = 0;
1155 
1156  __try
1157  {
1158  while (TRUE)
1159  {
1160  PhpMappedImageProbe(MappedImage, descriptor, sizeof(ImgDelayDescr));
1161 
1162  if (descriptor->rvaIAT == 0 && descriptor->rvaINT == 0)
1163  break;
1164 
1165  descriptor++;
1166  i++;
1167  }
1168  }
1169  __except (EXCEPTION_EXECUTE_HANDLER)
1170  {
1171  return GetExceptionCode();
1172  }
1173 
1174  Imports->NumberOfDlls = i;
1175 
1176  return STATUS_SUCCESS;
1177 }
1178 
1179 USHORT PhCheckSum(
1180  _In_ ULONG Sum,
1181  _In_reads_(Count) PUSHORT Buffer,
1182  _In_ ULONG Count
1183  )
1184 {
1185  while (Count--)
1186  {
1187  Sum += *Buffer++;
1188  Sum = (Sum >> 16) + (Sum & 0xffff);
1189  }
1190 
1191  Sum = (Sum >> 16) + Sum;
1192 
1193  return (USHORT)Sum;
1194 }
1195 
1197  _In_ PPH_MAPPED_IMAGE MappedImage
1198  )
1199 {
1200  ULONG checkSum;
1201  USHORT partialSum;
1202  PUSHORT adjust;
1203 
1204  partialSum = PhCheckSum(0, (PUSHORT)MappedImage->ViewBase, (ULONG)(MappedImage->Size + 1) / 2);
1205 
1206  // This is actually the same for 32-bit and 64-bit executables.
1207  adjust = (PUSHORT)&MappedImage->NtHeaders->OptionalHeader.CheckSum;
1208 
1209  // Subtract the existing check sum (with carry).
1210  partialSum -= partialSum < adjust[0];
1211  partialSum -= adjust[0];
1212  partialSum -= partialSum < adjust[1];
1213  partialSum -= adjust[1];
1214 
1215  checkSum = partialSum + (ULONG)MappedImage->Size;
1216 
1217  return checkSum;
1218 }