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, secOff = 0;
174 DWORD sectionAlign = 0, fileAlign = 0;
181 ERROR(
"[ERROR] Image at 0x%016llx is not page-aligned\n", ImageBase);
185 if (NULL != ImageBaseBuffer)
187 pBase = ImageBaseBuffer;
188 size = ImageBaseBufferSize;
194 ERROR(
"[ERROR] Can not map MZPE image at GVA 0x%016llx!\n", ImageBase);
201 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
223 if (e_lfanew >= size)
257 ERROR(
"[ERROR] Image at 0x%016llx has an invalid optional header!\n", ImageBase);
263 WARNING(
"[WARNING] Image 0x%016llx is AMD64 but has a PE32 optional header! Will consider it 32 bits\n",
285 ERROR(
"[ERROR] Image at 0x%016llx has an invalid optional header!\n", ImageBase);
291 WARNING(
"[WARNING] Image 0x%016llx is I386 but has a PE64 optional header! Will consider it 64 bits\n",
311 ERROR(
"[ERROR] Image at 0x%016llx has SizeOfImage (0x%08x) larger than the maximum allowed (0x%016llx)\n",
317 if (sectionAlign == 0)
319 ERROR(
"[ERROR] Section alignment is 0 for image at 0x%016llx\n", ImageBase);
324 if ((sectionAlign < fileAlign) || (fileAlign < MIN_FILE_ALIGNMENT || fileAlign >
MAX_FILE_ALIGNMENT))
326 WARNING(
"[WARNING] Image alignments invalid. FileAlignment: 0x%08x, SectionAlignment: 0x%08x. " 327 "The image at 0x%016llx may have been tampered with\n",
328 fileAlign, sectionAlign, ImageBase);
333 ERROR(
"[ERROR] Sections headers point out of the mapping. SectionOffset: 0x%08x; NrOfSections: %d; " 334 "MaxSize: 0x%08lx; MappingSize: 0x%08x. Image base: 0x%016llx\n",
335 secOff, numberOfSections, secOff +
sizeof(
IMAGE_SECTION_HEADER) * numberOfSections, size, ImageBase);
340 if (entryPoint >= sizeOfImage)
342 ERROR(
"[ERROR] EntryPoint points out of the file. EntryPoint: 0x%08x; SizeOfImage: 0x%08x; " 343 "ImageBase: 0x%016llx\n",
344 entryPoint, sizeOfImage, ImageBase);
350 if (e_lfanew >= sizeOfImage)
352 WARNING(
"[WARNING] e_lfanew 0x%llx points outside of image 0x%08x. Module 0x%016llx\n",
353 e_lfanew, sizeOfImage, ImageBase);
360 for (
DWORD i = 0; i < numberOfSections; i++, pSec++)
365 actualSectionSize =
ROUND_UP(secVirtSize ? secVirtSize : secSizeOfRawData, sectionAlign);
367 if (0 == actualSectionSize)
370 memcpy(name, pSec->
Name,
sizeof(pSec->
Name));
373 ERROR(
"[ERROR] Section %d (%s) for image at 0x%016llx has actual size 0. VirtualSize = 0x%08x " 374 "SizeOfRawData = 0x%08x Align = 0x%08x\n",
375 i, name, ImageBase, secVirtSize, secSizeOfRawData, sectionAlign);
383 memcpy(name, pSec->
Name,
sizeof(pSec->
Name));
386 ERROR(
"[ERROR] Section starting at 0. Section name: %s\n", name);
391 if (0 == secVirtSize && (0 == secSizeOfRawData || secSizeOfRawData >
PAGE_SIZE))
394 memcpy(name, pSec->
Name,
sizeof(pSec->
Name));
397 ERROR(
"[ERROR] Section %d (%s) size is invalid for image at 0x%016llx. " 398 "VirtualSize: 0x%08x. SizeOfRawData: 0x%08x\n",
406 (actualSectionSize > sizeOfImage) ||
410 memcpy(name, pSec->
Name,
sizeof(pSec->
Name));
413 ERROR(
"[ERROR] Section %d (%s) for image at 0x%016llx seems corrupted: " 414 "sizeOfImage = 0x%x, secStart = 0x%x, secSize = 0x%x, actualSecSize = 0x%08x\n",
423 PeInfo->Image64Bit = image64;
424 PeInfo->SectionOffset = secOff;
425 PeInfo->SizeOfImage = sizeOfImage;
426 PeInfo->TimeDateStamp = timeDateStamp;
427 PeInfo->EntryPoint = entryPoint;
428 PeInfo->NumberOfSections = numberOfSections;
429 PeInfo->Subsystem = subsystem;
430 PeInfo->ImageBase = imageBase;
431 PeInfo->SectionAlignment = sectionAlign;
432 PeInfo->Machine = machine;
438 if (NULL == ImageBaseBuffer)
474 if (NULL == FirstSectionOffset)
479 if (NULL == SectionCount)
484 if (NULL != ImageBuffer)
487 size = ImageBufferSize;
494 ERROR(
"[ERROR] IntVirtMemMap failed: 0x%08x\n", status);
504 ERROR(
"[ERROR] IntPeValidateHeader failed: 0x%08x\n", status);
505 goto cleanup_and_exit;
512 if (NULL == ImageBuffer)
518 ERROR(
"[ERROR] IntVirtMemUnmap failed: 0x%08x\n", status2);
561 if (NULL == Directory)
566 unmapNtHeaders =
FALSE;
568 if (NULL != ImageBaseBuffer)
570 map = ImageBaseBuffer;
577 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
601 status =
IntVirtMemMap(ImageBase + e_lfanew,
sizeof(*pNth64), 0, 0, &pNth64);
604 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase + e_lfanew, status);
608 unmapNtHeaders =
TRUE;
624 status =
IntVirtMemMap(ImageBase + e_lfanew,
sizeof(*pNth32), 0, 0, &pNth32);
627 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase + e_lfanew, status);
631 unmapNtHeaders =
TRUE;
638 if (Directory->VirtualAddress == 0 || Directory->Size == 0)
645 if ((
QWORD)Directory->Size + Directory->VirtualAddress > peInfo.
SizeOfImage)
666 if (NULL == ImageBaseBuffer)
673 Directory->VirtualAddress = 0;
710 if (NULL == SectionHeader)
715 if (NULL != ImageBaseBuffer)
717 map = ImageBaseBuffer;
724 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
729 unmapSecHeaders =
FALSE;
762 if (NULL == pSecHeader)
768 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host with size %llu: 0x%08x\n",
773 unmapSecHeaders =
TRUE;
781 if (GuestRva >= pSecHeader[i].VirtualAddress &&
798 if (NULL == ImageBaseBuffer)
805 memzero(SectionHeader,
sizeof(*SectionHeader));
838 if (NULL == SectionHeader)
843 if (NULL != ImageBaseBuffer)
845 map = ImageBaseBuffer;
852 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
886 if (NULL == pSecHeader)
894 ERROR(
"[ERROR] Failed reading section header from GVA 0x%016llx: 0x%08x\n",
907 if (NULL == ImageBaseBuffer)
921 _In_ DWORD NumberOfSectionHeadersAllocated,
946 DWORD numberSectionsFound;
952 if (0 == NumberOfSectionHeadersAllocated)
957 if (NULL == SectionHeaders)
962 if (NULL != ImageBaseBuffer)
964 map = ImageBaseBuffer;
971 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
976 unmapSecHeaders =
FALSE;
978 numberSectionsFound = 0;
1010 if (NULL == pSecHeader)
1016 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host with size 0x%016llx: 0x%08x\n",
1021 unmapSecHeaders =
TRUE;
1025 cmpSize = strlen(Name) + 1;
1030 if (memcmp(Name, pSecHeader[i].Name, cmpSize) == 0)
1034 numberSectionsFound++;
1036 if (numberSectionsFound == NumberOfSectionHeadersAllocated)
1043 if (0 == numberSectionsFound)
1052 if (NULL != NumberOfSectionHeadersFilled)
1054 *NumberOfSectionHeadersFilled = numberSectionsFound;
1058 if (unmapSecHeaders)
1063 if (NULL == ImageBaseBuffer)
1070 memzero(SectionHeaders,
sizeof(*SectionHeaders) * NumberOfSectionHeadersAllocated);
1099 DWORD beginRva, i, size;
1109 if (NULL != ImageBaseBuffer)
1111 map = ImageBaseBuffer;
1118 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
1157 ERROR(
"[ERROR] Failed mapping AddressOfFunctions 0x%016llx (0x%016llx + 0x%08x): 0x%08x\n",
1165 while (parsed + mappingSize <
PAGE_SIZE)
1168 if (*(
DWORD *)(functions + parsed) == beginRva)
1177 address += mappingSize;
1188 if (NULL == ImageBaseBuffer)
1263 if (size > BufferSize)
1268 for (
DWORD i = 0; i < size; i += 4)
1317 if (0 == ExportNameSize)
1322 if (NULL == ExportName)
1327 if (NULL != ImageBaseBuffer)
1329 map = ImageBaseBuffer;
1336 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
1345 goto _cleanup_and_leave;
1354 WARNING(
"[WARNING] Failed to read the export directory of 0x%016llx located at 0x%016llx: 0x%08x\n",
1357 goto _cleanup_and_leave;
1366 goto _cleanup_and_leave;
1371 DWORD exportOrdinal, exportRva, namePointer, retLen;
1379 exportOrdinal &= 0xFFFF;
1388 if (exportRva != Rva)
1397 goto _cleanup_and_leave;
1401 status =
IntKernVirtMemRead(ImageBase + namePointer, ExportNameSize, ExportName, &retLen);
1404 goto _cleanup_and_leave;
1408 ExportName[retLen - 1] = 0;
1418 goto _cleanup_and_leave;
1422 if (ImageBaseBuffer == NULL)
1466 if (0 == BufferSize)
1471 if (0 == ExportNameSize)
1476 if (NULL == ExportName)
1518 DWORD exportOrdinal, exportRva, namePointer;
1533 if (exportRva != Rva)
1545 if ((
QWORD)namePointer + ExportNameSize > BufferSize)
1551 strlcpy(ExportName, (
char *)Buffer + namePointer, ExportNameSize);
1585 size_t exportNameLen;
1599 if (NULL == ExportRva)
1604 exportNameLen = strlen(Name);
1607 if (exportNameLen >= 512)
1645 while (left < right)
1649 size_t cmpSize = exportNameLen + 1;
1652 mid = (left + right) / 2;
1655 if (offset +
sizeof(namePointer) > BufferSize)
1657 WARNING(
"[WARNING] Corrupted export name pointer: 0x%lx is outside of image size of 0x%x\n",
1658 offset +
sizeof(namePointer), BufferSize);
1662 namePointer = *(
DWORD *)(Buffer + offset);
1664 if (namePointer >= BufferSize)
1666 WARNING(
"[WARNING] Corrupted export name. Name pointer 0x%08x is outside of image size: 0x%08x\n",
1667 namePointer, BufferSize);
1671 if (namePointer + cmpSize > BufferSize)
1675 cmpSize = BufferSize - namePointer;
1679 res = memcmp(Name, Buffer + namePointer, cmpSize);
1686 if (offset +
sizeof(ord) > BufferSize)
1688 WARNING(
"[WARNING] Corrupted export ordinal: 0x%lx is outside of image size of 0x%x\n",
1689 offset +
sizeof(ord), BufferSize);
1693 ord = *(
WORD *)(Buffer + offset);
1696 if (offset +
sizeof(*ExportRva) > BufferSize)
1698 WARNING(
"[WARNING] Corrupted export address: 0x%lx is outside of image size of 0x%x\n",
1699 offset +
sizeof(*ExportRva), BufferSize);
1703 *ExportRva = *(
DWORD *)(Buffer + offset);
1784 BYTE *exportNameBuffer;
1793 if (NULL == ExportRva)
1798 exportNameBuffer = NULL;
1800 exportNameLen = strlen(Name);
1802 if (exportNameLen >= 512)
1807 if (NULL != ImageBaseBuffer)
1809 map = ImageBaseBuffer;
1816 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
1835 WARNING(
"[ERROR] Failed to read the export directory of 0x%016llx located at 0x%016llx: 0x%08x\n",
1843 if (NULL == exportNameBuffer)
1853 while (left < right)
1858 mid = (left + right) / 2;
1873 res = memcmp(Name, exportNameBuffer, exportNameLen + 1ull);
1877 DWORD exportOrdinal;
1886 exportOrdinal &= 0xFFFF;
1911 if (NULL != exportNameBuffer)
1916 if (ImageBaseBuffer == NULL)
1962 if (NULL == ExportRva)
1969 if (NULL != ImageBaseBuffer)
1971 map = ImageBaseBuffer;
1978 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
1997 WARNING(
"[ERROR] Failed to read the export directory of 0x%016llx located at 0x%016llx: 0x%08x\n",
2017 if (ImageBaseBuffer == NULL)
2061 QWORD currentAddress;
2066 if (NULL == RuntimeFunction)
2072 pRuntimeFunction = NULL;
2074 if (NULL != ImageBaseBuffer)
2076 map = ImageBaseBuffer;
2083 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
2104 ERROR(
"[ERROR] No exception directory for ImageBase 0x%016llx: 0x%08x\n", ImageBase, status);
2132 ERROR(
"[ERROR] IntKernVirtMemFetchDword failed for GVA 0x%016llx (dir->RVA 0x%08x, dir->Size 0x%08x, " 2133 "ImageBase 0x%016llx: 0x%08x\n", currentAddress + lastTableInPage, dir.
VirtualAddress,
2134 dir.
Size, ImageBase, status);
2137 else if (beginRva == Rva)
2143 ERROR(
"[ERROR] Failed reading runtime function from address 0x%016llx: 0x%08x\n",
2144 currentAddress + lastTableInPage, status);
2149 else if (beginRva > Rva)
2168 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", currentAddress, status);
2176 if (pRuntimeFunction[i].BeginAddress <= Rva && pRuntimeFunction[i].EndAddress > Rva)
2186 if (pRuntimeFunction[i].UnwindData %
sizeof(
DWORD) != 0)
2199 ERROR(
"[ERROR] Failed mapping next unwind data for runtime function at " 2200 "0x%016llx in driver 0x%016llx",
2210 TRACE(
"[INFO] We have a function at 0x%016llx but it's not inside the exception dir (0x%016llx, %x)\n",
2214 goto _cleanup_and_leave;
2232 if (NULL == ImageBaseBuffer)
2277 if (0 == BufferSize)
2282 if (NULL == RuntimeFunction)
2302 ERROR(
"[ERROR] No exception directory for ImageBase 0x%016llx: 0x%08x\n", ImageBase, status);
2315 while (left < right)
2317 size_t midd = (left + right) / 2;
2356 TRACE(
"[INFO] We have a function at 0x%016llx but it's not inside the exception dir (0x%016llx, %x)\n",
2401 QWORD unwindInfoAddress;
2402 DWORD unwindInfoSize, i, extraSpace;
2410 if (NULL == RuntimeFunction)
2415 if (RipOffset > RuntimeFunction->EndAddress - RuntimeFunction->BeginAddress)
2417 ERROR(
"[ERROR] RipOffset %x, End %x, Begin %x, Total %x\n", RipOffset, RuntimeFunction->EndAddress,
2418 RuntimeFunction->BeginAddress, RuntimeFunction->EndAddress - RuntimeFunction->BeginAddress);
2422 if (NULL != ImageBaseBuffer)
2424 map = ImageBaseBuffer;
2431 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", ImageBase, status);
2436 hasChainedUnwind =
FALSE;
2437 interrupt = exception =
FALSE;
2438 pUnwindInfoMap = NULL;
2441 if (NULL != BeginAddress)
2446 if (NULL != HasFramePointer)
2448 *HasFramePointer =
FALSE;
2454 unwindInfoAddress =
ALIGN_DOWN(ImageBase + RuntimeFunction->UnwindData,
sizeof(
DWORD));
2457 if (NULL != InterruptFunction)
2459 *InterruptFunction =
FALSE;
2462 if (NULL != ExceptionFunction)
2464 *ExceptionFunction =
FALSE;
2472 if (pUnwindInfoMap != NULL)
2480 ERROR(
"[ERROR] Reached MAX_UNWIND_INFO_TRIES for image at 0x%016llx\n", ImageBase);
2485 status =
IntVirtMemMap(unwindInfoAddress, unwindInfoSize, 0, 0, &pUnwindInfoMap);
2488 ERROR(
"[ERROR] IntVirtMemMap failed for GVA 0x%016llx (chained: %s, RIP: 0x%016llx): 0x%08x\n",
2489 unwindInfoAddress, hasChainedUnwind ?
"TRUE" :
"FALSE", ImageBase + RuntimeFunction->BeginAddress,
2499 WARNING(
"[WARNING] Function with %d codes at RVA %08x in driver 0x%016llx with unwind info %llx\n",
2500 countOfCodes, RuntimeFunction->BeginAddress, ImageBase, unwindInfoAddress);
2505 if (ReservedStack == NULL)
2507 goto _get_chained_info;
2513 while (i < countOfCodes)
2516 if (pUnwindInfoMap->
Version != 1 && pUnwindInfoMap->
Version != 2)
2525 if (!hasChainedUnwind)
2531 saveExtraSpace =
TRUE;
2577 if (HasFramePointer != NULL)
2579 *HasFramePointer =
TRUE;
2628 WARNING(
"[WARNING] Unknown info for UWOP_PUSH_MACHFRAME: %d\n",
2654 if (hasChainedUnwind && BeginAddress != NULL)
2658 }
while (hasChainedUnwind);
2660 if (NULL != ReservedStack)
2662 *ReservedStack = extraSpace;
2665 if (exception && interrupt)
2667 WARNING(
"[WARNING] Why do we have both exception and interrupt context ? RIP 0x%016llx, Module 0x%016llx\n",
2668 ImageBase + RuntimeFunction->BeginAddress + RipOffset, ImageBase);
2671 if (NULL != ExceptionFunction)
2673 *ExceptionFunction = exception;
2676 if (NULL != InterruptFunction)
2678 *InterruptFunction = interrupt;
2684 if (pUnwindInfoMap != NULL)
2689 if (NULL == ImageBaseBuffer)
2732 DWORD unwindInfoRva;
2733 DWORD i, extraSpace;
2745 if (0 == BufferSize)
2750 if (NULL == RuntimeFunction)
2755 if (RipOffset > RuntimeFunction->EndAddress - RuntimeFunction->BeginAddress)
2757 ERROR(
"[ERROR] RipOffset %x, End %x, Begin %x, Total %x\n", RipOffset, RuntimeFunction->EndAddress,
2758 RuntimeFunction->BeginAddress, RuntimeFunction->EndAddress - RuntimeFunction->BeginAddress);
2762 hasChainedUnwind =
FALSE;
2763 interrupt = exception =
FALSE;
2766 if (BeginAddress != NULL)
2771 if (HasFramePointer != NULL)
2773 *HasFramePointer =
FALSE;
2779 unwindInfoRva =
ALIGN_DOWN(RuntimeFunction->UnwindData,
sizeof(
DWORD));
2781 if ((
QWORD)unwindInfoRva +
sizeof(*pUnwindInfo) + unwindInfoSize >= BufferSize)
2783 ERROR(
"[ERROR] Invalid unwind info at 0x%04x, we have only 0x%04x\n", unwindInfoRva, BufferSize);
2787 if (NULL != InterruptFunction)
2789 *InterruptFunction =
FALSE;
2792 if (NULL != ExceptionFunction)
2794 *ExceptionFunction =
FALSE;
2800 if ((
QWORD)unwindInfoRva +
sizeof(*pUnwindInfo) > BufferSize)
2808 ERROR(
"[ERROR] Reached MAX_UNWIND_INFO_TRIES for image at 0x%016llx\n", ImageBase);
2817 WARNING(
"[WARNING] Function with %d codes at RVA %08x in driver 0x%016llx with unwind info 0x%04x\n",
2818 pUnwindInfo->
CountOfCodes, RuntimeFunction->BeginAddress, ImageBase, unwindInfoRva);
2822 if (ReservedStack == NULL)
2824 goto _get_chained_info;
2830 while (i < pUnwindInfo->CountOfCodes)
2844 if (!hasChainedUnwind)
2850 saveExtraSpace =
TRUE;
2896 if (HasFramePointer != NULL)
2898 *HasFramePointer =
TRUE;
2947 WARNING(
"[WARNING] Unknown info for UWOP_PUSH_MACHFRAME: %d\n",
2973 if (hasChainedUnwind && (
QWORD)unwindInfoRva +
sizeof(*pUnwindInfo) + unwindInfoSize >= BufferSize)
2975 ERROR(
"[ERROR] Invalid unwind info at 0x%04x, we have only 0x%04x\n", unwindInfoRva, BufferSize);
2980 if (hasChainedUnwind && BeginAddress != NULL)
2984 }
while (hasChainedUnwind);
2986 if (NULL != ReservedStack)
2988 *ReservedStack = extraSpace;
2991 if (exception && interrupt)
2993 WARNING(
"[WARNING] Why do we have both exception and interrupt context ? RIP 0x%016llx, Module 0x%016llx\n",
2994 ImageBase + RuntimeFunction->BeginAddress + RipOffset, ImageBase);
2997 if (NULL != ExceptionFunction)
2999 *ExceptionFunction = exception;
3002 if (NULL != InterruptFunction)
3004 *InterruptFunction = interrupt;
3038 DWORD secheadersRva;
3066 if (Pattern->SectionHint[0] && !IgnoreSectionHint && 0 != memcmp(pSec->
Name, Pattern->SectionHint, 8))
3074 memcpy(name, pSec->
Name,
sizeof(pSec->
Name));
3077 ERROR(
"[ERROR] Section %s %08x with size %08x outside of image size %08x...\n",
3089 for (
DWORD k = 0; k < Pattern->Signature.Length; k++)
3091 if (
__likely(Pattern->Signature.Pattern[k] != 0x100 &&
3092 Pattern->Signature.Pattern[k] != p[j + k]))
3102 if (IgnoreSectionHint)
3104 TRACE(
"[DEBUG] Found function inside section %d:%s, was supposed to find in %s\n",
3105 i, pSec->
Name, Pattern->SectionHint);
3141 QWORD secheadersRva;
3148 ERROR(
"IntPeValidateHeader failed for image at 0x%016llx: 0x%08x\n", ImageBase, status);
3156 PBYTE pPage1, pPage2;
3157 DWORD rva, k, j, origStart;
3171 if (!IgnoreSectionHint && 0 != memcmp(hSec.
Name, Pattern->SectionHint, 8))
3191 origStart = j = k = 0;
3198 while ((k <
PAGE_SIZE) && (j < Pattern->Signature.Length) &&
3199 ((pPage1[k] == Pattern->Signature.Pattern[j]) ||
3200 (0x100 == Pattern->Signature.Pattern[j])))
3220 while ((l <
PAGE_SIZE) && (j < Pattern->Signature.Length) &&
3221 ((pPage2[l] == Pattern->Signature.Pattern[j]) ||
3222 (0x100 == Pattern->Signature.Pattern[j])))
3231 if (j != Pattern->Signature.Length)
3248 *Rva = rva + origStart;
3249 if (IgnoreSectionHint)
3251 TRACE(
"[DEBUG] Found function inside section %lld:%s, was supposed to find in %s\n",
3252 i, hSec.
Name, Pattern->SectionHint);
3296 if (NULL == BeginAddress)
3304 if (NULL != ImageBaseBuffer)
3306 map = ImageBaseBuffer;
3339 ERROR(
"[ERROR] IntCr3Read failed: 0x%08x\n", status);
3357 status =
IntPeParseUnwindData(ImageBase, map, &runtimeFunction, 0, NULL, BeginAddress, NULL, NULL, NULL);
3360 WARNING(
"[WARNING] IntPeParseUnwindData failed for 0x%08x: 0x%08x\n", *BeginAddress, status);
3367 PBYTE pageMap, code;
3368 QWORD currentAddress, functionStart;
3372 currentAddress = ImageBase + Rva;
3377 ERROR(
"[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", currentAddress, status);
3396 physicalUnmap =
FALSE;
3398 while (bytesToScan > 0)
3401 INSTRUX instruction;
3405 if (*code != 0xCC && *code != 0x90)
3411 functionStart = currentAddress + 1;
3417 while (*code == sepByte && bytesToScan > 1)
3444 ERROR(
"[ERROR] Failed mapping VA 0x%016llx with GPA 0x%016llx to host: 0x%08x\n",
3445 currentAddress & PAGE_MASK, prevPage, status);
3449 physicalUnmap =
TRUE;
3455 if (functionStart - currentAddress < 3)
3462 if ((*code == 0xc3 || *code == 0xCB) || ((((
QWORD)code &
PAGE_OFFSET) >= 0x2) && (*(code - 2) == 0xc2)) ||
3464 ((((
QWORD)code & PAGE_OFFSET) >= 0x4) && (*(code - 4) == 0xe9 || *(code - 4) == 0xe8)))
3473 if ((functionStart & PAGE_MASK) != (currentAddress &
PAGE_MASK) || (functionStart & PAGE_OFFSET) >= 0xff0)
3486 ndstatus = NdDecodeEx(&instruction, pageMap + pageMapOffset,
PAGE_SIZE - pageMapOffset,
3487 ND_CODE_32, ND_DATA_32);
3488 if (!ND_SUCCESS(ndstatus))
3496 if ((instruction.Instruction == ND_INS_MOV || instruction.Instruction == ND_INS_MOVZX ||
3497 instruction.Instruction == ND_INS_MOVS || instruction.Instruction == ND_INS_MOVSXD ||
3498 instruction.Instruction == ND_INS_MOVNTI) &&
3499 instruction.HasModRm)
3501 if (instruction.Operands[0].Size != 4)
3506 if ((instruction.ModRm.reg == 5 && instruction.ModRm.rm == 4) ||
3507 (instruction.ModRm.reg == 7 && instruction.ModRm.rm == 7))
3516 if ((ND_CAT_PUSH == instruction.Category) || (ND_INS_XOR == instruction.Instruction))
3548 ERROR(
"[ERROR] Failed mapping VA 0x%016llx with GPA 0x%016llx to host: 0x%08x\n",
3549 currentAddress & PAGE_MASK, prevPage, status);
3553 physicalUnmap =
TRUE;
3559 if (pageMap != NULL && physicalUnmap)
3563 else if (pageMap != NULL)
3578 *BeginAddress = 0xffffffff & (functionStart -
ImageBase);
3582 if (NULL == ImageBaseBuffer)
3628 if (0 == BufferSize)
3633 if (NULL == BeginAddress)
3638 if (Rva >= BufferSize)
3678 &runtimeFunction, 0, NULL, BeginAddress, NULL, NULL, NULL);
3681 WARNING(
"[WARNING] IntPeParseUnwindDataInBuffer failed for 0x%08x: 0x%08x\n", *BeginAddress, status);
3688 BYTE *code = Buffer + Rva;
3689 QWORD functionStartRva = 0;
3691 QWORD currentRva = Rva;
3704 while (bytesToScan > 0)
3707 INSTRUX instruction;
3716 if (*code != 0xCC && *code != 0x90)
3722 functionStartRva = currentRva + 1;
3724 if (functionStartRva >= BufferSize)
3733 while (code >= Buffer && *code == sepByte && bytesToScan)
3746 if (functionStartRva - currentRva < 3)
3753 if ((*code == 0xc3 || *code == 0xCB) ||
3755 ((((
QWORD)code & PAGE_OFFSET) >= 0x4) && (*(code - 4) == 0xe9 || *(code - 4) == 0xe8)))
3761 ndstatus = NdDecodeEx(&instruction, Buffer + functionStartRva, BufferSize - functionStartRva,
3762 ND_CODE_32, ND_DATA_32);
3763 if (!ND_SUCCESS(ndstatus))
3770 if ((instruction.Instruction == ND_INS_MOV || instruction.Instruction == ND_INS_MOVZX ||
3771 instruction.Instruction == ND_INS_MOVS || instruction.Instruction == ND_INS_MOVSXD ||
3772 instruction.Instruction == ND_INS_MOVNTI) &&
3773 instruction.HasModRm)
3775 if (instruction.Operands[0].Size != 4)
3780 if ((instruction.ModRm.reg == 5 && instruction.ModRm.rm == 4) ||
3781 (instruction.ModRm.reg == 7 && instruction.ModRm.rm == 7))
3790 if ((ND_CAT_PUSH == instruction.Category) || (ND_INS_XOR == instruction.Instruction))
3807 *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.
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.
union _IMAGE_SECTION_HEADER::@209 Misc
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)
struct _INTRO_UNWIND_INFO::@222 UnwindCode[]
#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
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