/** * Adds what we think is an image file to the cache. * * @returns IPRT status code. * @param pszPath Path to the image file. * @param pszExtraSuff Optional extra suffix. Mach-O dSYM hack. * @param pszUuidMapDir The UUID map subdirectory in the cache, if this is * wanted, otherwise NULL. * @param pCfg Configuration data. */ static int rtDbgSymCacheAddImageFile(const char *pszPath, const char *pszExtraSuff, const char *pszUuidMapDir, PCRTDBGSYMCACHEADDCFG pCfg) { /* * Use the loader to open the alleged image file. We need to open it with * arch set to amd64 and x86_32 in order to handle FAT images from the mac * guys (we should actually enumerate archs, but that's currently not * implemented nor necessary for our current use). */ /* Open it as AMD64. */ RTLDRMOD hLdrMod64; int rc = RTLdrOpen(pszPath, RTLDR_O_FOR_DEBUG, RTLDRARCH_AMD64, &hLdrMod64); if (RT_FAILURE(rc)) { if (rc != VERR_LDR_ARCH_MISMATCH) { if (rc != VERR_INVALID_EXE_SIGNATURE) return RTMsgErrorRc(rc, "RTLdrOpen failed opening '%s' [arch=amd64]: %Rrc", pszPath, rc); RTMsgInfo("Skipping '%s', no a recognizable image file...", pszPath); return VINF_SUCCESS; } hLdrMod64 = NIL_RTLDRMOD; } /* Open it as X86. */ RTLDRMOD hLdrMod32; rc = RTLdrOpen(pszPath, RTLDR_O_FOR_DEBUG, RTLDRARCH_X86_32, &hLdrMod32); if (RT_FAILURE(rc)) { if (rc != VERR_LDR_ARCH_MISMATCH) { RTLdrClose(hLdrMod32); return RTMsgErrorRc(rc, "RTLdrOpen failed opening '%s' [arch=x86]: %Rrc", pszPath, rc); } hLdrMod32 = NIL_RTLDRMOD; } /* * Add the file. */ if (hLdrMod32 == NIL_RTLDRMOD) rc = rtDbgSymCacheAddImageFileWorker(pszPath, pCfg, hLdrMod64, pszExtraSuff, pszUuidMapDir); else if (hLdrMod64 == NIL_RTLDRMOD) rc = rtDbgSymCacheAddImageFileWorker(pszPath, pCfg, hLdrMod32, pszExtraSuff, pszUuidMapDir); else { /* * Do we need to add it once or twice? */ RTLDRFMT enmFmt = RTLdrGetFormat(hLdrMod32); bool fSame = enmFmt == RTLdrGetFormat(hLdrMod64); if (fSame && enmFmt == RTLDRFMT_MACHO) { RTUUID Uuid32, Uuid64; int rc32 = RTLdrQueryProp(hLdrMod32, RTLDRPROP_UUID, &Uuid32, sizeof(Uuid32)); int rc64 = RTLdrQueryProp(hLdrMod64, RTLDRPROP_UUID, &Uuid64, sizeof(Uuid64)); fSame = RT_SUCCESS(rc32) == RT_SUCCESS(rc64); if (fSame && RT_SUCCESS(rc32)) fSame = RTUuidCompare(&Uuid32, &Uuid64) == 0; } else if (fSame && enmFmt == RTLDRFMT_PE) { fSame = RTLdrSize(hLdrMod32) == RTLdrSize(hLdrMod64); if (fSame) { uint32_t uTimestamp32, uTimestamp64; int rc32 = RTLdrQueryProp(hLdrMod32, RTLDRPROP_TIMESTAMP_SECONDS, &uTimestamp32, sizeof(uTimestamp32)); int rc64 = RTLdrQueryProp(hLdrMod64, RTLDRPROP_TIMESTAMP_SECONDS, &uTimestamp64, sizeof(uTimestamp64)); fSame = RT_SUCCESS(rc32) == RT_SUCCESS(rc64); if (fSame && RT_SUCCESS(rc32)) fSame = uTimestamp32 == uTimestamp64; } } rc = rtDbgSymCacheAddImageFileWorker(pszPath, pCfg, hLdrMod64, pszExtraSuff, pszUuidMapDir); if (!fSame) { /** @todo should symlink or hardlink this second copy. */ int rc2 = rtDbgSymCacheAddImageFileWorker(pszPath, pCfg, hLdrMod32, pszExtraSuff, pszUuidMapDir); if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) rc = rc2; } } RTLdrClose(hLdrMod32); RTLdrClose(hLdrMod64); return VINF_SUCCESS; }
/** * One test iteration with one file. * * The test is very simple, we load the file three times * into two different regions. The first two into each of the * regions the for compare usage. The third is loaded into one * and then relocated between the two and other locations a few times. * * @returns number of errors. * @param pszFilename The file to load the mess with. */ static int testLdrOne(const char *pszFilename) { int cErrors = 0; size_t cbImage = 0; struct Load { RTLDRMOD hLdrMod; void *pvBits; size_t cbBits; const char *pszName; } aLoads[6] = { { NULL, NULL, 0, "foo" }, { NULL, NULL, 0, "bar" }, { NULL, NULL, 0, "foobar" }, { NULL, NULL, 0, "kLdr-foo" }, { NULL, NULL, 0, "kLdr-bar" }, { NULL, NULL, 0, "kLdr-foobar" } }; unsigned i; int rc; /* * Load them. */ for (i = 0; i < RT_ELEMENTS(aLoads); i++) { if (!strncmp(aLoads[i].pszName, RT_STR_TUPLE("kLdr-"))) rc = RTLdrOpenkLdr(pszFilename, 0, RTLDRARCH_WHATEVER, &aLoads[i].hLdrMod); else rc = RTLdrOpen(pszFilename, 0, RTLDRARCH_WHATEVER, &aLoads[i].hLdrMod); if (RT_FAILURE(rc)) { RTPrintf("tstLdr-4: Failed to open '%s'/%d, rc=%Rrc. aborting test.\n", pszFilename, i, rc); Assert(aLoads[i].hLdrMod == NIL_RTLDRMOD); cErrors++; break; } /* size it */ size_t cb = RTLdrSize(aLoads[i].hLdrMod); if (cbImage && cb != cbImage) { RTPrintf("tstLdr-4: Size mismatch '%s'/%d. aborting test.\n", pszFilename, i); cErrors++; break; } aLoads[i].cbBits = cbImage = cb; /* Allocate bits. */ aLoads[i].pvBits = RTMemExecAlloc(cb); if (!aLoads[i].pvBits) { RTPrintf("tstLdr-4: Out of memory '%s'/%d cbImage=%d. aborting test.\n", pszFilename, i, cbImage); cErrors++; break; } /* Get the bits. */ rc = RTLdrGetBits(aLoads[i].hLdrMod, aLoads[i].pvBits, (uintptr_t)aLoads[i].pvBits, testGetImport, NULL); if (RT_FAILURE(rc)) { RTPrintf("tstLdr-4: Failed to get bits for '%s'/%d, rc=%Rrc. aborting test\n", pszFilename, i, rc); cErrors++; break; } } /* * Execute the code. */ if (!cErrors) { for (i = 0; i < RT_ELEMENTS(aLoads); i += 1) { /* get the pointer. */ RTUINTPTR Value; rc = RTLdrGetSymbolEx(aLoads[i].hLdrMod, aLoads[i].pvBits, (uintptr_t)aLoads[i].pvBits, UINT32_MAX, "DisasmTest1", &Value); if (rc == VERR_SYMBOL_NOT_FOUND) rc = RTLdrGetSymbolEx(aLoads[i].hLdrMod, aLoads[i].pvBits, (uintptr_t)aLoads[i].pvBits, UINT32_MAX, "_DisasmTest1", &Value); if (RT_FAILURE(rc)) { RTPrintf("tstLdr-4: Failed to get symbol \"DisasmTest1\" from load #%d: %Rrc\n", i, rc); cErrors++; break; } DECLCALLBACKPTR(int, pfnDisasmTest1)(void) = (DECLCALLBACKPTR(int, RT_NOTHING)(void))(uintptr_t)Value; /* eeeh. */ RTPrintf("tstLdr-4: pfnDisasmTest1=%p / add-symbol-file %s %#x\n", pfnDisasmTest1, pszFilename, aLoads[i].pvBits); /* call the test function. */ rc = pfnDisasmTest1(); if (rc) { RTPrintf("tstLdr-4: load #%d Test1 -> %#x\n", i, rc); cErrors++; } } } /* * Clean up. */ for (i = 0; i < RT_ELEMENTS(aLoads); i++) { if (aLoads[i].pvBits) RTMemExecFree(aLoads[i].pvBits, aLoads[i].cbBits); if (aLoads[i].hLdrMod) { rc = RTLdrClose(aLoads[i].hLdrMod); if (RT_FAILURE(rc)) { RTPrintf("tstLdr-4: Failed to close '%s' i=%d, rc=%Rrc.\n", pszFilename, i, rc); cErrors++; } } } return cErrors; }
/** * One test iteration with one file. * * The test is very simple, we load the file three times * into two different regions. The first two into each of the * regions the for compare usage. The third is loaded into one * and then relocated between the two and other locations a few times. * * @returns number of errors. * @param pszFilename The file to load the mess with. */ static int testLdrOne(const char *pszFilename) { RTLDRMOD hLdrMod; int rc = RTLdrOpen(pszFilename, 0, RTLDRARCH_WHATEVER, &hLdrMod); if (RT_FAILURE(rc)) { RTPrintf("tstLdr: Failed to open '%s', rc=%Rrc. aborting test.\n", pszFilename, rc); Assert(hLdrMod == NIL_RTLDRMOD); return 1; } int rcRet = 1; size_t cb = RTLdrSize(hLdrMod); if (cb > 100) { void *pvBits = RTMemAlloc(cb); if (pvBits) { RTUINTPTR Addr = 0xc0000000; rc = RTLdrGetBits(hLdrMod, pvBits, Addr, testGetImport, NULL); if (RT_SUCCESS(rc)) { RTUINTPTR Value; rc = RTLdrGetSymbolEx(hLdrMod, pvBits, Addr, "Entrypoint", &Value); if (RT_SUCCESS(rc)) { unsigned off = Value - Addr; if (off < cb) { DISCPUSTATE Cpu; memset(&Cpu, 0, sizeof(Cpu)); Cpu.mode = CPUMODE_32BIT; if (MyDisBlock(&Cpu, (uintptr_t)pvBits + off, 200, Addr - (uintptr_t)pvBits)) { RTUINTPTR Addr2 = 0xd0000000; rc = RTLdrRelocate(hLdrMod, pvBits, Addr2, Addr, testGetImport, NULL); if (RT_SUCCESS(rc)) { if (MyDisBlock(&Cpu, (uintptr_t)pvBits + off, 200, Addr2 - (uintptr_t)pvBits)) rcRet = 0; else RTPrintf("tstLdr: Disassembly failed!\n"); } else RTPrintf("tstLdr: Relocate of '%s' from %#x to %#x failed, rc=%Rrc. Aborting test.\n", pszFilename, Addr2, Addr, rc); } else RTPrintf("tstLdr: Disassembly failed!\n"); } else RTPrintf("tstLdr: Invalid value for symbol '%s' in '%s'. off=%#x Value=%#x\n", "Entrypoint", pszFilename, off, Value); } else RTPrintf("tstLdr: Failed to resolve symbol '%s' in '%s', rc=%Rrc.\n", "Entrypoint", pszFilename, rc); } else RTPrintf("tstLdr: Failed to get bits for '%s', rc=%Rrc. aborting test\n", pszFilename, rc); RTMemFree(pvBits); } else RTPrintf("tstLdr: Out of memory '%s' cb=%d. aborting test.\n", pszFilename, cb); } else RTPrintf("tstLdr: Size is odd, '%s'. aborting test.\n", pszFilename); /* cleanup */ rc = RTLdrClose(hLdrMod); if (RT_FAILURE(rc)) { RTPrintf("tstLdr: Failed to close '%s', rc=%Rrc.\n", pszFilename, rc); rcRet++; } return rcRet; }
static RTEXITCODE HandleExtractExeSignerCert(int cArgs, char **papszArgs) { /* * Parse arguments. */ static const RTGETOPTDEF s_aOptions[] = { { "--ber", 'b', RTGETOPT_REQ_NOTHING }, { "--cer", 'c', RTGETOPT_REQ_NOTHING }, { "--der", 'd', RTGETOPT_REQ_NOTHING }, { "--exe", 'e', RTGETOPT_REQ_STRING }, { "--output", 'o', RTGETOPT_REQ_STRING }, }; const char *pszExe = NULL; const char *pszOut = NULL; RTLDRARCH enmLdrArch = RTLDRARCH_WHATEVER; uint32_t fCursorFlags = RTASN1CURSOR_FLAGS_DER; RTGETOPTSTATE GetState; int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); AssertRCReturn(rc, RTEXITCODE_FAILURE); RTGETOPTUNION ValueUnion; int ch; while ((ch = RTGetOpt(&GetState, &ValueUnion))) { switch (ch) { case 'e': pszExe = ValueUnion.psz; break; case 'o': pszOut = ValueUnion.psz; break; case 'b': fCursorFlags = 0; break; case 'c': fCursorFlags = RTASN1CURSOR_FLAGS_CER; break; case 'd': fCursorFlags = RTASN1CURSOR_FLAGS_DER; break; case 'V': return HandleVersion(cArgs, papszArgs); case 'h': return HelpExtractExeSignerCert(g_pStdOut, RTSIGNTOOLHELP_FULL); case VINF_GETOPT_NOT_OPTION: if (!pszExe) pszExe = ValueUnion.psz; else if (!pszOut) pszOut = ValueUnion.psz; else return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many file arguments: %s", ValueUnion.psz); break; default: return RTGetOptPrintError(ch, &ValueUnion); } } if (!pszExe) return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given."); if (!pszOut) return RTMsgErrorExit(RTEXITCODE_FAILURE, "No output file given."); if (RTPathExists(pszOut)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "The output file '%s' exists.", pszOut); /* * Do it. */ /* Open the executable image and query the PKCS7 info. */ RTLDRMOD hLdrMod; rc = RTLdrOpen(pszExe, RTLDR_O_FOR_VALIDATION, enmLdrArch, &hLdrMod); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening executable image '%s': %Rrc", pszExe, rc); RTEXITCODE rcExit = RTEXITCODE_FAILURE; #ifdef DEBUG size_t cbBuf = 64; #else size_t cbBuf = _512K; #endif void *pvBuf = RTMemAlloc(cbBuf); size_t cbRet = 0; rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbRet); if (rc == VERR_BUFFER_OVERFLOW && cbRet < _4M && cbRet > 0) { RTMemFree(pvBuf); cbBuf = cbRet; pvBuf = RTMemAlloc(cbBuf); rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbRet); } if (RT_SUCCESS(rc)) { static RTERRINFOSTATIC s_StaticErrInfo; RTErrInfoInitStatic(&s_StaticErrInfo); /* * Decode the output. */ RTASN1CURSORPRIMARY PrimaryCursor; RTAsn1CursorInitPrimary(&PrimaryCursor, pvBuf, (uint32_t)cbRet, &s_StaticErrInfo.Core, &g_RTAsn1DefaultAllocator, fCursorFlags, "exe"); RTCRPKCS7CONTENTINFO Pkcs7Ci; rc = RTCrPkcs7ContentInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &Pkcs7Ci, "pkcs7"); if (RT_SUCCESS(rc)) { if (RTCrPkcs7ContentInfo_IsSignedData(&Pkcs7Ci)) { PCRTCRPKCS7SIGNEDDATA pSd = Pkcs7Ci.u.pSignedData; if (pSd->SignerInfos.cItems == 1) { PCRTCRPKCS7ISSUERANDSERIALNUMBER pISN = &pSd->SignerInfos.paItems[0].IssuerAndSerialNumber; PCRTCRX509CERTIFICATE pCert; pCert = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(&pSd->Certificates, &pISN->Name, &pISN->SerialNumber); if (pCert) { /* * Write it out. */ RTFILE hFile; rc = RTFileOpen(&hFile, pszOut, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE); if (RT_SUCCESS(rc)) { uint32_t cbCert = pCert->SeqCore.Asn1Core.cbHdr + pCert->SeqCore.Asn1Core.cb; rc = RTFileWrite(hFile, pCert->SeqCore.Asn1Core.uData.pu8 - pCert->SeqCore.Asn1Core.cbHdr, cbCert, NULL); if (RT_SUCCESS(rc)) { rc = RTFileClose(hFile); if (RT_SUCCESS(rc)) { hFile = NIL_RTFILE; rcExit = RTEXITCODE_SUCCESS; RTMsgInfo("Successfully wrote %u bytes to '%s'", cbCert, pszOut); } else RTMsgError("RTFileClose failed: %Rrc", rc); } else RTMsgError("RTFileWrite failed: %Rrc", rc); RTFileClose(hFile); } else RTMsgError("Error opening '%s': %Rrc", pszOut, rc); } else RTMsgError("Certificate not found."); } else RTMsgError("SignerInfo count: %u", pSd->SignerInfos.cItems); } else RTMsgError("No PKCS7 content: ContentType=%s", Pkcs7Ci.ContentType.szObjId); RTAsn1VtDelete(&Pkcs7Ci.SeqCore.Asn1Core); } else RTMsgError("RTPkcs7ContentInfoDecodeAsn1 failed: %Rrc - %s", rc, s_StaticErrInfo.szMsg); } else RTMsgError("RTLDRPROP_PKCS7_SIGNED_DATA failed on '%s': %Rrc", pszExe, rc); RTMemFree(pvBuf); rc = RTLdrClose(hLdrMod); if (RT_FAILURE(rc)) rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTLdrClose failed: %Rrc\n", rc); return rcExit; }