Runs a series of test cases to validate the behavior of the RSDS parser helper functions.
450{
451 BYTE Buffer[RsdsFixtureSize] = {0};
453
454 RsdsBuildMinimalPe(Buffer,
FALSE);
455 RsdsWriteValidDebugEntry(Buffer, RsdsGuid64, 7, "symbols\\valid64.pdb");
456 TestNum++;
457 if (RsdsExpectSuccess(Buffer, "valid64.pdb", RsdsGuid64, 7))
458 {
459 printf(
"[+] Test number %d Passed\n", TestNum);
460 }
461 else
462 {
463 printf(
"[-] Test number %d Failed\n", TestNum);
464 printf(
"[x] valid PE32+ RSDS entry was not parsed\n");
466 }
467
468 RsdsBuildMinimalPe(Buffer,
FALSE);
469 RsdsWriteValidDebugEntry(Buffer, RsdsGuid64, 7, "symbols\\unadvertised.pdb");
470 RsdsSetNumberOfRvaAndSizes(Buffer, IMAGE_DIRECTORY_ENTRY_DEBUG);
471 TestNum++;
472 if (RsdsExpectFailure(Buffer))
473 {
474 printf(
"[+] Test number %d Passed\n", TestNum);
475 }
476 else
477 {
478 printf(
"[-] Test number %d Failed\n", TestNum);
479 printf(
"[x] raw parser accepted an unadvertised debug directory\n");
481 }
482
483 RsdsBuildMinimalPe(Buffer,
TRUE);
484 RsdsWriteValidDebugEntry(Buffer, RsdsGuid32, 9, "symbols/valid32.pdb");
485 TestNum++;
486 if (RsdsExpectSuccess(Buffer, "valid32.pdb", RsdsGuid32, 9))
487 {
488 printf(
"[+] Test number %d Passed\n", TestNum);
489 }
490 else
491 {
492 printf(
"[-] Test number %d Failed\n", TestNum);
493 printf(
"[x] valid PE32 RSDS entry was not parsed\n");
495 }
496
497 RsdsBuildMinimalPe(Buffer,
FALSE);
498 RsdsWriteValidDebugEntry(Buffer, RsdsGuid64, 7, "symbols\\valid64.pdb");
499 RsdsSetDebugDirectory(Buffer, 0x3000, sizeof(IMAGE_DEBUG_DIRECTORY));
500 TestNum++;
501 if (RsdsExpectFailure(Buffer))
502 {
503 printf(
"[+] Test number %d Passed\n", TestNum);
504 }
505 else
506 {
507 printf(
"[-] Test number %d Failed\n", TestNum);
508 printf(
"[x] unmapped debug directory parsed successfully\n");
510 }
511
512 RsdsBuildMinimalPe(Buffer,
FALSE);
513 RsdsWriteValidDebugEntry(Buffer, RsdsGuid64, 7, "symbols\\invalid.pdb");
514 CopyMemory(Buffer + RsdsPayloadRaw,
"ABCD",
sizeof(
DWORD));
515 TestNum++;
516 if (RsdsExpectFailure(Buffer))
517 {
518 printf(
"[+] Test number %d Passed\n", TestNum);
519 }
520 else
521 {
522 printf(
"[-] Test number %d Failed\n", TestNum);
523 printf(
"[x] unsupported CodeView signature parsed successfully\n");
525 }
526
527 RsdsBuildMinimalPe(Buffer,
FALSE);
528 RsdsWritePayload(Buffer, RsdsPayloadRaw, RsdsGuid64, 7,
"symbols\\missing-nul.pdb",
FALSE);
529 RsdsWriteDebugEntry(Buffer,
530 RsdsDebugDirectoryRaw,
531 IMAGE_DEBUG_TYPE_CODEVIEW,
532 RsdsPayloadRva,
533 RsdsPayloadRaw,
534 RsdsPayloadSize(
"symbols\\missing-nul.pdb",
FALSE));
535 TestNum++;
536 if (RsdsExpectFailure(Buffer))
537 {
538 printf(
"[+] Test number %d Passed\n", TestNum);
539 }
540 else
541 {
542 printf(
"[-] Test number %d Failed\n", TestNum);
543 printf(
"[x] RSDS path without NUL terminator parsed successfully\n");
545 }
546
547 RsdsBuildMinimalPe(Buffer,
FALSE);
548 RsdsSetDebugDirectory(Buffer, RsdsDebugDirectoryRva, sizeof(IMAGE_DEBUG_DIRECTORY) * 2);
549 RsdsWriteDebugEntry(Buffer, RsdsDebugDirectoryRaw, IMAGE_DEBUG_TYPE_CODEVIEW, RsdsPayloadRva, RsdsPayloadRaw,
sizeof(
DWORD));
550 CopyMemory(Buffer + RsdsPayloadRaw,
"NB10",
sizeof(
DWORD));
551 RsdsWritePayload(Buffer, 0x390, RsdsGuidMulti, 11,
"alt/second-valid.pdb",
TRUE);
552 RsdsWriteDebugEntry(Buffer,
553 RsdsDebugDirectoryRaw + sizeof(IMAGE_DEBUG_DIRECTORY),
554 IMAGE_DEBUG_TYPE_CODEVIEW,
555 0x1190,
556 0x390,
557 RsdsPayloadSize(
"alt/second-valid.pdb",
TRUE));
558 TestNum++;
559 if (RsdsExpectSuccess(Buffer, "second-valid.pdb", RsdsGuidMulti, 11))
560 {
561 printf(
"[+] Test number %d Passed\n", TestNum);
562 }
563 else
564 {
565 printf(
"[-] Test number %d Failed\n", TestNum);
566 printf(
"[x] parser did not skip invalid first entry and parse second RSDS entry\n");
568 }
569
570 RsdsBuildLoadedPe(Buffer,
FALSE);
571 RsdsWriteValidLoadedDebugEntry(Buffer, RsdsGuid64, 0x21, "loaded\\loaded64.pdb");
572 TestNum++;
573 if (RsdsExpectLoadedSuccess(Buffer, "loaded64.pdb", RsdsGuid64, 0x21))
574 {
575 printf(
"[+] Test number %d Passed\n", TestNum);
576 }
577 else
578 {
579 printf(
"[-] Test number %d Failed\n", TestNum);
580 printf(
"[x] loaded PE32+ RSDS entry was not parsed\n");
582 }
583
584 RsdsBuildLoadedPe(Buffer,
FALSE);
585 RsdsWriteValidLoadedDebugEntry(Buffer, RsdsGuid64, 0x21, "loaded\\unadvertised.pdb");
586 RsdsSetNumberOfRvaAndSizes(Buffer, IMAGE_DIRECTORY_ENTRY_DEBUG);
587 TestNum++;
588 if (RsdsExpectLoadedFailure(Buffer))
589 {
590 printf(
"[+] Test number %d Passed\n", TestNum);
591 }
592 else
593 {
594 printf(
"[-] Test number %d Failed\n", TestNum);
595 printf(
"[x] loaded parser accepted an unadvertised debug directory\n");
597 }
598
599 RsdsBuildLoadedPe(Buffer,
TRUE);
600 RsdsWriteValidLoadedDebugEntry(Buffer, RsdsGuid32, 0x22, "loaded/loaded32.pdb");
601 TestNum++;
602 if (RsdsExpectLoadedSuccess(Buffer, "loaded32.pdb", RsdsGuid32, 0x22))
603 {
604 printf(
"[+] Test number %d Passed\n", TestNum);
605 }
606 else
607 {
608 printf(
"[-] Test number %d Failed\n", TestNum);
609 printf(
"[x] loaded PE32 RSDS entry was not parsed\n");
611 }
612
613 RsdsBuildLoadedPe(Buffer,
FALSE);
614 RsdsWriteValidLoadedDebugEntry(Buffer, RsdsGuid64, 0x23, "loaded\\bogus-raw-ignored.pdb");
615 TestNum++;
616 if (RsdsExpectLoadedSuccess(Buffer, "bogus-raw-ignored.pdb", RsdsGuid64, 0x23))
617 {
618 printf(
"[+] Test number %d Passed\n", TestNum);
619 }
620 else
621 {
622 printf(
"[-] Test number %d Failed\n", TestNum);
623 printf(
"[x] loaded parser used bogus PointerToRawData instead of loaded RVA\n");
625 }
626
627 std::vector<BYTE> HighLoadedBuffer(RsdsHighLoadedSize);
628 RsdsBuildLoadedPe(HighLoadedBuffer.data(),
FALSE);
629 RsdsSetSizeOfImage(HighLoadedBuffer.data(), (
DWORD)HighLoadedBuffer.size());
630 RsdsSetDebugDirectory(HighLoadedBuffer.data(), RsdsHighLoadedDebugRva, sizeof(IMAGE_DEBUG_DIRECTORY));
631 RsdsWritePayload(HighLoadedBuffer.data(), RsdsHighLoadedPayloadRva, RsdsGuid64, 0x28,
"loaded\\high-rva.pdb",
TRUE);
632 RsdsWriteDebugEntry(HighLoadedBuffer.data(),
633 RsdsHighLoadedDebugRva,
634 IMAGE_DEBUG_TYPE_CODEVIEW,
635 RsdsHighLoadedPayloadRva,
636 RsdsBogusRawPointer,
637 RsdsPayloadSize(
"loaded\\high-rva.pdb",
TRUE));
638 CHAR HighLoadedPdbFileName[MAX_PATH] = {0};
639 GUID HighLoadedGuid = {0};
640 DWORD HighLoadedAge = 0;
641 TestNum++;
643 HighLoadedBuffer.size(),
644 HighLoadedPdbFileName,
645 sizeof(HighLoadedPdbFileName),
646 &HighLoadedGuid,
647 &HighLoadedAge) &&
648 strcmp(HighLoadedPdbFileName, "high-rva.pdb") == 0 && RsdsGuidEquals(HighLoadedGuid, RsdsGuid64) &&
649 HighLoadedAge == 0x28)
650 {
651 printf(
"[+] Test number %d Passed\n", TestNum);
652 }
653 else
654 {
655 printf(
"[-] Test number %d Failed\n", TestNum);
656 printf(
"[x] loaded parser did not parse high-RVA RSDS data\n");
658 }
659
660 RsdsBuildLoadedPe(Buffer,
FALSE);
661 RsdsWriteValidLoadedDebugEntry(Buffer, RsdsGuid64, 0x24, "loaded\\invalid-dir.pdb");
662 RsdsSetDebugDirectory(Buffer, RsdsFixtureSize - sizeof(IMAGE_DEBUG_DIRECTORY) / 2, sizeof(IMAGE_DEBUG_DIRECTORY));
663 TestNum++;
664 if (RsdsExpectLoadedFailure(Buffer))
665 {
666 printf(
"[+] Test number %d Passed\n", TestNum);
667 }
668 else
669 {
670 printf(
"[-] Test number %d Failed\n", TestNum);
671 printf(
"[x] loaded parser accepted malformed debug directory bounds\n");
673 }
674
675 RsdsBuildLoadedPe(Buffer,
FALSE);
676 RsdsWriteValidLoadedDebugEntry(Buffer, RsdsGuid64, 0x25, "loaded\\unsupported.pdb");
677 CopyMemory(Buffer + RsdsLoadedPayloadRva,
"ABCD",
sizeof(
DWORD));
678 TestNum++;
679 if (RsdsExpectLoadedFailure(Buffer))
680 {
681 printf(
"[+] Test number %d Passed\n", TestNum);
682 }
683 else
684 {
685 printf(
"[-] Test number %d Failed\n", TestNum);
686 printf(
"[x] loaded parser accepted unsupported CodeView signature\n");
688 }
689
690 RsdsBuildLoadedPe(Buffer,
FALSE);
691 RsdsWritePayload(Buffer, RsdsLoadedPayloadRva, RsdsGuid64, 0x26,
"loaded\\missing-nul.pdb",
FALSE);
692 RsdsWriteDebugEntry(Buffer,
693 RsdsLoadedDebugRva,
694 IMAGE_DEBUG_TYPE_CODEVIEW,
695 RsdsLoadedPayloadRva,
696 RsdsBogusRawPointer,
697 RsdsPayloadSize(
"loaded\\missing-nul.pdb",
FALSE));
698 TestNum++;
699 if (RsdsExpectLoadedFailure(Buffer))
700 {
701 printf(
"[+] Test number %d Passed\n", TestNum);
702 }
703 else
704 {
705 printf(
"[-] Test number %d Failed\n", TestNum);
706 printf(
"[x] loaded parser accepted RSDS path without NUL terminator\n");
708 }
709
710 RsdsBuildLoadedPe(Buffer,
FALSE);
711 RsdsSetDebugDirectory(Buffer, RsdsLoadedDebugRva, sizeof(IMAGE_DEBUG_DIRECTORY) * 2);
712 RsdsWriteDebugEntry(Buffer, RsdsLoadedDebugRva, IMAGE_DEBUG_TYPE_CODEVIEW, RsdsLoadedPayloadRva, RsdsBogusRawPointer,
sizeof(
DWORD));
713 CopyMemory(Buffer + RsdsLoadedPayloadRva,
"NB10",
sizeof(
DWORD));
714 RsdsWritePayload(Buffer, 0x330, RsdsGuidMulti, 0x27,
"loaded/second-loaded.pdb",
TRUE);
715 RsdsWriteDebugEntry(Buffer,
716 RsdsLoadedDebugRva + sizeof(IMAGE_DEBUG_DIRECTORY),
717 IMAGE_DEBUG_TYPE_CODEVIEW,
718 0x330,
719 RsdsBogusRawPointer,
720 RsdsPayloadSize(
"loaded/second-loaded.pdb",
TRUE));
721 TestNum++;
722 if (RsdsExpectLoadedSuccess(Buffer, "second-loaded.pdb", RsdsGuidMulti, 0x27))
723 {
724 printf(
"[+] Test number %d Passed\n", TestNum);
725 }
726 else
727 {
728 printf(
"[-] Test number %d Failed\n", TestNum);
729 printf(
"[x] loaded parser did not skip invalid first entry and parse second RSDS entry\n");
731 }
732
733 CHAR SymbolServerRelativePath[MAX_PATH] = {0};
734 CHAR GuidAndAgeDetails[MAX_PATH] = {0};
736 const GUID Guid = {0x01234567, 0x89ab, 0xcdef, {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}};
737 TestNum++;
739 &Guid,
740 0x1a,
741 SymbolServerRelativePath,
742 sizeof(SymbolServerRelativePath),
743 GuidAndAgeDetails,
744 sizeof(GuidAndAgeDetails)) &&
745 strcmp(GuidAndAgeDetails, "0123456789abcdeffedcba98765432101a") == 0 &&
746 strcmp(SymbolServerRelativePath, "valid32.pdb/0123456789abcdeffedcba98765432101a/valid32.pdb") == 0)
747 {
748 printf(
"[+] Test number %d Passed\n", TestNum);
749 }
750 else
751 {
752 printf(
"[-] Test number %d Failed\n", TestNum);
753 printf(
"[x] PDB identity formatting did not match symbol server path and GUID+age expectations\n");
755 }
756
757 TestNum++;
759 &Guid,
760 0x1a,
761 NULL,
762 0,
763 SmallGuidAndAgeDetails,
764 sizeof(SmallGuidAndAgeDetails)) &&
765 strcmp(SmallGuidAndAgeDetails, "0123456789abcdeffedcba98765432101a") == 0)
766 {
767 printf(
"[+] Test number %d Passed\n", TestNum);
768 }
769 else
770 {
771 printf(
"[-] Test number %d Failed\n", TestNum);
772 printf(
"[x] GUID+age identity did not fit the SDK-sized buffer\n");
774 }
775
776 RsdsBuildMinimalPe(Buffer,
FALSE);
777 RsdsWriteValidDebugEntry(Buffer, RsdsGuid64, 0x1c, "preferred\\preferred.pdb");
779 CHAR PreferredPath[MAX_PATH] = {0};
780 TestNum++;
782 RsdsFixtureSize,
783 PreferredPath,
784 sizeof(PreferredPath),
785 NULL,
786 0,
787 NULL,
788 0,
789 RsdsFakeFallback,
790 &FallbackContext) &&
791 strcmp(PreferredPath, "preferred.pdb/67452301ab89efcd1032547698badcfe1c/preferred.pdb") == 0 &&
793 {
794 printf(
"[+] Test number %d Passed\n", TestNum);
795 }
796 else
797 {
798 printf(
"[-] Test number %d Failed\n", TestNum);
799 printf(
"[x] PE RSDS identity was not preferred over fallback identity\n");
801 }
802
804 CHAR ZeroSizeOutput =
'x';
805 TestNum++;
807 RsdsFixtureSize,
808 &ZeroSizeOutput,
809 0,
810 NULL,
811 0,
812 NULL,
813 0,
814 RsdsFakeFallback,
815 &FallbackContext) &&
816 ZeroSizeOutput ==
'x' && FallbackContext.
CallCount == 0)
817 {
818 printf(
"[+] Test number %d Passed\n", TestNum);
819 }
820 else
821 {
822 printf(
"[-] Test number %d Failed\n", TestNum);
823 printf(
"[x] zero-sized output buffer was written or reported success\n");
825 }
826
828 TestNum++;
830 RsdsFixtureSize,
831 NULL,
832 0,
833 NULL,
834 0,
835 NULL,
836 0,
837 RsdsFakeFallback,
838 &FallbackContext) &&
840 {
841 printf(
"[+] Test number %d Passed\n", TestNum);
842 }
843 else
844 {
845 printf(
"[-] Test number %d Failed\n", TestNum);
846 printf(
"[x] identity formatting without requested output reported success or used fallback\n");
848 }
849
851 CHAR SmallPdbPath[4] = {
'x'};
852 CHAR SmallFailureGuidAge[64] = {
'x'};
853 TestNum++;
855 RsdsFixtureSize,
856 NULL,
857 0,
858 SmallPdbPath,
859 sizeof(SmallPdbPath),
860 SmallFailureGuidAge,
861 sizeof(SmallFailureGuidAge),
862 RsdsFakeFallback,
863 &FallbackContext) &&
864 SmallPdbPath[0] ==
'\0' && SmallFailureGuidAge[0] ==
'\0' && FallbackContext.
CallCount == 0)
865 {
866 printf(
"[+] Test number %d Passed\n", TestNum);
867 }
868 else
869 {
870 printf(
"[-] Test number %d Failed\n", TestNum);
871 printf(
"[x] output formatting failure leaked partial identity data\n");
873 }
874
875 ZeroMemory(Buffer, sizeof(Buffer));
878 CHAR FallbackPdb[MAX_PATH] = {0};
879 CHAR FallbackGuidAge[MAX_PATH] = {0};
880 TestNum++;
882 RsdsFixtureSize,
883 NULL,
884 0,
885 FallbackPdb,
886 sizeof(FallbackPdb),
887 FallbackGuidAge,
888 sizeof(FallbackGuidAge),
889 RsdsFakeFallback,
890 &FallbackContext) &&
891 strcmp(FallbackPdb, "fallback.pdb") == 0 &&
892 strcmp(FallbackGuidAge, "aabbccddeeff112233445566778899aa2b") == 0 &&
894 {
895 printf(
"[+] Test number %d Passed\n", TestNum);
896 }
897 else
898 {
899 printf(
"[-] Test number %d Failed\n", TestNum);
900 printf(
"[x] malformed PE bytes did not use fallback identity\n");
902 }
903
906 CHAR FailedPath[MAX_PATH] = {
'x'};
907 CHAR FailedPdb[MAX_PATH] = {
'x'};
908 CHAR FailedGuidAge[MAX_PATH] = {
'x'};
909 TestNum++;
911 RsdsFixtureSize,
912 FailedPath,
913 sizeof(FailedPath),
914 FailedPdb,
915 sizeof(FailedPdb),
916 FailedGuidAge,
917 sizeof(FailedGuidAge),
918 RsdsFakeFallback,
919 &FallbackContext) &&
920 FailedPath[0] ==
'\0' && FailedPdb[0] ==
'\0' && FailedGuidAge[0] ==
'\0' && FallbackContext.
CallCount == 1)
921 {
922 printf(
"[+] Test number %d Passed\n", TestNum);
923 }
924 else
925 {
926 printf(
"[-] Test number %d Failed\n", TestNum);
927 printf(
"[x] fallback failure reported success or left success-looking output\n");
929 }
930
932}
BOOLEAN SymExtractCodeViewRsdsInfoFromLoadedPeImage(const BYTE *ImageBase, SIZE_T ImageSize, CHAR *PdbFileName, SIZE_T PdbFileNameSize, GUID *Guid, DWORD *Age)
Extracts CodeView RSDS information from a PE image in memory, interpreting the image as it would be l...
Definition codeview-rsds.cpp:551
BOOLEAN SymFormatPdbIdentity(const CHAR *PdbFile, const GUID *Guid, DWORD Age, CHAR *SymbolServerRelativePath, SIZE_T SymbolServerRelativePathSize, CHAR *GuidAndAgeDetails, SIZE_T GuidAndAgeDetailsSize)
Helper function to format the PDB identity information into the specified output buffers.
Definition pdb-identity.cpp:67
BOOLEAN SymFormatPdbIdentityFromPeImageOrFallback(const BYTE *PeImageBytes, SIZE_T PeImageSize, CHAR *SymbolServerRelativePath, SIZE_T SymbolServerRelativePathSize, CHAR *PdbFilePath, SIZE_T PdbFilePathSize, CHAR *GuidAndAgeDetails, SIZE_T GuidAndAgeDetailsSize, PSYM_PDB_IDENTITY_FALLBACK_CALLBACK FallbackCallback, PVOID FallbackContext)
Extracts PDB identity information from a PE image using the specified extractor callback,...
Definition pdb-identity.cpp:267
BOOLEAN Succeed
Definition test-codeview-rsds-parser.cpp:407
INT32 CallCount
Definition test-codeview-rsds-parser.cpp:406
struct _RSDS_FAKE_FALLBACK_CONTEXT RSDS_FAKE_FALLBACK_CONTEXT