#include "common/common.h" #include "common/json.h" #include "archo.h" #include "signing.h" static uint64_t execSegLimit = 0; ZArchO::ZArchO() { m_pBase = nullptr; m_uLength = 0; m_uCodeLength = 0; m_pSignBase = nullptr; m_uSignLength = 0; m_pHeader = nullptr; m_uHeaderSize = 0; m_bEncrypted = false; m_b64 = false; m_bBigEndian = false; m_bEnoughSpace = true; m_pCodeSignSegment = nullptr; m_pLinkEditSegment = nullptr; m_uLoadCommandsFreeSpace = 0; } bool ZArchO::Init(uint8_t *pBase, uint32_t uLength) { if (nullptr == pBase || uLength <= 0) { return false; } m_pBase = pBase; m_uLength = uLength; m_uCodeLength = (uLength % 16 == 0) ? uLength : uLength + 16 - (uLength % 16); m_pHeader = (mach_header *) m_pBase; if (MH_MAGIC != m_pHeader->magic && MH_CIGAM != m_pHeader->magic && MH_MAGIC_64 != m_pHeader->magic && MH_CIGAM_64 != m_pHeader->magic) { return false; } m_b64 = (MH_MAGIC_64 == m_pHeader->magic || MH_CIGAM_64 == m_pHeader->magic); m_bBigEndian = (MH_CIGAM == m_pHeader->magic || MH_CIGAM_64 == m_pHeader->magic); m_uHeaderSize = m_b64 ? sizeof(mach_header_64) : sizeof(mach_header); uint8_t *pLoadCommand = m_pBase + m_uHeaderSize; for (uint32_t i = 0; i < BO(m_pHeader->ncmds); i++) { auto *plc = (load_command *) pLoadCommand; switch (BO(plc->cmd)) { case LC_SEGMENT: { auto *seglc = (segment_command *) pLoadCommand; if (0 == strcmp("__TEXT", seglc->segname)) { execSegLimit = seglc->vmsize; for (uint32_t j = 0; j < BO(seglc->nsects); j++) { auto *sect = (section *) ((pLoadCommand + sizeof(segment_command)) + sizeof(section) * j); if (0 == strcmp("__text", sect->sectname)) { if (BO(sect->offset) > (BO(m_pHeader->sizeofcmds) + m_uHeaderSize)) { m_uLoadCommandsFreeSpace = BO(sect->offset) - BO(m_pHeader->sizeofcmds) - m_uHeaderSize; } } else if (0 == strcmp("__info_plist", sect->sectname)) { m_strInfoPlist.append((const char *) m_pBase + BO(sect->offset), BO(sect->size)); } } } else if (0 == strcmp("__LINKEDIT", seglc->segname)) { m_pLinkEditSegment = pLoadCommand; } } break; case LC_SEGMENT_64: { auto *seglc = (segment_command_64 *) pLoadCommand; if (0 == strcmp("__TEXT", seglc->segname)) { execSegLimit = seglc->vmsize; for (uint32_t j = 0; j < BO(seglc->nsects); j++) { auto *sect = (section_64 *) ((pLoadCommand + sizeof(segment_command_64)) + sizeof(section_64) * j); if (0 == strcmp("__text", sect->sectname)) { if (BO(sect->offset) > (BO(m_pHeader->sizeofcmds) + m_uHeaderSize)) { m_uLoadCommandsFreeSpace = BO(sect->offset) - BO(m_pHeader->sizeofcmds) - m_uHeaderSize; } } else if (0 == strcmp("__info_plist", sect->sectname)) { m_strInfoPlist.append((const char *) m_pBase + BO(sect->offset), BO(sect->size)); } } } else if (0 == strcmp("__LINKEDIT", seglc->segname)) { m_pLinkEditSegment = pLoadCommand; } } break; case LC_ENCRYPTION_INFO: case LC_ENCRYPTION_INFO_64: { auto *crypt_cmd = (encryption_info_command *) pLoadCommand; if (BO(crypt_cmd->cryptid) >= 1) { m_bEncrypted = true; } } break; case LC_CODE_SIGNATURE: { auto *pcslc = (codesignature_command *) pLoadCommand; m_pCodeSignSegment = pLoadCommand; m_uCodeLength = BO(pcslc->dataoff); m_pSignBase = m_pBase + m_uCodeLength; m_uSignLength = GetCodeSignatureLength(m_pSignBase); } break; } pLoadCommand += BO(plc->cmdsize); } return true; } const char *ZArchO::GetArch(int cpuType, int cpuSubType) { switch (cpuType) { case CPU_TYPE_ARM: { switch (cpuSubType) { case CPU_SUBTYPE_ARM_V6: return "armv6"; case CPU_SUBTYPE_ARM_V7: return "armv7"; case CPU_SUBTYPE_ARM_V7S: return "armv7s"; case CPU_SUBTYPE_ARM_V7K: return "armv7k"; case CPU_SUBTYPE_ARM_V8: return "armv8"; } } break; case CPU_TYPE_ARM64: { switch (cpuSubType) { case CPU_SUBTYPE_ARM64_ALL: return "arm64"; case CPU_SUBTYPE_ARM64_V8: return "arm64v8"; case CPU_SUBTYPE_ARM64E: return "arm64e"; } } break; case CPU_TYPE_ARM64_32: { switch (cpuSubType) { case CPU_SUBTYPE_ARM64_ALL: return "arm64_32"; case CPU_SUBTYPE_ARM64_32_V8: return "arm64e_32"; } } break; case CPU_TYPE_X86: { switch (cpuSubType) { default: return "x86_32"; } } break; case CPU_TYPE_X86_64: { switch (cpuSubType) { default: return "x86_64"; } } break; } return "unknown"; } const char *ZArchO::GetFileType(uint32_t uFileType) { switch (uFileType) { case MH_OBJECT: return "MH_OBJECT"; case MH_EXECUTE: return "MH_EXECUTE"; case MH_FVMLIB: return "MH_FVMLIB"; case MH_CORE: return "MH_CORE"; case MH_PRELOAD: return "MH_PRELOAD"; case MH_DYLIB: return "MH_DYLIB"; case MH_DYLINKER: return "MH_DYLINKER"; case MH_BUNDLE: return "MH_BUNDLE"; case MH_DYLIB_STUB: return "MH_DYLIB_STUB"; case MH_DSYM: return "MH_DSYM"; case MH_KEXT_BUNDLE: return "MH_KEXT_BUNDLE"; } return "MH_UNKNOWN"; } uint32_t ZArchO::BO(uint32_t uValue) { return m_bBigEndian ? LE(uValue) : uValue; } bool ZArchO::IsExecute() { if (nullptr != m_pHeader) { return (MH_EXECUTE == BO(m_pHeader->filetype)); } return false; } void ZArchO::PrintInfo() { if (nullptr == m_pHeader) { return; } ZLog::Print("------------------------------------------------------------------\n"); ZLog::Print(">>> MachO Info: \n"); ZLog::PrintV("\tFileType: \t%s\n", GetFileType(BO(m_pHeader->filetype))); ZLog::PrintV("\tTotalSize: \t%u (%s)\n", m_uLength, FormatSize(m_uLength).c_str()); ZLog::PrintV("\tPlatform: \t%u\n", m_b64 ? 64 : 32); ZLog::PrintV("\tCPUArch: \t%s\n", GetArch(BO(m_pHeader->cputype), BO(m_pHeader->cpusubtype))); ZLog::PrintV("\tCPUType: \t0x%x\n", BO(m_pHeader->cputype)); ZLog::PrintV("\tCPUSubType: \t0x%x\n", BO(m_pHeader->cpusubtype)); ZLog::PrintV("\tBigEndian: \t%d\n", m_bBigEndian); ZLog::PrintV("\tEncrypted: \t%d\n", m_bEncrypted); ZLog::PrintV("\tCommandCount: \t%d\n", BO(m_pHeader->ncmds)); ZLog::PrintV("\tCodeLength: \t%d (%s)\n", m_uCodeLength, FormatSize(m_uCodeLength).c_str()); ZLog::PrintV("\tSignLength: \t%d (%s)\n", m_uSignLength, FormatSize(m_uSignLength).c_str()); ZLog::PrintV("\tSpareLength: \t%d (%s)\n", m_uLength - m_uCodeLength - m_uSignLength, FormatSize(m_uLength - m_uCodeLength - m_uSignLength).c_str()); uint8_t *pLoadCommand = m_pBase + m_uHeaderSize; for (uint32_t i = 0; i < BO(m_pHeader->ncmds); i++) { auto *plc = (load_command *) pLoadCommand; if (LC_VERSION_MIN_IPHONEOS == BO(plc->cmd)) { ZLog::PrintV("\tMIN_IPHONEOS: \t0x%x\n", *((uint32_t *) (pLoadCommand + sizeof(load_command)))); } else if (LC_RPATH == BO(plc->cmd)) { ZLog::PrintV("\tLC_RPATH: \t%s\n", (char *) (pLoadCommand + sizeof(load_command) + 4)); } pLoadCommand += BO(plc->cmdsize); } bool bHasWeakDylib = false; ZLog::PrintV("\tLC_LOAD_DYLIB: \n"); pLoadCommand = m_pBase + m_uHeaderSize; for (uint32_t i = 0; i < BO(m_pHeader->ncmds); i++) { auto *plc = (load_command *) pLoadCommand; if (LC_LOAD_DYLIB == BO(plc->cmd)) { auto *dlc = (dylib_command *) pLoadCommand; const char *szDyLib = (const char *) (pLoadCommand + BO(dlc->dylib.name.offset)); ZLog::PrintV("\t\t\t%s\n", szDyLib); } else if (LC_LOAD_WEAK_DYLIB == BO(plc->cmd)) { bHasWeakDylib = true; } pLoadCommand += BO(plc->cmdsize); } if (bHasWeakDylib) { ZLog::PrintV("\tLC_LOAD_WEAK_DYLIB: \n"); pLoadCommand = m_pBase + m_uHeaderSize; for (uint32_t i = 0; i < BO(m_pHeader->ncmds); i++) { auto *plc = (load_command *) pLoadCommand; if (LC_LOAD_WEAK_DYLIB == BO(plc->cmd)) { auto *dlc = (dylib_command *) pLoadCommand; const char *szDyLib = (const char *) (pLoadCommand + BO(dlc->dylib.name.offset)); ZLog::PrintV("\t\t\t%s (weak)\n", szDyLib); } pLoadCommand += BO(plc->cmdsize); } } if (!m_strInfoPlist.empty()) { ZLog::Print("\n>>> Embedded Info.plist: \n"); ZLog::PrintV("\tlength: \t%lu\n", m_strInfoPlist.size()); string strInfoPlist = m_strInfoPlist; PWriter::StringReplace(strInfoPlist, "\n", "\n\t\t\t"); ZLog::PrintV("\tcontent: \t%s\n", strInfoPlist.c_str()); PrintDataSHASum("\tSHA-1: \t", E_SHASUM_TYPE_1, m_strInfoPlist); PrintDataSHASum("\tSHA-256:\t", E_SHASUM_TYPE_256, m_strInfoPlist); } if (nullptr == m_pSignBase || m_uSignLength <= 0) { ZLog::Warn(">>> Can't Find CodeSignature Segment!\n"); } else { ParseCodeSignature(m_pSignBase); } ZLog::Print("------------------------------------------------------------------\n"); } bool ZArchO::BuildCodeSignature(ZSignAsset *pSignAsset, bool bForce, const string &strBundleId, const string &strInfoPlistSHA1, const string &strInfoPlistSHA256, const string &strCodeResourcesSHA1, const string &strCodeResourcesSHA256, string &strOutput) { string strRequirementsSlot; string strEntitlementsSlot; string strDerEntitlementsSlot; string strEmptyEntitlements = "\n\n\n\n\n"; SlotBuildRequirements(strBundleId, pSignAsset->m_strSubjectCN, strRequirementsSlot); SlotBuildEntitlements(IsExecute() ? pSignAsset->m_strEntitlementsData : strEmptyEntitlements, strEntitlementsSlot); SlotBuildDerEntitlements(IsExecute() ? pSignAsset->m_strEntitlementsData : "", strDerEntitlementsSlot); string strRequirementsSlotSHA1; string strRequirementsSlotSHA256; if (strRequirementsSlot.empty()) { //empty strRequirementsSlotSHA1.append(20, 0); strRequirementsSlotSHA256.append(32, 0); } else { SHASum(strRequirementsSlot, strRequirementsSlotSHA1, strRequirementsSlotSHA256); } string strEntitlementsSlotSHA1; string strEntitlementsSlotSHA256; if (strEntitlementsSlot.empty()) { //empty strEntitlementsSlotSHA1.append(20, 0); strEntitlementsSlotSHA256.append(32, 0); } else { SHASum(strEntitlementsSlot, strEntitlementsSlotSHA1, strEntitlementsSlotSHA256); } string strDerEntitlementsSlotSHA1; string strDerEntitlementsSlotSHA256; if (strDerEntitlementsSlot.empty()) { //empty strDerEntitlementsSlotSHA1.append(20, 0); strDerEntitlementsSlotSHA256.append(32, 0); } else { SHASum(strDerEntitlementsSlot, strDerEntitlementsSlotSHA1, strDerEntitlementsSlotSHA256); } uint8_t *pCodeSlots1Data = nullptr; uint8_t *pCodeSlots256Data = nullptr; uint32_t uCodeSlots1DataLength = 0; uint32_t uCodeSlots256DataLength = 0; if (!bForce) { GetCodeSignatureExistsCodeSlotsData(m_pSignBase, pCodeSlots1Data, uCodeSlots1DataLength, pCodeSlots256Data, uCodeSlots256DataLength); } uint64_t execSegFlags = 0; if (nullptr != strstr(strEntitlementsSlot.data() + 8, "get-task-allow")) { // TODO: Check if get-task-allow is actually set to true execSegFlags = CS_EXECSEG_MAIN_BINARY | CS_EXECSEG_ALLOW_UNSIGNED; } string strCMSSignatureSlot; string strCodeDirectorySlot; string strAltnateCodeDirectorySlot; SlotBuildCodeDirectory(false, m_pBase, m_uCodeLength, pCodeSlots1Data, uCodeSlots1DataLength, execSegLimit, execSegFlags, strBundleId, pSignAsset->m_strTeamId, strInfoPlistSHA1, strRequirementsSlotSHA1, strCodeResourcesSHA1, strEntitlementsSlotSHA1, strDerEntitlementsSlotSHA1, IsExecute(), strCodeDirectorySlot); SlotBuildCodeDirectory(true, m_pBase, m_uCodeLength, pCodeSlots256Data, uCodeSlots256DataLength, execSegLimit, execSegFlags, strBundleId, pSignAsset->m_strTeamId, strInfoPlistSHA256, strRequirementsSlotSHA256, strCodeResourcesSHA256, strEntitlementsSlotSHA256, strDerEntitlementsSlotSHA256, IsExecute(), strAltnateCodeDirectorySlot); SlotBuildCMSSignature(pSignAsset, strCodeDirectorySlot, strAltnateCodeDirectorySlot, strCMSSignatureSlot); auto uCodeDirectorySlotLength = (uint32_t) strCodeDirectorySlot.size(); auto uRequirementsSlotLength = (uint32_t) strRequirementsSlot.size(); auto uEntitlementsSlotLength = (uint32_t) strEntitlementsSlot.size(); auto uDerEntitlementsLength = (uint32_t) strDerEntitlementsSlot.size(); auto uAltnateCodeDirectorySlotLength = (uint32_t) strAltnateCodeDirectorySlot.size(); auto uCMSSignatureSlotLength = (uint32_t) strCMSSignatureSlot.size(); uint32_t uCodeSignBlobCount = 0; uCodeSignBlobCount += (uCodeDirectorySlotLength > 0) ? 1 : 0; uCodeSignBlobCount += (uRequirementsSlotLength > 0) ? 1 : 0; uCodeSignBlobCount += (uEntitlementsSlotLength > 0) ? 1 : 0; uCodeSignBlobCount += (uDerEntitlementsLength > 0) ? 1 : 0; uCodeSignBlobCount += (uAltnateCodeDirectorySlotLength > 0) ? 1 : 0; uCodeSignBlobCount += (uCMSSignatureSlotLength > 0) ? 1 : 0; uint32_t uSuperBlobHeaderLength = sizeof(CS_SuperBlob) + uCodeSignBlobCount * sizeof(CS_BlobIndex); uint32_t uCodeSignLength = uSuperBlobHeaderLength + uCodeDirectorySlotLength + uRequirementsSlotLength + uEntitlementsSlotLength + uDerEntitlementsLength + uAltnateCodeDirectorySlotLength + uCMSSignatureSlotLength; vector arrBlobIndexes; if (uCodeDirectorySlotLength > 0) { CS_BlobIndex blob{}; blob.type = BE(CSSLOT_CODEDIRECTORY); blob.offset = BE(uSuperBlobHeaderLength); arrBlobIndexes.push_back(blob); } if (uRequirementsSlotLength > 0) { CS_BlobIndex blob{}; blob.type = BE(CSSLOT_REQUIREMENTS); blob.offset = BE(uSuperBlobHeaderLength + uCodeDirectorySlotLength); arrBlobIndexes.push_back(blob); } if (uEntitlementsSlotLength > 0) { CS_BlobIndex blob{}; blob.type = BE(CSSLOT_ENTITLEMENTS); blob.offset = BE(uSuperBlobHeaderLength + uCodeDirectorySlotLength + uRequirementsSlotLength); arrBlobIndexes.push_back(blob); } if (uDerEntitlementsLength > 0) { CS_BlobIndex blob{}; blob.type = BE(CSSLOT_DER_ENTITLEMENTS); blob.offset = BE( uSuperBlobHeaderLength + uCodeDirectorySlotLength + uRequirementsSlotLength + uEntitlementsSlotLength); arrBlobIndexes.push_back(blob); } if (uAltnateCodeDirectorySlotLength > 0) { CS_BlobIndex blob{}; blob.type = BE(CSSLOT_ALTERNATE_CODEDIRECTORIES); blob.offset = BE( uSuperBlobHeaderLength + uCodeDirectorySlotLength + uRequirementsSlotLength + uEntitlementsSlotLength + uDerEntitlementsLength); arrBlobIndexes.push_back(blob); } if (uCMSSignatureSlotLength > 0) { CS_BlobIndex blob{}; blob.type = BE(CSSLOT_SIGNATURESLOT); blob.offset = BE( uSuperBlobHeaderLength + uCodeDirectorySlotLength + uRequirementsSlotLength + uEntitlementsSlotLength + uDerEntitlementsLength + uAltnateCodeDirectorySlotLength); arrBlobIndexes.push_back(blob); } CS_SuperBlob superblob{}; superblob.magic = BE(CSMAGIC_EMBEDDED_SIGNATURE); superblob.length = BE(uCodeSignLength); superblob.count = BE(uCodeSignBlobCount); strOutput.clear(); strOutput.reserve(uCodeSignLength); strOutput.append((const char *) &superblob, sizeof(superblob)); for (auto &blob: arrBlobIndexes) { strOutput.append((const char *) &blob, sizeof(blob)); } strOutput += strCodeDirectorySlot; strOutput += strRequirementsSlot; strOutput += strEntitlementsSlot; strOutput += strDerEntitlementsSlot; strOutput += strAltnateCodeDirectorySlot; strOutput += strCMSSignatureSlot; if (ZLog::IsDebug()) { WriteFile("./.zsign_debug/Requirements.slot.new", strRequirementsSlot); WriteFile("./.zsign_debug/Entitlements.slot.new", strEntitlementsSlot); WriteFile("./.zsign_debug/Entitlements.der.slot.new", strDerEntitlementsSlot); WriteFile("./.zsign_debug/Entitlements.plist.new", strEntitlementsSlot.data() + 8, strEntitlementsSlot.size() - 8); WriteFile("./.zsign_debug/CodeDirectory_SHA1.slot.new", strCodeDirectorySlot); WriteFile("./.zsign_debug/CodeDirectory_SHA256.slot.new", strAltnateCodeDirectorySlot); WriteFile("./.zsign_debug/CMSSignature.slot.new", strCMSSignatureSlot); WriteFile("./.zsign_debug/CMSSignature.der.new", strCMSSignatureSlot.data() + 8, strCMSSignatureSlot.size() - 8); WriteFile("./.zsign_debug/CodeSignature.blob.new", strOutput); } return true; } bool ZArchO::Sign(ZSignAsset *pSignAsset, bool bForce, const string &strBundleId, const string &strInfoPlistSHA1, const string &strInfoPlistSHA256, const string &strCodeResourcesData) { if (nullptr == m_pSignBase) { m_bEnoughSpace = false; ZLog::Warn("Can't Find CodeSignature Segment!\n"); return false; } string strCodeResourcesSHA1; string strCodeResourcesSHA256; if (strCodeResourcesData.empty()) { strCodeResourcesSHA1.append(20, 0); strCodeResourcesSHA256.append(32, 0); } else { SHASum(strCodeResourcesData, strCodeResourcesSHA1, strCodeResourcesSHA256); } string strCodeSignBlob; BuildCodeSignature(pSignAsset, bForce, strBundleId, strInfoPlistSHA1, strInfoPlistSHA256, strCodeResourcesSHA1, strCodeResourcesSHA256, strCodeSignBlob); if (strCodeSignBlob.empty()) { ZLog::Error("Build CodeSignature Failed!\n"); return false; } int nSpaceLength = (int) m_uLength - (int) m_uCodeLength - (int) strCodeSignBlob.size(); if (nSpaceLength < 0) { m_bEnoughSpace = false; ZLog::WarnV("No Enough CodeSignature Space. Length => Now: %d, Need: %d\n", (int) m_uLength - (int) m_uCodeLength, (int) strCodeSignBlob.size()); return false; } memcpy(m_pBase + m_uCodeLength, strCodeSignBlob.data(), strCodeSignBlob.size()); //memset(m_pBase + m_uCodeLength + strCodeSignBlob.size(), 0, nSpaceLength); return true; } uint32_t ZArchO::ReallocCodeSignSpace(const string &strNewFile) { RemoveFile(strNewFile.c_str()); uint32_t uNewLength = m_uCodeLength + ByteAlign(((m_uCodeLength / 4096) + 1) * (20 + 32), 4096) + 16384; //16K May Be Enough if (nullptr == m_pLinkEditSegment || uNewLength <= m_uLength) { return 0; } auto *pseglc = (load_command *) m_pLinkEditSegment; switch (BO(pseglc->cmd)) { case LC_SEGMENT: { auto *seglc = (segment_command *) m_pLinkEditSegment; seglc->vmsize = ByteAlign(BO(seglc->vmsize) + (uNewLength - m_uLength), 4096); seglc->vmsize = BO(seglc->vmsize); seglc->filesize = uNewLength - BO(seglc->fileoff); seglc->filesize = BO(seglc->filesize); } break; case LC_SEGMENT_64: { auto *seglc = (segment_command_64 *) m_pLinkEditSegment; seglc->vmsize = ByteAlign(BO(seglc->vmsize) + (uNewLength - m_uLength), 4096); seglc->vmsize = BO(seglc->vmsize); seglc->filesize = uNewLength - BO(seglc->fileoff); seglc->filesize = BO(seglc->filesize); } break; } auto *pcslc = (codesignature_command *) m_pCodeSignSegment; if (nullptr == pcslc) { if (m_uLoadCommandsFreeSpace < 4) { ZLog::Error("Can't Find Free Space Of LoadCommands For CodeSignature!\n"); return 0; } pcslc = (codesignature_command *) (m_pBase + m_uHeaderSize + BO(m_pHeader->sizeofcmds)); pcslc->cmd = BO(LC_CODE_SIGNATURE); pcslc->cmdsize = BO((uint32_t) sizeof(codesignature_command)); pcslc->dataoff = BO(m_uCodeLength); m_pHeader->ncmds = BO(BO(m_pHeader->ncmds) + 1); m_pHeader->sizeofcmds = BO(BO(m_pHeader->sizeofcmds) + sizeof(codesignature_command)); } pcslc->datasize = BO(uNewLength - m_uCodeLength); if (!AppendFile(strNewFile.c_str(), (const char *) m_pBase, m_uLength)) { return 0; } string strPadding; strPadding.append(uNewLength - m_uLength, 0); if (!AppendFile(strNewFile.c_str(), strPadding)) { RemoveFile(strNewFile.c_str()); return 0; } return uNewLength; } bool ZArchO::RemoveDyLib(const char *szDyLibPath, bool showLog) { if (nullptr == m_pHeader) { return false; } uint8_t *pLoadCommand = m_pBase + m_uHeaderSize; for (uint32_t i = 0; i < BO(m_pHeader->ncmds); i++) { auto *plc = (load_command *) pLoadCommand; if (LC_LOAD_DYLIB == BO(plc->cmd) || LC_LOAD_WEAK_DYLIB == BO(plc->cmd)) { auto *dlc = (dylib_command *) pLoadCommand; const char *szDyLib = (const char *) (pLoadCommand + BO(dlc->dylib.name.offset)); if (0 == strcmp(szDyLib, szDyLibPath)) { uint32_t uLoadCommandSize = BO(plc->cmdsize); uint32_t uLoadCommandOffset = (uint32_t) (pLoadCommand - m_pBase); uint32_t uLoadCommandEnd = uLoadCommandOffset + uLoadCommandSize; uint32_t uLoadCommandsEnd = m_uHeaderSize + BO(m_pHeader->sizeofcmds); uint32_t uLoadCommandsLength = m_uLength - uLoadCommandsEnd; if (uLoadCommandsEnd < uLoadCommandEnd || uLoadCommandsLength <= 0) { return false; } memmove(pLoadCommand, pLoadCommand + uLoadCommandSize, uLoadCommandsLength); m_pHeader->ncmds = BO(BO(m_pHeader->ncmds) - 1); m_pHeader->sizeofcmds = BO(BO(m_pHeader->sizeofcmds) - uLoadCommandSize); return true; } } pLoadCommand += BO(plc->cmdsize); } return false; } bool ZArchO::InjectDyLib(bool bWeakInject, const char *szDyLibPath, bool &bCreate, bool showLog) { if (nullptr == m_pHeader) { return false; } uint8_t *pLoadCommand = m_pBase + m_uHeaderSize; for (uint32_t i = 0; i < BO(m_pHeader->ncmds); i++) { auto *plc = (load_command *) pLoadCommand; uint32_t uLoadType = BO(plc->cmd); if (LC_LOAD_DYLIB == uLoadType || LC_LOAD_WEAK_DYLIB == uLoadType) { auto *dlc = (dylib_command *) pLoadCommand; const char *szDyLib = (const char *) (pLoadCommand + BO(dlc->dylib.name.offset)); if (0 == strcmp(szDyLib, szDyLibPath)) { if ((bWeakInject && (LC_LOAD_WEAK_DYLIB != uLoadType)) || (!bWeakInject && (LC_LOAD_DYLIB != uLoadType))) { dlc->cmd = BO((uint32_t) (bWeakInject ? LC_LOAD_WEAK_DYLIB : LC_LOAD_DYLIB)); if (showLog) { ZLog::WarnV("DyLib Load Type Changed! %s -> %s\n", (LC_LOAD_DYLIB == uLoadType) ? "LC_LOAD_DYLIB" : "LC_LOAD_WEAK_DYLIB", bWeakInject ? "LC_LOAD_WEAK_DYLIB" : "LC_LOAD_DYLIB"); } } else { if (showLog) { ZLog::WarnV("插件已存在:\t%s\n", szDyLibPath); } } return true; } } pLoadCommand += BO(plc->cmdsize); } uint32_t uDylibPathLength = strlen(szDyLibPath); uint32_t uDylibPathPadding = (8 - uDylibPathLength % 8); uint32_t uDyLibCommandSize = sizeof(dylib_command) + uDylibPathLength + uDylibPathPadding; if (m_uLoadCommandsFreeSpace > 0 && m_uLoadCommandsFreeSpace < uDyLibCommandSize) // some bin doesn't have '__text' { if (showLog) { ZLog::Error( "Can't Find Free Space Of LoadCommands For LC_LOAD_DYLIB Or LC_LOAD_WEAK_DYLIB!\n"); } throw "Can't Find Free Space Of LoadCommands For LC_LOAD_DYLIB Or LC_LOAD_WEAK_DYLIB!"; } //add auto *dlc = (dylib_command *) (m_pBase + m_uHeaderSize + BO(m_pHeader->sizeofcmds)); dlc->cmd = BO((uint32_t) (bWeakInject ? LC_LOAD_WEAK_DYLIB : LC_LOAD_DYLIB)); dlc->cmdsize = BO(uDyLibCommandSize); dlc->dylib.name.offset = BO((uint32_t) sizeof(dylib_command)); dlc->dylib.timestamp = BO((uint32_t) 2); dlc->dylib.current_version = 0; dlc->dylib.compatibility_version = 0; string strDylibPath = szDyLibPath; strDylibPath.append(uDylibPathPadding, 0); uint8_t *pDyLibPath = (uint8_t *) dlc + sizeof(dylib_command); memcpy(pDyLibPath, strDylibPath.data(), uDylibPathLength + uDylibPathPadding); m_pHeader->ncmds = BO(BO(m_pHeader->ncmds) + 1); m_pHeader->sizeofcmds = BO(BO(m_pHeader->sizeofcmds) + uDyLibCommandSize); bCreate = true; if (showLog) { ZLog::WarnV("插件注入成功:\t%s\n", szDyLibPath); } return true; } void ZArchO::uninstallDylibs(set dylibNames) { uint8_t *pLoadCommand = m_pBase + m_uHeaderSize; uint32_t old_load_command_size = m_pHeader->sizeofcmds; auto *new_load_command_data = (uint8_t *) malloc(old_load_command_size); memset(new_load_command_data, 0, old_load_command_size); uint32_t new_load_command_size = 0; uint32_t clear_num = 0; uint32_t clear_data_size = 0; for (uint32_t i = 0; i < BO(m_pHeader->ncmds); i++) { auto *plc = (load_command *) pLoadCommand; uint32_t load_command_size = BO(plc->cmdsize); if (LC_LOAD_DYLIB == BO(plc->cmd) || LC_LOAD_WEAK_DYLIB == BO(plc->cmd)) { auto *dlc = (dylib_command *) pLoadCommand; const char *szDyLib = (const char *) (pLoadCommand + BO(dlc->dylib.name.offset)); string dylibName = szDyLib; if (dylibNames.count(dylibName) > 0) { ZLog::PrintV("\t\t\t%s\tclear\n", szDyLib); clear_num++; clear_data_size += load_command_size; pLoadCommand += BO(plc->cmdsize); continue; } ZLog::PrintV("\t\t\t%s\n", szDyLib); } new_load_command_size += load_command_size; memcpy(new_load_command_data, pLoadCommand, load_command_size); new_load_command_data += load_command_size; pLoadCommand += BO(plc->cmdsize); } pLoadCommand -= m_pHeader->sizeofcmds; m_pHeader->ncmds -= clear_num; m_pHeader->sizeofcmds -= clear_data_size; new_load_command_data -= new_load_command_size; memset(pLoadCommand, 0, old_load_command_size); memcpy(pLoadCommand, new_load_command_data, new_load_command_size); free(new_load_command_data); }