Index: trunk/src/VBox/Runtime/tools/RTSignTool.cpp
===================================================================
--- trunk/src/VBox/Runtime/tools/RTSignTool.cpp	(revision 95633)
+++ trunk/src/VBox/Runtime/tools/RTSignTool.cpp	(revision 95637)
@@ -1566,5 +1566,110 @@
                                                       RTDIGESTTYPE enmSigType)
 {
-    RT_NOREF(pThis, pSpcIndData, enmSigType);
+    PCRTASN1ALLOCATORVTABLE const pAllocator = &g_RTAsn1DefaultAllocator;
+    PRTCRSPCPEIMAGEDATA const     pPeImage   = pSpcIndData->Data.uValue.pPeImage;
+    Assert(pPeImage);
+
+    /*
+     * The hashes are stored in the 'Moniker' attribute.
+     */
+    /* Create a temporary SpcLink with a default moniker. */
+    RTCRSPCLINK SpcLink;
+    int rc = RTCrSpcLink_Init(&SpcLink, pAllocator);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExitFailure("RTCrSpcLink_Init failed: %Rrc", rc);
+    rc = RTCrSpcLink_SetMoniker(&SpcLink, NULL, pAllocator);
+    if (RT_SUCCESS(rc))
+    {
+        /* Use the setter to copy SpcLink to the PeImage structure. */
+        rc = RTCrSpcPeImageData_SetFile(pPeImage, &SpcLink, pAllocator);
+        if (RT_FAILURE(rc))
+            RTMsgError("RTCrSpcLink_SetFile failed: %Rrc", rc);
+    }
+    else
+        RTMsgError("RTCrSpcLink_SetMoniker failed: %Rrc", rc);
+    RTCrSpcLink_Delete(&SpcLink);
+    if (RT_FAILURE(rc))
+        return RTEXITCODE_FAILURE;
+
+    /*
+     * Now go to work on the moniker.  It doesn't have any autogenerated
+     * setters, so we must do stuff manually.
+     */
+    PRTCRSPCSERIALIZEDOBJECT pMoniker = pPeImage->T0.File.u.pMoniker;
+    RTUUID                   Uuid;
+    rc = RTUuidFromStr(&Uuid, RTCRSPCSERIALIZEDOBJECT_UUID_STR);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExitFailure("RTUuidFromStr failed: %Rrc", rc);
+
+    rc = RTAsn1OctetString_AllocContent(&pMoniker->Uuid, &Uuid, sizeof(Uuid), pAllocator);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExitFailure("RTAsn1String_InitWithValue/UUID failed: %Rrc", rc);
+
+    /* Create a new set of attributes and associate this with the SerializedData member. */
+    PRTCRSPCSERIALIZEDOBJECTATTRIBUTES pSpcAttribs;
+    rc = RTAsn1MemAllocZ(&pMoniker->SerializedData.EncapsulatedAllocation,
+                         (void **)&pSpcAttribs, sizeof(*pSpcAttribs));
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExitFailure("RTAsn1MemAllocZ/pSpcAttribs failed: %Rrc", rc);
+    pMoniker->SerializedData.pEncapsulated = RTCrSpcSerializedObjectAttributes_GetAsn1Core(pSpcAttribs);
+    pMoniker->enmType                      = RTCRSPCSERIALIZEDOBJECTTYPE_ATTRIBUTES;
+    pMoniker->u.pData                      = pSpcAttribs;
+
+    rc = RTCrSpcSerializedObjectAttributes_Init(pSpcAttribs, pAllocator);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExitFailure("RTCrSpcSerializedObjectAttributes_Init failed: %Rrc", rc);
+
+    /*
+     * Add a single attribute to the set that we'll use for page hashes.
+     */
+    int32_t iPos = RTCrSpcSerializedObjectAttributes_Append(pSpcAttribs);
+    if (iPos < 0)
+        return RTMsgErrorExitFailure("RTCrSpcSerializedObjectAttributes_Append failed: %Rrc", iPos);
+    PRTCRSPCSERIALIZEDOBJECTATTRIBUTE pSpcObjAttr = pSpcAttribs->papItems[iPos];
+
+    if (enmSigType == RTDIGESTTYPE_SHA1)
+        rc = RTCrSpcSerializedObjectAttribute_SetV1Hashes(pSpcObjAttr, NULL, pAllocator);
+    else if (enmSigType == RTDIGESTTYPE_SHA256)
+        rc = RTCrSpcSerializedObjectAttribute_SetV2Hashes(pSpcObjAttr, NULL, pAllocator);
+    else
+        rc = VERR_CR_DIGEST_NOT_SUPPORTED;
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExitFailure("RTCrSpcSerializedObjectAttribute_SetV1Hashes/SetV2Hashes failed: %Rrc", rc);
+    PRTCRSPCSERIALIZEDPAGEHASHES pSpcPageHashes = pSpcObjAttr->u.pPageHashes;
+    Assert(pSpcPageHashes);
+
+    /*
+     * Now ask the loader for the number of pages in the page hash table
+     * and calculate its size.
+     */
+    uint32_t cPages = 0;
+    rc = RTLdrQueryPropEx(pThis->hLdrMod, RTLDRPROP_HASHABLE_PAGES, NULL, &cPages, sizeof(cPages), NULL);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExitFailure("RTLdrQueryPropEx/RTLDRPROP_HASHABLE_PAGES failed: %Rrc", rc);
+
+    uint32_t const cbHash  = RTCrDigestTypeToHashSize(enmSigType);
+    AssertReturn(cbHash > 0, RTMsgErrorExitFailure("Invalid value: enmSigType=%d", enmSigType));
+    uint32_t const cbTable = (sizeof(uint32_t) + cbHash) * cPages;
+
+    /*
+     * Allocate memory in the octect string.
+     */
+    rc = RTAsn1ContentAllocZ(&pSpcPageHashes->RawData.Asn1Core, cbTable, pAllocator);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExitFailure("RTAsn1ContentAllocZ failed to allocate %#x bytes for page hashes: %Rrc", cbTable, rc);
+    pSpcPageHashes->pData = (PCRTCRSPCPEIMAGEPAGEHASHES)pSpcPageHashes->RawData.Asn1Core.uData.pu8;
+
+    RTLDRPROP enmLdrProp;
+    switch (enmSigType)
+    {
+        case RTDIGESTTYPE_SHA1:     enmLdrProp = RTLDRPROP_SHA1_PAGE_HASHES; break;
+        case RTDIGESTTYPE_SHA256:   enmLdrProp = RTLDRPROP_SHA256_PAGE_HASHES; break;
+        default: AssertFailedReturn(RTMsgErrorExitFailure("Invalid value: enmSigType=%d", enmSigType));
+
+    }
+    rc = RTLdrQueryPropEx(pThis->hLdrMod, enmLdrProp, NULL, (void *)pSpcPageHashes->RawData.Asn1Core.uData.pv, cbTable, NULL);
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExitFailure("RTLdrQueryPropEx/RTLDRPROP_SHA?_PAGE_HASHES/%#x failed: %Rrc", cbTable, rc);
+
     return RTEXITCODE_SUCCESS;
 }
