记一次Parquet iOS版本逆向

今天在浏览百科时发现酸柚子社的Parquet居然有iOS版本,于是我下载下来进行了研究。

如图,原版游戏在完成一定章节后会出现购买弹窗,导致无法进行后续章节。

遂砸壳开始研究

从ipa结构来看,包括metadata,mono,是unity il2cpp的游戏,所以使用IL2CPPDumper和IDA分析。

在查看global-metadata.dat后发现魔法头文件还在,未加密,所以直接丢进il2cppdumper。由于本游戏的unity版本较新,所以il2cpp可执行文件是在UnityFramework中。

在il2cppdumper生成的dump.cs文件中有许多purchase相关的函数。在研究了一段时间后,我发现了一个比较可疑的函数UIBilling__UpdateEpisodeButton。

由于此函数返回的是GameObject类,所以我选择了查找调用函数

在查看两个函数的伪代码后,发现UIBilling__UpdateEpisodeButton函数较为可疑(以下为部分)

bool __cdecl UIBilling__UpdateEpisodeButton(UIBilling_o *this, EpisodeButton_o *button, PurchasableEpisode_o *episode, const MethodInfo *method)
{

  ...
  v12 = PurchasableEpisode__get_Available(episode, 0LL);
  EpisodeButton__set_Disabled(button, !v12, 0LL);
  v13 = EpisodeButton__get_PurchasedCue(button, 0LL);
  if ( !v13 )
    goto LABEL_23;
 
 ...
LABEL_23:
    sub_2099C();
  }
  return 1;
}

但是貌似没有特别直接返回内容是否购买的部分,尝试更改LABEL_23的函数为return 1;后无果,遂放弃。

于是开始寻找关键词Episode的其他可疑函数 ,然后找到了IAPManager__IsEpisodePurchased

IAP 是指 "In-App Purchases"(应用内购买),是指在移动应用程序中购买虚拟物品或服务的功能。这种购买通常与应用内的特定功能、游戏内的道具或者内容解锁相关联。IAP 的实现方式通常是通过应用商店(如苹果的 App Store 或者 Google Play 商店)提供的支付系统完成的。

所以这个函数很可疑。但是这个函数有很多返回处,不太好改,于是决定看调用函数

void __cdecl IAPManager__OnInitialized(IAPManager_o *this, UnityEngine_Purchasing_IStoreController_o *controller, UnityEngine_Purchasing_IExtensionProvider_o *extensions, const MethodInfo *method)
{
    ...
    v58->fields.PriceString = v71;
    sub_20684(&v58->fields.PriceString, v71);
    if ( v58->fields.Bought )
      v56 = 1;
    else
      v56 = IAPManager__IsEpisodePurchased(this, v58, v72);
    v58->fields.Bought = v56;
  }
  System_Collections_Generic_List_Enumerator_object___Dispose(
    &v76,
    (const MethodInfo_15B00DC *)Method_System_Collections_Generic_List_Enumerator_PurchasableEpisode__Dispose__);
  IAPManager__NormalizeOwnedEpisodes(this, v73);
  this->fields._InitDone_k__BackingField = 1;
  v74 = this->fields.Initialized;
  if ( v74 )
    ((void (__fastcall *)(intptr_t, intptr_t))v74->fields.invoke_impl)(v74->fields.method_code, v74->fields.method);
}

看起来就是如果已经缓存买过了则直接为v56赋值为true(1),没有则调用IAPManager__IsEpisodePurchased,然后让v56赋值给fields.Bought

这样的话就可以直接改成无论如何都让v56为1就行了 剩下的就是改汇编patch了

成果展示:

其实没有联网认证,可以注入通杀插件解决

 

THE END
分享
二维码
< <上一篇
下一篇>>