User Tools

Site Tools


howto:fridahooklibrary

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
Next revision Both sides next revision
howto:fridahooklibrary [2017/10/19 11:47]
czokie created
howto:fridahooklibrary [2017/11/06 22:59]
czokie [PrettyWoman.sh]
Line 8: Line 8:
 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. 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.
  
 +===== Configuration =====
 +The config below can be used for stand-alone hooks, allowing you to open DJI GO 4 from springboard.
 +<code java FridaGadget.config>
 +{
 +  "interaction": {
 +    "type": "script",
 +    "path": "Tweak.js",
 +    "on_change": "reload"
 +  },
 +  "code_signing": "required"
 +}
 +</code>
 ===== Template hook ===== ===== Template hook =====
  
Line 16: Line 28:
 We'll dig into this more later when/if we need to access parameter data etc. We'll dig into this more later when/if we need to access parameter data etc.
  
-So. For now, our template hook is +====== PrettyWoman ====== 
 +As part of this workI looked at how to "standardise" our hooks, since they all appeared to be based on a couple of patterns. Below, you will find source and a CSV file for "PrettyWoman". This app name was picked by Jezzab because "PrettyWoman - She was a hooker".
  
 +Anyway. Naming conventions aside. How does it work? There is a shell script that parses a CSV file that contains configuration information for a list of hooks that will be created in the output.
 +
 +===== PrettyWoman.sh =====
 +<code bash PrettyWoman.sh>
 +#!/bin/bash
 +
 +function iosheader {
 +cat <<EOF
 +//
 +// DJI GO 4 - Frida Tweaks
 +//
 +
 +if (ObjC.available) {
 +
 +EOF
 +}
 +
 +function iosfooter {
 +cat <<EOF
 +}
 +EOF
 +}
 +
 +function functionheader {
 +cat <<EOF
 +
 +  //
 +  // ${1}
 +  //
 +
 +EOF
 +}
 +function jsobject {
 +
 +cat <<EOF
 +  var ${1} = ObjC.classes.${1};
 +  var ${3} = ${1}['${2} ${3}:'];
 +  var ${3}Impl = ${3}.implementation;
 +  ${3}.implementation = ObjC.implement(${3}, function (handle, selector, originalResult) {
 +    ${3}Impl(handle, selector, ${4});
 +    if ( originalResult != ${4} ) {
 +      if ( ${7} == 0 || ${CLASS}${METHOD}SeenReplace == 0 ) {
 +        console.log("${5}");
 +        ${CLASS}${METHOD}SeenReplace = 1;
 +      }
 +    } else {
 +      if ( ${7} == 0 || ${CLASS}${METHOD}SeenHit == 0 ) {
 +        console.log("${6}");
 +        ${CLASS}${METHOD}SeenHit = 1;
 +      }
 +    }
 +  });
 +EOF
 +}
 +
 +function jsfunction {
 +cat <<EOF
 +  var ${1} = ObjC.classes.${1};
 +  var ${3} = ${1}['${2} ${3}'];
 +  var ${3}Impl = ${3}.implementation;
 +  ${3}.implementation = ObjC.implement(${3}, function (handle, selector) {
 +    var originalResult = ${3}Impl(handle, selector);
 +    if ( originalResult != ${4} ) {
 +      if ( ${7} == 0 || ${CLASS}${METHOD}SeenReplace == 0 ) {
 +        console.log("${5}");
 +        ${CLASS}${METHOD}SeenReplace = 1;
 +      }
 +    } else {
 +      if ( ${7} == 0 || ${CLASS}${METHOD}SeenHit == 0 ) {
 +        console.log("${6}");
 +        ${CLASS}${METHOD}SeenHit = 1;
 +      }
 +    }
 +    return ${4};
 +  });
 +EOF
 +}
 +
 +
 +function jsfunctioniffcc {
 +cat <<EOF
 +  var ${1} = ObjC.classes.${1};
 +  var ${3} = ${1}['${2} ${3}'];
 +  var ${3}Impl = ${3}.implementation;
 +  ${3}.implementation = ObjC.implement(${3}, function (handle, selector) {
 +    var originalResult = ${3}Impl(handle, selector);
 +    if ( originalResult != ${4} ) {
 +      if ( ${7} == 0 || ${CLASS}${METHOD}SeenReplace == 0 ) {
 +        console.log("${5}");
 +        ${CLASS}${METHOD}SeenReplace = 1;
 +      }
 +    }
 +
 +    if( DJIAppSettingssdr_force_fccSeenReplace == 0 ) {
 +      return ${4}; //mavic
 +    } else {
 +      return originalResult;
 +    }
 +  });
 +EOF
 +}
 +
 +
 +function defines {
 +cat <<EOF
 +//
 +// Create variables that we can use for "one shot" rules
 +//
 +EOF
 +
 +while read X
 +do
 +        #TEMPLATE=`echo $X | cut -d "," -f 1`
 +        CLASS=`echo $X | cut -d "," -f 2`
 +        METHOD=`echo $X | cut -d "," -f 3`
 + PLUSMINUS=`echo $X | cut -d "," -f 4`
 +        #REPLACE=`echo $X | cut -d "," -f 5`
 +        #LOGHIT=`echo $X | cut -d "," -f 6`
 +        #LOGCHANGED=`echo $X | cut -d "," -f 7`
 + #ONESHOT=`echo $X | cut -d "," -f 8`
 +
 + echo "${CLASS}${METHOD}SeenHit=0;"
 + echo "${CLASS}${METHOD}SeenReplace=0;"
 +
 +done < PrettyWoman.csv
 +}
 +
 +function mainloop {
 +while read X
 +do
 +        TEMPLATE=`echo $X | cut -d "," -f 1`
 +        CLASS=`echo $X | cut -d "," -f 2`
 +        METHOD=`echo $X | cut -d "," -f 3`
 + PLUSMINUS=`echo $X | cut -d "," -f 4`
 +        REPLACE=`echo $X | cut -d "," -f 5`
 +        LOGHIT=`echo $X | cut -d "," -f 6`
 +        LOGCHANGED=`echo $X | cut -d "," -f 7`
 + ONESHOT=`echo $X | cut -d "," -f 8`
 +
 +        functionheader "${CLASS} ${METHOD} ${TEMPLATE}"
 +        ${TEMPLATE} ${CLASS} ${PLUSMINUS} ${METHOD} ${REPLACE} "${LOGHIT}" "${LOGCHANGED}" "0${ONESHOT}"
 +done < PrettyWoman.csv
 +}
 +
 +iosheader
 +defines
 +mainloop
 +iosfooter
 +</code>
 +
 +===== PrettyWoman.csv =====
 +Below is a CSV config file for PrettyWoman.sh. This file has the following fields:
 +
 +^Template|The name of a template, as listed in PrettyWoman.sh|
 +^Class|A class name from the DJI Application source code|
 +^Method|The name of a method or function within the class|
 +^PlusMinus|A plus or a minus sign (as defined in the DJI reversed source code)|
 +^OurValue|What should we replace the original function return value with?|
 +^LogMessageTweaked|What to display in debug when we successfully bypass DJI functions etc|
 +^LogSeen|What to display in debug when we are called, but we don't change anything|
 +^OneShot|Set this to 1 if you want to see a log message for this once only|
 +
 +<code text PrettyWoman.csv>
 +jsobject,AFSecurityPolicy,setSSLPinningMode,-,0,[*] SSL Pinning BYPASSED, [*] SSL Pinning not used this time,0
 +jsfunction,DJIAccountManager,checkIsAdminUser,-,1,[*] Flight Records admin user ENABLED,[*] Flight Records admin user already enabled,0
 +jsfunction,DJIAppSettings,canUseIllegalChannels,-,1,[*] Illegal Channels config (32) ENABLED,[*] Illegal Channels config (32) already enabled,0
 +jsfunction,DJIRadioLogic,canUseIllegalChannels,-,1,[*] Illegal Channels SDR (32) ENABLED,[*] Illegal Channels SDR(32) already enabled,0
 +jsfunction,DJIAppSettings,sdr_force_fcc,-,1,[*] Forced FCC Mode ACTIVATED,[*] Forced FCC mode already active,0
 +jsfunction,DJITermsNotificationController,shouldShowTerms,-,0,[*] Terms and conditions BYPASSED,[*] Terms and conditions already accepted,0
 +jsfunction,DJIAppForceUpdateManager,hasChecked,-,1,[*] Upgrade Check: DISABLED,[*] Upgrade Check: Already checked,0
 +jsfunction,DJIUpgradeNotifyViewModel,notifyHidden,-,1,[*] Upgrade Notification DISABLLED,[*] Upgrade Notification already disabled,0
 +jsfunctioniffcc,DJIProductManager,currentProductCode,+,13,[*] Changed product code to MAVIC,,1
 +</code>
 +
 +===== Tweak.js =====
 +
 +This code was generated by PrettyWoman.sh - using the CSV file above. Feel free to just use this set of hooks for your tweaking pleasure.
 +
 +<code java Tweak.js>
 +//
 +// DJI GO 4 - Frida Tweaks
 +//
 +
 +if (ObjC.available) {
 +
 +//
 +// Create variables that we can use for "one shot" rules
 +//
 +AFSecurityPolicysetSSLPinningModeSeenHit=0;
 +AFSecurityPolicysetSSLPinningModeSeenReplace=0;
 +DJIAccountManagercheckIsAdminUserSeenHit=0;
 +DJIAccountManagercheckIsAdminUserSeenReplace=0;
 +DJIAppSettingscanUseIllegalChannelsSeenHit=0;
 +DJIAppSettingscanUseIllegalChannelsSeenReplace=0;
 +DJIRadioLogiccanUseIllegalChannelsSeenHit=0;
 +DJIRadioLogiccanUseIllegalChannelsSeenReplace=0;
 +DJIAppSettingssdr_force_fccSeenHit=0;
 +DJIAppSettingssdr_force_fccSeenReplace=0;
 +DJITermsNotificationControllershouldShowTermsSeenHit=0;
 +DJITermsNotificationControllershouldShowTermsSeenReplace=0;
 +DJIAppForceUpdateManagerhasCheckedSeenHit=0;
 +DJIAppForceUpdateManagerhasCheckedSeenReplace=0;
 +DJIUpgradeNotifyViewModelnotifyHiddenSeenHit=0;
 +DJIUpgradeNotifyViewModelnotifyHiddenSeenReplace=0;
 +DJIProductManagercurrentProductCodeSeenHit=0;
 +DJIProductManagercurrentProductCodeSeenReplace=0;
 +
 +  //
 +  // AFSecurityPolicy setSSLPinningMode jsobject
 +  //
 +
 +  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);
 +    if ( originalResult != 0 ) {
 +      if ( 00 == 0 || AFSecurityPolicysetSSLPinningModeSeenReplace == 0 ) {
 +        console.log("[*] SSL Pinning BYPASSED");
 +        AFSecurityPolicysetSSLPinningModeSeenReplace = 1;
 +      }
 +    } else {
 +      if ( 00 == 0 || AFSecurityPolicysetSSLPinningModeSeenHit == 0 ) {
 +        console.log(" [*] SSL Pinning not used this time");
 +        AFSecurityPolicysetSSLPinningModeSeenHit = 1;
 +      }
 +    }
 +  });
 +
 +  //
 +  // DJIAccountManager checkIsAdminUser jsfunction
 +  //
 +
 +  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);
 +    if ( originalResult != 1 ) {
 +      if ( 00 == 0 || DJIAccountManagercheckIsAdminUserSeenReplace == 0 ) {
 +        console.log("[*] Flight Records admin user ENABLED");
 +        DJIAccountManagercheckIsAdminUserSeenReplace = 1;
 +      }
 +    } else {
 +      if ( 00 == 0 || DJIAccountManagercheckIsAdminUserSeenHit == 0 ) {
 +        console.log("[*] Flight Records admin user already enabled");
 +        DJIAccountManagercheckIsAdminUserSeenHit = 1;
 +      }
 +    }
 +    return 1;
 +  });
 +
 +  //
 +  // DJIAppSettings canUseIllegalChannels jsfunction
 +  //
 +
 +  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);
 +    if ( originalResult != 1 ) {
 +      if ( 00 == 0 || DJIAppSettingscanUseIllegalChannelsSeenReplace == 0 ) {
 +        console.log("[*] Illegal Channels config (32) ENABLED");
 +        DJIAppSettingscanUseIllegalChannelsSeenReplace = 1;
 +      }
 +    } else {
 +      if ( 00 == 0 || DJIAppSettingscanUseIllegalChannelsSeenHit == 0 ) {
 +        console.log("[*] Illegal Channels config (32) already enabled");
 +        DJIAppSettingscanUseIllegalChannelsSeenHit = 1;
 +      }
 +    }
 +    return 1;
 +  });
 +
 +  //
 +  // DJIRadioLogic canUseIllegalChannels jsfunction
 +  //
 +
 +  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);
 +    if ( originalResult != 1 ) {
 +      if ( 00 == 0 || DJIRadioLogiccanUseIllegalChannelsSeenReplace == 0 ) {
 +        console.log("[*] Illegal Channels SDR (32) ENABLED");
 +        DJIRadioLogiccanUseIllegalChannelsSeenReplace = 1;
 +      }
 +    } else {
 +      if ( 00 == 0 || DJIRadioLogiccanUseIllegalChannelsSeenHit == 0 ) {
 +        console.log("[*] Illegal Channels SDR(32) already enabled");
 +        DJIRadioLogiccanUseIllegalChannelsSeenHit = 1;
 +      }
 +    }
 +    return 1;
 +  });
 +
 +  //
 +  // DJIAppSettings sdr_force_fcc jsfunction
 +  //
 +
 +  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);
 +    if ( originalResult != 1 ) {
 +      if ( 00 == 0 || DJIAppSettingssdr_force_fccSeenReplace == 0 ) {
 +        console.log("[*] Forced FCC Mode ACTIVATED");
 +        DJIAppSettingssdr_force_fccSeenReplace = 1;
 +      }
 +    } else {
 +      if ( 00 == 0 || DJIAppSettingssdr_force_fccSeenHit == 0 ) {
 +        console.log("[*] Forced FCC mode already active");
 +        DJIAppSettingssdr_force_fccSeenHit = 1;
 +      }
 +    }
 +    return 1;
 +  });
 +
 +  //
 +  // DJITermsNotificationController shouldShowTerms jsfunction
 +  //
 +
 +  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);
 +    if ( originalResult != 0 ) {
 +      if ( 00 == 0 || DJITermsNotificationControllershouldShowTermsSeenReplace == 0 ) {
 +        console.log("[*] Terms and conditions BYPASSED");
 +        DJITermsNotificationControllershouldShowTermsSeenReplace = 1;
 +      }
 +    } else {
 +      if ( 00 == 0 || DJITermsNotificationControllershouldShowTermsSeenHit == 0 ) {
 +        console.log("[*] Terms and conditions already accepted");
 +        DJITermsNotificationControllershouldShowTermsSeenHit = 1;
 +      }
 +    }
 +    return 0;
 +  });
 +
 +  //
 +  // DJIAppForceUpdateManager hasChecked jsfunction
 +  //
 +
 +  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);
 +    if ( originalResult != 1 ) {
 +      if ( 00 == 0 || DJIAppForceUpdateManagerhasCheckedSeenReplace == 0 ) {
 +        console.log("[*] Upgrade Check: DISABLED");
 +        DJIAppForceUpdateManagerhasCheckedSeenReplace = 1;
 +      }
 +    } else {
 +      if ( 00 == 0 || DJIAppForceUpdateManagerhasCheckedSeenHit == 0 ) {
 +        console.log("[*] Upgrade Check: Already checked");
 +        DJIAppForceUpdateManagerhasCheckedSeenHit = 1;
 +      }
 +    }
 +    return 1;
 +  });
 +
 +  //
 +  // DJIUpgradeNotifyViewModel notifyHidden jsfunction
 +  //
 +
 +  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);
 +    if ( originalResult != 1 ) {
 +      if ( 00 == 0 || DJIUpgradeNotifyViewModelnotifyHiddenSeenReplace == 0 ) {
 +        console.log("[*] Upgrade Notification DISABLLED");
 +        DJIUpgradeNotifyViewModelnotifyHiddenSeenReplace = 1;
 +      }
 +    } else {
 +      if ( 00 == 0 || DJIUpgradeNotifyViewModelnotifyHiddenSeenHit == 0 ) {
 +        console.log("[*] Upgrade Notification already disabled");
 +        DJIUpgradeNotifyViewModelnotifyHiddenSeenHit = 1;
 +      }
 +    }
 +    return 1;
 +  });
 +
 +  //
 +  // DJIProductManager currentProductCode jsfunctioniffcc
 +  //
 +
 +  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 ( originalResult != 13 ) {
 +      if ( 01 == 0 || DJIProductManagercurrentProductCodeSeenReplace == 0 ) {
 +        console.log("[*] Changed product code to MAVIC");
 +        DJIProductManagercurrentProductCodeSeenReplace = 1;
 +      }
 +    }
 +
 +    if( DJIAppSettingssdr_force_fccSeenReplace == 0 ) {
 +      return 13; //mavic
 +    } else {
 +      return originalResult;
 +    }
 +  });
 +}
 +</code>
 ====== Hooks ====== ====== Hooks ======
 ===== DJITermsNotificationController - shouldShowTerms ===== ===== DJITermsNotificationController - shouldShowTerms =====
  
 <code javascript DJITermsNotificationController.shouldShowTerms.js> <code javascript DJITermsNotificationController.shouldShowTerms.js>
 +'use strict';
 if (ObjC.available) { if (ObjC.available) {
 +
   var DJITermsNotificationController = ObjC.classes.DJITermsNotificationController;   var DJITermsNotificationController = ObjC.classes.DJITermsNotificationController;
-  +
   var shouldShowTerms = DJITermsNotificationController['- shouldShowTerms'];   var shouldShowTerms = DJITermsNotificationController['- shouldShowTerms'];
   var shouldShowTermsImpl = shouldShowTerms.implementation;   var shouldShowTermsImpl = shouldShowTerms.implementation;
   shouldShowTerms.implementation = ObjC.implement(shouldShowTerms, function (handle, selector) {   shouldShowTerms.implementation = ObjC.implement(shouldShowTerms, function (handle, selector) {
     var originalResult = shouldShowTermsImpl(handle, selector);     var originalResult = shouldShowTermsImpl(handle, selector);
-    console.log('Original says:', originalResult, 'we say: false'); +    console.log('Original says:', originalResult, 'we say: 0'); 
-    return false;+    return 0;
   });   });
 } }
 </code> </code>
- 
 ===== DJIAppSettings - sdr_force_fcc ===== ===== DJIAppSettings - sdr_force_fcc =====
 <code javascript DJIAppSettings.sdr_force_fcc.js> <code javascript DJIAppSettings.sdr_force_fcc.js>
Line 44: Line 472:
   sdr_force_fcc.implementation = ObjC.implement(sdr_force_fcc, function (handle, selector) {   sdr_force_fcc.implementation = ObjC.implement(sdr_force_fcc, function (handle, selector) {
     var originalResult = sdr_force_fccImpl(handle, selector);     var originalResult = sdr_force_fccImpl(handle, selector);
-    console.log('DJIAppSettings:sdr_force_fcc  Original says:', originalResult, 'we say: true'); +    console.log('DJIAppSettings:sdr_force_fcc  Original says:', originalResult, 'we say: 1'); 
-    return true;+    return 1;
   });   });
 } }
 </code> </code>
  
-===== DJIAppSettings - canUseIllegalChannels =====+===== canUseIllegalChannels =====
 <code javascript DJIAppSettings.canUseIllegalChannels.js> <code javascript DJIAppSettings.canUseIllegalChannels.js>
 if (ObjC.available) { if (ObjC.available) {
   var DJIAppSettings = ObjC.classes.DJIAppSettings;   var DJIAppSettings = ObjC.classes.DJIAppSettings;
 +  
   var canUseIllegalChannels = DJIAppSettings['- canUseIllegalChannels'];   var canUseIllegalChannels = DJIAppSettings['- canUseIllegalChannels'];
   var canUseIllegalChannelsImpl = canUseIllegalChannels.implementation;   var canUseIllegalChannelsImpl = canUseIllegalChannels.implementation;
   canUseIllegalChannels.implementation = ObjC.implement(canUseIllegalChannels, function (handle, selector) {   canUseIllegalChannels.implementation = ObjC.implement(canUseIllegalChannels, function (handle, selector) {
     var originalResult = canUseIllegalChannelsImpl(handle, selector);     var originalResult = canUseIllegalChannelsImpl(handle, selector);
-    console.log('DJIAppSettings:canUseIllegalChannels  Original says:', originalResult, 'we say: true'); +    console.log('DJIAppSettings:canUseIllegalChannels  Original says:', originalResult, 'we say: 1'); 
-    return true;+    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; 
 +  }); 
 +
 +</code> 
 + 
 +===== AFSecurityPolicy - setSSLPinningMode ===== 
 +<code javascript AFSecurityPolicy.setSSLPinningMode.js> 
 +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'); 
 +  }); 
 +
 +</code> 
 + 
 +===== DJIAccountManager - checkIsAdminUser ===== 
 +<code javascript DJIAccountManager.checkIsAdminUser.js> 
 +//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; 
 +}); 
 +</code> 
 + 
 +===== DJIUpgradeNotifyViewModel - notifyHidden ===== 
 +<code javascript DJIUpgradeNotifyViewModel.notifyHidden.js> 
 +//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; 
 +}); 
 +</code> 
 + 
 +===== DJIAppSettings - sdr_force_fcc ===== 
 +<code javascript DJIAppSettings.sdr_force_fcc.js> 
 +//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 
 +}); 
 +</code> 
 + 
 +===== DJIAppForceUpdateManager - hasChecked ===== 
 +<code javascript DJIAppForceUpdateManager.hasChecked.js> 
 +//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; 
 +}); 
 +</code> 
 + 
 +===== DJIAppSettings - canUseIllegalChannels ===== 
 +<code javascript DJIAppForceUpdateManager.hasChecked.js> 
 +//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;
   });   });
 } }
 </code> </code>
howto/fridahooklibrary.txt · Last modified: 2017/11/12 09:45 by czokie