UNPKG

rms-runtime-mobile-security

Version:

Runtime Mobile Security (RMS), powered by FRIDA, is a powerful web interface that helps you to manipulate Android and iOS Apps at Runtime

255 lines (223 loc) 8.05 kB
/************************************************************************ * Name: Dump Keychain * OS: iOS * Author: @chaitin * Source: https://github.com/chaitin/passionfruit *************************************************************************/ function constantLookup(v) { if(v in kSecConstantReverse) { return kSecConstantReverse[v]; } else { return v; } } function odas(raw) { try { const data = new ObjC.Object(raw) return ptr(data.bytes()).readUtf8String(data.length()) } catch (_) { try { return raw.toString() } catch (__) { return '' } } } function decodeOd(item, flags) { const constraints = item const constraintEnumerator = constraints.keyEnumerator() var constraintKey; for (constraintKey = 0; constraintKey !== null; constraintEnumerator.nextObject()) { switch (odas(constraintKey)) { case 'cpo': flags.push('kSecAccessControlUserPresence') break case 'cup': flags.push('kSecAccessControlDevicePasscode') break case 'pkofn': flags.push(constraints.objectForKey_('pkofn') === 1 ? 'Or' : 'And') break case 'cbio': flags.push(constraints.objectForKey_('cbio').count() === 1 ? 'kSecAccessControlTouchIDAny' : 'kSecAccessControlTouchIDCurrentSet') break default: break } } } function decodeAcl(entry,SecAccessControlGetConstraints) { // No access control? Move along. if (!entry.containsKey_(kSecAttrAccessControl)) return [] const constraints = SecAccessControlGetConstraints(entry.objectForKey_(kSecAttrAccessControl)) if (constraints.isNull()) return [] const accessControls = ObjC.Object(constraints) const flags = [] const enumerator = accessControls.keyEnumerator() var key; for (key = enumerator.nextObject(); key !== null; key = enumerator.nextObject()) { const item = accessControls.objectForKey_(key) switch (odas(key)) { case 'dacl': break case 'osgn': flags.push('PrivateKeyUsage') case 'od': decodeOd(item, flags) break case 'prp': flags.push('ApplicationPassword') break default: break } } return flags } const kSecReturnAttributes = 'r_Attributes', kSecReturnData = 'r_Data', kSecReturnRef = 'r_Ref', kSecMatchLimit = 'm_Limit', kSecMatchLimitAll = 'm_LimitAll', kSecClass = 'class', kSecClassKey = 'keys', kSecClassIdentity = 'idnt', kSecClassCertificate = 'cert', kSecClassGenericPassword = 'genp', kSecClassInternetPassword = 'inet', kSecAttrService = 'svce', kSecAttrAccount = 'acct', kSecAttrAccessGroup = 'agrp', kSecAttrLabel = 'labl', kSecAttrCreationDate = 'cdat', kSecAttrAccessControl = 'accc', kSecAttrGeneric = 'gena', kSecAttrSynchronizable = 'sync', kSecAttrModificationDate = 'mdat', kSecAttrServer = 'srvr', kSecAttrDescription = 'desc', kSecAttrComment = 'icmt', kSecAttrCreator = 'crtr', kSecAttrType = 'type', kSecAttrScriptCode = 'scrp', kSecAttrAlias = 'alis', kSecAttrIsInvisible = 'invi', kSecAttrIsNegative = 'nega', kSecAttrHasCustomIcon = 'cusi', kSecProtectedDataItemAttr = 'prot', kSecAttrAccessible = 'pdmn', kSecAttrAccessibleWhenUnlocked = 'ak', kSecAttrAccessibleAfterFirstUnlock = 'ck', kSecAttrAccessibleAlways = 'dk', kSecAttrAccessibleWhenUnlockedThisDeviceOnly = 'aku', kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly = 'cku', kSecAttrAccessibleAlwaysThisDeviceOnly = 'dku' const kSecConstantReverse = { r_Attributes: 'kSecReturnAttributes', r_Data: 'kSecReturnData', r_Ref: 'kSecReturnRef', m_Limit: 'kSecMatchLimit', m_LimitAll: 'kSecMatchLimitAll', class: 'kSecClass', keys: 'kSecClassKey', idnt: 'kSecClassIdentity', cert: 'kSecClassCertificate', genp: 'kSecClassGenericPassword', inet: 'kSecClassInternetPassword', svce: 'kSecAttrService', acct: 'kSecAttrAccount', agrp: 'kSecAttrAccessGroup', labl: 'kSecAttrLabel', srvr: 'kSecAttrServer', cdat: 'kSecAttrCreationDate', accc: 'kSecAttrAccessControl', gena: 'kSecAttrGeneric', sync: 'kSecAttrSynchronizable', mdat: 'kSecAttrModificationDate', desc: 'kSecAttrDescription', icmt: 'kSecAttrComment', crtr: 'kSecAttrCreator', type: 'kSecAttrType', scrp: 'kSecAttrScriptCode', alis: 'kSecAttrAlias', invi: 'kSecAttrIsInvisible', nega: 'kSecAttrIsNegative', cusi: 'kSecAttrHasCustomIcon', prot: 'kSecProtectedDataItemAttr', pdmn: 'kSecAttrAccessible', ak: 'kSecAttrAccessibleWhenUnlocked', ck: 'kSecAttrAccessibleAfterFirstUnlock', dk: 'kSecAttrAccessibleAlways', aku: 'kSecAttrAccessibleWhenUnlockedThisDeviceOnly', cku: 'kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly', dku: 'kSecAttrAccessibleAlwaysThisDeviceOnly' } const kSecClasses = [ kSecClassKey,kSecClassIdentity,kSecClassCertificate, kSecClassGenericPassword,kSecClassInternetPassword ]; const NSMutableDictionary = ObjC.classes.NSMutableDictionary var securityMod = Process.getModuleByName('Security'); const SecItemCopyMatching = new NativeFunction(ptr(securityMod.findExportByName('SecItemCopyMatching')), 'pointer', ['pointer', 'pointer']) const SecItemDelete = new NativeFunction(ptr(securityMod.findExportByName('SecItemDelete')), 'pointer', ['pointer']) const SecAccessControlGetConstraints = new NativeFunction( ptr(securityMod.findExportByName('SecAccessControlGetConstraints')), 'pointer', ['pointer'] ) const NSCFBoolean = ObjC.classes.__NSCFBoolean const kCFBooleanTrue = NSCFBoolean.numberWithBool_(true) const result = [] const query = NSMutableDictionary.alloc().init() query.setObject_forKey_(kCFBooleanTrue, kSecReturnAttributes) query.setObject_forKey_(kCFBooleanTrue, kSecReturnData) query.setObject_forKey_(kCFBooleanTrue, kSecReturnRef) query.setObject_forKey_(kSecMatchLimitAll, kSecMatchLimit) kSecClasses.forEach(function(clazz) { query.setObject_forKey_(clazz, kSecClass) const p = Memory.alloc(Process.pointerSize) const status = SecItemCopyMatching(query, p) /* eslint eqeqeq: 0 */ if (status != 0x00) return const arr = new ObjC.Object(p.readPointer()) var i,size; for (i = 0, size = arr.count(); i < size; i++) { const item = arr.objectAtIndex_(i) result.push({ clazz: constantLookup(clazz), creation: odas(item.objectForKey_(kSecAttrCreationDate)), modification: odas(item.objectForKey_(kSecAttrModificationDate)), description: odas(item.objectForKey_(kSecAttrDescription)), comment: odas(item.objectForKey_(kSecAttrComment)), creator: odas(item.objectForKey_(kSecAttrCreator)), type: odas(item.objectForKey_(kSecAttrType)), scriptCode: odas(item.objectForKey_(kSecAttrScriptCode)), alias: odas(item.objectForKey_(kSecAttrAlias)), invisible: odas(item.objectForKey_(kSecAttrIsInvisible)), negative: odas(item.objectForKey_(kSecAttrIsNegative)), customIcon: odas(item.objectForKey_(kSecAttrHasCustomIcon)), protected: odas(item.objectForKey_(kSecProtectedDataItemAttr)), accessControl: decodeAcl(item,SecAccessControlGetConstraints).join(' '), accessibleAttribute: constantLookup(odas(item.objectForKey_(kSecAttrAccessible))), entitlementGroup: odas(item.objectForKey_(kSecAttrAccessGroup)), generic: odas(item.objectForKey_(kSecAttrGeneric)), service: odas(item.objectForKey_(kSecAttrService)), account: odas(item.objectForKey_(kSecAttrAccount)), label: odas(item.objectForKey_(kSecAttrLabel)), data: odas(item.objectForKey_('v_Data')) }) } }); send("**** KEYCHAIN DUMP ****"); var j,k,currentEntry; for(k in result) { send("\tEntry " + k); currentEntry = result[k]; for(j in currentEntry) { if(currentEntry[j]) { send("\t\t" + j + ": " + currentEntry[j]); } } } send("**** END KEYCHAIN DUMP ****");