The snippet below shows sample code that performs virtual device indicator checks and reports the queried values and indicator results. See Virtual Devices Detection for more information about common virtual device checks and values.
The checks query device properties and Apple Metal GPU availability as generic virtual device indicators, and also check for a specific Corellium virtualization artifact.
Note
The sample avoids NFC and Bluetooth checks because they can require additional entitlements, usage descriptions, or user-controlled state, which would make the demo less deterministic.
Note
The sample avoids App Attest checks because they require server-side validation, which breaks the self-contained requirement for MASTG demos.
importFoundationimportMetalimportDarwinstructMastgTest{//SUMMARY:ThissampledemonstratesiOSvirtualdevicedetectionbyexecutingvirtualdeviceindicatorchecksandreportingafinalverdictintheUI.staticfuncmastgTest(completion:@escaping(String)->Void){completion(VirtualDeviceDetector().run())}}privateenumIndicatorLevel{caseexpectedcasesuspiciouscaseconfirmedcaseinconclusivevarlabel:String{switchself{case.expected:return"expected"case.suspicious:return"suspicious"case.confirmed:return"confirmed"case.inconclusive:return"inconclusive"}}}privatestructIndicatorResult{letorder:Intletname:Stringletobserved:Stringletlevel:IndicatorLevelletreason:String}privatestructVirtualDeviceDetector{funcrun()->String{letmachineIdentifier=currentMachineIdentifier()letresults=[machineIndicator(for:machineIdentifier),metalIndicator(),corelliumIndicator()]returnbuildReport(from:results)}privatefuncmachineIndicator(formachineIdentifier:String)->IndicatorResult{letlevel:IndicatorLevel=machineIdentifier=="unknown"?.inconclusive:.expectedletreason:StringifmachineIdentifier=="unknown"{reason="The app could not resolve the device model."}else{reason="The reported model can be cross-checked against the hardware capabilities observed at runtime."}//PASS:[MASTG-TEST-0367]Theappquerieshw.machinethroughsysctlbynameasavirtual-deviceindicator.returnIndicatorResult(order:1,name:"hw.machine",observed:machineIdentifier,level:level,reason:reason)}privatefuncmetalIndicator()->IndicatorResult{//PASS:[MASTG-TEST-0367]TheappcheckswhetheraMetalGPUisavailable.ifMTLCreateSystemDefaultDevice()!=nil{returnIndicatorResult(order:2,name:"Metal GPU",observed:"available",level:.expected,reason:"A Metal device is available, which is consistent with a physical iOS device.")}returnIndicatorResult(order:2,name:"Metal GPU",observed:"missing",level:.suspicious,reason:"No Metal device is available, which is unusual for a supported physical iOS device.")}privatefunccorelliumIndicator()->IndicatorResult{//PASS:[MASTG-TEST-0367]TheappchecksfortheCorelliumdaemonfile.ifcorelliumDaemonExists(){returnIndicatorResult(order:3,name:"Corellium daemon",observed:"present",level:.confirmed,reason:"The file /usr/libexec/corelliumd exists, which is a strong Corellium indicator.")}returnIndicatorResult(order:3,name:"Corellium daemon",observed:"not found",level:.expected,reason:"The file /usr/libexec/corelliumd was not found.")}privatefuncbuildReport(fromresults:[IndicatorResult])->String{letorderedResults=results.sorted{lhs,rhsinlhs.order<rhs.order}letconfirmedResults=orderedResults.filter{$0.level==.confirmed}letsuspiciousResults=orderedResults.filter{$0.level==.suspicious}varlines=["Virtual device detection results:","","Indicators:"]forresultinorderedResults{lines.append("- \(result.name): \(result.observed) [\(result.level.label)] - \(result.reason)")}lines.append("")lines.append("Verdict:")if!confirmedResults.isEmpty{lines.append("- Likely virtual device.")forresultinconfirmedResults{lines.append(" - \(result.name): \(result.reason)")}}elseif!suspiciousResults.isEmpty{lines.append("- No strong virtual-device verdict yet. Review the suspicious indicator below.")forresultinsuspiciousResults{lines.append(" - \(result.name): \(result.reason)")}}else{lines.append("- Likely physical device. No strong virtual-device indicators were observed.")}returnlines.joined(separator:"\n")}privatefunccurrentMachineIdentifier()->String{varsize:size_t=0guardsysctlbyname("hw.machine",nil,&size,nil,0)==0,size>1else{return"unknown"}varbuffer=[CChar](repeating:0,count:Int(size))letresult=buffer.withUnsafeMutableBufferPointer{pointerinsysctlbyname("hw.machine",pointer.baseAddress,&size,nil,0)}guardresult==0else{return"unknown"}returnString(cString:buffer)}privatefunccorelliumDaemonExists()->Bool{varfileInfo=stat()return"/usr/libexec/corelliumd".withCString{pathinstat(path,&fileInfo)==0}}}
sysctlbyname("hw.machine")=>iPhone10,6Backtrace:0x1c2ac4368CoreFoundation!___CFGetProductName_block_invoke0x1c9794780libdispatch.dylib!_dispatch_client_callout0x1c9764ddclibdispatch.dylib!_dispatch_once_callout0x1c2a0fe1cCoreFoundation!_CFBundleInfoPlistProcessInfoDictionary0x1c2a39e30CoreFoundation!_CFBundleCopyInfoDictionaryInDirectoryWithVersion0x1c2a2e588CoreFoundation!_CFBundleRefreshInfoDictionaryAlreadyLockedsysctlbyname("hw.machine")=>iPhone10,6Backtrace:0x104e29fb0MASTestApp.debug.dylib!closure#1 in VirtualDeviceDetector.currentMachineIdentifier()0x104e2a000MASTestApp.debug.dylib!partialapplyforclosure#1 in VirtualDeviceDetector.currentMachineIdentifier()0x104e2a108MASTestApp.debug.dylib!$sSa30withUnsafeMutableBufferPointeryqd__qd__SryxGzqd_0_YKXEqd_0_YKs5ErrorRd_0_r0_lF0x104e287ccMASTestApp.debug.dylib!VirtualDeviceDetector.currentMachineIdentifier()0x104e28090MASTestApp.debug.dylib!VirtualDeviceDetector.run()0x104e28040MASTestApp.debug.dylib!staticMastgTest.mastgTest(completion:)MTLCreateSystemDefaultDevice()=>availableBacktrace:0x104e28b4cMASTestApp.debug.dylib!VirtualDeviceDetector.metalIndicator()0x104e28104MASTestApp.debug.dylib!VirtualDeviceDetector.run()0x104e28040MASTestApp.debug.dylib!staticMastgTest.mastgTest(completion:)0x104e2d018MASTestApp.debug.dylib!closure#1 in closure #1 in closure #1 in ContentView.body.getter0x1c686b35cSwiftUI!0x7d735c(0x18ac6f35c)0x1c686b844SwiftUI!0x7d7844(0x18ac6f844)stat("/usr/libexec/corelliumd")=>missingBacktrace:0x104e2a5c4MASTestApp.debug.dylib!closure#1 in VirtualDeviceDetector.corelliumDaemonExists()0x104e2a5fcMASTestApp.debug.dylib!partialapplyforclosure#1 in VirtualDeviceDetector.corelliumDaemonExists()0x1bc937a1clibswiftCore.dylib!String.withCString<A>(_:)0x104e29decMASTestApp.debug.dylib!VirtualDeviceDetector.corelliumDaemonExists()0x104e28d60MASTestApp.debug.dylib!VirtualDeviceDetector.corelliumIndicator()0x104e28124MASTestApp.debug.dylib!VirtualDeviceDetector.run()
The runtime trace shows that tapping the Start button triggers the following checks:
sysctlbyname("hw.machine") is called and returns iPhone10,6. The trace shows one early framework-level call from CoreFoundation and one app-level call from VirtualDeviceDetector.currentMachineIdentifier(), confirming that the sample queries the runtime device model.
MTLCreateSystemDefaultDevice() is called from VirtualDeviceDetector.metalIndicator() and returns available, confirming that the sample checks for Metal GPU availability.
stat("/usr/libexec/corelliumd") is called from VirtualDeviceDetector.corelliumDaemonExists() and returns missing, confirming that the sample checks for the specific Corellium daemon file.