├── .gitattributes ├── .gitignore ├── IPALibrary ├── CodeSignature │ ├── CodeSignatureSuperBlob.cs │ ├── Enums │ │ ├── CodeDirectoryFlags.cs │ │ ├── CodeSignatureEntryType.cs │ │ ├── HashType.cs │ │ └── SecurityRequirementType.cs │ ├── Helpers │ │ ├── CMSGenerator.cs │ │ ├── CMSHelper.cs │ │ ├── CertificateValidationHelper.cs │ │ ├── CodeSignatureHelper.cs │ │ ├── HashAlgorithmHelper.cs │ │ └── RSAHelper.cs │ └── Structures │ │ ├── CodeRequirementBlobs │ │ ├── CodeRequirementBlob.cs │ │ └── RequirementExpression │ │ │ ├── AnchorHash.cs │ │ │ ├── AndExpression.cs │ │ │ ├── AppleAnchor.cs │ │ │ ├── AppleGenericAnchor.cs │ │ │ ├── BooleanValue.cs │ │ │ ├── CertificateField.cs │ │ │ ├── CertificateGeneric.cs │ │ │ ├── CodeDirectoryHash.cs │ │ │ ├── Enums │ │ │ ├── MatchOperationName.cs │ │ │ └── RequirementOperatorName.cs │ │ │ ├── IdentValue.cs │ │ │ ├── InfoKeyField.cs │ │ │ ├── InfoKeyValue.cs │ │ │ ├── NotExpression.cs │ │ │ ├── OrExpression.cs │ │ │ ├── RequirementExpression.cs │ │ │ ├── Structures │ │ │ └── MatchSuffix.cs │ │ │ ├── TrustedCertificate.cs │ │ │ └── TrustedCertificates.cs │ │ └── CodeSignatureBlobs │ │ ├── CmsSignatureBlob.cs │ │ ├── CodeDirectoryBlob.cs │ │ ├── CodeRequirementsBlob.cs │ │ ├── CodeSignatureBlob.cs │ │ ├── CodeSignatureGenericBlob.cs │ │ └── EntitlementsBlob.cs ├── Components │ ├── BouncyCastle.dll │ ├── ICSharpCode.SharpZipLib.dll │ ├── PListNet.dll │ └── System.Core.dll ├── Helpers │ ├── Asn1Helper.cs │ ├── CertificateHelper.cs │ ├── MemoryStreamDataSource.cs │ └── PListHelper.cs ├── ILMerge │ └── ILMerge.bat ├── IPAFile.cs ├── IPALibrary.csproj ├── MachO │ ├── Enums │ │ ├── CpuType.cs │ │ ├── FileType.cs │ │ ├── LoadCommandType.cs │ │ └── MachHeaderFlags.cs │ ├── Helpers │ │ ├── MachObjectHelper.cs │ │ └── SegmentCommandHelper.cs │ ├── MachObjectFile.cs │ ├── Structures │ │ ├── FatArch.cs │ │ ├── FatHeader.cs │ │ ├── LoadCommands │ │ │ ├── CodeSignatureCommand.cs │ │ │ ├── LoadCommand.cs │ │ │ ├── Section32.cs │ │ │ ├── Section64.cs │ │ │ ├── SegmentCommand.cs │ │ │ ├── SegmentCommand32.cs │ │ │ └── SegmentCommand64.cs │ │ └── MachHeader.cs │ └── UniversalBinaryFile.cs ├── MobileProvision │ ├── MobileProvisionFile.cs │ └── MobileProvisionPList.cs ├── PListFiles │ ├── CodeResourcesFile.cs │ ├── EntitlementsFile.cs │ ├── InfoFile.cs │ └── PListFile.cs └── Properties │ └── AssemblyInfo.cs ├── IPASign.png ├── IPASign.sln ├── IPASign ├── Certificates │ ├── AppleIncRootCertificate.cer │ └── AppleWWDRCA.cer ├── IPASign.csproj ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── Program.cs └── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Readme.md └── Utilities ├── ByteUtils ├── BigEndianReader.cs ├── BigEndianWriter.cs ├── ByteReader.cs ├── ByteUtils.cs ├── ByteWriter.cs ├── LittleEndianReader.cs └── LittleEndianWriter.cs ├── Comparers └── ReverseComparer.cs ├── Conversion ├── BigEndianConverter.cs ├── Conversion.SimpleTypes.cs └── LittleEndianConverter.cs ├── Generics └── KeyValuePairList.cs ├── Properties └── AssemblyInfo.cs └── Utilities.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | # Unsetting the text attribute on a path tells Git not to attempt any end-of-line conversion upon checkin or checkout 2 | * -text 3 | 4 | # Custom for Visual Studio 5 | *.cs -text diff=csharp 6 | *.csproj -text merge=union 7 | *.sln -text merge=union eol=crlf 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # Build results 11 | [Dd]ebug/ 12 | [Dd]ebugPublic/ 13 | [Rr]elease/ 14 | [Rr]eleases/ 15 | x64/ 16 | x86/ 17 | build/ 18 | bld/ 19 | [Bb]in/ 20 | [Oo]bj/ 21 | 22 | # Roslyn cache directories 23 | *.ide/ 24 | 25 | # MSTest test Results 26 | [Tt]est[Rr]esult*/ 27 | [Bb]uild[Ll]og.* 28 | 29 | #NUNIT 30 | *.VisualState.xml 31 | TestResult.xml 32 | 33 | # Build Results of an ATL Project 34 | [Dd]ebugPS/ 35 | [Rr]eleasePS/ 36 | dlldata.c 37 | 38 | *_i.c 39 | *_p.c 40 | *_i.h 41 | *.ilk 42 | *.meta 43 | *.obj 44 | *.pch 45 | *.pdb 46 | *.pgc 47 | *.pgd 48 | *.rsp 49 | *.sbr 50 | *.tlb 51 | *.tli 52 | *.tlh 53 | *.tmp 54 | *.tmp_proj 55 | *.log 56 | *.vspscc 57 | *.vssscc 58 | .builds 59 | *.pidb 60 | *.svclog 61 | *.scc 62 | 63 | # Chutzpah Test files 64 | _Chutzpah* 65 | 66 | # Visual C++ cache files 67 | ipch/ 68 | *.aps 69 | *.ncb 70 | *.opensdf 71 | *.sdf 72 | *.cachefile 73 | 74 | # Visual Studio profiler 75 | *.psess 76 | *.vsp 77 | *.vspx 78 | 79 | # TFS 2012 Local Workspace 80 | $tf/ 81 | 82 | # Guidance Automation Toolkit 83 | *.gpState 84 | 85 | # ReSharper is a .NET coding add-in 86 | _ReSharper*/ 87 | *.[Rr]e[Ss]harper 88 | *.DotSettings.user 89 | 90 | # JustCode is a .NET coding addin-in 91 | .JustCode 92 | 93 | # TeamCity is a build add-in 94 | _TeamCity* 95 | 96 | # DotCover is a Code Coverage Tool 97 | *.dotCover 98 | 99 | # NCrunch 100 | _NCrunch_* 101 | .*crunch*.local.xml 102 | 103 | # MightyMoose 104 | *.mm.* 105 | AutoTest.Net/ 106 | 107 | # Web workbench (sass) 108 | .sass-cache/ 109 | 110 | # Installshield output folder 111 | [Ee]xpress/ 112 | 113 | # DocProject is a documentation generator add-in 114 | DocProject/buildhelp/ 115 | DocProject/Help/*.HxT 116 | DocProject/Help/*.HxC 117 | DocProject/Help/*.hhc 118 | DocProject/Help/*.hhk 119 | DocProject/Help/*.hhp 120 | DocProject/Help/Html2 121 | DocProject/Help/html 122 | 123 | # Click-Once directory 124 | publish/ 125 | 126 | # Publish Web Output 127 | *.[Pp]ublish.xml 128 | *.azurePubxml 129 | # TODO: Comment the next line if you want to checkin your web deploy settings 130 | # but database connection strings (with potential passwords) will be unencrypted 131 | *.pubxml 132 | *.publishproj 133 | 134 | # NuGet Packages 135 | *.nupkg 136 | # The packages folder can be ignored because of Package Restore 137 | **/packages/* 138 | # except build/, which is used as an MSBuild target. 139 | !**/packages/build/ 140 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 141 | #!**/packages/repositories.config 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | 163 | # RIA/Silverlight projects 164 | Generated_Code/ 165 | 166 | # Backup & report files from converting an old project file 167 | # to a newer Visual Studio version. Backup files are not needed, 168 | # because we have git ;-) 169 | _UpgradeReport_Files/ 170 | Backup*/ 171 | UpgradeLog*.XML 172 | UpgradeLog*.htm 173 | 174 | # SQL Server files 175 | *.mdf 176 | *.ldf 177 | 178 | # Business Intelligence projects 179 | *.rdl.data 180 | *.bim.layout 181 | *.bim_*.settings 182 | 183 | # Microsoft Fakes 184 | FakesAssemblies/ 185 | 186 | # ========================= 187 | # Operating System Files 188 | # ========================= 189 | 190 | # OSX 191 | # ========================= 192 | 193 | .DS_Store 194 | .AppleDouble 195 | .LSOverride 196 | 197 | # Thumbnails 198 | ._* 199 | 200 | # Files that might appear on external disk 201 | .Spotlight-V100 202 | .Trashes 203 | 204 | # Directories potentially created on remote AFP share 205 | .AppleDB 206 | .AppleDesktop 207 | Network Trash Folder 208 | Temporary Items 209 | .apdisk 210 | 211 | # Windows 212 | # ========================= 213 | 214 | # Windows image file caches 215 | Thumbs.db 216 | ehthumbs.db 217 | 218 | # Folder config file 219 | Desktop.ini 220 | 221 | # Recycle Bin used on file shares 222 | $RECYCLE.BIN/ 223 | 224 | # Windows Installer files 225 | *.cab 226 | *.msi 227 | *.msm 228 | *.msp 229 | 230 | # Windows shortcuts 231 | *.lnk 232 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/CodeSignatureSuperBlob.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | /// 16 | /// Implements the CS_SuperBlob structure which is defined in codesign.c 17 | /// https://opensource.apple.com/source/Security/Security-55471/sec/Security/Tool/codesign.c 18 | /// 19 | public class CodeSignatureSuperBlob 20 | { 21 | public const uint Signature = 0xfade0cc0; // CSMAGIC_EMBEDDED_SIGNATURE 22 | public const int FixedLength = 12; 23 | 24 | // uint Magic; 25 | // uint Length; 26 | // uint Count; 27 | public KeyValuePairList Entries = new KeyValuePairList(); 28 | 29 | public CodeSignatureSuperBlob() 30 | { 31 | } 32 | 33 | public CodeSignatureSuperBlob(byte[] buffer, int offset) 34 | { 35 | uint length = BigEndianConverter.ToUInt32(buffer, offset + 4); 36 | uint count = BigEndianConverter.ToUInt32(buffer, offset + 8); 37 | for (int index = 0; index < count; index++) 38 | { 39 | CodeSignatureEntryType entryType = (CodeSignatureEntryType)BigEndianConverter.ToUInt32(buffer, offset + 12 + index * 8); 40 | uint entryOffset = BigEndianConverter.ToUInt32(buffer, offset + 12 + index * 8 + 4); 41 | CodeSignatureBlob blob = CodeSignatureBlob.ReadBlob(buffer, offset + (int)entryOffset); 42 | Entries.Add(entryType, blob); 43 | } 44 | } 45 | 46 | public CodeSignatureBlob GetEntry(CodeSignatureEntryType entryType) 47 | { 48 | for (int index = 0; index < Entries.Count; index++) 49 | { 50 | if (Entries[index].Key == entryType) 51 | { 52 | return Entries[index].Value; 53 | } 54 | } 55 | return null; 56 | } 57 | 58 | public void WriteBytes(byte[] buffer, int offset) 59 | { 60 | BigEndianWriter.WriteUInt32(buffer, offset + 0, Signature); 61 | BigEndianWriter.WriteUInt32(buffer, offset + 4, (uint)Length); 62 | BigEndianWriter.WriteUInt32(buffer, offset + 8, (uint)Entries.Count); 63 | int blobOffset = FixedLength + Entries.Count * 8; 64 | for (int index = 0; index < Entries.Count; index++) 65 | { 66 | BigEndianWriter.WriteUInt32(buffer, offset + 12 + index * 8, (uint)Entries[index].Key); 67 | BigEndianWriter.WriteUInt32(buffer, offset + 12 + index * 8 + 4, (uint)blobOffset); 68 | Entries[index].Value.WriteBytes(buffer, offset + blobOffset); 69 | blobOffset += Entries[index].Value.Length; 70 | } 71 | } 72 | 73 | public byte[] GetBytes() 74 | { 75 | byte[] buffer = new byte[Length]; 76 | WriteBytes(buffer, 0); 77 | return buffer; 78 | } 79 | 80 | public int Length 81 | { 82 | get 83 | { 84 | int length = FixedLength + Entries.Count * 8; 85 | for (int index = 0; index < Entries.Count; index++) 86 | { 87 | length += Entries[index].Value.Length; 88 | } 89 | return length; 90 | } 91 | } 92 | 93 | public static bool IsCodeSignatureSuperBlob(byte[] buffer, int offset) 94 | { 95 | uint magic = BigEndianConverter.ToUInt32(buffer, offset + 0); 96 | return (magic == Signature); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Enums/CodeDirectoryFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace IPALibrary.CodeSignature 4 | { 5 | [Flags] 6 | public enum CodeDirectoryFlags : uint 7 | { 8 | Valid = 0x00000001, // CS_VALID 9 | AdHoc = 0x00000002, // CS_ADHOC 10 | GetTaskAllow = 0x00000004, // CS_GET_TASK_ALLOW 11 | Installer = 0x00000008, // CS_INSTALLER 12 | Hard = 0x00000100, // CS_HARD 13 | Kill = 0x00000200, // CS_KILL 14 | CheckExpiration = 0x00000400, // CS_CHECK_EXPIRATION 15 | Restrict = 0x00000800, // CS_RESTRICT 16 | Enforcement = 0x00001000, // CS_ENFORCEMENT 17 | RequireLibraryValidation = 0x00002000, // CS_REQUIRE_LV 18 | EntitlementsValidated = 0x00004000, // CS_ENTITLEMENTS_VALIDATED 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Enums/CodeSignatureEntryType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace IPALibrary.CodeSignature 4 | { 5 | public enum CodeSignatureEntryType : uint 6 | { 7 | CodeDirectory = 0x00000000, // CSSLOT_CODEDIRECTORY, The signature of this entry type will be CSMAGIC_CODEDIRECTORY 8 | Requirements = 0x00000002, // CSSLOT_REQUIREMENTS, The signature of this entry type will be CSMAGIC_REQUIREMENTS 9 | Entitlements = 0x00000005, // CSSLOT_ENTITLEMENTS, The signature of this entry type will be CSMAGIC_EMBEDDED_ENTITLEMENTS 10 | AlternateCodeDirectory1 = 0x00001000, // CSSLOT_ALTERNATE_CODEDIRECTORIES, The signature of this entry type will be CSMAGIC_CODEDIRECTORY 11 | CmsSignature = 0x00010000, // CSSLOT_SIGNATURESLOT, The signature of this entry type will be CSMAGIC_BLOBWRAPPER 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Enums/HashType.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace IPALibrary.CodeSignature 3 | { 4 | public enum HashType : byte 5 | { 6 | SHA1 = 0x01, // CS_HASHTYPE_SHA1 7 | SHA256 = 0x02, // CS_HASHTYPE_SHA256 8 | SHA256Truncated = 0x03, // CS_HASHTYPE_SHA256_TRUNCATED - SHA256 truncated to 20 bytes 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Enums/SecurityRequirementType.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace IPALibrary.CodeSignature 3 | { 4 | /// 5 | /// SecRequirementType 6 | /// 7 | public enum SecurityRequirementType : uint 8 | { 9 | HostRequirementType = 0x00000001, // kSecHostRequirementType 10 | GuestRequirementType = 0x00000002, // kSecGuestRequirementType 11 | DesignatedRequirementType = 0x00000003, // kSecDesignatedRequirementType 12 | LibraryRequirementType = 0x00000004, // kSecLibraryRequirementType 13 | PluginRequirementType = 0x00000005, // kSecPluginRequirementType 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Helpers/CMSHelper.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections; 11 | using System.Collections.Generic; 12 | using Org.BouncyCastle.Asn1.Cms; 13 | using Org.BouncyCastle.Cms; 14 | using Org.BouncyCastle.Crypto; 15 | using Org.BouncyCastle.Pkcs; 16 | using Org.BouncyCastle.X509; 17 | using Org.BouncyCastle.X509.Store; 18 | using IPALibrary.MachO; 19 | using Utilities; 20 | 21 | namespace IPALibrary.CodeSignature 22 | { 23 | public class CMSHelper 24 | { 25 | public static byte[] GenerateSignature(List certificateChain, AsymmetricKeyEntry privateKey, byte[] messageToSign) 26 | { 27 | return GenerateSignature(certificateChain, privateKey, messageToSign, null); 28 | } 29 | 30 | public static byte[] GenerateSignature(List certificateChain, AsymmetricKeyEntry privateKey, byte[] messageToSign, AttributeTable signedAttributesTable) 31 | { 32 | X509Certificate signingCertificate = certificateChain[certificateChain.Count - 1]; 33 | #if MAX_CMS_COMPATIBILITY 34 | // Optional: This is the order that codesign uses: 35 | List cmsChain = new List(); 36 | if (certificateChain.Count > 1) 37 | { 38 | cmsChain.AddRange(certificateChain.GetRange(0, certificateChain.Count - 1)); 39 | cmsChain.Reverse(); 40 | } 41 | cmsChain.Add(signingCertificate); 42 | certificateChain = cmsChain; 43 | #endif 44 | IX509Store certificateStore = X509StoreFactory.Create("Certificate/Collection", new X509CollectionStoreParameters(certificateChain)); 45 | 46 | CmsSignedDataGenerator generator = new CmsSignedDataGenerator(); 47 | #if MAX_CMS_COMPATIBILITY 48 | // Optional: BouncyCastle v1.8.3 has the option to use DER instead of BER to store the certificate chain 49 | generator.UseDerForCerts = true; 50 | #endif 51 | generator.AddSigner(privateKey.Key, signingCertificate, CmsSignedDataGenerator.DigestSha256, signedAttributesTable, null); 52 | generator.AddCertificates(certificateStore); 53 | CmsSignedData cmsSignature = generator.Generate(CmsSignedGenerator.Data, new CmsProcessableByteArray(messageToSign), false); 54 | return cmsSignature.GetEncoded(); 55 | } 56 | 57 | public static bool ValidateSignature(byte[] messageBytes, byte[] signatureBytes, X509Certificate certificate) 58 | { 59 | CmsProcessable signedContent = new CmsProcessableByteArray(messageBytes); 60 | CmsSignedData signedData = new CmsSignedData(signedContent, signatureBytes); 61 | IX509Store certificateStore = signedData.GetCertificates("Collection"); 62 | SignerInformationStore signerInfoStore = signedData.GetSignerInfos(); 63 | ICollection signers = signerInfoStore.GetSigners(); 64 | foreach (SignerInformation signer in signers) 65 | { 66 | bool isChainValid = ValidateCertificateChain(certificateStore, signer.SignerID); 67 | if (!isChainValid) 68 | { 69 | return false; 70 | } 71 | 72 | bool verified = signer.Verify(certificate); 73 | if (!verified) 74 | { 75 | return false; 76 | } 77 | } 78 | 79 | return true; 80 | } 81 | 82 | public static bool ValidateCertificateChain(IX509Store certificateStore, SignerID signerID) 83 | { 84 | List certificateChain = GetCertificateChain(certificateStore, signerID); 85 | List certificateChainBytes = new List(); 86 | foreach (X509Certificate certficate in certificateChain) 87 | { 88 | certificateChainBytes.Add(certficate.GetEncoded()); 89 | } 90 | 91 | return CertificateValidationHelper.VerifyCertificateChain(certificateChainBytes); 92 | } 93 | 94 | /// The first element in the returned list will be the leaf, and the last will be the root certificate 95 | public static List GetCertificateChain(IX509Store certificateStore, SignerID signerID) 96 | { 97 | X509Certificate parent = null; 98 | List chain = new List(); 99 | SignerID nextSignerID = signerID; 100 | do 101 | { 102 | ICollection matches = certificateStore.GetMatches(nextSignerID); 103 | foreach (X509Certificate certificate in matches) 104 | { 105 | parent = certificate; 106 | nextSignerID = new SignerID(); 107 | nextSignerID.Subject = certificate.IssuerDN; 108 | break; 109 | } 110 | chain.Add(parent); 111 | } 112 | while (parent != null && !parent.IssuerDN.Equivalent(parent.SubjectDN)); 113 | 114 | if (parent != null) 115 | { 116 | return chain; 117 | } 118 | else 119 | { 120 | return null; 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Helpers/CertificateValidationHelper.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Security; 12 | using System.Security.Cryptography; 13 | using System.Security.Cryptography.X509Certificates; 14 | using Utilities; 15 | 16 | namespace IPALibrary.CodeSignature 17 | { 18 | public class CertificateValidationHelper 19 | { 20 | public static byte[] SHA_160_PKCS_ID = new byte[] { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14 }; 21 | public static byte[] SHA_256_PKCS_ID = new byte[] { 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; 22 | 23 | public static int GetRootCertificateIndex(List certificates) 24 | { 25 | int index; 26 | for (index = 0; index < certificates.Count; index++) 27 | { 28 | byte[] certificateBytes = certificates[index]; 29 | X509Certificate2 certificate = new X509Certificate2(certificateBytes); 30 | if (certificate.Issuer == certificate.Subject) 31 | { 32 | return index; 33 | } 34 | } 35 | return -1; 36 | } 37 | 38 | public static bool VerifyCertificateChain(List certificates) 39 | { 40 | int rootCertificateIndex = GetRootCertificateIndex(certificates); 41 | if (rootCertificateIndex == -1) 42 | { 43 | return false; 44 | } 45 | 46 | for (int index = 0; index < rootCertificateIndex; index++) 47 | { 48 | byte[] certificateBytes = certificates[index]; 49 | X509Certificate2 certificate = new X509Certificate2(certificateBytes); 50 | byte[] issuingCertificateBytes = certificates[index + 1]; 51 | bool isValid = ValidateCertificate(issuingCertificateBytes, certificateBytes); 52 | if (!isValid) 53 | { 54 | return false; 55 | } 56 | } 57 | 58 | return ValidateCertificate(certificates[rootCertificateIndex], certificates[rootCertificateIndex]); 59 | } 60 | 61 | public static bool ValidateCertificate(byte[] issuingCertificate, byte[] certificateToValidate) 62 | { 63 | RSAParameters rsaParameters = GetRSAParameters(issuingCertificate); 64 | byte[] certificateSignature = ByteReader.ReadBytes(certificateToValidate, certificateToValidate.Length - 256, 256); 65 | byte[] decodedSignature = RSAHelper.DecryptSignature(certificateSignature, rsaParameters); 66 | byte[] tbsCertificate = CertificateHelper.ExtractTbsCertificate(certificateToValidate); 67 | if (StartsWith(decodedSignature, SHA_256_PKCS_ID)) 68 | { 69 | byte[] expectedHash = ByteReader.ReadBytes(decodedSignature, SHA_256_PKCS_ID.Length, 32); 70 | SHA256Managed sha256 = new SHA256Managed(); 71 | byte[] hash = sha256.ComputeHash(tbsCertificate); 72 | return ByteUtils.AreByteArraysEqual(hash, expectedHash); 73 | 74 | } 75 | else if (StartsWith(decodedSignature, SHA_160_PKCS_ID)) 76 | { 77 | byte[] expectedHash = ByteReader.ReadBytes(decodedSignature, SHA_160_PKCS_ID.Length, 20); 78 | SHA1Managed sha1 = new SHA1Managed(); 79 | byte[] hash = sha1.ComputeHash(tbsCertificate); 80 | return ByteUtils.AreByteArraysEqual(hash, expectedHash); 81 | } 82 | else 83 | { 84 | throw new NotImplementedException("Unsupported Signature PKCS ID"); 85 | } 86 | } 87 | 88 | public static bool StartsWith(byte[] array1, byte[] array2) 89 | { 90 | if (array1.Length >= array2.Length) 91 | { 92 | byte[] start = ByteReader.ReadBytes(array1, 0, array2.Length); 93 | return ByteUtils.AreByteArraysEqual(start, array2); 94 | } 95 | return false; 96 | } 97 | 98 | public static RSAParameters GetRSAParameters(byte[] certificateBytes) 99 | { 100 | X509Certificate2 x509certificate = new X509Certificate2(certificateBytes); 101 | if (x509certificate.HasPrivateKey) 102 | { 103 | RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)x509certificate.PrivateKey; 104 | return rsa.ExportParameters(true); 105 | } 106 | else 107 | { 108 | RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)x509certificate.PublicKey.Key; 109 | return rsa.ExportParameters(false); 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Helpers/HashAlgorithmHelper.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Security.Cryptography; 12 | using Utilities; 13 | 14 | namespace IPALibrary.CodeSignature 15 | { 16 | public class HashAlgorithmHelper 17 | { 18 | private const int SHA1Length = 20; 19 | private const int SHA256Length = 32; 20 | private const int SHA256TruncatedLength = 20; 21 | 22 | public static int GetHashLength(HashType hashType) 23 | { 24 | switch (hashType) 25 | { 26 | case HashType.SHA1: 27 | return SHA1Length; 28 | case HashType.SHA256: 29 | return SHA256Length; 30 | case HashType.SHA256Truncated: 31 | return SHA256TruncatedLength; 32 | default: 33 | throw new NotImplementedException("Unsupported HashType"); 34 | } 35 | } 36 | 37 | private static HashAlgorithm CreateHashAlgorithm(HashType hashType) 38 | { 39 | switch (hashType) 40 | { 41 | case HashType.SHA1: 42 | return SHA1Managed.Create(); 43 | case HashType.SHA256: 44 | case HashType.SHA256Truncated: 45 | return SHA256Managed.Create(); 46 | default: 47 | throw new NotImplementedException("Unsupported HashType"); 48 | } 49 | } 50 | 51 | public static byte[] ComputeHash(HashType hashType, byte[] data) 52 | { 53 | return ComputeHash(hashType, data, 0, data.Length); 54 | } 55 | 56 | public static byte[] ComputeHash(HashType hashType, byte[] data, int offset, int length) 57 | { 58 | HashAlgorithm hashAlgorithm = CreateHashAlgorithm(hashType); 59 | byte[] hash = hashAlgorithm.ComputeHash(data, offset, length); 60 | if (hashType == HashType.SHA256Truncated) 61 | { 62 | hash = ByteReader.ReadBytes(hash, 0, SHA256TruncatedLength); 63 | } 64 | return hash; 65 | } 66 | 67 | public static List ComputeHashes(HashType hashType, int pageSize, byte[] data) 68 | { 69 | HashAlgorithm hashAlgorithm = CreateHashAlgorithm(hashType); 70 | 71 | List hashes = new List(); 72 | for(int offset = 0; offset < data.Length; offset += pageSize) 73 | { 74 | int remaining = data.Length - offset; 75 | int length = Math.Min(remaining, pageSize); 76 | byte[] hash = ComputeHash(hashType, data, offset, length); 77 | hashes.Add(hash); 78 | } 79 | return hashes; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Helpers/RSAHelper.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Security; 12 | using System.Security.Cryptography; 13 | using System.Security.Cryptography.X509Certificates; 14 | using Org.BouncyCastle; 15 | using Org.BouncyCastle.Math; 16 | using Org.BouncyCastle.Security; 17 | using Org.BouncyCastle.Crypto; 18 | using Org.BouncyCastle.Crypto.Parameters; 19 | using Org.BouncyCastle.X509; 20 | 21 | namespace IPALibrary.CodeSignature 22 | { 23 | public class RSAHelper 24 | { 25 | public static byte[] DecryptSignature(byte[] signatureBytes, RSAParameters rsaParameters) 26 | { 27 | RsaKeyParameters publicKey = new RsaKeyParameters(false, new BigInteger(1, rsaParameters.Modulus), new BigInteger(rsaParameters.Exponent)); 28 | IBufferedCipher cipher = CipherUtilities.GetCipher("RSA/NONE/PKCS1Padding"); 29 | cipher.Init(false, publicKey); 30 | 31 | byte[] decrypted = cipher.DoFinal(signatureBytes); 32 | return decrypted; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/CodeRequirementBlob.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class CodeRequirementBlob 16 | { 17 | public const uint Signature = 0xfade0c00; // CSMAGIC_REQUIREMENT 18 | public const uint CodeRequirementKind = 1; 19 | 20 | // uint Magic; 21 | // uint Length; 22 | public uint Kind; 23 | public RequirementExpression Expression; 24 | 25 | public CodeRequirementBlob() 26 | { 27 | Kind = CodeRequirementKind; 28 | } 29 | 30 | public CodeRequirementBlob(byte[] buffer, int offset) 31 | { 32 | uint length = BigEndianConverter.ToUInt32(buffer, offset + 4); 33 | Kind = BigEndianConverter.ToUInt32(buffer, offset + 8); 34 | offset += 12; 35 | Expression = RequirementExpression.ReadExpression(buffer, ref offset); 36 | } 37 | 38 | public void WriteBytes(byte[] buffer, int offset) 39 | { 40 | BigEndianWriter.WriteUInt32(buffer, ref offset, Signature); 41 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)Length); 42 | BigEndianWriter.WriteUInt32(buffer, ref offset, Kind); 43 | Expression.WriteBytes(buffer, ref offset); 44 | } 45 | 46 | public byte[] GetBytes() 47 | { 48 | byte[] buffer = new byte[Length]; 49 | WriteBytes(buffer, 0); 50 | return buffer; 51 | } 52 | 53 | public int Length 54 | { 55 | get 56 | { 57 | return 12 + Expression.Length; 58 | } 59 | } 60 | 61 | public static CodeRequirementBlob ReadCodeRequirementBlob(byte[] buffer, int offset) 62 | { 63 | uint magic = BigEndianConverter.ToUInt32(buffer, offset); 64 | switch (magic) 65 | { 66 | case Signature: 67 | return new CodeRequirementBlob(buffer, offset); 68 | default: 69 | throw new NotImplementedException(); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/AnchorHash.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class AnchorHash : RequirementExpression 16 | { 17 | public uint Slot; 18 | public byte[] Hash; 19 | 20 | public AnchorHash() 21 | { 22 | } 23 | 24 | public AnchorHash(byte[] buffer, ref int offset) 25 | { 26 | Slot = BigEndianReader.ReadUInt32(buffer, ref offset); 27 | Hash = ReadData(buffer, ref offset); 28 | } 29 | 30 | public override void WriteBytes(byte[] buffer, ref int offset) 31 | { 32 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.AnchorHash); 33 | BigEndianWriter.WriteUInt32(buffer, ref offset, Slot); 34 | WriteData(buffer, ref offset, Hash); 35 | } 36 | 37 | public override int Length 38 | { 39 | get 40 | { 41 | return 8 + GetDataLength(Hash); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/AndExpression.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class AndExpression : RequirementExpression 16 | { 17 | public RequirementExpression Expression1; 18 | public RequirementExpression Expression2; 19 | 20 | public AndExpression(RequirementExpression expression1, RequirementExpression expression2) 21 | { 22 | Expression1 = expression1; 23 | Expression2 = expression2; 24 | } 25 | 26 | public AndExpression(byte[] buffer, ref int offset) 27 | { 28 | Expression1 = ReadExpression(buffer, ref offset); 29 | Expression2 = ReadExpression(buffer, ref offset); 30 | } 31 | 32 | public override void WriteBytes(byte[] buffer, ref int offset) 33 | { 34 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.And); 35 | Expression1.WriteBytes(buffer, ref offset); 36 | Expression2.WriteBytes(buffer, ref offset); 37 | } 38 | 39 | public override int Length 40 | { 41 | get 42 | { 43 | return 4 + Expression1.Length + Expression2.Length; 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/AppleAnchor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class AppleAnchor : RequirementExpression 16 | { 17 | public AppleAnchor() 18 | { 19 | } 20 | 21 | public override void WriteBytes(byte[] buffer, ref int offset) 22 | { 23 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.AppleAnchor); 24 | } 25 | 26 | public override int Length 27 | { 28 | get 29 | { 30 | return 4; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/AppleGenericAnchor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class AppleGenericAnchor : RequirementExpression 16 | { 17 | public AppleGenericAnchor() 18 | { 19 | } 20 | 21 | public override void WriteBytes(byte[] buffer, ref int offset) 22 | { 23 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.AppleGenericAnchor); 24 | } 25 | 26 | public override int Length 27 | { 28 | get 29 | { 30 | return 4; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/BooleanValue.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class BooleanValue : RequirementExpression 16 | { 17 | public bool Value; 18 | 19 | public BooleanValue(bool value) 20 | { 21 | } 22 | 23 | public override void WriteBytes(byte[] buffer, ref int offset) 24 | { 25 | if (Value) 26 | { 27 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.True); 28 | } 29 | else 30 | { 31 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.False); 32 | } 33 | } 34 | 35 | public override int Length 36 | { 37 | get 38 | { 39 | return 4; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/CertificateField.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class CertificateField : RequirementExpression 16 | { 17 | public uint CertificateIndex; 18 | public string FieldName; 19 | public MatchSuffix Match; 20 | 21 | public CertificateField() 22 | { 23 | } 24 | 25 | public CertificateField(byte[] buffer, ref int offset) 26 | { 27 | CertificateIndex = BigEndianReader.ReadUInt32(buffer, ref offset); 28 | FieldName = ReadAnsiString(buffer, ref offset); 29 | Match = new MatchSuffix(buffer, ref offset); 30 | } 31 | 32 | public override void WriteBytes(byte[] buffer, ref int offset) 33 | { 34 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.CertificateField); 35 | BigEndianWriter.WriteUInt32(buffer, ref offset, CertificateIndex); 36 | WriteAnsiString(buffer, ref offset, FieldName); 37 | Match.WriteBytes(buffer, ref offset); 38 | } 39 | 40 | public override int Length 41 | { 42 | get 43 | { 44 | return 8 + GetAnsiStringLength(FieldName) + Match.Length; 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/CertificateGeneric.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class CertificateGeneric : RequirementExpression 16 | { 17 | public uint CertificateIndex; 18 | public byte[] OID; 19 | public MatchSuffix Match; 20 | 21 | public CertificateGeneric() 22 | { 23 | } 24 | 25 | public CertificateGeneric(byte[] buffer, ref int offset) 26 | { 27 | CertificateIndex = BigEndianReader.ReadUInt32(buffer, ref offset); 28 | OID = ReadData(buffer, ref offset); 29 | Match = new MatchSuffix(buffer, ref offset); 30 | } 31 | 32 | public override void WriteBytes(byte[] buffer, ref int offset) 33 | { 34 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.CertificateGeneric); 35 | BigEndianWriter.WriteUInt32(buffer, ref offset, CertificateIndex); 36 | WriteData(buffer, ref offset, OID); 37 | Match.WriteBytes(buffer, ref offset); 38 | } 39 | 40 | public override int Length 41 | { 42 | get 43 | { 44 | return 8 + GetDataLength(OID) + Match.Length; 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/CodeDirectoryHash.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class CodeDirectoryHash : RequirementExpression 16 | { 17 | public byte[] Hash; 18 | 19 | public CodeDirectoryHash() 20 | { 21 | } 22 | 23 | public CodeDirectoryHash(byte[] buffer, ref int offset) 24 | { 25 | Hash = ReadData(buffer, ref offset); 26 | } 27 | 28 | public override void WriteBytes(byte[] buffer, ref int offset) 29 | { 30 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.CodeDirectoryHash); 31 | WriteData(buffer, ref offset, Hash); 32 | } 33 | 34 | public override int Length 35 | { 36 | get 37 | { 38 | return 4 + GetDataLength(Hash); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/Enums/MatchOperationName.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace IPALibrary.CodeSignature 3 | { 4 | /// 5 | /// Defined in requirement.h 6 | /// https://opensource.apple.com/source/libsecurity_codesigning/libsecurity_codesigning-55037.15/lib/requirement.h.auto.html 7 | /// 8 | public enum MatchOperationName : uint 9 | { 10 | Exists = 0, 11 | Equal = 1, 12 | Contains = 2, 13 | BeginsWith = 3, 14 | EndsWith = 4, 15 | LessThan = 5, 16 | GreaterThan = 6, 17 | LessThanOrEqual = 7, 18 | GreaterThanOrEqual = 8, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/Enums/RequirementOperatorName.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace IPALibrary.CodeSignature 3 | { 4 | /// 5 | /// Defined in requirement.h 6 | /// https://opensource.apple.com/source/libsecurity_codesigning/libsecurity_codesigning-55037.15/lib/requirement.h.auto.html 7 | /// 8 | public enum RequirementOperatorName : uint 9 | { 10 | False = 0, 11 | True = 1, 12 | Ident = 2, // Match canonical code [string] 13 | AppleAnchor = 3, // Signed by Apple as Apple's product 14 | AnchorHash = 4, // Match anchor [cert hash] 15 | InfoKeyValue = 5, // Legacy [key; value] 16 | And = 6, // Binary prefix expr AND expr [expr; expr] 17 | Or = 7, // Binary prefix expr OR expr [expr; expr] 18 | CodeDirectoryHash = 8, 19 | Not = 9, 20 | InfoKeyField = 10, // Info.plist key field [string; match suffix] 21 | CertificateField = 11, // Certificate field [cert index; field name; match suffix] 22 | TrustedCertificate = 12, // Require trust settings to approve one particular cert [cert index] 23 | TrustedCertificates = 13, // Require trust settings to approve the cert chain. 24 | CertificateGeneric = 14, // Certificate component by OID [cert index; oid; match suffix] 25 | AppleGenericAnchor = 15, // Signed by Apple in any capacity 26 | EntitlementField = 16, // Entitlement dictionary field [string; match suffix] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/IdentValue.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class IdentValue : RequirementExpression 16 | { 17 | public string Value; 18 | 19 | public IdentValue(string value) 20 | { 21 | Value = value; 22 | } 23 | 24 | public IdentValue(byte[] buffer, ref int offset) 25 | { 26 | Value = ReadAnsiString(buffer, ref offset); 27 | } 28 | 29 | public override void WriteBytes(byte[] buffer, ref int offset) 30 | { 31 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.Ident); 32 | WriteAnsiString(buffer, ref offset, Value); 33 | } 34 | 35 | public override int Length 36 | { 37 | get 38 | { 39 | return 4 + GetAnsiStringLength(Value); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/InfoKeyField.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class InfoKeyField : RequirementExpression 16 | { 17 | public string Key; 18 | public MatchSuffix Match; 19 | 20 | public InfoKeyField() 21 | { 22 | } 23 | 24 | public InfoKeyField(byte[] buffer, ref int offset) 25 | { 26 | Key = ReadAnsiString(buffer, ref offset); 27 | Match = new MatchSuffix(buffer, ref offset); 28 | } 29 | 30 | public override void WriteBytes(byte[] buffer, ref int offset) 31 | { 32 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.InfoKeyField); 33 | WriteAnsiString(buffer, ref offset, Key); 34 | Match.WriteBytes(buffer, ref offset); 35 | } 36 | 37 | public override int Length 38 | { 39 | get 40 | { 41 | return 4 + GetAnsiStringLength(Key) + Match.Length; 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/InfoKeyValue.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class InfoKeyValue : RequirementExpression 16 | { 17 | public string Key; 18 | public string Value; 19 | 20 | public InfoKeyValue(string key, string value) 21 | { 22 | Key = key; 23 | Value = value; 24 | } 25 | 26 | public InfoKeyValue(byte[] buffer, ref int offset) 27 | { 28 | Key = ReadAnsiString(buffer, ref offset); 29 | Value = ReadAnsiString(buffer, ref offset); 30 | } 31 | 32 | public override void WriteBytes(byte[] buffer, ref int offset) 33 | { 34 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.InfoKeyValue); 35 | WriteAnsiString(buffer, ref offset, Key); 36 | WriteAnsiString(buffer, ref offset, Value); 37 | } 38 | 39 | public override int Length 40 | { 41 | get 42 | { 43 | return 4 + GetAnsiStringLength(Key) + GetAnsiStringLength(Value); 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/NotExpression.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class NotExpression : RequirementExpression 16 | { 17 | public RequirementExpression Expression; 18 | 19 | public NotExpression(RequirementExpression expression) 20 | { 21 | Expression = expression; 22 | } 23 | 24 | public NotExpression(byte[] buffer, ref int offset) 25 | { 26 | Expression = ReadExpression(buffer, ref offset); 27 | } 28 | 29 | public override void WriteBytes(byte[] buffer, ref int offset) 30 | { 31 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.Not); 32 | Expression.WriteBytes(buffer, ref offset); 33 | } 34 | 35 | public override int Length 36 | { 37 | get 38 | { 39 | return 4 + Expression.Length; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/OrExpression.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class OrExpression : RequirementExpression 16 | { 17 | public RequirementExpression Expression1; 18 | public RequirementExpression Expression2; 19 | 20 | public OrExpression(RequirementExpression expression1, RequirementExpression expression2) 21 | { 22 | Expression1 = expression1; 23 | Expression2 = expression2; 24 | } 25 | 26 | public OrExpression(byte[] buffer, ref int offset) 27 | { 28 | Expression1 = ReadExpression(buffer, ref offset); 29 | Expression2 = ReadExpression(buffer, ref offset); 30 | } 31 | 32 | public override void WriteBytes(byte[] buffer, ref int offset) 33 | { 34 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.Or); 35 | Expression1.WriteBytes(buffer, ref offset); 36 | Expression2.WriteBytes(buffer, ref offset); 37 | } 38 | 39 | public override int Length 40 | { 41 | get 42 | { 43 | return 4 + Expression1.Length + Expression2.Length; 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/RequirementExpression.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Text; 12 | using Utilities; 13 | 14 | namespace IPALibrary.CodeSignature 15 | { 16 | public abstract class RequirementExpression 17 | { 18 | public abstract void WriteBytes(byte[] buffer, ref int offset); 19 | 20 | public abstract int Length 21 | { 22 | get; 23 | } 24 | 25 | public static string ReadAnsiString(byte[] buffer, ref int offset) 26 | { 27 | byte[] data = ReadData(buffer, ref offset); 28 | return ASCIIEncoding.GetEncoding(28591).GetString(data); 29 | } 30 | 31 | public static byte[] ReadData(byte[] buffer, ref int offset) 32 | { 33 | uint length = BigEndianReader.ReadUInt32(buffer, ref offset); 34 | byte[] data = ByteReader.ReadBytes(buffer, ref offset, (int)length); 35 | int padding = (4 - ((int)length % 4)) % 4; 36 | offset += padding; 37 | return data; 38 | } 39 | 40 | public static void WriteAnsiString(byte[] buffer, ref int offset, string value) 41 | { 42 | byte[] data = ASCIIEncoding.GetEncoding(28591).GetBytes(value); 43 | WriteData(buffer, ref offset, data); 44 | } 45 | 46 | public static void WriteData(byte[] buffer, ref int offset, byte[] data) 47 | { 48 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)data.Length); 49 | ByteWriter.WriteBytes(buffer, ref offset, data); 50 | int padding = (4 - (data.Length % 4)) % 4; 51 | ByteWriter.WriteBytes(buffer, ref offset, new byte[padding]); 52 | } 53 | 54 | public static int GetAnsiStringLength(string value) 55 | { 56 | return 4 + (int)Math.Ceiling((double)value.Length / 4) * 4; 57 | } 58 | 59 | public static int GetDataLength(byte[] data) 60 | { 61 | return 4 + (int)Math.Ceiling((double)data.Length / 4) * 4; 62 | } 63 | 64 | public static RequirementExpression ReadExpression(byte[] buffer, ref int offset) 65 | { 66 | RequirementOperatorName opName = (RequirementOperatorName)BigEndianReader.ReadUInt32(buffer, ref offset); 67 | switch(opName) 68 | { 69 | case RequirementOperatorName.False: 70 | return new BooleanValue(false); 71 | case RequirementOperatorName.True: 72 | return new BooleanValue(true); 73 | case RequirementOperatorName.Ident: 74 | return new IdentValue(buffer, ref offset); 75 | case RequirementOperatorName.AppleAnchor: 76 | return new AppleAnchor(); 77 | case RequirementOperatorName.AnchorHash: 78 | return new AnchorHash(buffer, ref offset); 79 | case RequirementOperatorName.InfoKeyValue: 80 | return new InfoKeyValue(buffer, ref offset); 81 | case RequirementOperatorName.And: 82 | return new AndExpression(buffer, ref offset); 83 | case RequirementOperatorName.Or: 84 | return new OrExpression(buffer, ref offset); 85 | case RequirementOperatorName.CodeDirectoryHash: 86 | return new CodeDirectoryHash(buffer, ref offset); 87 | case RequirementOperatorName.Not: 88 | return new NotExpression(buffer, ref offset); 89 | case RequirementOperatorName.InfoKeyField: 90 | return new InfoKeyField(buffer, ref offset); 91 | case RequirementOperatorName.CertificateField: 92 | return new CertificateField(buffer, ref offset); 93 | case RequirementOperatorName.TrustedCertificate: 94 | return new TrustedCertificate(buffer, ref offset); 95 | case RequirementOperatorName.TrustedCertificates: 96 | return new TrustedCertificates(buffer, ref offset); 97 | case RequirementOperatorName.CertificateGeneric: 98 | return new CertificateGeneric(buffer, ref offset); 99 | case RequirementOperatorName.AppleGenericAnchor: 100 | return new AppleGenericAnchor(); 101 | default: 102 | throw new NotImplementedException("Requirement operator not implemented"); 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/Structures/MatchSuffix.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class MatchSuffix 16 | { 17 | public MatchOperationName MatchOperation; 18 | public string MatchValue; 19 | 20 | public MatchSuffix(MatchOperationName matchOperation) 21 | { 22 | MatchOperation = matchOperation; 23 | } 24 | 25 | public MatchSuffix(MatchOperationName matchOperation, string matchValue) 26 | { 27 | MatchOperation = matchOperation; 28 | MatchValue = matchValue; 29 | } 30 | 31 | public MatchSuffix(byte[] buffer, ref int offset) 32 | { 33 | MatchOperation = (MatchOperationName)BigEndianReader.ReadUInt32(buffer, ref offset); 34 | if (MatchOperation != MatchOperationName.Exists) 35 | { 36 | MatchValue = RequirementExpression.ReadAnsiString(buffer, ref offset); 37 | } 38 | } 39 | 40 | public void WriteBytes(byte[] buffer, ref int offset) 41 | { 42 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)MatchOperation); 43 | if (MatchOperation != MatchOperationName.Exists) 44 | { 45 | RequirementExpression.WriteAnsiString(buffer, ref offset, MatchValue); 46 | } 47 | } 48 | 49 | public int Length 50 | { 51 | get 52 | { 53 | int length = 4; 54 | if (MatchOperation != MatchOperationName.Exists) 55 | { 56 | length += RequirementExpression.GetAnsiStringLength(MatchValue); 57 | } 58 | return length; 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/TrustedCertificate.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class TrustedCertificate : RequirementExpression 16 | { 17 | public uint CertificateIndex; 18 | 19 | public TrustedCertificate() 20 | { 21 | } 22 | 23 | public TrustedCertificate(byte[] buffer, ref int offset) 24 | { 25 | CertificateIndex = BigEndianReader.ReadUInt32(buffer, ref offset); 26 | } 27 | 28 | public override void WriteBytes(byte[] buffer, ref int offset) 29 | { 30 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.TrustedCertificate); 31 | BigEndianWriter.WriteUInt32(buffer, ref offset, CertificateIndex); 32 | } 33 | 34 | public override int Length 35 | { 36 | get 37 | { 38 | return 8; 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeRequirementBlobs/RequirementExpression/TrustedCertificates.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class TrustedCertificates : RequirementExpression 16 | { 17 | public TrustedCertificates() 18 | { 19 | } 20 | 21 | public TrustedCertificates(byte[] buffer, ref int offset) 22 | { 23 | } 24 | 25 | public override void WriteBytes(byte[] buffer, ref int offset) 26 | { 27 | BigEndianWriter.WriteUInt32(buffer, ref offset, (uint)RequirementOperatorName.TrustedCertificates); 28 | } 29 | 30 | public override int Length 31 | { 32 | get 33 | { 34 | return 4; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeSignatureBlobs/CmsSignatureBlob.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class CmsSignatureBlob : CodeSignatureBlob 16 | { 17 | public const uint Signature = 0xfade0b01; // CSMAGIC_BLOBWRAPPER 18 | 19 | // uint Magic; 20 | // uint Length; 21 | public byte[] Data; // CMS Signature Data in ASN.1 22 | 23 | public CmsSignatureBlob() 24 | { 25 | Data = new byte[0]; 26 | } 27 | 28 | public CmsSignatureBlob(byte[] buffer, int offset) : base(buffer, offset) 29 | { 30 | uint length = BigEndianConverter.ToUInt32(buffer, offset + 4); 31 | Data = ByteReader.ReadBytes(buffer, offset + 8, (int)length - 8); 32 | } 33 | 34 | public override void WriteBytes(byte[] buffer, int offset) 35 | { 36 | BigEndianWriter.WriteUInt32(buffer, offset + 0, Signature); 37 | BigEndianWriter.WriteUInt32(buffer, offset + 4, (uint)Length); 38 | ByteWriter.WriteBytes(buffer, offset + 8, Data); 39 | } 40 | 41 | public override int Length 42 | { 43 | get 44 | { 45 | return 8 + Data.Length; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeSignatureBlobs/CodeRequirementsBlob.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | /// 16 | /// Implements the CS_SuperBlob structure which is defined in codesign.c 17 | /// https://opensource.apple.com/source/Security/Security-55471/sec/Security/Tool/codesign.c 18 | /// 19 | public class CodeRequirementsBlob : CodeSignatureBlob 20 | { 21 | public const uint Signature = 0xfade0c01; // CSMAGIC_REQUIREMENTS 22 | public const int FixedLength = 12; 23 | 24 | // uint Magic; 25 | // uint Length; 26 | // uint Count; 27 | public KeyValuePairList Entries = new KeyValuePairList(); 28 | 29 | public CodeRequirementsBlob() 30 | { 31 | } 32 | 33 | public CodeRequirementsBlob(byte[] buffer, int offset) : base(buffer, offset) 34 | { 35 | uint length = BigEndianConverter.ToUInt32(buffer, offset + 4); 36 | uint count = BigEndianConverter.ToUInt32(buffer, offset + 8); 37 | for (int index = 0; index < count; index++) 38 | { 39 | SecurityRequirementType entryType = (SecurityRequirementType)BigEndianConverter.ToUInt32(buffer, offset + 12 + index * 8); 40 | uint entryOffset = BigEndianConverter.ToUInt32(buffer, offset + 12 + index * 8 + 4); 41 | CodeRequirementBlob blob = CodeRequirementBlob.ReadCodeRequirementBlob(buffer, offset + (int)entryOffset); 42 | Entries.Add(entryType, blob); 43 | } 44 | } 45 | 46 | public override void WriteBytes(byte[] buffer, int offset) 47 | { 48 | BigEndianWriter.WriteUInt32(buffer, offset + 0, Signature); 49 | BigEndianWriter.WriteUInt32(buffer, offset + 4, (uint)Length); 50 | BigEndianWriter.WriteUInt32(buffer, offset + 8, (uint)Entries.Count); 51 | int blobOffset = FixedLength + Entries.Count * 8; 52 | for (int index = 0; index < Entries.Count; index++) 53 | { 54 | BigEndianWriter.WriteUInt32(buffer, offset + 12 + index * 8, (uint)Entries[index].Key); 55 | BigEndianWriter.WriteUInt32(buffer, offset + 12 + index * 8 + 4, (uint)blobOffset); 56 | Entries[index].Value.WriteBytes(buffer, offset + blobOffset); 57 | blobOffset += Entries[index].Value.Length; 58 | } 59 | } 60 | 61 | public override int Length 62 | { 63 | get 64 | { 65 | int length = FixedLength + Entries.Count * 8; 66 | for (int index = 0; index < Entries.Count; index++) 67 | { 68 | length += Entries[index].Value.Length; 69 | } 70 | return length; 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeSignatureBlobs/CodeSignatureBlob.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public abstract class CodeSignatureBlob 16 | { 17 | public CodeSignatureBlob() 18 | { 19 | } 20 | 21 | public CodeSignatureBlob(byte[] buffer, int offset) 22 | { 23 | } 24 | 25 | public abstract void WriteBytes(byte[] buffer, int offset); 26 | 27 | public byte[] GetBytes() 28 | { 29 | byte[] buffer = new byte[Length]; 30 | WriteBytes(buffer, 0); 31 | return buffer; 32 | } 33 | 34 | public abstract int Length 35 | { 36 | get; 37 | } 38 | 39 | public static CodeSignatureBlob ReadBlob(byte[] buffer, int offset) 40 | { 41 | uint magic = BigEndianConverter.ToUInt32(buffer, offset); 42 | switch (magic) 43 | { 44 | case CodeDirectoryBlob.Signature: 45 | return new CodeDirectoryBlob(buffer, offset); 46 | case CodeRequirementsBlob.Signature: 47 | return new CodeRequirementsBlob(buffer, offset); 48 | case EntitlementsBlob.Signature: 49 | return new EntitlementsBlob(buffer, offset); 50 | case CmsSignatureBlob.Signature: 51 | return new CmsSignatureBlob(buffer, offset); 52 | default: 53 | return new CodeSignatureGenericBlob(buffer, offset); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeSignatureBlobs/CodeSignatureGenericBlob.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | /// 16 | /// Implements the CS_GenericBlob structure which is defined in codesign.c 17 | /// https://opensource.apple.com/source/Security/Security-55471/sec/Security/Tool/codesign.c 18 | /// 19 | public class CodeSignatureGenericBlob : CodeSignatureBlob 20 | { 21 | public uint Magic; 22 | // uint Length; 23 | public byte[] Data; 24 | 25 | public CodeSignatureGenericBlob() 26 | { 27 | Data = new byte[0]; 28 | } 29 | 30 | public CodeSignatureGenericBlob(byte[] buffer, int offset) : base(buffer, offset) 31 | { 32 | Magic = BigEndianConverter.ToUInt32(buffer, offset + 0); 33 | uint length = BigEndianConverter.ToUInt32(buffer, offset + 4); 34 | Data = ByteReader.ReadBytes(buffer, offset + 8, (int)length - 8); 35 | } 36 | 37 | public override void WriteBytes(byte[] buffer, int offset) 38 | { 39 | BigEndianWriter.WriteUInt32(buffer, offset + 0, Magic); 40 | BigEndianWriter.WriteUInt32(buffer, offset + 4, (uint)Length); 41 | ByteWriter.WriteBytes(buffer, offset + 8, Data); 42 | } 43 | 44 | public override int Length 45 | { 46 | get 47 | { 48 | return 8 + Data.Length; 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /IPALibrary/CodeSignature/Structures/CodeSignatureBlobs/EntitlementsBlob.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.CodeSignature 14 | { 15 | public class EntitlementsBlob : CodeSignatureGenericBlob 16 | { 17 | public const uint Signature = 0xfade7171; // CSMAGIC_EMBEDDED_ENTITLEMENTS 18 | 19 | public EntitlementsBlob() 20 | { 21 | Magic = Signature; 22 | } 23 | 24 | public EntitlementsBlob(byte[] buffer, int offset) : base(buffer, offset) 25 | { 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /IPALibrary/Components/BouncyCastle.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ROM-Knowledgeware/IPASign/7cf1716ba29dd3a0fd8f5bc6155237b15305ca72/IPALibrary/Components/BouncyCastle.dll -------------------------------------------------------------------------------- /IPALibrary/Components/ICSharpCode.SharpZipLib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ROM-Knowledgeware/IPASign/7cf1716ba29dd3a0fd8f5bc6155237b15305ca72/IPALibrary/Components/ICSharpCode.SharpZipLib.dll -------------------------------------------------------------------------------- /IPALibrary/Components/PListNet.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ROM-Knowledgeware/IPASign/7cf1716ba29dd3a0fd8f5bc6155237b15305ca72/IPALibrary/Components/PListNet.dll -------------------------------------------------------------------------------- /IPALibrary/Components/System.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ROM-Knowledgeware/IPASign/7cf1716ba29dd3a0fd8f5bc6155237b15305ca72/IPALibrary/Components/System.Core.dll -------------------------------------------------------------------------------- /IPALibrary/Helpers/Asn1Helper.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Org.BouncyCastle.Asn1; 12 | 13 | namespace IPALibrary 14 | { 15 | public class Asn1Helper 16 | { 17 | // https://stackoverflow.com/a/32328582/3419770 18 | public static Asn1Object FindAsn1Value(string oid, Asn1Object obj) 19 | { 20 | Asn1Object result = null; 21 | if (obj is Asn1Sequence) 22 | { 23 | bool foundOID = false; 24 | foreach (Asn1Object entry in (Asn1Sequence)obj) 25 | { 26 | DerObjectIdentifier derOID = entry as DerObjectIdentifier; 27 | if (derOID != null && derOID.Id == oid) 28 | { 29 | foundOID = true; 30 | } 31 | else if (foundOID) 32 | { 33 | return entry; 34 | } 35 | else 36 | { 37 | result = FindAsn1Value(oid, entry); 38 | if (result != null) 39 | { 40 | return result; 41 | } 42 | } 43 | } 44 | } 45 | else if (obj is DerTaggedObject) 46 | { 47 | result = FindAsn1Value(oid, ((DerTaggedObject)obj).GetObject()); 48 | if (result != null) 49 | { 50 | return result; 51 | } 52 | } 53 | else 54 | { 55 | if (obj is DerSet) 56 | { 57 | foreach (Asn1Object entry in (DerSet)obj) 58 | { 59 | result = FindAsn1Value(oid, entry); 60 | if (result != null) 61 | { 62 | return result; 63 | } 64 | } 65 | } 66 | } 67 | return null; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /IPALibrary/Helpers/CertificateHelper.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections; 11 | using System.Collections.Generic; 12 | using System.IO; 13 | using Org.BouncyCastle.Asn1; 14 | using Org.BouncyCastle.Asn1.X509; 15 | using Org.BouncyCastle.Pkcs; 16 | using Org.BouncyCastle.X509; 17 | using Utilities; 18 | 19 | namespace IPALibrary 20 | { 21 | public class CertificateHelper 22 | { 23 | public const string X509CertificateCommonNameOID = "2.5.4.3"; 24 | public const string X509CertificateOrganizationalUnitOID = "2.5.4.11"; 25 | public const string X509CertificateUserOID = "0.9.2342.19200300.100.1.1"; 26 | 27 | public static string GetCertificateTeamID(string certificateCN) 28 | { 29 | int index = certificateCN.LastIndexOf('('); 30 | if (index >= 0 && certificateCN[certificateCN.Length - 1] == ')') 31 | { 32 | return certificateCN.Substring(index, certificateCN.Length - index - 1); 33 | } 34 | return null; 35 | } 36 | 37 | public static X509Certificate GetCertificateAndKeyFromBytes(byte[] certificateBytes, string password, out AsymmetricKeyEntry privateKey) 38 | { 39 | privateKey = null; 40 | MemoryStream certificateStream = new MemoryStream(certificateBytes); 41 | Pkcs12Store certificateStore; 42 | try 43 | { 44 | certificateStore = new Pkcs12Store(certificateStream, password.ToCharArray()); 45 | } 46 | catch(IOException) 47 | { 48 | return null; 49 | } 50 | 51 | foreach (string alias in certificateStore.Aliases) 52 | { 53 | AsymmetricKeyEntry key = certificateStore.GetKey(alias); 54 | X509CertificateEntry certificateEntry = certificateStore.GetCertificate(alias); 55 | X509Certificate certificate = certificateEntry.Certificate; 56 | if (key != null) 57 | { 58 | privateKey = key; 59 | return certificate; 60 | } 61 | } 62 | return null; 63 | } 64 | 65 | public static X509Certificate GetCertificatesFromBytes(byte[] certificateBytes) 66 | { 67 | return new X509CertificateParser().ReadCertificate(certificateBytes); 68 | } 69 | 70 | public static string GetCertificateCommonName(byte[] certificateBytes) 71 | { 72 | X509Certificate certificate = GetCertificatesFromBytes(certificateBytes); 73 | return GetCertificateCommonName(certificate); 74 | } 75 | 76 | public static string GetCertificateCommonName(X509Certificate certificate) 77 | { 78 | return GetCertificateValue(certificate, X509CertificateCommonNameOID); 79 | } 80 | 81 | public static string GetCertificateOrganizationalUnit(X509Certificate certificate) 82 | { 83 | return GetCertificateValue(certificate, X509CertificateOrganizationalUnitOID); 84 | } 85 | 86 | public static string GetCertificateUserID(X509Certificate certificate) 87 | { 88 | return GetCertificateValue(certificate, X509CertificateUserOID); 89 | } 90 | 91 | public static string GetCertificateValue(X509Certificate certificate, string identifier) 92 | { 93 | DerObjectIdentifier commonNameOID = new Org.BouncyCastle.Asn1.DerObjectIdentifier(identifier); 94 | IList values = certificate.SubjectDN.GetValueList(commonNameOID); 95 | if (values.Count > 0) 96 | { 97 | return (string)values[0]; 98 | } 99 | return null; 100 | } 101 | 102 | public static X509Certificate FindBySubjectDN(List certificates, X509Name subjectDN) 103 | { 104 | foreach (X509Certificate certificate in certificates) 105 | { 106 | if (certificate.SubjectDN.Equivalent(subjectDN)) 107 | { 108 | return certificate; 109 | } 110 | } 111 | return null; 112 | } 113 | 114 | public static List BuildCertificateChain(X509Certificate leaf, List certificateStore) 115 | { 116 | List chain = new List(); 117 | chain.Add(leaf); 118 | 119 | X509Certificate node = leaf; 120 | while (!node.IssuerDN.Equivalent(node.SubjectDN)) 121 | { 122 | X509Certificate parent = FindBySubjectDN(certificateStore, node.IssuerDN); 123 | if (parent == null) 124 | { 125 | return null; 126 | } 127 | chain.Insert(0, parent); 128 | node = parent; 129 | } 130 | return chain; 131 | } 132 | 133 | /// 134 | /// TBS: To Be Signed - the portion of the X.509 certificate that is signed with the CA's private key. 135 | /// 136 | // http://www.codeproject.com/Questions/252741/Where-is-the-signature-value-in-the-certificate 137 | public static byte[] ExtractTbsCertificate(byte[] certificateBytes) 138 | { 139 | if (certificateBytes[0] == 0x30 && certificateBytes[1] == 0x82) 140 | { 141 | if (certificateBytes[4] == 0x30 && certificateBytes[5] == 0x82) 142 | { 143 | ushort length = BigEndianConverter.ToUInt16(certificateBytes, 6); 144 | return ByteReader.ReadBytes(certificateBytes, 4, 4 + (int)length); 145 | } 146 | } 147 | throw new ArgumentException("The given certificate is not a BER-encoded ASN.1 X.509 certificate"); 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /IPALibrary/Helpers/MemoryStreamDataSource.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.IO; 12 | using ICSharpCode.SharpZipLib.Core; 13 | using ICSharpCode.SharpZipLib.Zip; 14 | using ICSharpCode.SharpZipLib.Zip.Compression; 15 | using ICSharpCode.SharpZipLib.Zip.Compression.Streams; 16 | 17 | namespace IPALibrary 18 | { 19 | public class MemoryStreamDataSource : IStaticDataSource 20 | { 21 | private MemoryStream m_stream; 22 | 23 | public MemoryStreamDataSource(MemoryStream stream) 24 | { 25 | m_stream = stream; 26 | } 27 | 28 | public MemoryStreamDataSource(byte[] data) 29 | { 30 | m_stream = new MemoryStream(data); 31 | } 32 | 33 | public Stream GetSource() 34 | { 35 | return m_stream; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /IPALibrary/Helpers/PListHelper.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.IO; 12 | using System.Text; 13 | using PListNet; 14 | using PListNet.Nodes; 15 | 16 | namespace IPALibrary 17 | { 18 | public class PListHelper 19 | { 20 | public static PListFormat DetectFormat(byte[] fileBytes) 21 | { 22 | // compare to known indicator 23 | if (Encoding.UTF8.GetString(fileBytes, 0, 8) == "bplist00") 24 | { 25 | return PListFormat.Binary; 26 | } 27 | else 28 | { 29 | return PListFormat.Xml; 30 | } 31 | } 32 | 33 | public static string GetStringValueFromPList(PNode rootNode, string key) 34 | { 35 | if (rootNode is DictionaryNode) 36 | { 37 | PNode value; 38 | if (((DictionaryNode)rootNode).TryGetValue(key, out value)) 39 | { 40 | if (value is StringNode) 41 | { 42 | return ((StringNode)value).Value; 43 | } 44 | } 45 | } 46 | return null; 47 | } 48 | 49 | public static DateTime? GetDateTimeValueFromPList(PNode rootNode, string key) 50 | { 51 | if (rootNode is DictionaryNode) 52 | { 53 | PNode value; 54 | if (((DictionaryNode)rootNode).TryGetValue(key, out value)) 55 | { 56 | if (value is DateNode) 57 | { 58 | return ((DateNode)value).Value; 59 | } 60 | } 61 | } 62 | return null; 63 | } 64 | 65 | public static byte[] GetDataValueFromPList(PNode rootNode, string key) 66 | { 67 | if (rootNode is DictionaryNode) 68 | { 69 | PNode value; 70 | if (((DictionaryNode)rootNode).TryGetValue(key, out value)) 71 | { 72 | if (value is DataNode) 73 | { 74 | return ((DataNode)value).Value; 75 | } 76 | } 77 | } 78 | return null; 79 | } 80 | 81 | public static List GetStringArrayValueFromPList(PNode rootNode, string key) 82 | { 83 | if (rootNode is DictionaryNode) 84 | { 85 | PNode value; 86 | if (((DictionaryNode)rootNode).TryGetValue(key, out value)) 87 | { 88 | if (value is ArrayNode) 89 | { 90 | ArrayNode array = (ArrayNode)value; 91 | List result = new List(); 92 | foreach (PNode node in array) 93 | { 94 | StringNode stringNode = node as StringNode; 95 | if (stringNode != null) 96 | { 97 | result.Add(stringNode.Value); 98 | } 99 | } 100 | return result; 101 | } 102 | } 103 | } 104 | return null; 105 | } 106 | 107 | public static List GetDataArrayValueFromPList(PNode rootNode, string key) 108 | { 109 | if (rootNode is DictionaryNode) 110 | { 111 | PNode value; 112 | if (((DictionaryNode)rootNode).TryGetValue(key, out value)) 113 | { 114 | if (value is ArrayNode) 115 | { 116 | ArrayNode array = (ArrayNode)value; 117 | List result = new List(); 118 | foreach (PNode node in array) 119 | { 120 | DataNode dataNode = node as DataNode; 121 | if (dataNode != null) 122 | { 123 | result.Add(dataNode.Value); 124 | } 125 | } 126 | return result; 127 | } 128 | } 129 | } 130 | return null; 131 | } 132 | 133 | public static DictionaryNode GetDictionaryValueFromPList(PNode rootNode, string key) 134 | { 135 | if (rootNode is DictionaryNode) 136 | { 137 | PNode value; 138 | if (((DictionaryNode)rootNode).TryGetValue(key, out value)) 139 | { 140 | if (value is DictionaryNode) 141 | { 142 | return (DictionaryNode)value; 143 | } 144 | } 145 | } 146 | return null; 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /IPALibrary/ILMerge/ILMerge.bat: -------------------------------------------------------------------------------- 1 | set binaryPath=%CD%\..\bin\Release 2 | set outputPath=%CD%\..\bin\ILMerge 3 | IF NOT EXIST "%outputPath%" MKDIR "%outputPath%" 4 | IF ["%programfiles(x86)%"]==[""] SET ilmergePath="%programfiles%\Microsoft\ILMerge" 5 | IF NOT ["%programfiles(x86)%"]==[""] SET ilmergePath="%programfiles(x86)%\Microsoft\ILMerge" 6 | %ilmergePath%\ilmerge /ndebug /target:library /out:"%outputPath%\IPALibrary.dll" /internalize "%binaryPath%\IPALibrary.dll" "%binaryPath%\ICSharpCode.SharpZipLib.dll" "%binaryPath%\PListNet.dll" "%binaryPath%\Utilities.dll" -------------------------------------------------------------------------------- /IPALibrary/MachO/Enums/CpuType.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace IPALibrary.MachO 3 | { 4 | public enum CpuType : uint 5 | { 6 | Vax = 1, 7 | Romp = 2, 8 | NS32032 = 4, 9 | NS32332 = 5, 10 | MC680x0 = 6, 11 | I386 = 7, 12 | MIPS = 8, 13 | NS32532 = 9, 14 | HPPA = 11, 15 | Arm = 12, 16 | MC88000 = 13, 17 | Sparc = 14, 18 | I860BigEndian = 15, 19 | I860LittleEndian = 16, 20 | RS6000 = 17, 21 | MC98000 = 18, 22 | PowerPC = 18, 23 | Veo = 255, 24 | CPU_TYPE_X86_64 = 0x01000007, 25 | Arm64 = 0x0100000C, 26 | PowerPC64 = 0x01000012, 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Enums/FileType.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace IPALibrary.MachO 3 | { 4 | public enum FileType : uint 5 | { 6 | Object = 0x00000001, // MH_OBJECT 7 | Executable = 0x00000002, // MH_EXECUTE 8 | FixedVMLibrary = 0x00000003, // MH_FVMLIB 9 | CoreFile = 0x00000004, // MH_CORE 10 | PreloadedExecutable = 0x00000005, // MH_PRELOAD 11 | DynamicLibrary = 0x00000006, // MH_DYLIB 12 | DynamicLinkEditor = 0x0000007, // MH_DYLINKER 13 | Bundle = 0x00000008, // MH_BUNDLE 14 | DynamicLibraryStub = 0x00000009, // MH_DYLIB_STUB 15 | DebugSymbols = 0x0000000A, // MH_DSYM 16 | KExtBundle = 0x0000000B, // MH_KEXT_BUNDLE 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Enums/LoadCommandType.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace IPALibrary.MachO 3 | { 4 | public enum LoadCommandType : uint 5 | { 6 | Segment = 0x00000001, // LC_SEGMENT 7 | SymbolTable = 0x00000002, // LC_SYMTAB 8 | Thread = 0x00000004, // LC_THREAD 9 | UnixThread = 0x00000005, // LC_UNIXTHREAD 10 | LoadFixedVMLibrary = 0x00000006, // LC_LOADFVMLIB 11 | DynamicSymbolTable = 0x0000000B, // LC_DYSYMTAB 12 | LoadDynamicLibrary = 0x0000000C, // LC_LOAD_DYLIB 13 | IDDynamicLibrary = 0x0000000D, // LC_ID_DYLIB 14 | LoadDynamicLinker = 0x0000000E, // LC_LOAD_DYLINKER 15 | IDDynamicLinker = 0x0000000F, // LC_ID_DYLINKER 16 | PreboundDynamicLibrary = 0x00000010, // LC_PREBOUND_DYLIB 17 | Routines = 0x00000011, // LC_ROUTINES 18 | SubFramework = 0x00000012, // LC_SUB_FRAMEWORK 19 | SubUmbrella = 0x00000013, // LC_SUB_UMBRELLA 20 | SubClient = 0x00000014, // LC_SUB_CLIENT 21 | SubLibrary = 0x00000015, // LC_SUB_LIBRARY 22 | TwoLevelHints = 0x00000016, // LC_TWOLEVEL_HINTS 23 | Segment64 = 0x00000019, // LC_SEGMENT_64 24 | Routines64 = 0x0000001A, // LC_ROUTINES_64 25 | UUID = 0x0000001B, // LC_UUID 26 | CodeSignature = 0x0000001D, // LC_CODE_SIGNATURE 27 | FunctionStarts = 0x00000026, // LC_FUNCTION_STARTS 28 | EncryptionInfo = 0x00000021, // LC_ENCRYPTION_INFO 29 | VersionMinIPhoneOS = 0x00000025, // LC_VERSION_MIN_IPHONEOS 30 | DataInCode = 0x00000029, // LC_DATA_IN_CODE 31 | SourceVersion = 0x0000002A, // LC_SOURCE_VERSION 32 | EncryptionInfo64 = 0x0000002C, // LC_ENCRYPTION_INFO_64 33 | LoadWeakDynamicLibrary = 0x80000018, // LC_LOAD_WEAK_DYLIB 34 | DynamicLinkerInfoOnly = 0x80000022, // LC_DYLD_INFO_ONLY 35 | MainEntryPoint = 0x80000028, // LC_MAIN 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Enums/MachHeaderFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace IPALibrary.MachO 4 | { 5 | [Flags] 6 | public enum MachHeaderFlags : uint 7 | { 8 | NoUndefinedReferences = 0x00000001, // MH_NOUNDEFS 9 | IncrementalLink = 0x00000002, // MH_INCRLINK 10 | DynamicLink = 0x00000004, // MH_DYLDLINK 11 | BindAtLoad = 0x00000008, // MH_BINDATLOAD 12 | Prebound = 0x00000010, // MH_PREBOUND 13 | SplitSegments = 0x00000020, // MH_SPLIT_SEGS 14 | LazyInit = 0x00000040, // MH_LAZY_INIT 15 | TwoLevelNamespace = 0x00000080, // MH_TWOLEVEL 16 | ForceFlatNamespace = 0x00000100, // MH_FORCE_FLAT 17 | NoMultipleDefinitions = 0x00000200, // MH_NOMULTIDEFS 18 | NoFixPrebinding = 0x00000400, // MH_NOFIXPREBINDING 19 | Prebindable = 0x00000800, // MH_PREBINDABLE 20 | AllModsBound = 0x00001000, // MH_ALLMODSBOUND 21 | SubsectionsViaSymbols = 0x00002000, // MH_SUBSECTIONS_VIA_SYMBOLS 22 | Canonical = 0x00004000, // MH_CANONICAL 23 | WeakDefines = 0x00008000, // MH_WEAK_DEFINES 24 | BindsToWeak = 0x00010000, // MH_BINDS_TO_WEAK 25 | AllowStackExecution = 0x00020000, // MH_ALLOW_STACK_EXECUTION 26 | LoadAtRandomAddress = 0x00200000, // MH_PIE 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Helpers/MachObjectHelper.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | 12 | namespace IPALibrary.MachO 13 | { 14 | public class MachObjectHelper 15 | { 16 | public static List ReadMachObjects(byte[] buffer) 17 | { 18 | if (UniversalBinaryFile.IsUniversalBinaryFile(buffer)) 19 | { 20 | UniversalBinaryFile file = new UniversalBinaryFile(buffer); 21 | return file.MachObjects; 22 | } 23 | else if (MachObjectFile.IsMachObjectFile(buffer, 0)) 24 | { 25 | List result = new List(); 26 | result.Add(new MachObjectFile(buffer, 0, buffer.Length)); 27 | return result; 28 | } 29 | else 30 | { 31 | return null; 32 | } 33 | } 34 | 35 | public static byte[] PackMachObjects(List files) 36 | { 37 | if (files.Count == 1) 38 | { 39 | return files[0].GetBytes(); 40 | } 41 | else 42 | { 43 | UniversalBinaryFile universalBinaryFile = new UniversalBinaryFile(); 44 | universalBinaryFile.Header.NumberOfArchitectures = (uint)files.Count; 45 | foreach(MachObjectFile machObject in files) 46 | { 47 | FatArch fatArch = new FatArch(); 48 | fatArch.CpuType = machObject.Header.CpuType; 49 | fatArch.CpuSubType = machObject.Header.CpuSubType; 50 | universalBinaryFile.Architectures.Add(fatArch, machObject); 51 | } 52 | return universalBinaryFile.GetBytes(); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Helpers/SegmentCommandHelper.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | 12 | namespace IPALibrary.MachO 13 | { 14 | public class SegmentCommandHelper 15 | { 16 | public const string LinkEditSegmentName = "__LINKEDIT"; 17 | 18 | public static SegmentCommand FindLinkEditSegment(List loadCommands) 19 | { 20 | foreach (LoadCommand loadCommand in loadCommands) 21 | { 22 | if (loadCommand is SegmentCommand) 23 | { 24 | SegmentCommand segmentCommand = (SegmentCommand)loadCommand; 25 | if (segmentCommand.SegmentName == LinkEditSegmentName) 26 | { 27 | return segmentCommand; 28 | } 29 | } 30 | } 31 | return null; 32 | } 33 | 34 | public static void SetEndOffset(SegmentCommand segmentCommand, uint endOffset) 35 | { 36 | if (segmentCommand is SegmentCommand32) 37 | { 38 | SegmentCommand32 segmentCommand32 = (SegmentCommand32)segmentCommand; 39 | segmentCommand32.FileSize = endOffset - segmentCommand32.FileOffset; 40 | } 41 | else if (segmentCommand is SegmentCommand64) 42 | { 43 | SegmentCommand64 segmentCommand64 = (SegmentCommand64)segmentCommand; 44 | segmentCommand64.FileSize = endOffset - segmentCommand64.FileOffset; 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /IPALibrary/MachO/MachObjectFile.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.MachO 14 | { 15 | public class MachObjectFile 16 | { 17 | public MachHeader Header; 18 | public List LoadCommands = new List(); 19 | public int DataOffset; 20 | public byte[] Data; 21 | 22 | public MachObjectFile() 23 | { 24 | } 25 | 26 | public MachObjectFile(byte[] buffer, int offset, int length) 27 | { 28 | Header = new MachHeader(buffer, offset); 29 | offset += Header.Length; 30 | for (int index = 0; index < Header.NumberOfLoadCommands; index++) 31 | { 32 | LoadCommand command = LoadCommand.ReadCommand(buffer, offset); 33 | LoadCommands.Add(command); 34 | offset += (int)command.CommandSize; 35 | } 36 | int dataLength = (int)(length - Header.Length - Header.SizeOfLoadCommands); 37 | DataOffset = (int)(Header.Length + Header.SizeOfLoadCommands); 38 | Data = ByteReader.ReadBytes(buffer, offset, dataLength); 39 | } 40 | 41 | public LoadCommand GetLoadCommand(LoadCommandType commandType) 42 | { 43 | foreach (LoadCommand command in LoadCommands) 44 | { 45 | if (command.CommandType == commandType) 46 | { 47 | return command; 48 | } 49 | } 50 | return null; 51 | } 52 | 53 | public byte[] GetCodeSignatureBytes() 54 | { 55 | CodeSignatureCommand command = GetLoadCommand(LoadCommandType.CodeSignature) as CodeSignatureCommand; 56 | if (command != null) 57 | { 58 | return ByteReader.ReadBytes(Data, (int)command.DataOffset - DataOffset, (int)command.DataSize); 59 | } 60 | return null; 61 | } 62 | 63 | public void WriteBytes(byte[] buffer, int offset) 64 | { 65 | Header.WriteBytes(buffer, offset + 0); 66 | offset += Header.Length; 67 | foreach (LoadCommand command in LoadCommands) 68 | { 69 | command.WriteBytes(buffer, offset); 70 | offset += (int)command.CommandSize; 71 | } 72 | ByteWriter.WriteBytes(buffer, offset, Data); 73 | } 74 | 75 | public byte[] GetBytes() 76 | { 77 | byte[] buffer = new byte[Length]; 78 | WriteBytes(buffer, 0); 79 | return buffer; 80 | } 81 | 82 | public int Length 83 | { 84 | get 85 | { 86 | int length = Header.Length; 87 | foreach (LoadCommand command in LoadCommands) 88 | { 89 | length += (int)command.CommandSize; 90 | } 91 | length += Data.Length; 92 | return length; 93 | } 94 | } 95 | 96 | public static bool IsMachObjectFile(byte[] buffer, int offset) 97 | { 98 | return MachHeader.IsMachHeader(buffer, offset); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Structures/FatArch.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.MachO 14 | { 15 | /// 16 | /// Describes the location within the binary of an object file targeted at a single architecture. 17 | /// Regardless of the content this data structure describes, all its fields are stored in big-endian byte order. 18 | /// 19 | public class FatArch 20 | { 21 | public const int Length = 20; 22 | 23 | public CpuType CpuType; 24 | public uint CpuSubType; 25 | public uint Offset; 26 | public uint Size; 27 | public uint AlignLog2; 28 | 29 | public FatArch() 30 | { 31 | } 32 | 33 | public FatArch(byte[] buffer, int offset) 34 | { 35 | CpuType = (CpuType)BigEndianConverter.ToUInt32(buffer, offset + 0); 36 | CpuSubType = BigEndianConverter.ToUInt32(buffer, offset + 4); 37 | Offset = BigEndianConverter.ToUInt32(buffer, offset + 8); 38 | Size = BigEndianConverter.ToUInt32(buffer, offset + 12); 39 | AlignLog2 = BigEndianConverter.ToUInt32(buffer, offset + 16); 40 | } 41 | 42 | public void WriteBytes(byte[] buffer, int offset) 43 | { 44 | BigEndianWriter.WriteUInt32(buffer, offset + 0, (uint)CpuType); 45 | BigEndianWriter.WriteUInt32(buffer, offset + 4, CpuSubType); 46 | BigEndianWriter.WriteUInt32(buffer, offset + 8, Offset); 47 | BigEndianWriter.WriteUInt32(buffer, offset + 12, Size); 48 | BigEndianWriter.WriteUInt32(buffer, offset + 16, AlignLog2); 49 | } 50 | 51 | public int Align 52 | { 53 | get 54 | { 55 | return 1 << (int)AlignLog2; 56 | } 57 | set 58 | { 59 | AlignLog2 = (byte)Math.Log(value, 2); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Structures/FatHeader.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.MachO 14 | { 15 | public class FatHeader 16 | { 17 | public const int Length = 8; 18 | public const uint FatSignature = 0xcafebabe; 19 | 20 | // uint Magic; 21 | public uint NumberOfArchitectures; // nfat_arch 22 | 23 | public FatHeader() 24 | { 25 | } 26 | 27 | public FatHeader(byte[] buffer) 28 | { 29 | NumberOfArchitectures = BigEndianConverter.ToUInt32(buffer, 4); 30 | } 31 | 32 | public void WriteBytes(byte[] buffer) 33 | { 34 | BigEndianWriter.WriteUInt32(buffer, 0, FatSignature); 35 | BigEndianWriter.WriteUInt32(buffer, 4, NumberOfArchitectures); 36 | } 37 | 38 | internal static bool IsFatHeader(byte[] buffer) 39 | { 40 | uint magic = BigEndianConverter.ToUInt32(buffer, 0); 41 | return (magic == FatSignature); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Structures/LoadCommands/CodeSignatureCommand.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.MachO 14 | { 15 | public class CodeSignatureCommand : LoadCommand 16 | { 17 | public const int Size = 16; 18 | 19 | public uint DataOffset; 20 | public uint DataSize; 21 | 22 | public CodeSignatureCommand() : base(LoadCommandType.CodeSignature, Size) 23 | { 24 | } 25 | 26 | public CodeSignatureCommand(byte[] buffer, int offset) : base(buffer, offset) 27 | { 28 | DataOffset = LittleEndianConverter.ToUInt32(buffer, offset + 8); 29 | DataSize = LittleEndianConverter.ToUInt32(buffer, offset + 12); 30 | } 31 | 32 | public override void WriteBytes(byte[] buffer, int offset) 33 | { 34 | base.WriteBytes(buffer, offset); 35 | LittleEndianWriter.WriteUInt32(buffer, offset + 8, DataOffset); 36 | LittleEndianWriter.WriteUInt32(buffer, offset + 12, DataSize); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Structures/LoadCommands/LoadCommand.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.MachO 14 | { 15 | public class LoadCommand 16 | { 17 | private LoadCommandType m_commandType; 18 | private uint m_commandSize; 19 | public byte[] Data; // LoadCommand data, only used for unrecognized LoadCommand structures 20 | 21 | public LoadCommand(LoadCommandType commandType, uint commandSize) 22 | { 23 | } 24 | 25 | public LoadCommand(byte[] buffer, int offset) 26 | { 27 | m_commandType = (LoadCommandType)LittleEndianConverter.ToUInt32(buffer, offset + 0); 28 | m_commandSize = LittleEndianConverter.ToUInt32(buffer, offset + 4); 29 | if (this.GetType() == typeof(LoadCommand)) // We check if the current class is LoadCommand and not a class that inherits from LoadCommand 30 | { 31 | Data = ByteReader.ReadBytes(buffer, offset + 8, (int)(CommandSize - 8)); 32 | } 33 | } 34 | 35 | public virtual void WriteBytes(byte[] buffer, int offset) 36 | { 37 | LittleEndianWriter.WriteUInt32(buffer, offset + 0, (uint)m_commandType); 38 | LittleEndianWriter.WriteUInt32(buffer, offset + 4, m_commandSize); 39 | if (this.GetType() == typeof(LoadCommand)) // We check if the current class is LoadCommand and not a class that inherits from LoadCommand 40 | { 41 | ByteWriter.WriteBytes(buffer, offset + 8, Data); 42 | } 43 | } 44 | 45 | public LoadCommandType CommandType 46 | { 47 | get 48 | { 49 | return m_commandType; 50 | } 51 | } 52 | 53 | public virtual uint CommandSize 54 | { 55 | get 56 | { 57 | return m_commandSize; 58 | } 59 | } 60 | 61 | public static LoadCommand ReadCommand(byte[] buffer, int offset) 62 | { 63 | LoadCommandType commandType = (LoadCommandType)LittleEndianConverter.ToUInt32(buffer, offset + 0); 64 | switch (commandType) 65 | { 66 | case LoadCommandType.Segment: 67 | return new SegmentCommand32(buffer, offset + 0); 68 | case LoadCommandType.Segment64: 69 | return new SegmentCommand64(buffer, offset + 0); 70 | case LoadCommandType.CodeSignature: 71 | return new CodeSignatureCommand(buffer, offset + 0); 72 | default: 73 | return new LoadCommand(buffer, offset + 0); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Structures/LoadCommands/Section32.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.MachO 14 | { 15 | /// 16 | /// section 17 | /// 18 | public class Section32 19 | { 20 | public const int Length = 68; 21 | 22 | public string SectionName; // sectname, 16 bytes 23 | public string SegmentName; // segname, 16 bytes 24 | public uint Address; 25 | public uint Size; 26 | public uint Offset; 27 | public uint Align; 28 | public uint RelocationOffset; // reloff; 29 | public uint NumberOfRelocationOffsets; 30 | public uint Flags; 31 | public uint Reserved1; 32 | public uint Reserved2; 33 | 34 | public Section32() 35 | { 36 | } 37 | 38 | public Section32(byte[] buffer, int offset) 39 | { 40 | SectionName = ByteReader.ReadAnsiString(buffer, offset + 0, 16).Trim('\0'); 41 | SegmentName = ByteReader.ReadAnsiString(buffer, offset + 16, 16).Trim('\0'); 42 | Address = LittleEndianConverter.ToUInt32(buffer, offset + 32); 43 | Size = LittleEndianConverter.ToUInt32(buffer, offset + 36); 44 | Offset = LittleEndianConverter.ToUInt32(buffer, offset + 40); 45 | Align = LittleEndianConverter.ToUInt32(buffer, offset + 44); 46 | RelocationOffset = LittleEndianConverter.ToUInt32(buffer, offset + 48); 47 | NumberOfRelocationOffsets = LittleEndianConverter.ToUInt32(buffer, offset + 52); 48 | Flags = LittleEndianConverter.ToUInt32(buffer, offset + 56); 49 | Reserved1 = LittleEndianConverter.ToUInt32(buffer, offset + 60); 50 | Reserved2 = LittleEndianConverter.ToUInt32(buffer, offset + 64); 51 | } 52 | 53 | public void WriteBytes(byte[] buffer, int offset) 54 | { 55 | ByteWriter.WriteAnsiString(buffer, offset + 0, SectionName, 16); 56 | ByteWriter.WriteAnsiString(buffer, offset + 16, SegmentName, 16); 57 | LittleEndianWriter.WriteUInt32(buffer, offset + 32, Address); 58 | LittleEndianWriter.WriteUInt32(buffer, offset + 36, Size); 59 | LittleEndianWriter.WriteUInt32(buffer, offset + 40, Offset); 60 | LittleEndianWriter.WriteUInt32(buffer, offset + 44, Align); 61 | LittleEndianWriter.WriteUInt32(buffer, offset + 48, RelocationOffset); 62 | LittleEndianWriter.WriteUInt32(buffer, offset + 52, NumberOfRelocationOffsets); 63 | LittleEndianWriter.WriteUInt32(buffer, offset + 56, Flags); 64 | LittleEndianWriter.WriteUInt32(buffer, offset + 60, Reserved1); 65 | LittleEndianWriter.WriteUInt32(buffer, offset + 64, Reserved2); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Structures/LoadCommands/Section64.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.MachO 14 | { 15 | /// 16 | /// section_64 17 | /// 18 | public class Section64 19 | { 20 | public const int Length = 80; 21 | 22 | public string SectionName; // sectname, 16 bytes 23 | public string SegmentName; // segname, 16 bytes 24 | public ulong Address; 25 | public ulong Size; 26 | public uint Offset; 27 | public uint Align; 28 | public uint RelocationOffset; // reloff; 29 | public uint NumberOfRelocationOffsets; 30 | public uint Flags; 31 | public uint Reserved1; 32 | public uint Reserved2; 33 | public uint Reserved3; // Defined in 'loader.h' 34 | 35 | public Section64() 36 | { 37 | } 38 | 39 | public Section64(byte[] buffer, int offset) 40 | { 41 | SectionName = ByteReader.ReadAnsiString(buffer, offset + 0, 16).Trim('\0'); 42 | SegmentName = ByteReader.ReadAnsiString(buffer, offset + 16, 16).Trim('\0'); 43 | Address = LittleEndianConverter.ToUInt64(buffer, offset + 32); 44 | Size = LittleEndianConverter.ToUInt64(buffer, offset + 40); 45 | Offset = LittleEndianConverter.ToUInt32(buffer, offset + 48); 46 | Align = LittleEndianConverter.ToUInt32(buffer, offset + 52); 47 | RelocationOffset = LittleEndianConverter.ToUInt32(buffer, offset + 56); 48 | NumberOfRelocationOffsets = LittleEndianConverter.ToUInt32(buffer, offset + 60); 49 | Flags = LittleEndianConverter.ToUInt32(buffer, offset + 64); 50 | Reserved1 = LittleEndianConverter.ToUInt32(buffer, offset + 68); 51 | Reserved2 = LittleEndianConverter.ToUInt32(buffer, offset + 72); 52 | Reserved3 = LittleEndianConverter.ToUInt32(buffer, offset + 76); 53 | } 54 | 55 | public void WriteBytes(byte[] buffer, int offset) 56 | { 57 | ByteWriter.WriteAnsiString(buffer, offset + 0, SectionName, 16); 58 | ByteWriter.WriteAnsiString(buffer, offset + 16, SegmentName, 16); 59 | LittleEndianWriter.WriteUInt64(buffer, offset + 32, Address); 60 | LittleEndianWriter.WriteUInt64(buffer, offset + 40, Size); 61 | LittleEndianWriter.WriteUInt32(buffer, offset + 48, Offset); 62 | LittleEndianWriter.WriteUInt32(buffer, offset + 52, Align); 63 | LittleEndianWriter.WriteUInt32(buffer, offset + 56, RelocationOffset); 64 | LittleEndianWriter.WriteUInt32(buffer, offset + 60, NumberOfRelocationOffsets); 65 | LittleEndianWriter.WriteUInt32(buffer, offset + 64, Flags); 66 | LittleEndianWriter.WriteUInt32(buffer, offset + 68, Reserved1); 67 | LittleEndianWriter.WriteUInt32(buffer, offset + 72, Reserved2); 68 | LittleEndianWriter.WriteUInt32(buffer, offset + 76, Reserved3); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Structures/LoadCommands/SegmentCommand.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | 10 | namespace IPALibrary.MachO 11 | { 12 | public abstract class SegmentCommand : LoadCommand 13 | { 14 | public string SegmentName; // segname, 16 bytes 15 | 16 | public SegmentCommand(LoadCommandType commandType, uint commandSize) : base(commandType, commandSize) 17 | { 18 | } 19 | 20 | public SegmentCommand(byte[] buffer, int offset) : base(buffer, offset) 21 | { 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Structures/LoadCommands/SegmentCommand32.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.MachO 14 | { 15 | /// 16 | /// segment_command 17 | /// 18 | public class SegmentCommand32 : SegmentCommand 19 | { 20 | public const int FixedSize = 56; 21 | 22 | // string SegmentName; // segname, 16 bytes 23 | public uint VMAddress; 24 | public uint VMSize; 25 | public uint FileOffset; 26 | public uint FileSize; // The number of bytes occupied by this segment on disk 27 | public uint MaxProt; 28 | public uint InitProt; 29 | // uint NumberOfSections; // nsects 30 | public uint Flags; 31 | public List Sections = new List(); 32 | 33 | public SegmentCommand32() : base(LoadCommandType.Segment, FixedSize) 34 | { 35 | } 36 | 37 | public SegmentCommand32(byte[] buffer, int offset) : base(buffer, offset) 38 | { 39 | SegmentName = ByteReader.ReadAnsiString(buffer, offset + 8, 16).Trim('\0'); 40 | VMAddress = LittleEndianConverter.ToUInt32(buffer, offset + 24); 41 | VMSize = LittleEndianConverter.ToUInt32(buffer, offset + 28); 42 | FileOffset = LittleEndianConverter.ToUInt32(buffer, offset + 32); 43 | FileSize = LittleEndianConverter.ToUInt32(buffer, offset + 36); 44 | MaxProt = LittleEndianConverter.ToUInt32(buffer, offset + 40); 45 | InitProt = LittleEndianConverter.ToUInt32(buffer, offset + 44); 46 | uint numberOfSections = LittleEndianConverter.ToUInt32(buffer, offset + 48); 47 | Flags = LittleEndianConverter.ToUInt32(buffer, offset + 52); 48 | 49 | for (int index = 0; index < numberOfSections; index++) 50 | { 51 | Section32 section = new Section32(buffer, offset + FixedSize + index * Section32.Length); 52 | Sections.Add(section); 53 | } 54 | } 55 | 56 | public override void WriteBytes(byte[] buffer, int offset) 57 | { 58 | base.WriteBytes(buffer, offset); 59 | ByteWriter.WriteAnsiString(buffer, offset + 8, SegmentName, 16); 60 | LittleEndianWriter.WriteUInt32(buffer, offset + 24, VMAddress); 61 | LittleEndianWriter.WriteUInt32(buffer, offset + 28, VMSize); 62 | LittleEndianWriter.WriteUInt32(buffer, offset + 32, FileOffset); 63 | LittleEndianWriter.WriteUInt32(buffer, offset + 36, FileSize); 64 | LittleEndianWriter.WriteUInt32(buffer, offset + 40, MaxProt); 65 | LittleEndianWriter.WriteUInt32(buffer, offset + 44, InitProt); 66 | LittleEndianWriter.WriteUInt32(buffer, offset + 48, (uint)Sections.Count); 67 | LittleEndianWriter.WriteUInt32(buffer, offset + 52, Flags); 68 | 69 | for (int index = 0; index < Sections.Count; index++) 70 | { 71 | Sections[index].WriteBytes(buffer, offset + FixedSize + index * Section32.Length); 72 | } 73 | } 74 | 75 | public override uint CommandSize 76 | { 77 | get 78 | { 79 | return FixedSize + (uint)Sections.Count * Section32.Length; 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Structures/LoadCommands/SegmentCommand64.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.MachO 14 | { 15 | /// 16 | /// segment_command_64 17 | /// 18 | public class SegmentCommand64 : SegmentCommand 19 | { 20 | public const int FixedSize = 72; 21 | 22 | // string SegmentName; // segname, 16 bytes 23 | public ulong VMAddress; 24 | public ulong VMSize; 25 | public ulong FileOffset; 26 | public ulong FileSize; // The number of bytes occupied by this segment on disk 27 | public uint MaxProt; 28 | public uint InitProt; 29 | // uint NumberOfSections; // nsects 30 | public uint Flags; 31 | public uint Reserved1; 32 | public uint Reserved2; 33 | public List Sections = new List(); 34 | 35 | public SegmentCommand64() : base(LoadCommandType.Segment64, FixedSize) 36 | { 37 | } 38 | 39 | public SegmentCommand64(byte[] buffer, int offset) : base(buffer, offset) 40 | { 41 | SegmentName = ByteReader.ReadAnsiString(buffer, offset + 8, 16).Trim('\0'); 42 | VMAddress = LittleEndianConverter.ToUInt64(buffer, offset + 24); 43 | VMSize = LittleEndianConverter.ToUInt64(buffer, offset + 32); 44 | FileOffset = LittleEndianConverter.ToUInt64(buffer, offset + 40); 45 | FileSize = LittleEndianConverter.ToUInt64(buffer, offset + 48); 46 | MaxProt = LittleEndianConverter.ToUInt32(buffer, offset + 56); 47 | InitProt = LittleEndianConverter.ToUInt32(buffer, offset + 60); 48 | uint numberOfSections = LittleEndianConverter.ToUInt32(buffer, offset + 64); 49 | Flags = LittleEndianConverter.ToUInt32(buffer, offset + 68); 50 | 51 | for (int index = 0; index < numberOfSections; index++) 52 | { 53 | Section64 section = new Section64(buffer, offset + FixedSize + index * Section64.Length); 54 | Sections.Add(section); 55 | } 56 | } 57 | 58 | public override void WriteBytes(byte[] buffer, int offset) 59 | { 60 | base.WriteBytes(buffer, offset); 61 | ByteWriter.WriteAnsiString(buffer, offset + 8, SegmentName, 16); 62 | LittleEndianWriter.WriteUInt64(buffer, offset + 24, VMAddress); 63 | LittleEndianWriter.WriteUInt64(buffer, offset + 32, VMSize); 64 | LittleEndianWriter.WriteUInt64(buffer, offset + 40, FileOffset); 65 | LittleEndianWriter.WriteUInt64(buffer, offset + 48, FileSize); 66 | LittleEndianWriter.WriteUInt32(buffer, offset + 56, MaxProt); 67 | LittleEndianWriter.WriteUInt32(buffer, offset + 60, InitProt); 68 | LittleEndianWriter.WriteUInt32(buffer, offset + 64, (uint)Sections.Count); 69 | LittleEndianWriter.WriteUInt32(buffer, offset + 68, Flags); 70 | 71 | for (int index = 0; index < Sections.Count; index++) 72 | { 73 | Sections[index].WriteBytes(buffer, offset + FixedSize + index * Section64.Length); 74 | } 75 | } 76 | 77 | public override uint CommandSize 78 | { 79 | get 80 | { 81 | return FixedSize + (uint)Sections.Count * Section64.Length; 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /IPALibrary/MachO/Structures/MachHeader.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.IO; 12 | using Utilities; 13 | 14 | namespace IPALibrary.MachO 15 | { 16 | public class MachHeader 17 | { 18 | public const int Length32Bit = 28; 19 | public const int Length64Bit = 32; 20 | 21 | public const uint MachO32BitLittleEndianSignature = 0xcefaedfe; 22 | public const uint MachO64BitLittleEndianSignature = 0xcffaedfe; 23 | public const uint MachO32BitBigEndianSignature = 0xfeedface; 24 | public const uint MachO64BitBigEndianSignature = 0xfeedfacf; 25 | public const uint CpuArchitecture64BitFlag = 0x01000000; // CPU_ARCH_ABI64 26 | 27 | private bool m_is64BitHeader; 28 | // uint Magic; 29 | public CpuType CpuType; 30 | public uint CpuSubType; 31 | public FileType FileType; 32 | public uint NumberOfLoadCommands; // ncmds 33 | public uint SizeOfLoadCommands; // sizeofcmds 34 | public MachHeaderFlags Flags; 35 | public uint Reserved; // 64-Bit only 36 | 37 | public MachHeader(bool is64Bit) 38 | { 39 | m_is64BitHeader = is64Bit; 40 | } 41 | 42 | public MachHeader(byte[] buffer, int offset) 43 | { 44 | uint magic = BigEndianConverter.ToUInt32(buffer, offset); 45 | m_is64BitHeader = (magic == MachO64BitLittleEndianSignature); 46 | CpuType = (CpuType)LittleEndianConverter.ToUInt32(buffer, offset + 4); 47 | CpuSubType = LittleEndianConverter.ToUInt32(buffer, offset + 8); 48 | FileType = (FileType)LittleEndianConverter.ToUInt32(buffer, offset + 12); 49 | NumberOfLoadCommands = LittleEndianConverter.ToUInt32(buffer, offset + 16); 50 | SizeOfLoadCommands = LittleEndianConverter.ToUInt32(buffer, offset + 20); 51 | Flags = (MachHeaderFlags)LittleEndianConverter.ToUInt32(buffer, offset + 24); 52 | if (m_is64BitHeader) 53 | { 54 | Reserved = LittleEndianConverter.ToUInt32(buffer, offset + 28); 55 | } 56 | } 57 | 58 | public void WriteBytes(byte[] buffer, int offset) 59 | { 60 | if (m_is64BitHeader) 61 | { 62 | BigEndianWriter.WriteUInt32(buffer, offset + 0, MachO64BitLittleEndianSignature); 63 | } 64 | else 65 | { 66 | BigEndianWriter.WriteUInt32(buffer, offset + 0, MachO32BitLittleEndianSignature); 67 | } 68 | LittleEndianWriter.WriteUInt32(buffer, offset + 4, (uint)CpuType); 69 | LittleEndianWriter.WriteUInt32(buffer, offset + 8, CpuSubType); 70 | LittleEndianWriter.WriteUInt32(buffer, offset + 12, (uint)FileType); 71 | LittleEndianWriter.WriteUInt32(buffer, offset + 16, NumberOfLoadCommands); 72 | LittleEndianWriter.WriteUInt32(buffer, offset + 20, SizeOfLoadCommands); 73 | LittleEndianWriter.WriteUInt32(buffer, offset + 24, (uint)Flags); 74 | if (m_is64BitHeader) 75 | { 76 | LittleEndianWriter.WriteUInt32(buffer, offset + 28, Reserved); 77 | } 78 | } 79 | 80 | public int Length 81 | { 82 | get 83 | { 84 | if (m_is64BitHeader) 85 | { 86 | return Length64Bit; 87 | } 88 | else 89 | { 90 | return Length32Bit; 91 | } 92 | } 93 | } 94 | 95 | public bool Is64Bit 96 | { 97 | get 98 | { 99 | return m_is64BitHeader; 100 | } 101 | } 102 | 103 | public static bool IsMachHeader(byte[] buffer, int offset) 104 | { 105 | uint magic = BigEndianConverter.ToUInt32(buffer, offset); 106 | return (magic == MachO32BitLittleEndianSignature || 107 | magic == MachO64BitLittleEndianSignature); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /IPALibrary/MachO/UniversalBinaryFile.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using Utilities; 12 | 13 | namespace IPALibrary.MachO 14 | { 15 | public class UniversalBinaryFile 16 | { 17 | public const int DefaultAlignment = 16384; 18 | 19 | public FatHeader Header; 20 | public KeyValuePairList Architectures = new KeyValuePairList(); 21 | 22 | public UniversalBinaryFile() 23 | { 24 | Header = new FatHeader(); 25 | } 26 | 27 | public UniversalBinaryFile(byte[] buffer) 28 | { 29 | Header = new FatHeader(buffer); 30 | 31 | List architectures = new List(); 32 | for (int index = 0; index < Header.NumberOfArchitectures; index++) 33 | { 34 | FatArch architecture = new FatArch(buffer, FatHeader.Length + index * FatArch.Length); 35 | architectures.Add(architecture); 36 | } 37 | 38 | foreach (FatArch architecture in architectures) 39 | { 40 | MachObjectFile machObject = new MachObjectFile(buffer, (int)architecture.Offset, (int)architecture.Size); 41 | Architectures.Add(architecture, machObject); 42 | } 43 | } 44 | 45 | public List MachObjects 46 | { 47 | get 48 | { 49 | return Architectures.Values; 50 | } 51 | } 52 | 53 | public byte[] GetBytes() 54 | { 55 | foreach (FatArch fatArch in Architectures.Keys) 56 | { 57 | if (fatArch.AlignLog2 == 0) 58 | { 59 | fatArch.Align = DefaultAlignment; 60 | } 61 | } 62 | 63 | byte[] buffer = new byte[Length]; 64 | Header.WriteBytes(buffer); 65 | int nextObjectOffset = FatHeader.Length + Architectures.Count * FatArch.Length; 66 | for(int index = 0; index < Architectures.Count; index++) 67 | { 68 | FatArch fatArch = Architectures[index].Key; 69 | MachObjectFile file = Architectures[index].Value; 70 | int align = fatArch.Align; 71 | int padding = (align - (nextObjectOffset % align)) % align; 72 | nextObjectOffset += padding; 73 | fatArch.Offset = (uint)nextObjectOffset; 74 | fatArch.Size = (uint)file.Length; 75 | fatArch.WriteBytes(buffer, FatHeader.Length + index * FatArch.Length); 76 | file.WriteBytes(buffer, nextObjectOffset); 77 | nextObjectOffset += file.Length; 78 | } 79 | return buffer; 80 | } 81 | 82 | public int Length 83 | { 84 | get 85 | { 86 | int length = FatHeader.Length + Architectures.Count * FatArch.Length; 87 | int nextObjectOffset = length; 88 | for (int index = 0; index < Architectures.Count; index++) 89 | { 90 | FatArch fatArch = Architectures[index].Key; 91 | MachObjectFile file = Architectures[index].Value; 92 | int align = fatArch.Align; 93 | int padding = (align - (nextObjectOffset % align)) % align; 94 | length += padding; 95 | length += file.Length; 96 | nextObjectOffset = length; 97 | } 98 | return length; 99 | } 100 | } 101 | 102 | public static bool IsUniversalBinaryFile(byte[] buffer) 103 | { 104 | return FatHeader.IsFatHeader(buffer); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /IPALibrary/MobileProvision/MobileProvisionFile.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.IO; 12 | using Org.BouncyCastle.Asn1; 13 | using PListNet; 14 | using PListNet.Nodes; 15 | using Utilities; 16 | 17 | namespace IPALibrary 18 | { 19 | public class MobileProvisionFile 20 | { 21 | public const string PListOID = "1.2.840.113549.1.7.1"; 22 | 23 | private Asn1Object m_rootObject; 24 | private MobileProvisionPList m_plist; 25 | 26 | public MobileProvisionFile(byte[] fileBytes) 27 | { 28 | Asn1InputStream stream = new Asn1InputStream(fileBytes); 29 | m_rootObject = Asn1Object.FromByteArray(fileBytes); 30 | byte[] plistBytes = GetPListBytes(m_rootObject); 31 | m_plist = new MobileProvisionPList(plistBytes); 32 | } 33 | 34 | public static byte[] GetPListBytes(Asn1Object rootObject) 35 | { 36 | Asn1Object plistObj = Asn1Helper.FindAsn1Value(PListOID, rootObject); 37 | if (plistObj is DerTaggedObject) 38 | { 39 | DerOctetString value = ((DerTaggedObject)plistObj).GetObject() as DerOctetString; 40 | if (value != null) 41 | { 42 | return value.GetOctets(); 43 | } 44 | } 45 | return null; 46 | } 47 | 48 | public MobileProvisionPList PList 49 | { 50 | get 51 | { 52 | return m_plist; 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /IPALibrary/MobileProvision/MobileProvisionPList.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.IO; 12 | using PListNet; 13 | using PListNet.Nodes; 14 | using Utilities; 15 | 16 | namespace IPALibrary 17 | { 18 | public class MobileProvisionPList : PListFile 19 | { 20 | public MobileProvisionPList(byte[] plistBytes) : base(plistBytes) 21 | { 22 | } 23 | 24 | public string AppIDName 25 | { 26 | get 27 | { 28 | return PListHelper.GetStringValueFromPList(RootNode, "AppIDName"); 29 | } 30 | } 31 | 32 | public List ApplicationIdentifierPrefix 33 | { 34 | get 35 | { 36 | return PListHelper.GetStringArrayValueFromPList(RootNode, "ApplicationIdentifierPrefix"); 37 | } 38 | } 39 | 40 | public DateTime? CreationDate 41 | { 42 | get 43 | { 44 | return PListHelper.GetDateTimeValueFromPList(RootNode, "CreationDate"); 45 | } 46 | } 47 | 48 | public DictionaryNode EntitlementsNode 49 | { 50 | get 51 | { 52 | return PListHelper.GetDictionaryValueFromPList(RootNode, "Entitlements"); 53 | } 54 | } 55 | 56 | public EntitlementsFile Entitlements 57 | { 58 | get 59 | { 60 | DictionaryNode entitlementsNode = EntitlementsNode; 61 | if (entitlementsNode != null) 62 | { 63 | return new EntitlementsFile(entitlementsNode); 64 | } 65 | return null; 66 | } 67 | } 68 | 69 | public List DeveloperCertificates 70 | { 71 | get 72 | { 73 | return PListHelper.GetDataArrayValueFromPList(RootNode, "DeveloperCertificates"); 74 | } 75 | } 76 | 77 | public DateTime? ExpirationDate 78 | { 79 | get 80 | { 81 | return PListHelper.GetDateTimeValueFromPList(RootNode, "ExpirationDate"); 82 | } 83 | } 84 | 85 | public string ProfileName 86 | { 87 | get 88 | { 89 | return PListHelper.GetStringValueFromPList(RootNode, "Name"); 90 | } 91 | } 92 | 93 | public List ProvisionedDevices 94 | { 95 | get 96 | { 97 | return PListHelper.GetStringArrayValueFromPList(RootNode, "ProvisionedDevices"); 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /IPALibrary/PListFiles/CodeResourcesFile.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017-2018 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Security.Cryptography; 12 | using System.IO; 13 | using PListNet; 14 | using PListNet.Nodes; 15 | 16 | namespace IPALibrary 17 | { 18 | public class CodeResourcesFile : PListFile 19 | { 20 | public CodeResourcesFile(byte[] codeResourcesBytes) : base(codeResourcesBytes) 21 | { 22 | } 23 | 24 | public byte[] GetFileHash(string fileName) 25 | { 26 | DictionaryNode filesNode = PListHelper.GetDictionaryValueFromPList(RootNode, "files"); 27 | return PListHelper.GetDataValueFromPList(filesNode, fileName); 28 | } 29 | 30 | public void UpdateFileHash(string fileName, byte[] fileBytes) 31 | { 32 | DictionaryNode filesNode = PListHelper.GetDictionaryValueFromPList(RootNode, "files"); 33 | byte[] sha1Hash = new SHA1Managed().ComputeHash(fileBytes); 34 | byte[] sha256Hash = new SHA256Managed().ComputeHash(fileBytes); 35 | if (filesNode.ContainsKey(fileName)) 36 | { 37 | filesNode[fileName] = new DataNode(sha1Hash); 38 | } 39 | 40 | DictionaryNode files2Node = PListHelper.GetDictionaryValueFromPList(RootNode, "files2"); 41 | if (files2Node != null && files2Node.ContainsKey(fileName)) 42 | { 43 | DictionaryNode entryNode = new DictionaryNode(); 44 | entryNode.Add("hash", new DataNode(sha1Hash)); 45 | entryNode.Add("hash2", new DataNode(sha256Hash)); 46 | files2Node[fileName] = entryNode; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /IPALibrary/PListFiles/EntitlementsFile.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Security.Cryptography; 12 | using System.IO; 13 | using PListNet; 14 | 15 | namespace IPALibrary 16 | { 17 | public class EntitlementsFile : PListFile 18 | { 19 | public EntitlementsFile() 20 | { 21 | } 22 | 23 | public EntitlementsFile(PNode rootNode) 24 | { 25 | RootNode = rootNode; 26 | } 27 | 28 | public EntitlementsFile(byte[] entitlementsBytes) : base(entitlementsBytes) 29 | { 30 | } 31 | 32 | public string ApplicationIdentifier 33 | { 34 | get 35 | { 36 | return PListHelper.GetStringValueFromPList(RootNode, "application-identifier"); 37 | } 38 | } 39 | 40 | public string TeamIdentifier 41 | { 42 | get 43 | { 44 | return PListHelper.GetStringValueFromPList(RootNode, "com.apple.developer.team-identifier"); 45 | } 46 | } 47 | 48 | public string BundleIdentifier 49 | { 50 | get 51 | { 52 | string teamID = TeamIdentifier; 53 | string applicationID = ApplicationIdentifier; 54 | if (teamID != null && applicationID != null) 55 | { 56 | if (applicationID.StartsWith(teamID) && applicationID.Length > teamID.Length) 57 | { 58 | return applicationID.Substring(teamID.Length + 1); 59 | } 60 | } 61 | return null; 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /IPALibrary/PListFiles/InfoFile.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Security.Cryptography; 12 | using System.IO; 13 | using PListNet; 14 | using PListNet.Nodes; 15 | 16 | namespace IPALibrary 17 | { 18 | public class InfoFile : PListFile 19 | { 20 | public InfoFile(byte[] infoBytes) : base(infoBytes) 21 | { 22 | } 23 | 24 | public string ExecutableName 25 | { 26 | get 27 | { 28 | return PListHelper.GetStringValueFromPList(RootNode, "CFBundleExecutable"); 29 | } 30 | } 31 | 32 | public string BundleIdentifier 33 | { 34 | get 35 | { 36 | return PListHelper.GetStringValueFromPList(RootNode, "CFBundleIdentifier"); 37 | } 38 | set 39 | { 40 | if (RootNode is DictionaryNode) 41 | { 42 | StringNode stringNode = new StringNode(value); 43 | ((DictionaryNode)RootNode)["CFBundleIdentifier"] = stringNode; 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /IPALibrary/PListFiles/PListFile.cs: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2017 ROM Knowledgeware. All rights reserved. 2 | * 3 | * You can redistribute this program and/or modify it under the terms of 4 | * the GNU Lesser Public License as published by the Free Software Foundation, 5 | * either version 3 of the License, or (at your option) any later version. 6 | * 7 | * Maintainer: Tal Aloni 8 | */ 9 | using System; 10 | using System.Collections.Generic; 11 | using System.IO; 12 | using System.Text; 13 | using PListNet; 14 | using PListNet.Nodes; 15 | using Utilities; 16 | 17 | namespace IPALibrary 18 | { 19 | public class PListFile 20 | { 21 | private PListFormat m_format; 22 | public PNode RootNode; 23 | 24 | public PListFile() 25 | { 26 | } 27 | 28 | public PListFile(byte[] plistBytes) 29 | { 30 | m_format = PListHelper.DetectFormat(plistBytes); 31 | MemoryStream stream = new MemoryStream(plistBytes); 32 | RootNode = PList.Load(stream); 33 | } 34 | 35 | public byte[] GetBytes() 36 | { 37 | return GetBytes(m_format); 38 | } 39 | 40 | public byte[] GetBytes(PListFormat format) 41 | { 42 | MemoryStream result = new MemoryStream(); 43 | PList.Save(RootNode, result, format); 44 | if (format == PListFormat.Xml) 45 | { 46 | result.Position = 0; 47 | string xml = new StreamReader(result).ReadToEnd(); 48 | xml = RemoveUTF8BOM(xml); 49 | // iOS 10.3.3 Will crash the application if it's using '' instead of '' 50 | // in the entitlements file embedded in the executable. 51 | xml = xml.Replace(" />", "/>"); 52 | #if MAX_PLIST_COMPATIBILITY 53 | // Optional: Use exactly the same XML declaration and indentation as XCode 54 | const string DesiredXmlDeclaration = ""; 55 | if (xml.StartsWith(DesiredXmlDeclaration, StringComparison.OrdinalIgnoreCase)) 56 | { 57 | // PList produces by Apple have encoding set to "UTF-8" in uppercase letters. 58 | xml = DesiredXmlDeclaration + xml.Substring(DesiredXmlDeclaration.Length); 59 | } 60 | 61 | string[] lines = xml.Split('\n'); 62 | for(int index = 0; index < lines.Length; index++) 63 | { 64 | if (lines[index].StartsWith("\t")) 65 | { 66 | lines[index] = lines[index].Substring(1); 67 | } 68 | } 69 | xml = String.Join("\n", lines) + "\n"; 70 | #endif 71 | byte[] bytes = Encoding.UTF8.GetBytes(xml); 72 | return bytes; 73 | } 74 | return result.ToArray(); 75 | } 76 | 77 | public static string RemoveUTF8BOM(string text) 78 | { 79 | return text.TrimStart('\uFEFF'); // Remove Byte Order Mark 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /IPALibrary/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("IPALibrary")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("ROM Knowledgeware")] 12 | [assembly: AssemblyProduct("IPALibrary")] 13 | [assembly: AssemblyCopyright("Copyright © ROM Knowledgeware 2017-2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a71e4ce7-53c2-4371-9d74-2f5a7067c4b6")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.4.0")] 35 | [assembly: AssemblyFileVersion("1.0.4.0")] 36 | -------------------------------------------------------------------------------- /IPASign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ROM-Knowledgeware/IPASign/7cf1716ba29dd3a0fd8f5bc6155237b15305ca72/IPASign.png -------------------------------------------------------------------------------- /IPASign.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual Studio 2005 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPASign", "IPASign\IPASign.csproj", "{5C21815D-04CA-4F7C-886F-63E32E5DB754}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPALibrary", "IPALibrary\IPALibrary.csproj", "{F6143BA3-9C76-4C0A-87B9-98014CB02F26}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utilities", "Utilities\Utilities.csproj", "{D89261E5-9611-4A9E-8F23-31AE0BD196AC}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {5C21815D-04CA-4F7C-886F-63E32E5DB754}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {5C21815D-04CA-4F7C-886F-63E32E5DB754}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {5C21815D-04CA-4F7C-886F-63E32E5DB754}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {5C21815D-04CA-4F7C-886F-63E32E5DB754}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {F6143BA3-9C76-4C0A-87B9-98014CB02F26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {F6143BA3-9C76-4C0A-87B9-98014CB02F26}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {F6143BA3-9C76-4C0A-87B9-98014CB02F26}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {F6143BA3-9C76-4C0A-87B9-98014CB02F26}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {D89261E5-9611-4A9E-8F23-31AE0BD196AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {D89261E5-9611-4A9E-8F23-31AE0BD196AC}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {D89261E5-9611-4A9E-8F23-31AE0BD196AC}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {D89261E5-9611-4A9E-8F23-31AE0BD196AC}.Release|Any CPU.Build.0 = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /IPASign/Certificates/AppleIncRootCertificate.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ROM-Knowledgeware/IPASign/7cf1716ba29dd3a0fd8f5bc6155237b15305ca72/IPASign/Certificates/AppleIncRootCertificate.cer -------------------------------------------------------------------------------- /IPASign/Certificates/AppleWWDRCA.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ROM-Knowledgeware/IPASign/7cf1716ba29dd3a0fd8f5bc6155237b15305ca72/IPASign/Certificates/AppleWWDRCA.cer -------------------------------------------------------------------------------- /IPASign/IPASign.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Debug 4 | AnyCPU 5 | 8.0.50727 6 | 2.0 7 | {5C21815D-04CA-4F7C-886F-63E32E5DB754} 8 | WinExe 9 | Properties 10 | IPASign 11 | IPASign 12 | 13 | 14 | true 15 | full 16 | false 17 | bin\Debug\ 18 | DEBUG;TRACE 19 | prompt 20 | 4 21 | 22 | 23 | pdbonly 24 | true 25 | bin\Release\ 26 | TRACE 27 | prompt 28 | 4 29 | 30 | 31 | 32 | False 33 | ..\IPALibrary\Components\BouncyCastle.dll 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Form 45 | 46 | 47 | MainForm.cs 48 | 49 | 50 | 51 | 52 | Designer 53 | MainForm.cs 54 | 55 | 56 | ResXFileCodeGenerator 57 | Resources.Designer.cs 58 | Designer 59 | 60 | 61 | True 62 | Resources.resx 63 | 64 | 65 | Always 66 | 67 | 68 | Always 69 | 70 | 71 | SettingsSingleFileGenerator 72 | Settings.Designer.cs 73 | 74 | 75 | True 76 | Settings.settings 77 | True 78 | 79 | 80 | 81 | 82 | {F6143BA3-9C76-4C0A-87B9-98014CB02F26} 83 | IPALibrary 84 | 85 | 86 | {D89261E5-9611-4A9E-8F23-31AE0BD196AC} 87 | Utilities 88 | 89 | 90 | 91 | 98 | -------------------------------------------------------------------------------- /IPASign/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows.Forms; 4 | 5 | namespace IPASign 6 | { 7 | static class Program 8 | { 9 | /// 10 | /// The main entry point for the application. 11 | /// 12 | [STAThread] 13 | static void Main() 14 | { 15 | Application.EnableVisualStyles(); 16 | Application.SetCompatibleTextRenderingDefault(false); 17 | Application.Run(new MainForm()); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /IPASign/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("IPASign")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("ROM Knowledgeware")] 12 | [assembly: AssemblyProduct("IPASign")] 13 | [assembly: AssemblyCopyright("Copyright © ROM Knowledgeware 2017-2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("ee7655e3-9cb4-4e2f-b8ef-52ba2e4e5b76")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | [assembly: AssemblyVersion("1.0.4.0")] 33 | [assembly: AssemblyFileVersion("1.0.4.0")] 34 | -------------------------------------------------------------------------------- /IPASign/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:2.0.50727.3053 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace IPASign.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("IPASign.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /IPASign/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /IPASign/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:2.0.50727.3053 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace IPASign.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /IPASign/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | About IPASign: 2 | ========================== 3 | This library and tool were designed to update the provisioning profile inside an IPA file and update the file signature. 4 | This tool is an alternative to Apple's codesign. 5 | This tool can be used on Windows, Linux and etc. 6 | 7 | ![IPASign](IPASign.png) 8 | 9 | ##### Q: Where is the provisioning profile stored? 10 | The provisioning profile is stored as 'embedded.mobileprovision' in the IPA file. 11 | 12 | ##### Q: What is being signed? 13 | - The Mach-O executable (Identified by 'CFBundleExecutable' in Info.plist). 14 | - Info.plist 15 | - Code requirements expression. 16 | - Code entitlements plist. 17 | - The '_CodeSignature\CodeResource' file containing the file hashes (including 'embedded.mobileprovision'). 18 | 19 | ##### Q: Where is the signature stored? 20 | The CMS signature is stored as the last segment of the Mach-O executable (Identified by 'CFBundleExecutable' in Info.plist). 21 | 22 | Contact: 23 | ======== 24 | If you have any question, feel free to contact me. 25 | Tal Aloni 26 | -------------------------------------------------------------------------------- /Utilities/ByteUtils/BigEndianReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Utilities 5 | { 6 | public class BigEndianReader 7 | { 8 | public static short ReadInt16(byte[] buffer, ref int offset) 9 | { 10 | offset += 2; 11 | return BigEndianConverter.ToInt16(buffer, offset - 2); 12 | } 13 | 14 | public static ushort ReadUInt16(byte[] buffer, ref int offset) 15 | { 16 | offset += 2; 17 | return BigEndianConverter.ToUInt16(buffer, offset - 2); 18 | } 19 | 20 | public static uint ReadUInt24(byte[] buffer, int offset) 21 | { 22 | return (uint)((buffer[offset + 0] << 16) | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 0)); 23 | } 24 | 25 | public static uint ReadUInt24(byte[] buffer, ref int offset) 26 | { 27 | offset += 3; 28 | return ReadUInt24(buffer, offset - 3); 29 | } 30 | 31 | public static int ReadInt32(byte[] buffer, ref int offset) 32 | { 33 | offset += 4; 34 | return BigEndianConverter.ToInt32(buffer, offset - 4); 35 | } 36 | 37 | public static uint ReadUInt32(byte[] buffer, ref int offset) 38 | { 39 | offset += 4; 40 | return BigEndianConverter.ToUInt32(buffer, offset - 4); 41 | } 42 | 43 | public static long ReadInt64(byte[] buffer, ref int offset) 44 | { 45 | offset += 8; 46 | return BigEndianConverter.ToInt64(buffer, offset - 8); 47 | } 48 | 49 | public static ulong ReadUInt64(byte[] buffer, ref int offset) 50 | { 51 | offset += 8; 52 | return BigEndianConverter.ToUInt64(buffer, offset - 8); 53 | } 54 | 55 | public static Guid ReadGuidBytes(byte[] buffer, ref int offset) 56 | { 57 | offset += 16; 58 | return BigEndianConverter.ToGuid(buffer, offset - 16); 59 | } 60 | 61 | public static short ReadInt16(Stream stream) 62 | { 63 | byte[] buffer = new byte[2]; 64 | stream.Read(buffer, 0, 2); 65 | return BigEndianConverter.ToInt16(buffer, 0); 66 | } 67 | 68 | public static ushort ReadUInt16(Stream stream) 69 | { 70 | byte[] buffer = new byte[2]; 71 | stream.Read(buffer, 0, 2); 72 | return BigEndianConverter.ToUInt16(buffer, 0); 73 | } 74 | 75 | public static uint ReadUInt24(Stream stream) 76 | { 77 | byte[] buffer = new byte[4]; 78 | stream.Read(buffer, 1, 3); 79 | return BigEndianConverter.ToUInt32(buffer, 0); 80 | } 81 | 82 | public static int ReadInt32(Stream stream) 83 | { 84 | byte[] buffer = new byte[4]; 85 | stream.Read(buffer, 0, 4); 86 | return BigEndianConverter.ToInt32(buffer, 0); 87 | } 88 | 89 | public static uint ReadUInt32(Stream stream) 90 | { 91 | byte[] buffer = new byte[4]; 92 | stream.Read(buffer, 0, 4); 93 | return BigEndianConverter.ToUInt32(buffer, 0); 94 | } 95 | 96 | public static long ReadInt64(Stream stream) 97 | { 98 | byte[] buffer = new byte[8]; 99 | stream.Read(buffer, 0, 8); 100 | return BigEndianConverter.ToInt64(buffer, 0); 101 | } 102 | 103 | public static ulong ReadUInt64(Stream stream) 104 | { 105 | byte[] buffer = new byte[8]; 106 | stream.Read(buffer, 0, 8); 107 | return BigEndianConverter.ToUInt64(buffer, 0); 108 | } 109 | 110 | public static Guid ReadGuidBytes(Stream stream) 111 | { 112 | byte[] buffer = new byte[16]; 113 | stream.Read(buffer, 0, 16); 114 | return BigEndianConverter.ToGuid(buffer, 0); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Utilities/ByteUtils/BigEndianWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Utilities 5 | { 6 | public class BigEndianWriter 7 | { 8 | public static void WriteInt16(byte[] buffer, int offset, short value) 9 | { 10 | byte[] bytes = BigEndianConverter.GetBytes(value); 11 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 12 | } 13 | 14 | public static void WriteInt16(byte[] buffer, ref int offset, short value) 15 | { 16 | WriteInt16(buffer, offset, value); 17 | offset += 2; 18 | } 19 | 20 | public static void WriteUInt16(byte[] buffer, int offset, ushort value) 21 | { 22 | byte[] bytes = BigEndianConverter.GetBytes(value); 23 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 24 | } 25 | 26 | public static void WriteUInt16(byte[] buffer, ref int offset, ushort value) 27 | { 28 | WriteUInt16(buffer, offset, value); 29 | offset += 2; 30 | } 31 | 32 | public static void WriteUInt24(byte[] buffer, int offset, uint value) 33 | { 34 | byte[] bytes = BigEndianConverter.GetBytes(value); 35 | Array.Copy(bytes, 1, buffer, offset, 3); 36 | } 37 | 38 | public static void WriteUInt24(byte[] buffer, ref int offset, uint value) 39 | { 40 | WriteUInt24(buffer, offset, value); 41 | offset += 3; 42 | } 43 | 44 | public static void WriteInt32(byte[] buffer, int offset, int value) 45 | { 46 | byte[] bytes = BigEndianConverter.GetBytes(value); 47 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 48 | } 49 | 50 | public static void WriteInt32(byte[] buffer, ref int offset, int value) 51 | { 52 | WriteInt32(buffer, offset, value); 53 | offset += 4; 54 | } 55 | 56 | public static void WriteUInt32(byte[] buffer, int offset, uint value) 57 | { 58 | byte[] bytes = BigEndianConverter.GetBytes(value); 59 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 60 | } 61 | 62 | public static void WriteUInt32(byte[] buffer, ref int offset, uint value) 63 | { 64 | WriteUInt32(buffer, offset, value); 65 | offset += 4; 66 | } 67 | 68 | public static void WriteInt64(byte[] buffer, int offset, long value) 69 | { 70 | byte[] bytes = BigEndianConverter.GetBytes(value); 71 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 72 | } 73 | 74 | public static void WriteInt64(byte[] buffer, ref int offset, long value) 75 | { 76 | WriteInt64(buffer, offset, value); 77 | offset += 8; 78 | } 79 | 80 | public static void WriteUInt64(byte[] buffer, int offset, ulong value) 81 | { 82 | byte[] bytes = BigEndianConverter.GetBytes(value); 83 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 84 | } 85 | 86 | public static void WriteUInt64(byte[] buffer, ref int offset, ulong value) 87 | { 88 | WriteUInt64(buffer, offset, value); 89 | offset += 8; 90 | } 91 | 92 | public static void WriteGuidBytes(byte[] buffer, int offset, Guid value) 93 | { 94 | byte[] bytes = BigEndianConverter.GetBytes(value); 95 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 96 | } 97 | 98 | public static void WriteGuidBytes(byte[] buffer, ref int offset, Guid value) 99 | { 100 | WriteGuidBytes(buffer, offset, value); 101 | offset += 16; 102 | } 103 | 104 | public static void WriteInt16(Stream stream, short value) 105 | { 106 | byte[] bytes = BigEndianConverter.GetBytes(value); 107 | stream.Write(bytes, 0, bytes.Length); 108 | } 109 | 110 | public static void WriteUInt16(Stream stream, ushort value) 111 | { 112 | byte[] bytes = BigEndianConverter.GetBytes(value); 113 | stream.Write(bytes, 0, bytes.Length); 114 | } 115 | 116 | public static void WriteUInt24(Stream stream, uint value) 117 | { 118 | byte[] bytes = BigEndianConverter.GetBytes(value); 119 | stream.Write(bytes, 1, 3); 120 | } 121 | 122 | public static void WriteInt32(Stream stream, int value) 123 | { 124 | byte[] bytes = BigEndianConverter.GetBytes(value); 125 | stream.Write(bytes, 0, bytes.Length); 126 | } 127 | 128 | public static void WriteUInt32(Stream stream, uint value) 129 | { 130 | byte[] bytes = BigEndianConverter.GetBytes(value); 131 | stream.Write(bytes, 0, bytes.Length); 132 | } 133 | 134 | public static void WriteInt64(Stream stream, long value) 135 | { 136 | byte[] bytes = BigEndianConverter.GetBytes(value); 137 | stream.Write(bytes, 0, bytes.Length); 138 | } 139 | 140 | public static void WriteUInt64(Stream stream, ulong value) 141 | { 142 | byte[] bytes = BigEndianConverter.GetBytes(value); 143 | stream.Write(bytes, 0, bytes.Length); 144 | } 145 | 146 | public static void WriteGuidBytes(Stream stream, Guid value) 147 | { 148 | byte[] bytes = BigEndianConverter.GetBytes(value); 149 | stream.Write(bytes, 0, bytes.Length); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /Utilities/ByteUtils/ByteReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace Utilities 6 | { 7 | public class ByteReader 8 | { 9 | public static byte ReadByte(byte[] buffer, int offset) 10 | { 11 | return buffer[offset]; 12 | } 13 | 14 | public static byte ReadByte(byte[] buffer, ref int offset) 15 | { 16 | offset++; 17 | return buffer[offset - 1]; 18 | } 19 | 20 | public static byte[] ReadBytes(byte[] buffer, int offset, int length) 21 | { 22 | byte[] result = new byte[length]; 23 | Array.Copy(buffer, offset, result, 0, length); 24 | return result; 25 | } 26 | 27 | public static byte[] ReadBytes(byte[] buffer, ref int offset, int length) 28 | { 29 | offset += length; 30 | return ReadBytes(buffer, offset - length, length); 31 | } 32 | 33 | /// 34 | /// Will return the ANSI string stored in the buffer 35 | /// 36 | public static string ReadAnsiString(byte[] buffer, int offset, int count) 37 | { 38 | // ASCIIEncoding.ASCII.GetString will convert some values to '?' (byte value of 63) 39 | // Any codepage will do, but the only one that Mono supports is 28591. 40 | return ASCIIEncoding.GetEncoding(28591).GetString(buffer, offset, count); 41 | } 42 | 43 | public static string ReadAnsiString(byte[] buffer, ref int offset, int count) 44 | { 45 | offset += count; 46 | return ReadAnsiString(buffer, offset - count, count); 47 | } 48 | 49 | public static string ReadUTF16String(byte[] buffer, int offset, int numberOfCharacters) 50 | { 51 | int numberOfBytes = numberOfCharacters * 2; 52 | return Encoding.Unicode.GetString(buffer, offset, numberOfBytes); 53 | } 54 | 55 | public static string ReadUTF16String(byte[] buffer, ref int offset, int numberOfCharacters) 56 | { 57 | int numberOfBytes = numberOfCharacters * 2; 58 | offset += numberOfBytes; 59 | return ReadUTF16String(buffer, offset - numberOfBytes, numberOfCharacters); 60 | } 61 | 62 | public static string ReadNullTerminatedAnsiString(byte[] buffer, int offset) 63 | { 64 | StringBuilder builder = new StringBuilder(); 65 | char c = (char)ByteReader.ReadByte(buffer, offset); 66 | while (c != '\0') 67 | { 68 | builder.Append(c); 69 | offset++; 70 | c = (char)ByteReader.ReadByte(buffer, offset); 71 | } 72 | return builder.ToString(); 73 | } 74 | 75 | public static string ReadNullTerminatedUTF16String(byte[] buffer, int offset) 76 | { 77 | StringBuilder builder = new StringBuilder(); 78 | char c = (char)LittleEndianConverter.ToUInt16(buffer, offset); 79 | while (c != 0) 80 | { 81 | builder.Append(c); 82 | offset += 2; 83 | c = (char)LittleEndianConverter.ToUInt16(buffer, offset); 84 | } 85 | return builder.ToString(); 86 | } 87 | 88 | public static string ReadNullTerminatedAnsiString(byte[] buffer, ref int offset) 89 | { 90 | string result = ReadNullTerminatedAnsiString(buffer, offset); 91 | offset += result.Length + 1; 92 | return result; 93 | } 94 | 95 | public static string ReadNullTerminatedUTF16String(byte[] buffer, ref int offset) 96 | { 97 | string result = ReadNullTerminatedUTF16String(buffer, offset); 98 | offset += result.Length * 2 + 2; 99 | return result; 100 | } 101 | 102 | public static byte[] ReadBytes(Stream stream, int count) 103 | { 104 | MemoryStream temp = new MemoryStream(); 105 | ByteUtils.CopyStream(stream, temp, count); 106 | return temp.ToArray(); 107 | } 108 | 109 | /// 110 | /// Return all bytes from current stream position to the end of the stream 111 | /// 112 | public static byte[] ReadAllBytes(Stream stream) 113 | { 114 | MemoryStream temp = new MemoryStream(); 115 | ByteUtils.CopyStream(stream, temp); 116 | return temp.ToArray(); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Utilities/ByteUtils/ByteUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Utilities 5 | { 6 | public class ByteUtils 7 | { 8 | public static byte[] Concatenate(byte[] a, byte[] b) 9 | { 10 | byte[] result = new byte[a.Length + b.Length]; 11 | Array.Copy(a, 0, result, 0, a.Length); 12 | Array.Copy(b, 0, result, a.Length, b.Length); 13 | return result; 14 | } 15 | 16 | public static bool AreByteArraysEqual(byte[] array1, byte[] array2) 17 | { 18 | if (array1.Length != array2.Length) 19 | { 20 | return false; 21 | } 22 | 23 | for (int index = 0; index < array1.Length; index++) 24 | { 25 | if (array1[index] != array2[index]) 26 | { 27 | return false; 28 | } 29 | } 30 | 31 | return true; 32 | } 33 | 34 | public static byte[] XOR(byte[] array1, byte[] array2) 35 | { 36 | if (array1.Length == array2.Length) 37 | { 38 | return XOR(array1, 0, array2, 0, array1.Length); 39 | } 40 | else 41 | { 42 | throw new ArgumentException("Arrays must be of equal length"); 43 | } 44 | } 45 | 46 | public static byte[] XOR(byte[] array1, int offset1, byte[] array2, int offset2, int length) 47 | { 48 | if (offset1 + length <= array1.Length && offset2 + length <= array2.Length) 49 | { 50 | byte[] result = new byte[length]; 51 | for (int index = 0; index < length; index++) 52 | { 53 | result[index] = (byte)(array1[offset1 + index] ^ array2[offset2 + index]); 54 | } 55 | return result; 56 | } 57 | else 58 | { 59 | throw new ArgumentOutOfRangeException(); 60 | } 61 | } 62 | 63 | public static long CopyStream(Stream input, Stream output) 64 | { 65 | // input may not support seeking, so don't use input.Position 66 | return CopyStream(input, output, Int64.MaxValue); 67 | } 68 | 69 | public static long CopyStream(Stream input, Stream output, long count) 70 | { 71 | const int MaxBufferSize = 1048576; // 1 MB 72 | int bufferSize = (int)Math.Min(MaxBufferSize, count); 73 | byte[] buffer = new byte[bufferSize]; 74 | long totalBytesRead = 0; 75 | while (totalBytesRead < count) 76 | { 77 | int numberOfBytesToRead = (int)Math.Min(bufferSize, count - totalBytesRead); 78 | int bytesRead = input.Read(buffer, 0, numberOfBytesToRead); 79 | totalBytesRead += bytesRead; 80 | output.Write(buffer, 0, bytesRead); 81 | if (bytesRead == 0) // no more bytes to read from input stream 82 | { 83 | return totalBytesRead; 84 | } 85 | } 86 | return totalBytesRead; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Utilities/ByteUtils/ByteWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace Utilities 6 | { 7 | public class ByteWriter 8 | { 9 | public static void WriteByte(byte[] buffer, int offset, byte value) 10 | { 11 | buffer[offset] = value; 12 | } 13 | 14 | public static void WriteByte(byte[] buffer, ref int offset, byte value) 15 | { 16 | buffer[offset] = value; 17 | offset += 1; 18 | } 19 | 20 | public static void WriteBytes(byte[] buffer, int offset, byte[] bytes) 21 | { 22 | WriteBytes(buffer, offset, bytes, bytes.Length); 23 | } 24 | 25 | public static void WriteBytes(byte[] buffer, ref int offset, byte[] bytes) 26 | { 27 | WriteBytes(buffer, offset, bytes); 28 | offset += bytes.Length; 29 | } 30 | 31 | public static void WriteBytes(byte[] buffer, int offset, byte[] bytes, int length) 32 | { 33 | Array.Copy(bytes, 0, buffer, offset, length); 34 | } 35 | 36 | public static void WriteBytes(byte[] buffer, ref int offset, byte[] bytes, int length) 37 | { 38 | Array.Copy(bytes, 0, buffer, offset, length); 39 | offset += length; 40 | } 41 | 42 | public static void WriteAnsiString(byte[] buffer, int offset, string value) 43 | { 44 | WriteAnsiString(buffer, offset, value, value.Length); 45 | } 46 | 47 | public static void WriteAnsiString(byte[] buffer, ref int offset, string value) 48 | { 49 | WriteAnsiString(buffer, ref offset, value, value.Length); 50 | } 51 | 52 | public static void WriteAnsiString(byte[] buffer, int offset, string value, int maximumLength) 53 | { 54 | byte[] bytes = ASCIIEncoding.GetEncoding(28591).GetBytes(value); 55 | Array.Copy(bytes, 0, buffer, offset, Math.Min(value.Length, maximumLength)); 56 | } 57 | 58 | public static void WriteAnsiString(byte[] buffer, ref int offset, string value, int fieldLength) 59 | { 60 | WriteAnsiString(buffer, offset, value, fieldLength); 61 | offset += fieldLength; 62 | } 63 | 64 | public static void WriteUTF16String(byte[] buffer, int offset, string value) 65 | { 66 | WriteUTF16String(buffer, offset, value, value.Length); 67 | } 68 | 69 | public static void WriteUTF16String(byte[] buffer, ref int offset, string value) 70 | { 71 | WriteUTF16String(buffer, ref offset, value, value.Length); 72 | } 73 | 74 | public static void WriteUTF16String(byte[] buffer, int offset, string value, int maximumNumberOfCharacters) 75 | { 76 | byte[] bytes = UnicodeEncoding.Unicode.GetBytes(value); 77 | int maximumNumberOfBytes = Math.Min(value.Length, maximumNumberOfCharacters) * 2; 78 | Array.Copy(bytes, 0, buffer, offset, maximumNumberOfBytes); 79 | } 80 | 81 | public static void WriteUTF16String(byte[] buffer, ref int offset, string value, int numberOfCharacters) 82 | { 83 | WriteUTF16String(buffer, offset, value, numberOfCharacters); 84 | offset += numberOfCharacters * 2; 85 | } 86 | 87 | public static void WriteNullTerminatedAnsiString(byte[] buffer, int offset, string value) 88 | { 89 | WriteAnsiString(buffer, offset, value); 90 | WriteByte(buffer, offset + value.Length, 0x00); 91 | } 92 | 93 | public static void WriteNullTerminatedAnsiString(byte[] buffer, ref int offset, string value) 94 | { 95 | WriteNullTerminatedAnsiString(buffer, offset, value); 96 | offset += value.Length + 1; 97 | } 98 | 99 | public static void WriteNullTerminatedUTF16String(byte[] buffer, int offset, string value) 100 | { 101 | WriteUTF16String(buffer, offset, value); 102 | WriteBytes(buffer, offset + value.Length * 2, new byte[] { 0x00, 0x00 }); 103 | } 104 | 105 | public static void WriteNullTerminatedUTF16String(byte[] buffer, ref int offset, string value) 106 | { 107 | WriteNullTerminatedUTF16String(buffer, offset, value); 108 | offset += value.Length * 2 + 2; 109 | } 110 | 111 | public static void WriteBytes(Stream stream, byte[] bytes) 112 | { 113 | stream.Write(bytes, 0, bytes.Length); 114 | } 115 | 116 | public static void WriteBytes(Stream stream, byte[] bytes, int count) 117 | { 118 | stream.Write(bytes, 0, count); 119 | } 120 | 121 | public static void WriteAnsiString(Stream stream, string value) 122 | { 123 | WriteAnsiString(stream, value, value.Length); 124 | } 125 | 126 | public static void WriteAnsiString(Stream stream, string value, int fieldLength) 127 | { 128 | byte[] bytes = ASCIIEncoding.GetEncoding(28591).GetBytes(value); 129 | stream.Write(bytes, 0, Math.Min(bytes.Length, fieldLength)); 130 | if (bytes.Length < fieldLength) 131 | { 132 | byte[] zeroFill = new byte[fieldLength - bytes.Length]; 133 | stream.Write(zeroFill, 0, zeroFill.Length); 134 | } 135 | } 136 | 137 | public static void WriteUTF16String(Stream stream, string value) 138 | { 139 | byte[] bytes = UnicodeEncoding.Unicode.GetBytes(value); 140 | stream.Write(bytes, 0, bytes.Length); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Utilities/ByteUtils/LittleEndianReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Utilities 5 | { 6 | public class LittleEndianReader 7 | { 8 | public static short ReadInt16(byte[] buffer, ref int offset) 9 | { 10 | offset += 2; 11 | return LittleEndianConverter.ToInt16(buffer, offset - 2); 12 | } 13 | 14 | public static ushort ReadUInt16(byte[] buffer, ref int offset) 15 | { 16 | offset += 2; 17 | return LittleEndianConverter.ToUInt16(buffer, offset - 2); 18 | } 19 | 20 | public static int ReadInt32(byte[] buffer, ref int offset) 21 | { 22 | offset += 4; 23 | return LittleEndianConverter.ToInt32(buffer, offset - 4); 24 | } 25 | 26 | public static uint ReadUInt32(byte[] buffer, ref int offset) 27 | { 28 | offset += 4; 29 | return LittleEndianConverter.ToUInt32(buffer, offset - 4); 30 | } 31 | 32 | public static long ReadInt64(byte[] buffer, ref int offset) 33 | { 34 | offset += 8; 35 | return LittleEndianConverter.ToInt64(buffer, offset - 8); 36 | } 37 | 38 | public static ulong ReadUInt64(byte[] buffer, ref int offset) 39 | { 40 | offset += 8; 41 | return LittleEndianConverter.ToUInt64(buffer, offset - 8); 42 | } 43 | 44 | public static Guid ReadGuid(byte[] buffer, ref int offset) 45 | { 46 | offset += 16; 47 | return LittleEndianConverter.ToGuid(buffer, offset - 16); 48 | } 49 | 50 | public static short ReadInt16(Stream stream) 51 | { 52 | byte[] buffer = new byte[2]; 53 | stream.Read(buffer, 0, 2); 54 | return LittleEndianConverter.ToInt16(buffer, 0); 55 | } 56 | 57 | public static ushort ReadUInt16(Stream stream) 58 | { 59 | byte[] buffer = new byte[2]; 60 | stream.Read(buffer, 0, 2); 61 | return LittleEndianConverter.ToUInt16(buffer, 0); 62 | } 63 | 64 | public static int ReadInt32(Stream stream) 65 | { 66 | byte[] buffer = new byte[4]; 67 | stream.Read(buffer, 0, 4); 68 | return LittleEndianConverter.ToInt32(buffer, 0); 69 | } 70 | 71 | public static uint ReadUInt32(Stream stream) 72 | { 73 | byte[] buffer = new byte[4]; 74 | stream.Read(buffer, 0, 4); 75 | return LittleEndianConverter.ToUInt32(buffer, 0); 76 | } 77 | 78 | public static long ReadInt64(Stream stream) 79 | { 80 | byte[] buffer = new byte[8]; 81 | stream.Read(buffer, 0, 8); 82 | return LittleEndianConverter.ToInt64(buffer, 0); 83 | } 84 | 85 | public static ulong ReadUInt64(Stream stream) 86 | { 87 | byte[] buffer = new byte[8]; 88 | stream.Read(buffer, 0, 8); 89 | return LittleEndianConverter.ToUInt64(buffer, 0); 90 | } 91 | 92 | public static Guid ReadGuidBytes(Stream stream) 93 | { 94 | byte[] buffer = new byte[16]; 95 | stream.Read(buffer, 0, 16); 96 | return LittleEndianConverter.ToGuid(buffer, 0); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Utilities/ByteUtils/LittleEndianWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Utilities 5 | { 6 | public class LittleEndianWriter 7 | { 8 | public static void WriteUInt16(byte[] buffer, int offset, ushort value) 9 | { 10 | byte[] bytes = LittleEndianConverter.GetBytes(value); 11 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 12 | } 13 | 14 | public static void WriteUInt16(byte[] buffer, ref int offset, ushort value) 15 | { 16 | WriteUInt16(buffer, offset, value); 17 | offset += 2; 18 | } 19 | 20 | public static void WriteInt16(byte[] buffer, int offset, short value) 21 | { 22 | byte[] bytes = LittleEndianConverter.GetBytes(value); 23 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 24 | } 25 | 26 | public static void WriteInt16(byte[] buffer, ref int offset, short value) 27 | { 28 | WriteInt16(buffer, offset, value); 29 | offset += 2; 30 | } 31 | 32 | public static void WriteUInt32(byte[] buffer, int offset, uint value) 33 | { 34 | byte[] bytes = LittleEndianConverter.GetBytes(value); 35 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 36 | } 37 | 38 | public static void WriteUInt32(byte[] buffer, ref int offset, uint value) 39 | { 40 | WriteUInt32(buffer, offset, value); 41 | offset += 4; 42 | } 43 | 44 | public static void WriteInt32(byte[] buffer, int offset, int value) 45 | { 46 | byte[] bytes = LittleEndianConverter.GetBytes(value); 47 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 48 | } 49 | 50 | public static void WriteInt32(byte[] buffer, ref int offset, int value) 51 | { 52 | WriteInt32(buffer, offset, value); 53 | offset += 4; 54 | } 55 | 56 | public static void WriteUInt64(byte[] buffer, int offset, ulong value) 57 | { 58 | byte[] bytes = LittleEndianConverter.GetBytes(value); 59 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 60 | } 61 | 62 | public static void WriteUInt64(byte[] buffer, ref int offset, ulong value) 63 | { 64 | WriteUInt64(buffer, offset, value); 65 | offset += 8; 66 | } 67 | 68 | public static void WriteInt64(byte[] buffer, int offset, long value) 69 | { 70 | byte[] bytes = LittleEndianConverter.GetBytes(value); 71 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 72 | } 73 | 74 | public static void WriteInt64(byte[] buffer, ref int offset, long value) 75 | { 76 | WriteInt64(buffer, offset, value); 77 | offset += 8; 78 | } 79 | 80 | public static void WriteGuidBytes(byte[] buffer, int offset, Guid value) 81 | { 82 | byte[] bytes = LittleEndianConverter.GetBytes(value); 83 | Array.Copy(bytes, 0, buffer, offset, bytes.Length); 84 | } 85 | 86 | public static void WriteGuidBytes(byte[] buffer, ref int offset, Guid value) 87 | { 88 | WriteGuidBytes(buffer, offset, value); 89 | offset += 16; 90 | } 91 | 92 | public static void WriteUInt16(Stream stream, ushort value) 93 | { 94 | byte[] bytes = LittleEndianConverter.GetBytes(value); 95 | stream.Write(bytes, 0, bytes.Length); 96 | } 97 | 98 | public static void WriteInt32(Stream stream, int value) 99 | { 100 | byte[] bytes = LittleEndianConverter.GetBytes(value); 101 | stream.Write(bytes, 0, bytes.Length); 102 | } 103 | 104 | public static void WriteUInt32(Stream stream, uint value) 105 | { 106 | byte[] bytes = LittleEndianConverter.GetBytes(value); 107 | stream.Write(bytes, 0, bytes.Length); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Utilities/Comparers/ReverseComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Utilities 5 | { 6 | public class ReverseComparer : IComparer 7 | { 8 | private IComparer m_comparer; 9 | 10 | public ReverseComparer(IComparer comparer) 11 | { 12 | m_comparer = comparer; 13 | } 14 | 15 | public int Compare(T x, T y) 16 | { 17 | return m_comparer.Compare(y, x); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Utilities/Conversion/BigEndianConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Utilities 5 | { 6 | public class BigEndianConverter 7 | { 8 | public static ushort ToUInt16(byte[] buffer, int offset) 9 | { 10 | return (ushort)((buffer[offset + 0] << 8) | (buffer[offset + 1] << 0)); 11 | } 12 | 13 | public static short ToInt16(byte[] buffer, int offset) 14 | { 15 | return (short)ToUInt16(buffer, offset); 16 | } 17 | 18 | public static uint ToUInt32(byte[] buffer, int offset) 19 | { 20 | return (uint)((buffer[offset + 0] << 24) | (buffer[offset + 1] << 16) 21 | | (buffer[offset + 2] << 8) | (buffer[offset + 3] << 0)); 22 | } 23 | 24 | public static int ToInt32(byte[] buffer, int offset) 25 | { 26 | return (int)ToUInt32(buffer, offset); 27 | } 28 | 29 | public static ulong ToUInt64(byte[] buffer, int offset) 30 | { 31 | return (((ulong)ToUInt32(buffer, offset + 0)) << 32) | ToUInt32(buffer, offset + 4); 32 | } 33 | 34 | public static long ToInt64(byte[] buffer, int offset) 35 | { 36 | return (long)ToUInt64(buffer, offset); 37 | } 38 | 39 | public static Guid ToGuid(byte[] buffer, int offset) 40 | { 41 | return new Guid( 42 | ToUInt32(buffer, offset + 0), 43 | ToUInt16(buffer, offset + 4), 44 | ToUInt16(buffer, offset + 6), 45 | buffer[offset + 8], 46 | buffer[offset + 9], 47 | buffer[offset + 10], 48 | buffer[offset + 11], 49 | buffer[offset + 12], 50 | buffer[offset + 13], 51 | buffer[offset + 14], 52 | buffer[offset + 15]); 53 | } 54 | 55 | public static byte[] GetBytes(ushort value) 56 | { 57 | byte[] result = new byte[2]; 58 | result[0] = (byte)((value >> 8) & 0xFF); 59 | result[1] = (byte)((value >> 0) & 0xFF); 60 | return result; 61 | } 62 | 63 | public static byte[] GetBytes(short value) 64 | { 65 | return GetBytes((ushort)value); 66 | } 67 | 68 | public static byte[] GetBytes(uint value) 69 | { 70 | byte[] result = new byte[4]; 71 | result[0] = (byte)((value >> 24) & 0xFF); 72 | result[1] = (byte)((value >> 16) & 0xFF); 73 | result[2] = (byte)((value >> 8) & 0xFF); 74 | result[3] = (byte)((value >> 0) & 0xFF); 75 | 76 | return result; 77 | } 78 | 79 | public static byte[] GetBytes(int value) 80 | { 81 | return GetBytes((uint)value); 82 | } 83 | 84 | public static byte[] GetBytes(ulong value) 85 | { 86 | byte[] result = new byte[8]; 87 | Array.Copy(GetBytes((uint)(value >> 32)), 0, result, 0, 4); 88 | Array.Copy(GetBytes((uint)(value & 0xFFFFFFFF)), 0, result, 4, 4); 89 | 90 | return result; 91 | } 92 | 93 | public static byte[] GetBytes(long value) 94 | { 95 | return GetBytes((ulong)value); 96 | } 97 | 98 | public static byte[] GetBytes(Guid value) 99 | { 100 | byte[] result = value.ToByteArray(); 101 | if (BitConverter.IsLittleEndian) 102 | { 103 | // reverse first 4 bytes 104 | byte temp = result[0]; 105 | result[0] = result[3]; 106 | result[3] = temp; 107 | 108 | temp = result[1]; 109 | result[1] = result[2]; 110 | result[2] = temp; 111 | 112 | // reverse next 2 bytes 113 | temp = result[4]; 114 | result[4] = result[5]; 115 | result[5] = temp; 116 | 117 | // reverse next 2 bytes 118 | temp = result[6]; 119 | result[6] = result[7]; 120 | result[7] = temp; 121 | } 122 | return result; 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /Utilities/Conversion/LittleEndianConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Utilities 5 | { 6 | public class LittleEndianConverter 7 | { 8 | public static ushort ToUInt16(byte[] buffer, int offset) 9 | { 10 | return (ushort)((buffer[offset + 1] << 8) | (buffer[offset + 0] << 0)); 11 | } 12 | 13 | public static short ToInt16(byte[] buffer, int offset) 14 | { 15 | return (short)ToUInt16(buffer, offset); 16 | } 17 | 18 | public static uint ToUInt32(byte[] buffer, int offset) 19 | { 20 | return (uint)((buffer[offset + 3] << 24) | (buffer[offset + 2] << 16) 21 | | (buffer[offset + 1] << 8) | (buffer[offset + 0] << 0)); 22 | } 23 | 24 | public static int ToInt32(byte[] buffer, int offset) 25 | { 26 | return (int)ToUInt32(buffer, offset); 27 | } 28 | 29 | public static ulong ToUInt64(byte[] buffer, int offset) 30 | { 31 | return (((ulong)ToUInt32(buffer, offset + 4)) << 32) | ToUInt32(buffer, offset + 0); 32 | } 33 | 34 | public static long ToInt64(byte[] buffer, int offset) 35 | { 36 | return (long)ToUInt64(buffer, offset); 37 | } 38 | 39 | public static float ToFloat32(byte[] buffer, int offset) 40 | { 41 | byte[] bytes = new byte[4]; 42 | Array.Copy(buffer, offset, bytes, 0, 4); 43 | if (!BitConverter.IsLittleEndian) 44 | { 45 | // reverse the order of 'bytes' 46 | for (int index = 0; index < 2; index++) 47 | { 48 | byte temp = bytes[index]; 49 | bytes[index] = bytes[3 - index]; 50 | bytes[3 - index] = temp; 51 | } 52 | } 53 | return BitConverter.ToSingle(bytes, 0); 54 | } 55 | 56 | public static double ToFloat64(byte[] buffer, int offset) 57 | { 58 | byte[] bytes = new byte[8]; 59 | Array.Copy(buffer, offset, bytes, 0, 8); 60 | if (!BitConverter.IsLittleEndian) 61 | { 62 | // reverse the order of 'bytes' 63 | for(int index = 0; index < 4; index++) 64 | { 65 | byte temp = bytes[index]; 66 | bytes[index] = bytes[7 - index]; 67 | bytes[7 - index] = temp; 68 | } 69 | } 70 | return BitConverter.ToDouble(bytes, 0); 71 | } 72 | 73 | public static Guid ToGuid(byte[] buffer, int offset) 74 | { 75 | return new Guid( 76 | ToUInt32(buffer, offset + 0), 77 | ToUInt16(buffer, offset + 4), 78 | ToUInt16(buffer, offset + 6), 79 | buffer[offset + 8], 80 | buffer[offset + 9], 81 | buffer[offset + 10], 82 | buffer[offset + 11], 83 | buffer[offset + 12], 84 | buffer[offset + 13], 85 | buffer[offset + 14], 86 | buffer[offset + 15]); 87 | } 88 | 89 | public static byte[] GetBytes(ushort value) 90 | { 91 | byte[] result = new byte[2]; 92 | result[0] = (byte)((value >> 0) & 0xFF); 93 | result[1] = (byte)((value >> 8) & 0xFF); 94 | return result; 95 | } 96 | 97 | public static byte[] GetBytes(short value) 98 | { 99 | return GetBytes((ushort)value); 100 | } 101 | 102 | public static byte[] GetBytes(uint value) 103 | { 104 | byte[] result = new byte[4]; 105 | result[0] = (byte)((value >> 0) & 0xFF); 106 | result[1] = (byte)((value >> 8) & 0xFF); 107 | result[2] = (byte)((value >> 16) & 0xFF); 108 | result[3] = (byte)((value >> 24) & 0xFF); 109 | 110 | return result; 111 | } 112 | 113 | public static byte[] GetBytes(int value) 114 | { 115 | return GetBytes((uint)value); 116 | } 117 | 118 | public static byte[] GetBytes(ulong value) 119 | { 120 | byte[] result = new byte[8]; 121 | Array.Copy(GetBytes((uint)(value & 0xFFFFFFFF)), 0, result, 0, 4); 122 | Array.Copy(GetBytes((uint)(value >> 32)), 0, result, 4, 4); 123 | 124 | return result; 125 | } 126 | 127 | public static byte[] GetBytes(long value) 128 | { 129 | return GetBytes((ulong)value); 130 | } 131 | 132 | public static byte[] GetBytes(Guid value) 133 | { 134 | byte[] result = value.ToByteArray(); 135 | if (!BitConverter.IsLittleEndian) 136 | { 137 | // reverse first 4 bytes 138 | byte temp = result[0]; 139 | result[0] = result[3]; 140 | result[3] = temp; 141 | 142 | temp = result[1]; 143 | result[1] = result[2]; 144 | result[2] = temp; 145 | 146 | // reverse next 2 bytes 147 | temp = result[4]; 148 | result[4] = result[5]; 149 | result[5] = temp; 150 | 151 | // reverse next 2 bytes 152 | temp = result[6]; 153 | result[6] = result[7]; 154 | result[7] = temp; 155 | } 156 | return result; 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /Utilities/Generics/KeyValuePairList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | 5 | namespace Utilities 6 | { 7 | public partial class KeyValuePairList : List> 8 | { 9 | public bool ContainsKey(TKey key) 10 | { 11 | return (this.IndexOfKey(key) != -1); 12 | } 13 | 14 | public int IndexOfKey(TKey key) 15 | { 16 | for (int index = 0; index < this.Count; index++) 17 | { 18 | if (this[index].Key.Equals(key)) 19 | { 20 | return index; 21 | } 22 | } 23 | 24 | return -1; 25 | } 26 | 27 | public TValue ValueOf(TKey key) 28 | { 29 | for (int index = 0; index < this.Count; index++) 30 | { 31 | if (this[index].Key.Equals(key)) 32 | { 33 | return this[index].Value; 34 | } 35 | } 36 | 37 | return default(TValue); 38 | } 39 | 40 | public void Add(TKey key, TValue value) 41 | { 42 | this.Add(new KeyValuePair(key, value)); 43 | } 44 | 45 | public List Keys 46 | { 47 | get 48 | { 49 | List result = new List(); 50 | foreach (KeyValuePair entity in this) 51 | { 52 | result.Add(entity.Key); 53 | } 54 | return result; 55 | } 56 | } 57 | 58 | public List Values 59 | { 60 | get 61 | { 62 | List result = new List(); 63 | foreach (KeyValuePair entity in this) 64 | { 65 | result.Add(entity.Value); 66 | } 67 | return result; 68 | } 69 | } 70 | 71 | new public void Sort() 72 | { 73 | this.Sort(Comparer.Default); 74 | } 75 | 76 | public void Sort(ListSortDirection sortDirection) 77 | { 78 | Sort(Comparer.Default, sortDirection); 79 | } 80 | 81 | public void Sort(IComparer comparer, ListSortDirection sortDirection) 82 | { 83 | if (sortDirection == ListSortDirection.Ascending) 84 | { 85 | Sort(comparer); 86 | } 87 | else 88 | { 89 | Sort(new ReverseComparer(comparer)); 90 | } 91 | } 92 | 93 | public void Sort(IComparer comparer) 94 | { 95 | this.Sort(delegate(KeyValuePair a, KeyValuePair b) 96 | { 97 | return comparer.Compare(a.Key, b.Key); 98 | }); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Utilities/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Utilities")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("ROM Knowledgeware")] 12 | [assembly: AssemblyProduct("Utilities")] 13 | [assembly: AssemblyCopyright("Copyright © ROM Knowledgeware 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("fc4d7cf1-d23c-4112-a9aa-1d0956d52927")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Utilities/Utilities.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Debug 4 | AnyCPU 5 | 8.0.50727 6 | 2.0 7 | {D89261E5-9611-4A9E-8F23-31AE0BD196AC} 8 | Library 9 | Properties 10 | Utilities 11 | Utilities 12 | 13 | 14 | true 15 | full 16 | false 17 | bin\Debug\ 18 | DEBUG;TRACE 19 | prompt 20 | 4 21 | 22 | 23 | pdbonly 24 | true 25 | bin\Release\ 26 | TRACE 27 | prompt 28 | 4 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 58 | --------------------------------------------------------------------------------