12 #define MAX_NUMBER_OF_EXPORT_NAMES 65535ul 15 #define MAX_UNWIND_INFO_TRIES 512 20 #define MAX_SIZE_OF_IMAGE (2 * ONE_GIGABYTE) 23 #define MAX_UNWIND_CODES 50 42 _In_ void *OptionalHeader,
66 WORD magic = ((
WORD *)OptionalHeader)[0];
71 DWORD actualSizeOfOptionalHeader = 0;
79 if (actualSizeOfOptionalHeader != SizeOfOptionalHeader)
81 WARNING(
"[WARNING] SizeOfOptionalHeader (0x%08x) different from actual size (0x%08x).\n",
82 SizeOfOptionalHeader, actualSizeOfOptionalHeader);
92 Info->Image64 =
FALSE;
97 DWORD actualSizeOfOptionalHeader = 0;
105 if (actualSizeOfOptionalHeader != SizeOfOptionalHeader)
107 WARNING(
"[WARNING] SizeOfOptionalHeader (0x%08x) different from actual size (0x%08x).\n",
108 SizeOfOptionalHeader, actualSizeOfOptionalHeader);
118 Info->Image64 =
TRUE;
122 ERROR(
"[ERROR] Optional header has an invalid magic: 0x%04x!\n", magic);
170 WORD subsystem = 0, machine = 0;
171 DWORD timeDateStamp = 0, sizeOfImage = 0;
172 DWORD entryPoint = 0, numberOfSections = 0;
173 DWORD actualSectionSize = 0;
174 DWORD sectionAlign = 0, fileAlign = 0;
177 QWORD e_lfanew, secOff = 0;
178 BYTE *pSmallBase = NULL;
182 ERROR(
"[ERROR] Image at 0x%016llx is not page-aligned\n", ImageBase);
186 if (NULL != ImageBaseBuffer)
191 TRACE(
"[TRACE] The MZPE to validate is smaller than 4K: 0x%08x\n", ImageBaseBufferSize);
194 if (pSmallBase == NULL)
202 memcpy(pBase, ImageBaseBuffer, ImageBaseBufferSize);
206 pBase = ImageBaseBuffer;
207 size = ImageBaseBufferSize;
214 ERROR(
"[ERROR] Can not map MZPE image at GVA 0x%016llx!\n", ImageBase);
221 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
243 if (e_lfanew >= size)
277 ERROR(
"[ERROR] Image at 0x%016llx has an invalid optional header!\n", ImageBase);
283 WARNING(
"[WARNING] Image 0x%016llx is AMD64 but has a PE32 optional header! Will consider it 32 bits\n",
305 ERROR(
"[ERROR] Image at 0x%016llx has an invalid optional header!\n", ImageBase);
311 WARNING(
"[WARNING] Image 0x%016llx is I386 but has a PE64 optional header! Will consider it 64 bits\n",
331 ERROR(
"[ERROR] Image at 0x%016llx has SizeOfImage (0x%08x) larger than the maximum allowed (0x%016llx)\n",
337 if (sectionAlign == 0)
339 ERROR(
"[ERROR] Section alignment is 0 for image at 0x%016llx\n", ImageBase);
344 if ((sectionAlign < fileAlign) || (fileAlign < MIN_FILE_ALIGNMENT || fileAlign >
MAX_FILE_ALIGNMENT))
346 WARNING(
"[WARNING] Image alignments invalid. FileAlignment: 0x%08x, SectionAlignment: 0x%08x. " 347 "The image at 0x%016llx may have been tampered with\n",
348 fileAlign, sectionAlign, ImageBase);
353 ERROR(
"[ERROR] Sections headers point out of the mapping. SectionOffset: 0x%08llx; NrOfSections: %d; " 354 "MaxSize: 0x%08llx; MappingSize: 0x%08x. Image base: 0x%016llx\n",
355 secOff, numberOfSections, secOff +
sizeof(
IMAGE_SECTION_HEADER) * numberOfSections, size, ImageBase);
360 if (entryPoint >= sizeOfImage)
362 ERROR(
"[ERROR] EntryPoint points out of the file. EntryPoint: 0x%08x; SizeOfImage: 0x%08x; " 363 "ImageBase: 0x%016llx\n",
364 entryPoint, sizeOfImage, ImageBase);
370 if (e_lfanew >= sizeOfImage)
372 WARNING(
"[WARNING] e_lfanew 0x%llx points outside of image 0x%08x. Module 0x%016llx\n",
373 e_lfanew, sizeOfImage, ImageBase);
380 for (
DWORD i = 0; i < numberOfSections; i++, pSec++)
385 actualSectionSize =
ROUND_UP(secVirtSize ? secVirtSize : secSizeOfRawData, sectionAlign);
387 if (0 == actualSectionSize)
390 memcpy(name, pSec->
Name,
sizeof(pSec->
Name));
393 ERROR(
"[ERROR] Section %d (%s) for image at 0x%016llx has actual size 0. VirtualSize = 0x%08x " 394 "SizeOfRawData = 0x%08x Align = 0x%08x\n",
395 i, name, ImageBase, secVirtSize, secSizeOfRawData, sectionAlign);
403 memcpy(name, pSec->
Name,
sizeof(pSec->
Name));
406 ERROR(
"[ERROR] Section starting at 0. Section name: %s\n", name);
411 if (0 == secVirtSize && (0 == secSizeOfRawData || secSizeOfRawData >
PAGE_SIZE))
414 memcpy(name, pSec->
Name,
sizeof(pSec->
Name));
417 ERROR(
"[ERROR] Section %d (%s) size is invalid for image at 0x%016llx. " 418 "VirtualSize: 0x%08x. SizeOfRawData: 0x%08x\n",
426 (actualSectionSize > sizeOfImage) ||
430 memcpy(name, pSec->
Name,
sizeof(pSec->
Name));
433 ERROR(
"[ERROR] Section %d (%s) for image at 0x%016llx seems corrupted: " 434 "sizeOfImage = 0x%x, secStart = 0x%x, secSize = 0x%x, actualSecSize = 0x%08x\n",
443 PeInfo->Image64Bit = image64;
444 PeInfo->SectionOffset = secOff;
445 PeInfo->SizeOfImage = sizeOfImage;
446 PeInfo->TimeDateStamp = timeDateStamp;
447 PeInfo->EntryPoint = entryPoint;
448 PeInfo->NumberOfSections = numberOfSections;
449 PeInfo->Subsystem = subsystem;
450 PeInfo->ImageBase = imageBase;
451 PeInfo->SectionAlignment = sectionAlign;
452 PeInfo->Machine = machine;
458 if (NULL == ImageBaseBuffer)
463 if (NULL != pSmallBase)
499 if (NULL == FirstSectionOffset)
504 if (NULL == SectionCount)
509 if (NULL != ImageBuffer)
512 size = ImageBufferSize;
519 ERROR(
"[ERROR] IntVirtMemMap failed: 0x%08x\n", status);
529 ERROR(
"[ERROR] IntPeValidateHeader failed: 0x%08x\n", status);
530 goto cleanup_and_exit;
537 if (NULL == ImageBuffer)
543 ERROR(
"[ERROR] IntVirtMemUnmap failed: 0x%08x\n", status2);
586 if (NULL == Directory)
591 unmapNtHeaders =
FALSE;
593 if (NULL != ImageBaseBuffer)
595 map = ImageBaseBuffer;
602 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
626 status =
IntVirtMemMap(ImageBase + e_lfanew,
sizeof(*pNth64), 0, 0, &pNth64);
629 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase + e_lfanew, status);
633 unmapNtHeaders =
TRUE;
649 status =
IntVirtMemMap(ImageBase + e_lfanew,
sizeof(*pNth32), 0, 0, &pNth32);
652 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase + e_lfanew, status);
656 unmapNtHeaders =
TRUE;
663 if (Directory->VirtualAddress == 0 || Directory->Size == 0)
670 if ((
QWORD)Directory->Size + Directory->VirtualAddress > peInfo.
SizeOfImage)
691 if (NULL == ImageBaseBuffer)
698 Directory->VirtualAddress = 0;
735 if (NULL == SectionHeader)
740 if (NULL != ImageBaseBuffer)
742 map = ImageBaseBuffer;
749 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
754 unmapSecHeaders =
FALSE;
787 if (NULL == pSecHeader)
793 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host with size %llu: 0x%08x\n",
798 unmapSecHeaders =
TRUE;
806 if (GuestRva >= pSecHeader[i].VirtualAddress &&
823 if (NULL == ImageBaseBuffer)
830 memzero(SectionHeader,
sizeof(*SectionHeader));
863 if (NULL == SectionHeader)
868 if (NULL != ImageBaseBuffer)
870 map = ImageBaseBuffer;
877 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
911 if (NULL == pSecHeader)
919 ERROR(
"[ERROR] Failed reading section header from GVA 0x%016llx: 0x%08x\n",
932 if (NULL == ImageBaseBuffer)
946 _In_ DWORD NumberOfSectionHeadersAllocated,
971 DWORD numberSectionsFound;
977 if (0 == NumberOfSectionHeadersAllocated)
982 if (NULL == SectionHeaders)
987 if (NULL != ImageBaseBuffer)
989 map = ImageBaseBuffer;
996 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
1001 unmapSecHeaders =
FALSE;
1003 numberSectionsFound = 0;
1035 if (NULL == pSecHeader)
1041 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host with size 0x%016llx: 0x%08x\n",
1046 unmapSecHeaders =
TRUE;
1050 cmpSize = strlen(Name) + 1;
1055 if (memcmp(Name, pSecHeader[i].Name, cmpSize) == 0)
1059 numberSectionsFound++;
1061 if (numberSectionsFound == NumberOfSectionHeadersAllocated)
1068 if (0 == numberSectionsFound)
1077 if (NULL != NumberOfSectionHeadersFilled)
1079 *NumberOfSectionHeadersFilled = numberSectionsFound;
1083 if (unmapSecHeaders)
1088 if (NULL == ImageBaseBuffer)
1095 memzero(SectionHeaders,
sizeof(*SectionHeaders) * NumberOfSectionHeadersAllocated);
1124 DWORD beginRva, i, size;
1134 if (NULL != ImageBaseBuffer)
1136 map = ImageBaseBuffer;
1143 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
1182 ERROR(
"[ERROR] Failed mapping AddressOfFunctions 0x%016llx (0x%016llx + 0x%08x): 0x%08x\n",
1190 while (parsed + mappingSize <
PAGE_SIZE)
1193 if (*(
DWORD *)(functions + parsed) == beginRva)
1202 address += mappingSize;
1213 if (NULL == ImageBaseBuffer)
1288 if (size > BufferSize)
1293 for (
DWORD i = 0; i < size; i += 4)
1342 if (0 == ExportNameSize)
1347 if (NULL == ExportName)
1352 if (NULL != ImageBaseBuffer)
1354 map = ImageBaseBuffer;
1361 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
1370 goto _cleanup_and_leave;
1379 WARNING(
"[WARNING] Failed to read the export directory of 0x%016llx located at 0x%016llx: 0x%08x\n",
1382 goto _cleanup_and_leave;
1391 goto _cleanup_and_leave;
1396 DWORD exportOrdinal, exportRva, namePointer, retLen;
1404 exportOrdinal &= 0xFFFF;
1413 if (exportRva != Rva)
1422 goto _cleanup_and_leave;
1426 status =
IntKernVirtMemRead(ImageBase + namePointer, ExportNameSize, ExportName, &retLen);
1429 goto _cleanup_and_leave;
1433 ExportName[retLen - 1] = 0;
1443 goto _cleanup_and_leave;
1447 if (ImageBaseBuffer == NULL)
1491 if (0 == BufferSize)
1496 if (0 == ExportNameSize)
1501 if (NULL == ExportName)
1543 DWORD exportOrdinal, exportRva, namePointer;
1558 if (exportRva != Rva)
1570 if ((
QWORD)namePointer + ExportNameSize > BufferSize)
1576 strlcpy(ExportName, (
char *)Buffer + namePointer, ExportNameSize);
1610 size_t exportNameLen;
1624 if (NULL == ExportRva)
1629 exportNameLen = strlen(Name);
1632 if (exportNameLen >= 512)
1670 while (left < right)
1674 size_t cmpSize = exportNameLen + 1;
1677 mid = (left + right) / 2;
1680 if (offset +
sizeof(namePointer) > BufferSize)
1682 WARNING(
"[WARNING] Corrupted export name pointer: 0x%lx is outside of image size of 0x%x\n",
1683 offset +
sizeof(namePointer), BufferSize);
1687 namePointer = *(
DWORD *)(Buffer + offset);
1689 if (namePointer >= BufferSize)
1691 WARNING(
"[WARNING] Corrupted export name. Name pointer 0x%08x is outside of image size: 0x%08x\n",
1692 namePointer, BufferSize);
1696 if (namePointer + cmpSize > BufferSize)
1700 cmpSize = BufferSize - namePointer;
1704 res = memcmp(Name, Buffer + namePointer, cmpSize);
1711 if (offset +
sizeof(ord) > BufferSize)
1713 WARNING(
"[WARNING] Corrupted export ordinal: 0x%lx is outside of image size of 0x%x\n",
1714 offset +
sizeof(ord), BufferSize);
1718 ord = *(
WORD *)(Buffer + offset);
1721 if (offset +
sizeof(*ExportRva) > BufferSize)
1723 WARNING(
"[WARNING] Corrupted export address: 0x%lx is outside of image size of 0x%x\n",
1724 offset +
sizeof(*ExportRva), BufferSize);
1728 *ExportRva = *(
DWORD *)(Buffer + offset);
1809 BYTE *exportNameBuffer;
1818 if (NULL == ExportRva)
1823 exportNameBuffer = NULL;
1825 exportNameLen = strlen(Name);
1827 if (exportNameLen >= 512)
1832 if (NULL != ImageBaseBuffer)
1834 map = ImageBaseBuffer;
1841 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
1860 WARNING(
"[ERROR] Failed to read the export directory of 0x%016llx located at 0x%016llx: 0x%08x\n",
1868 if (NULL == exportNameBuffer)
1878 while (left < right)
1883 mid = (left + right) / 2;
1898 res = memcmp(Name, exportNameBuffer, exportNameLen + 1ull);
1902 DWORD exportOrdinal;
1911 exportOrdinal &= 0xFFFF;
1936 if (NULL != exportNameBuffer)
1941 if (ImageBaseBuffer == NULL)
1987 if (NULL == ExportRva)
1994 if (NULL != ImageBaseBuffer)
1996 map = ImageBaseBuffer;
2003 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
2022 WARNING(
"[ERROR] Failed to read the export directory of 0x%016llx located at 0x%016llx: 0x%08x\n",
2042 if (ImageBaseBuffer == NULL)
2086 QWORD currentAddress;
2091 if (NULL == RuntimeFunction)
2097 pRuntimeFunction = NULL;
2099 if (NULL != ImageBaseBuffer)
2101 map = ImageBaseBuffer;
2108 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
2129 ERROR(
"[ERROR] No exception directory for ImageBase 0x%016llx: 0x%08x\n", ImageBase, status);
2157 ERROR(
"[ERROR] IntKernVirtMemFetchDword failed for GVA 0x%016llx (dir->RVA 0x%08x, dir->Size 0x%08x, " 2158 "ImageBase 0x%016llx: 0x%08x\n", currentAddress + lastTableInPage, dir.
VirtualAddress,
2159 dir.
Size, ImageBase, status);
2162 else if (beginRva == Rva)
2168 ERROR(
"[ERROR] Failed reading runtime function from address 0x%016llx: 0x%08x\n",
2169 currentAddress + lastTableInPage, status);
2174 else if (beginRva > Rva)
2193 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", currentAddress, status);
2201 if (pRuntimeFunction[i].BeginAddress <= Rva && pRuntimeFunction[i].EndAddress > Rva)
2211 if (pRuntimeFunction[i].UnwindData %
sizeof(
DWORD) != 0)
2224 ERROR(
"[ERROR] Failed mapping next unwind data for runtime function at " 2225 "0x%016llx in driver 0x%016llx",
2235 TRACE(
"[INFO] We have a function at 0x%016llx but it's not inside the exception dir (0x%016llx, %x)\n",
2239 goto _cleanup_and_leave;
2257 if (NULL == ImageBaseBuffer)
2302 if (0 == BufferSize)
2307 if (NULL == RuntimeFunction)
2327 ERROR(
"[ERROR] No exception directory for ImageBase 0x%016llx: 0x%08x\n", ImageBase, status);
2340 while (left < right)
2342 size_t midd = (left + right) / 2;
2381 TRACE(
"[INFO] We have a function at 0x%016llx but it's not inside the exception dir (0x%016llx, %x)\n",
2426 QWORD unwindInfoAddress;
2427 DWORD unwindInfoSize, i, extraSpace;
2435 if (NULL == RuntimeFunction)
2440 if (RipOffset > RuntimeFunction->EndAddress - RuntimeFunction->BeginAddress)
2442 ERROR(
"[ERROR] RipOffset %x, End %x, Begin %x, Total %x\n", RipOffset, RuntimeFunction->EndAddress,
2443 RuntimeFunction->BeginAddress, RuntimeFunction->EndAddress - RuntimeFunction->BeginAddress);
2447 if (NULL != ImageBaseBuffer)
2449 map = ImageBaseBuffer;
2456 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
2461 hasChainedUnwind =
FALSE;
2462 interrupt = exception =
FALSE;
2463 pUnwindInfoMap = NULL;
2466 if (NULL != BeginAddress)
2471 if (NULL != HasFramePointer)
2473 *HasFramePointer =
FALSE;
2479 unwindInfoAddress =
ALIGN_DOWN(ImageBase + RuntimeFunction->UnwindData,
sizeof(
DWORD));
2482 if (NULL != InterruptFunction)
2484 *InterruptFunction =
FALSE;
2487 if (NULL != ExceptionFunction)
2489 *ExceptionFunction =
FALSE;
2497 if (pUnwindInfoMap != NULL)
2505 ERROR(
"[ERROR] Reached MAX_UNWIND_INFO_TRIES for image at 0x%016llx\n", ImageBase);
2510 status =
IntVirtMemMap(unwindInfoAddress, unwindInfoSize, 0, 0, &pUnwindInfoMap);
2513 ERROR(
"[ERROR] IntVirtMemMap failed for GVA 0x%016llx (chained: %s, RIP: 0x%016llx): 0x%08x\n",
2514 unwindInfoAddress, hasChainedUnwind ?
"TRUE" :
"FALSE", ImageBase + RuntimeFunction->BeginAddress,
2524 WARNING(
"[WARNING] Function with %d codes at RVA %08x in driver 0x%016llx with unwind info %llx\n",
2525 countOfCodes, RuntimeFunction->BeginAddress, ImageBase, unwindInfoAddress);
2530 if (ReservedStack == NULL)
2532 goto _get_chained_info;
2538 while (i < countOfCodes)
2543 if (pUnwindInfoMap->
Version != 1 && pUnwindInfoMap->
Version != 2)
2552 if (!hasChainedUnwind)
2558 saveExtraSpace =
TRUE;
2604 if (HasFramePointer != NULL)
2606 *HasFramePointer =
TRUE;
2655 WARNING(
"[WARNING] Unknown info for UWOP_PUSH_MACHFRAME: %d\n",
2681 if (hasChainedUnwind && BeginAddress != NULL)
2683 *BeginAddress = *(
DWORD *)((
PBYTE)pUnwindInfoMap + (countOfCodes * 2ull) + 4);
2685 }
while (hasChainedUnwind);
2687 if (NULL != ReservedStack)
2689 *ReservedStack = extraSpace;
2692 if (exception && interrupt)
2694 WARNING(
"[WARNING] Why do we have both exception and interrupt context ? RIP 0x%016llx, Module 0x%016llx\n",
2695 ImageBase + RuntimeFunction->BeginAddress + RipOffset, ImageBase);
2698 if (NULL != ExceptionFunction)
2700 *ExceptionFunction = exception;
2703 if (NULL != InterruptFunction)
2705 *InterruptFunction = interrupt;
2711 if (pUnwindInfoMap != NULL)
2716 if (NULL == ImageBaseBuffer)
2759 DWORD unwindInfoRva;
2760 DWORD i, extraSpace;
2772 if (0 == BufferSize)
2777 if (NULL == RuntimeFunction)
2782 if (RipOffset > RuntimeFunction->EndAddress - RuntimeFunction->BeginAddress)
2784 ERROR(
"[ERROR] RipOffset %x, End %x, Begin %x, Total %x\n", RipOffset, RuntimeFunction->EndAddress,
2785 RuntimeFunction->BeginAddress, RuntimeFunction->EndAddress - RuntimeFunction->BeginAddress);
2789 hasChainedUnwind =
FALSE;
2790 interrupt = exception =
FALSE;
2793 if (BeginAddress != NULL)
2798 if (HasFramePointer != NULL)
2800 *HasFramePointer =
FALSE;
2806 unwindInfoRva =
ALIGN_DOWN(RuntimeFunction->UnwindData,
sizeof(
DWORD));
2808 if ((
QWORD)unwindInfoRva +
sizeof(*pUnwindInfo) + unwindInfoSize >= BufferSize)
2810 ERROR(
"[ERROR] Invalid unwind info at 0x%04x, we have only 0x%04x\n", unwindInfoRva, BufferSize);
2814 if (NULL != InterruptFunction)
2816 *InterruptFunction =
FALSE;
2819 if (NULL != ExceptionFunction)
2821 *ExceptionFunction =
FALSE;
2829 if ((
QWORD)unwindInfoRva +
sizeof(*pUnwindInfo) > BufferSize)
2837 ERROR(
"[ERROR] Reached MAX_UNWIND_INFO_TRIES for image at 0x%016llx\n", ImageBase);
2848 WARNING(
"[WARNING] Function with %d codes at RVA %08x in driver 0x%016llx with unwind info 0x%04x\n",
2849 countOfCodes, RuntimeFunction->BeginAddress, ImageBase, unwindInfoRva);
2853 if (ReservedStack == NULL)
2855 goto _get_chained_info;
2861 while (i < countOfCodes)
2876 if (!hasChainedUnwind)
2882 saveExtraSpace =
TRUE;
2928 if (HasFramePointer != NULL)
2930 *HasFramePointer =
TRUE;
2979 WARNING(
"[WARNING] Unknown info for UWOP_PUSH_MACHFRAME: %d\n",
3005 if (hasChainedUnwind && (
QWORD)unwindInfoRva +
sizeof(*pUnwindInfo) + unwindInfoSize >= BufferSize)
3007 ERROR(
"[ERROR] Invalid unwind info at 0x%04x, we have only 0x%04x\n", unwindInfoRva, BufferSize);
3012 if (hasChainedUnwind && BeginAddress != NULL)
3014 *BeginAddress = *(
DWORD *)((
BYTE *)pUnwindInfo + (countOfCodes * 2ull) + 4);
3016 }
while (hasChainedUnwind);
3018 if (NULL != ReservedStack)
3020 *ReservedStack = extraSpace;
3023 if (exception && interrupt)
3025 WARNING(
"[WARNING] Why do we have both exception and interrupt context ? RIP 0x%016llx, Module 0x%016llx\n",
3026 ImageBase + RuntimeFunction->BeginAddress + RipOffset, ImageBase);
3029 if (NULL != ExceptionFunction)
3031 *ExceptionFunction = exception;
3034 if (NULL != InterruptFunction)
3036 *InterruptFunction = interrupt;
3070 DWORD secheadersRva;
3098 if (Pattern->SectionHint[0] && !IgnoreSectionHint && 0 != memcmp(pSec->
Name, Pattern->SectionHint, 8))
3106 memcpy(name, pSec->
Name,
sizeof(pSec->
Name));
3109 ERROR(
"[ERROR] Section %s %08x with size %08x outside of image size %08x...\n",
3121 for (
DWORD k = 0; k < Pattern->Signature.Length; k++)
3123 if (
__likely(Pattern->Signature.Pattern[k] != 0x100 &&
3124 Pattern->Signature.Pattern[k] != p[j + k]))
3134 if (IgnoreSectionHint)
3136 TRACE(
"[DEBUG] Found function inside section %d:%s, was supposed to find in %s\n",
3137 i, pSec->
Name, Pattern->SectionHint);
3173 QWORD secheadersRva;
3180 ERROR(
"IntPeValidateHeader failed for image at 0x%016llx: 0x%08x\n", ImageBase, status);
3188 PBYTE pPage1, pPage2;
3189 DWORD rva, k, j, origStart;
3203 if (!IgnoreSectionHint && 0 != memcmp(hSec.
Name, Pattern->SectionHint, 8))
3223 origStart = j = k = 0;
3230 while ((k <
PAGE_SIZE) && (j < Pattern->Signature.Length) &&
3231 ((pPage1[k] == Pattern->Signature.Pattern[j]) ||
3232 (0x100 == Pattern->Signature.Pattern[j])))
3252 while ((l <
PAGE_SIZE) && (j < Pattern->Signature.Length) &&
3253 ((pPage2[l] == Pattern->Signature.Pattern[j]) ||
3254 (0x100 == Pattern->Signature.Pattern[j])))
3263 if (j != Pattern->Signature.Length)
3280 *Rva = rva + origStart;
3281 if (IgnoreSectionHint)
3283 TRACE(
"[DEBUG] Found function inside section %lld:%s, was supposed to find in %s\n",
3284 i, hSec.
Name, Pattern->SectionHint);
3328 if (NULL == BeginAddress)
3336 if (NULL != ImageBaseBuffer)
3338 map = ImageBaseBuffer;
3371 ERROR(
"[ERROR] IntCr3Read failed: 0x%08x\n", status);
3389 status =
IntPeParseUnwindData(ImageBase, map, &runtimeFunction, 0, NULL, BeginAddress, NULL, NULL, NULL);
3392 WARNING(
"[WARNING] IntPeParseUnwindData failed for 0x%08x: 0x%08x\n", *BeginAddress, status);
3399 PBYTE pageMap, code;
3400 QWORD currentAddress, functionStart;
3404 currentAddress = ImageBase + Rva;
3409 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", currentAddress, status);
3428 physicalUnmap =
FALSE;
3430 while (bytesToScan > 0)
3433 INSTRUX instruction;
3437 if (*code != 0xCC && *code != 0x90)
3443 functionStart = currentAddress + 1;
3449 while (*code == sepByte && bytesToScan > 1)
3476 ERROR(
"[ERROR] Failed mapping VA 0x%016llx with GPA 0x%016llx to host: 0x%08x\n",
3477 currentAddress & PAGE_MASK, prevPage, status);
3481 physicalUnmap =
TRUE;
3487 if (functionStart - currentAddress < 3)
3494 if ((*code == 0xc3 || *code == 0xCB) || ((((
QWORD)code &
PAGE_OFFSET) >= 0x2) && (*(code - 2) == 0xc2)) ||
3496 ((((
QWORD)code & PAGE_OFFSET) >= 0x4) && (*(code - 4) == 0xe9 || *(code - 4) == 0xe8)))
3505 if ((functionStart & PAGE_MASK) != (currentAddress &
PAGE_MASK) || (functionStart & PAGE_OFFSET) >= 0xff0)
3518 ndstatus = NdDecodeEx(&instruction, pageMap + pageMapOffset,
PAGE_SIZE - pageMapOffset,
3519 ND_CODE_32, ND_DATA_32);
3520 if (!ND_SUCCESS(ndstatus))
3528 if ((instruction.Instruction == ND_INS_MOV || instruction.Instruction == ND_INS_MOVZX ||
3529 instruction.Instruction == ND_INS_MOVS || instruction.Instruction == ND_INS_MOVSXD ||
3530 instruction.Instruction == ND_INS_MOVNTI) &&
3531 instruction.HasModRm)
3533 if (instruction.Operands[0].Size != 4)
3538 if ((instruction.ModRm.reg == 5 && instruction.ModRm.rm == 4) ||
3539 (instruction.ModRm.reg == 7 && instruction.ModRm.rm == 7))
3548 if ((ND_CAT_PUSH == instruction.Category) || (ND_INS_XOR == instruction.Instruction))
3580 ERROR(
"[ERROR] Failed mapping VA 0x%016llx with GPA 0x%016llx to host: 0x%08x\n",
3581 currentAddress & PAGE_MASK, prevPage, status);
3585 physicalUnmap =
TRUE;
3591 if (pageMap != NULL && physicalUnmap)
3595 else if (pageMap != NULL)
3610 *BeginAddress = 0xffffffff & (functionStart -
ImageBase);
3614 if (NULL == ImageBaseBuffer)
3660 if (0 == BufferSize)
3665 if (NULL == BeginAddress)
3670 if (Rva >= BufferSize)
3710 &runtimeFunction, 0, NULL, BeginAddress, NULL, NULL, NULL);
3713 WARNING(
"[WARNING] IntPeParseUnwindDataInBuffer failed for 0x%08x: 0x%08x\n", *BeginAddress, status);
3720 BYTE *code = Buffer + Rva;
3721 QWORD functionStartRva = 0;
3723 QWORD currentRva = Rva;
3736 while (bytesToScan > 0)
3739 INSTRUX instruction;
3748 if (*code != 0xCC && *code != 0x90)
3754 functionStartRva = currentRva + 1;
3756 if (functionStartRva >= BufferSize)
3765 while (code >= Buffer && *code == sepByte && bytesToScan)
3778 if (functionStartRva - currentRva < 3)
3785 if ((*code == 0xc3 || *code == 0xCB) ||
3787 ((((
QWORD)code & PAGE_OFFSET) >= 0x4) && (*(code - 4) == 0xe9 || *(code - 4) == 0xe8)))
3793 ndstatus = NdDecodeEx(&instruction, Buffer + functionStartRva, BufferSize - functionStartRva,
3794 ND_CODE_32, ND_DATA_32);
3795 if (!ND_SUCCESS(ndstatus))
3802 if ((instruction.Instruction == ND_INS_MOV || instruction.Instruction == ND_INS_MOVZX ||
3803 instruction.Instruction == ND_INS_MOVS || instruction.Instruction == ND_INS_MOVSXD ||
3804 instruction.Instruction == ND_INS_MOVNTI) &&
3805 instruction.HasModRm)
3807 if (instruction.Operands[0].Size != 4)
3812 if ((instruction.ModRm.reg == 5 && instruction.ModRm.rm == 4) ||
3813 (instruction.ModRm.reg == 7 && instruction.ModRm.rm == 7))
3822 if ((ND_CAT_PUSH == instruction.Category) || (ND_INS_XOR == instruction.Instruction))
3839 *BeginAddress = functionStartRva & 0xFFFFFFFF;
INTSTATUS IntPeFindFunctionByPattern(QWORD ImageBase, WIN_UNEXPORTED_FUNCTION_PATTERN *Pattern, BOOLEAN IgnoreSectionHint, DWORD *Rva)
Find a function using a pattern.
#define IMAGE_SCN_MEM_EXECUTE
INTSTATUS IntPeFindFunctionStartInBuffer(QWORD ImageBase, BYTE *Buffer, DWORD BufferSize, DWORD Rva, DWORD *BeginAddress)
Find the start address of a function, given a Rva pointing inside of it.
#define INT_STATUS_PAGE_NOT_PRESENT
Indicates that a virtual address is not present.
#define MAX_FUNC_LENGTH
The maximum length (in bytes) of a function.
INTSTATUS IntPeFindExportByName(QWORD ImageBase, BYTE *ImageBaseBuffer, CHAR *Name, DWORD *ExportRva)
Find the export name a Rva lies in.
INTSTATUS IntPeFindExportByRva(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD Rva)
Check if a RVA lies inside an exported function.
#define ROUND_UP(what, to)
struct _IMAGE_FILE_HEADER IMAGE_FILE_HEADER
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
IMAGE_OPTIONAL_HEADER64 OptionalHeader
WINDOWS_GUEST * gWinGuest
Global variable holding the state of a Windows guest.
QWORD SystemCr3
The Cr3 used to map the kernel.
#define INT_STATUS_SUCCESS
#define MAX_FILE_ALIGNMENT
#define PAGE_REMAINING(addr)
struct _IMAGE_DATA_DIRECTORY IMAGE_DATA_DIRECTORY
#define IMAGE_FILE_MACHINE_I386
#define IMAGE_OPTIONAL_HEADER_PE64
DWORD FileAlign
The number of bytes sections are aligned by on the disk.
#define UNW_FLAG_CHAININFO
UINT32 NumberOfRvaAndSizes
IMAGE_OPTIONAL_HEADER32 OptionalHeader
INTSTATUS IntPeGetRuntimeFunction(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD Rva, RUNTIME_FUNCTION *RuntimeFunction)
Parses the exception directory and gets the runtime function corresponding to the Rva...
#define INT_SUCCESS(Status)
#define MAX_UNWIND_INFO_TRIES
The maximum number of iterations done while parsing unwind data.
QWORD SectionOffset
Offset of the first section header.
IMAGE_FILE_HEADER FileHeader
INTSTATUS IntPeFindExportByRvaInBuffer(QWORD ImageBase, BYTE *Buffer, DWORD BufferSize, DWORD Rva)
Check if the indicated Rva belongs to an exported function.
INTSTATUS IntPeGetSectionHeadersByName(QWORD ImageBase, BYTE *ImageBaseBuffer, PCHAR Name, DWORD NumberOfSectionHeadersAllocated, QWORD Cr3, IMAGE_SECTION_HEADER *SectionHeaders, DWORD *NumberOfSectionHeadersFilled)
Return all the section headers matching the indicated Name.
#define _In_bytecount_(expr)
struct _RUNTIME_FUNCTION RUNTIME_FUNCTION
INTSTATUS IntPeGetDirectory(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD DirectoryEntry, IMAGE_DATA_DIRECTORY *Directory)
Validate & return the indicated image data directory.
#define HpAllocWithTag(Len, Tag)
int INTSTATUS
The status data type.
UINT32 AddressOfEntryPoint
#define INT_STATUS_NOT_FOUND
UINT32 AddressOfNameOrdinals
WORD Subsystem
The subsystem which the image belongs to.
INTSTATUS IntPeFindFunctionByPatternInBuffer(BYTE *Buffer, DWORD BufferSize, WIN_UNEXPORTED_FUNCTION_PATTERN *Pattern, BOOLEAN IgnoreSectionHint, DWORD *Rva)
Find a function using a pattern.
struct _OPTIONAL_HEADER_INFO OPTIONAL_HEADER_INFO
Structure describing relevant fields extracted from the optional header.
DWORD SectionAlign
The number of bytes sections are aligned by at runtime.
DWORD SectionAlignment
Sections alignment.
struct _INTRO_UNWIND_INFO::@227 UnwindCode[]
Describes a pattern for a kernel function that is not exported.
#define IMAGE_SIZEOF_SHORT_NAME
struct _IMAGE_OPTIONAL_HEADER IMAGE_OPTIONAL_HEADER32
UINT32 AddressOfEntryPoint
INTSTATUS IntPeFindExportByNameInBuffer(QWORD ImageBase, BYTE *Buffer, DWORD BufferSize, const char *Name, DWORD *ExportRva)
Find the export name a Rva lies in.
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
#define IMAGE_DOS_SIGNATURE
INTSTATUS IntKernVirtMemFetchDword(QWORD GuestVirtualAddress, DWORD *Data)
Reads 4 bytes from the guest kernel memory.
DWORD EntryPoint
Rva to the entry point of the image.
#define IG_CURRENT_VCPU
For APIs that take a VCPU number as a parameter, this can be used to specify that the current VCPU sh...
#define IMAGE_OPTIONAL_HEADER_PE32
QWORD ImageBase
The base of the image.
struct _IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER64
INTSTATUS IntTranslateVirtualAddress(QWORD Gva, QWORD Cr3, QWORD *PhysicalAddress)
Translates a guest virtual address to a guest physical address.
#define IN_RANGE_LEN(x, start, len)
#define INT_STATUS_INVALID_PARAMETER_4
QWORD NumberOfSections
Number of sections.
INTSTATUS IntPeValidateHeader(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD ImageBaseBufferSize, INTRO_PE_INFO *PeInfo, QWORD Cr3)
Validates a PE header.
UINT32 NumberOfRvaAndSizes
#define HpFreeAndNullWithTag(Add, Tag)
#define INT_STATUS_INVALID_PARAMETER_5
INTSTATUS IntPeParseUnwindData(QWORD ImageBase, BYTE *ImageBaseBuffer, RUNTIME_FUNCTION *RuntimeFunction, DWORD RipOffset, DWORD *ReservedStack, DWORD *BeginAddress, BOOLEAN *InterruptFunction, BOOLEAN *ExceptionFunction, BOOLEAN *HasFramePointer)
Parse the unwind data for the indicated function and return the prologue size.
QWORD KernelVa
The guest virtual address at which the kernel image.
#define _In_reads_or_z_(expr)
#define IMAGE_NT_SIGNATURE
union _IMAGE_SECTION_HEADER::@214 Misc
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]
size_t strlcpy(char *dst, const char *src, size_t dest_size)
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES
INTSTATUS IntPeGetSectionHeaderByRva(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD GuestRva, IMAGE_SECTION_HEADER *SectionHeader)
Given a relative virtual address, return the section header which describes the section the RVA lies ...
#define IMAGE_FILE_MACHINE_AMD64
INTSTATUS IntPeListSectionsHeaders(QWORD ImageBase, BYTE *ImageBuffer, DWORD ImageBufferSize, DWORD *FirstSectionOffset, DWORD *SectionCount)
Will get the offset to the first section header and the number of sections from the given module...
#define IMAGE_DIRECTORY_ENTRY_EXPORT
INTSTATUS IntPeGetRuntimeFunctionInBuffer(QWORD ImageBase, BYTE *Buffer, DWORD BufferSize, DWORD Rva, RUNTIME_FUNCTION *RuntimeFunction)
Parses the exception directory and gets the runtime function corresponding to the Rva...
#define INT_STATUS_DATA_BUFFER_TOO_SMALL
DWORD KernelBufferSize
The size of the KernelBuffer.
#define INT_STATUS_INVALID_PARAMETER_6
#define MAX_UNWIND_CODES
Maximum number of unwind codes to check.
#define IMAGE_SCN_CNT_CODE
#define INT_STATUS_INVALID_OBJECT_TYPE
__must_check INTSTATUS IntVirtMemMap(QWORD Gva, DWORD Length, QWORD Cr3, DWORD Flags, void **HostPtr)
Maps a guest virtual memory range inside Introcore virtual address space.
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Structure describing relevant fields extracted from the optional header.
GUEST_STATE gGuest
The current guest state.
#define INT_STATUS_INVALID_DATA_TYPE
INTSTATUS IntPeGetExportNameByRvaInBuffer(QWORD ImageBase, BYTE *Buffer, DWORD BufferSize, DWORD Rva, DWORD ExportNameSize, CHAR *ExportName)
Find the export name a Rva lies in.
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
INTSTATUS IntPeFindFunctionStart(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD Rva, DWORD *BeginAddress)
Find the start address of a function, given a Rva pointing inside of it.
DWORD SizeOfImage
The size of the image.
IMAGE_FILE_HEADER FileHeader
INTSTATUS IntCr3Read(DWORD CpuNumber, QWORD *Cr3Value)
Reads the value of the guest CR3.
static INTSTATUS IntPeValidateOptionalHeader(void *OptionalHeader, DWORD SizeOfOptionalHeader, OPTIONAL_HEADER_INFO *Info)
Validates and extracts info about the optional header.
#define _Out_writes_z_(expr)
__must_check INTSTATUS IntPhysMemMap(QWORD PhysAddress, DWORD Length, DWORD Flags, void **HostPtr)
Maps a guest physical address inside Introcore VA space.
struct _OPTIONAL_HEADER_INFO * POPTIONAL_HEADER_INFO
BYTE * KernelBuffer
A buffer containing the entire kernel image.
#define MAX_NUMBER_OF_EXPORT_NAMES
We won't consider a valid image if it has more than MAX_NUMBER_OF_EXPORT_NAMES names.
BOOLEAN Image64
True if the image is considered 64 bits, False otherwise.
#define INT_STATUS_NOT_SUPPORTED
UINT8 Name[IMAGE_SIZEOF_SHORT_NAME]
UINT32 AddressOfFunctions
INTSTATUS IntPeGetExportNameByRva(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD Rva, DWORD ExportNameSize, CHAR *ExportName)
Find the export name a Rva lies in.
INTSTATUS IntPeParseUnwindDataInBuffer(QWORD ImageBase, BYTE *Buffer, DWORD BufferSize, RUNTIME_FUNCTION *RuntimeFunction, DWORD RipOffset, DWORD *ReservedStack, DWORD *BeginAddress, BOOLEAN *InterruptFunction, BOOLEAN *ExceptionFunction, BOOLEAN *HasFramePointer)
Parse the unwind data for the indicated function and return the prologue size.
DWORD SizeOfImage
Size of the image.
BOOLEAN Image64Bit
True if the image is 64 bit.
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION
INTSTATUS IntPeFindExportByOrdinal(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD Ordinal, DWORD *ExportRva)
Find an exported function using its ordinal.
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]
#define MAX_SIZE_OF_IMAGE
INTSTATUS IntPhysMemUnmap(void **HostPtr)
Unmaps an address previously mapped with IntPhysMemMap.
INTSTATUS IntPeGetSectionHeaderByIndex(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD Index, IMAGE_SECTION_HEADER *SectionHeader)
Return the section header located on position Index (0 based).
#define INT_STATUS_INVALID_PARAMETER_2
INTSTATUS IntDecDecodeInstruction(IG_CS_TYPE CsType, QWORD Gva, void *Instrux)
Decode an instruction from the provided guest linear address.
INTSTATUS IntPeFindKernelExport(const char *Name, QWORD *ExportGva)
Find an export inside the NT kernel image.
UINT16 SizeOfOptionalHeader
#define INT_STATUS_INVALID_DATA_SIZE
#define INT_STATUS_INSUFFICIENT_RESOURCES
#define INT_STATUS_INVALID_PARAMETER_3