This is an old revision of the document!
The details below is a collection of Frida hooks, which we can use for our aircraft. New hooks will be added progressively. There are some tasks that need to be thought about so that we can make this scalable:
We need to build a data structure, and some methods for accessing and updating this data that will be used by all of the other methods. Why? As a longer term goal, it would be good to publish our own NIB files for IOS and equivalent for Android that will allow update of this data.
Our work at the moment is focussed on IOS. As a general rule of thumb, we should where possible use the “swizzle” method of hooking. In the near future, this type of hook method will be able to be run on a modified app launched from Springboard. This is pending a patch from the author, but we know that this is a requirement. Not sure yet what standards if any are required for Android to ensure any protection is not tripped up.
The config below can be used for stand-alone hooks, allowing you to open DJI GO 4 from springboard.
{ "interaction": { "type": "script", "path": "Tweak.js", "on_change": "reload" }, "code_signing": "required" }
We should look at creating a few template hooks. So far, we have a simple bool replacement template that we have used in three cases successfully. But, what about other more complex requirements. What if we need to read parameters etc? The author of Frida has advised:
oleavr: method arguments follow self and sel (the first two implicit arguments). you can use var self = new ObjC.Object(handle); then you can access the instance variables of self through self.$ivars depending on whether you want to access method arguments or instance variables (or other things on the instance)
We'll dig into this more later when/if we need to access parameter data etc.
'use strict'; if (ObjC.available) { var DJITermsNotificationController = ObjC.classes.DJITermsNotificationController; var shouldShowTerms = DJITermsNotificationController['- shouldShowTerms']; var shouldShowTermsImpl = shouldShowTerms.implementation; shouldShowTerms.implementation = ObjC.implement(shouldShowTerms, function (handle, selector) { var originalResult = shouldShowTermsImpl(handle, selector); console.log('Original says:', originalResult, 'we say: 0'); return 0; }); }
if (ObjC.available) { var DJIAppSettings = ObjC.classes.DJIAppSettings; var sdr_force_fcc = DJIAppSettings['- sdr_force_fcc']; var sdr_force_fccImpl = sdr_force_fcc.implementation; sdr_force_fcc.implementation = ObjC.implement(sdr_force_fcc, function (handle, selector) { var originalResult = sdr_force_fccImpl(handle, selector); console.log('DJIAppSettings:sdr_force_fcc Original says:', originalResult, 'we say: 1'); return 1; }); }
if (ObjC.available) { var DJIAppSettings = ObjC.classes.DJIAppSettings; var canUseIllegalChannels = DJIAppSettings['- canUseIllegalChannels']; var canUseIllegalChannelsImpl = canUseIllegalChannels.implementation; canUseIllegalChannels.implementation = ObjC.implement(canUseIllegalChannels, function (handle, selector) { var originalResult = canUseIllegalChannelsImpl(handle, selector); console.log('DJIAppSettings:canUseIllegalChannels Original says:', originalResult, 'we say: 1'); return 1; }); var DJIRadioLogic = ObjC.classes.DJIRadioLogic; var canUseIllegalChannels = DJIRadioLogic['- canUseIllegalChannels']; var canUseIllegalChannelsImpl = canUseIllegalChannels.implementation; canUseIllegalChannels.implementation = ObjC.implement(canUseIllegalChannels, function (handle, selector) { var originalResult = canUseIllegalChannelsImpl(handle, selector); console.log('DJIRadioLogic:canUseIllegalChannels Original says:', originalResult, 'we say: 1'); return 1; }); }
if (ObjC.available) { var AFSecurityPolicy = ObjC.classes.AFSecurityPolicy; var setSSLPinningMode = AFSecurityPolicy['- setSSLPinningMode:']; var setSSLPinningModeImpl = setSSLPinningMode.implementation; setSSLPinningMode.implementation = ObjC.implement(setSSLPinningMode, function (handle, selector, originalResult) { setSSLPinningModeImpl(handle, selector, 0); console.log('AFSecurityPolicy:setSSLPinningMode. Changing from: ', originalResult, 'to: 0'); }); }
//Set Admin mode in Flight Records var DJIAccountManager = ObjC.classes.DJIAccountManager; var checkIsAdminUser = DJIAccountManager['- checkIsAdminUser']; var checkIsAdminUserImpl = checkIsAdminUser.implementation; checkIsAdminUser.implementation = ObjC.implement(checkIsAdminUser, function (handle, selector) { var originalResult = checkIsAdminUserImpl(handle, selector); console.log('[*] Setting user to Admin for Flight Records'); return 1; });
//Bypass upgrade notification on splash screen var DJIUpgradeNotifyViewModel = ObjC.classes.DJIUpgradeNotifyViewModel; var notifyHidden = DJIUpgradeNotifyViewModel['- notifyHidden']; var notifyHiddenImpl = notifyHidden.implementation; notifyHidden.implementation = ObjC.implement(notifyHidden, function (handle, selector) { var originalResult = notifyHiddenImpl(handle, selector); console.log('[*] Disabling Upgrade Notification'); return 1; });
//Force FCC Mode var shown=0; var fcc_enabled; var DJIAppSettings = ObjC.classes.DJIAppSettings; var sdr_force_fcc = DJIAppSettings['- sdr_force_fcc']; var sdr_force_fccImpl = sdr_force_fcc.implementation; sdr_force_fcc.implementation = ObjC.implement(sdr_force_fcc, function (handle, selector) { var originalResult = sdr_force_fccImpl(handle, selector); console.log('[*] Setting Forced FCC Mode'); fcc_enabled = 1; return 1; }); //Fake Mavic for P4 FCC var DJIProductManager = ObjC.classes.DJIProductManager; var currentProductCode = DJIProductManager['+ currentProductCode']; var currentProductCodeImpl = currentProductCode.implementation; currentProductCode.implementation = ObjC.implement(currentProductCode, function (handle, selector) { var originalResult = currentProductCodeImpl(handle, selector); if(shown==0) { console.log('[*] Faking product code for FCC'); shown=1; } if(fcc_enabled==0) return 13; //mavic else return originalResult });
//Bypass DJI Go 4 new app version check var DJIAppForceUpdateManager = ObjC.classes.DJIAppForceUpdateManager; var hasChecked = DJIAppForceUpdateManager['- hasChecked']; var hasCheckedImpl = hasChecked.implementation; hasChecked.implementation = ObjC.implement(hasChecked, function (handle, selector) { var originalResult = hasCheckedImpl(handle, selector); console.log("[*] Disabling App Upgrade Check"); return 1; });
//Enable Illegal Channels (32 Channels) if (ObjC.available) { var DJIAppSettings = ObjC.classes.DJIAppSettings; var canUseIllegalChannels = DJIAppSettings['- canUseIllegalChannels']; var canUseIllegalChannelsImpl = canUseIllegalChannels.implementation; canUseIllegalChannels.implementation = ObjC.implement(canUseIllegalChannels, function (handle, selector) { var originalResult = canUseIllegalChannelsImpl(handle, selector); console.log('[*] Enabling Illegal Channels (32 Channels)'); return 1; }); var DJIRadioLogic = ObjC.classes.DJIRadioLogic; var canUseIllegalChannels = DJIRadioLogic['- canUseIllegalChannels']; var canUseIllegalChannelsImpl = canUseIllegalChannels.implementation; canUseIllegalChannels.implementation = ObjC.implement(canUseIllegalChannels, function (handle, selector) { var originalResult = canUseIllegalChannelsImpl(handle, selector); console.log('[*] Enabling Illegal Channels (32 Channels)'); return 1; }); }