The following sample checks whether the device has a set passcode.
MastgTest.swift
1 2 3 4 5 6 7 8 910111213141516171819202122
importSwiftUIimportLocalAuthenticationstructMastgTest{staticfuncmastgTest(completion:@escaping(String)->Void){ifdevicePasscodeSet(){completion("This device is protected with a passcode ✅")}else{completion("This device doesn't have a passcode ⚠️")}}staticfuncdevicePasscodeSet()->Bool{//UseLAPolicy.deviceOwnerAuthenticationtoverifyifthedevicehasapasscode.//Accordingtodocs:"In iOS, policy evaluation fails with the error passcodeNotSet if the device passcode isn’t enabled"//Ref:https://developer.apple.com/documentation/localauthentication/lapolicy/deviceownerauthenticationreturnLAContext().canEvaluatePolicy(.deviceOwnerAuthentication,error:nil)}}
Unzip the app package and locate the main binary file ( Exploring the App Package), which in this case is ./Payload/MASTestApp.app/MASTestApp.
Run run.sh.
isDevicePasscodeSet.r2
1 2 3 4 5 6 7 8 9101112131415161718192021
easm.bytes=falseescr.color=falseeasm.var=false?ePrintxrefsto \'canEvaluatePolicy\"f~canEvaluatePolicy?e?ePrintxrefsto0x100008360axt@0x100008360?e?ePrintxrefsto0x1000100a0axt@0x1000100a0?e?ePrintdisassemblyaround \"canEvaluatePolicy\" in the functionpdf@0x100004f10|grep-C5"canEvaluatePolicy:error:"
The output reveals the use of LAContext().canEvaluatePolicy(.deviceOwnerAuthentication, error: nil) in the app. However, it's not exactly the same in the output because the compiler transformed this function call into an Objective-C counterpart under the hood. Therefore, an equivalent Objective-C representation in the binary should look like objc_msgSend(void *address, "canEvaluatePolicy:error:", LAPolicyDeviceOwnerAuthentication). By looking at the output we can find this pattern at line 11/12.
The third argument of objc_msgSend(...) is LAPolicyDeviceOwnerAuthentication because w2 register at the time of the function invocation is set to 2 with a mov instruction at Line 9. 2 is an enum representation of LAPolicyDeviceOwnerAuthentication.