通过3类课程来破解PokemonGo iOS应用
在我之前的文章“如何对.ipa文件执行iOS代码注入”中,我通过概念证明展示了开发人员如何在不修改原始源代码的情况下将单个日志消息注入到iOS .ipa文件中。 由于PokemonGo应用程序最近在开发社区中的流行和兴趣,我选择了PokemonGo应用程序作为演示代码注入的目标。
这篇文章的灵感来自于PokeGo ++ mod的作者Will Cobb的作品。 可以在http://pokemongohacks.me/中找到有关他的mod应用程序的下载说明。 PokeGo ++ mod具有优雅的位置欺骗功能,已注入基础的PokemonGo游戏中。
我们将尝试为游戏创建我们自己的简单位置欺骗mod。 可以直接从iOS App Store破解原始的PokemonGo.ipa文件,然后将其安装到非越狱的手机上(敬请期待有关此内容的后续文章)。 为了简单起见,我将在一个破裂的.ipa文件上展示代码注入技术。 破裂的.ipa基本上是原始的ipa文件,其中删除了数字版权管理(DRM)。 这是您构建此mod应用程序(或修改)所需的资源
- 获取一个破解但未修改的PokemonGo .ipa文件。 您可以在https://www.iphonecake.com/app_1094591345_.html下载最新版本。
- 代码注入所需的位置欺骗代码https://github.com/depoon/InjectibleLocationSpoofing
- 执行代码注入的脚本https://github.com/depoon/iOSDylibInjectionDemo
- Cydia Impactor可以将应用程序辞职并将其侧面加载/安装到非越狱设备上。 Cydia Impactor可以从http://www.cydiaimpactor.com/下载。
由于代码注入过程和技术已在我之前的帖子https://medium.com/@kennethpoon/how-to-perform-ios-code-injection-on-ipa-files-1ba91d9438db中进行了描述,因此在本文中,我们将仅关注位置欺骗代码的内容。
只有3个文件???
那就对了。 入侵任何应用程序的复杂性取决于您想要实现的目标以及您对iOS应用程序开发的了解。 在我们的情况下,我们只需要提供管理设备位置伪造所需的最低UI。 现在,在XCode中创建一个Cocoa Touch Dynamic Framework目标,并创建链接到该框架目标的以下类
- PatchLoader(目标C)
- 位置Swizzler(快速)
- PatchUIManager(快速)
类说明
位置Swizzler.swift
进口基金会
导入CoreLocation
公共类LocationSwizzler :NSObject {
static var currentLocation = CLLocationCoordinate2DMake(1.293760,103.853709)// Raffles City
静态var originalMethod:方法?
static var swizzleMethod:方法?
静态var originalDelegate:CLLocationManagerDelegate吗?
静态公共函数turnOnSwizzleForCoordinate(){
让m1 = class_getInstanceMethod(CLLocation.self,#selector(getter:CLLocation.coordinate))
让m2 = class_getInstanceMethod(self,#selector(self.fakeCoordinate))
method_exchangeImplementations(m1,m2)
}
public func fakeCoordinate()-> CLLocationCoordinate2D {
返回LocationSwizzler.currentLocation
}
}
LocationSwizzler类在CLLocation的getter坐标方法上执行方法混淆,该方法将返回假位置而不是设备的位置。 由于用户的位置将表示为CLLocation对象,因此消耗坐标信息的对象将收到伪造的位置。 但是,这种攻击会影响所有CLLocation对象,并可能导致应用产生副作用。
进口基金会
打开类PatchUIManager :NSObject {
var hijackingSubviews = [UIView]()
覆盖init(){
super.init()
self.setupViewsForLoading()
}
fileprivate func setupViewsForLoading(){
守卫让委托= UIApplication.shared.delegate else {
返回
}
守卫让窗口=委托。窗口其他{
返回
}
让label = UILabel(frame:CGRect(x:0,y:80,width:window!.frame.size.width,height:50))
label.text =“←— UIWindow被劫持!!! —→”
label.textAlignment = .center
label.backgroundColor = UIColor(红色:0,绿色:1,蓝色:1,阿尔法:0.5)
label.tag = 29999
self.hijackingSubviews.append(label)
让buttonImage = self.imageFromColor(size:CGSize(width:40,height:40),color:UIColor(red:1,green:1,blue:0,alpha:0.5))
让nButton = UIButton(frame:CGRect(x:40,y:150,width:40,height:40))
nButton.setTitle(“ N”,for:.normal)
nButton.setTitleColor(UIColor.black,for:.normal)
nButton.titleLabel!.textAlignment = .center
nButton.setImage(buttonImage,for:.normal)
nButton.addTarget(self,action:#selector(self.moveN),for:.touchUpInside)
nButton.tag = 29998
让wButton = UIButton(frame:CGRect(x:0,y:190,宽度:40,高度:40))
wButton.setTitle(“ W”,for:.normal)
wButton.setTitleColor(UIColor.black,for:.normal)
wButton.titleLabel!.textAlignment = .center
wButton.setImage(buttonImage,用于:.normal)
wButton.addTarget(self,action:#selector(self.moveW),for:.touchUpInside)
wButton.tag = 29997
let sButton = UIButton(框架:CGRect(x:40,y:230,宽度:40,高度:40))
sButton.setTitle(“ S”,for:.normal)
sButton.setTitleColor(UIColor.black,for:.normal)
sButton.titleLabel!.textAlignment = .center
sButton.setImage(buttonImage,用于:.normal)
sButton.addTarget(self,action:#selector(self.moveS),for:.touchUpInside)
sButton.tag = 29996
让eButton = UIButton(frame:CGRect(x:80,y:190,width:40,height:40))
eButton.setTitle(“ E”,用于:.normal)
eButton.setTitleColor(UIColor.black,for:.normal)
eButton.titleLabel!.textAlignment = .center
eButton.setImage(buttonImage,用于:.normal)
eButton.addTarget(self,action:#selector(self.moveE),for:.touchUpInside)
eButton.tag = 29995
self.hijackingSubviews.append(nButton)
self.hijackingSubviews.append(wButton)
self.hijackingSubviews.append(sButton)
self.hijackingSubviews.append(eButton)
}
@objc open func hijackAppWindow(){
self.displayDisplayLabel()
}
fileprivate func displayDisplayLabel(){
守卫让委托= UIApplication.shared.delegate else {
返回
}
守卫让窗口=委托。窗口其他{
返回
}
用于hijackingSubviews {
如果让existingHijackView = window?.viewWithTag(hijackingView.tag){
现有的HijackView.removeFromSuperview()
}
window?.addSubview(hijackingView)
}
}
私人功能imageFromColor(大小:CGSize,颜色:UIColor)-> UIImage {
UIGraphicsBeginImageContext(CGSize(width:size.width,height:size.height))
UIBezierPath.init(roundedRect:CGRect(x:0,y:0,width:size.width,height:size.height),cornerRadius:3).addClip()
UIGraphicsGetCurrentContext()!. setFillColor(color.cgColor)
UIGraphicsGetCurrentContext()!. fill(CGRect(x:0,y:0,width:size.width,height:size.height))
让colorImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
返回colorImage !;
}
}
扩展程序PatchUIManager {
func moveN(){
var currentCoordinate = LocationSwizzler.currentLocation
currentCoordinate.latitude = currentCoordinate.latitude + 0.0001
LocationSwizzler.currentLocation = currentCoordinate
}
func moveW(){
var currentCoordinate = LocationSwizzler.currentLocation
currentCoordinate.longitude = currentCoordinate.longitude-0.0001
LocationSwizzler.currentLocation = currentCoordinate
}
func moveS(){
var currentCoordinate = LocationSwizzler.currentLocation
currentCoordinate.latitude = currentCoordinate.latitude-0.0001
LocationSwizzler.currentLocation = currentCoordinate
}
func moveE(){
var currentCoordinate = LocationSwizzler.currentLocation
currentCoordinate.longitude = currentCoordinate.longitude + 0.0001
LocationSwizzler.currentLocation = currentCoordinate
}
}
PatchUIManager有助于在UIApplication的主应用程序窗口上添加UIViews。 在此类中,我们将添加带有消息UIWindow Hijacked!!!
的标签UIWindow Hijacked!!!
,以及4个按钮,使我们可以在游戏中的任意位置走虚拟形象,而忽略设备的实际位置。
#import“ PatchLoader.h”
#import“ LocationSpoofing-Swift.h”
@implementation PatchLoader
静态void __attribute __((constructor))initialize(void){
NSLog(@” ====行动中的代码注入====”);
[LocationSwizzler turnOnSwizzleForCoordinate];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,2 * NSEC_PER_SEC),dispatch_get_main_queue(),^ {
静态PatchUIManager * patchUIManager;
patchUIManager = [PatchUIManager新];
[patchUIManager hijackAppWindow];
});
}
@结束
PatchLoader是我们将代码注入到.ipa文件中的入口。 当此文件加载到内存中时,将调用__attribute __((constructor))初始化方法。 该方法将通过LocationSwizzler类设置CLLocation Swizzling。 PatchLoader应用程序将初始化并使用PatchUIManager将自定义视图添加到UIWindow。 由于此时尚未启动实际的游戏,因此我们将在2秒后触发UI Hijack(希望UIWindow已准备好被利用)
继续并在XCode中构建动态库,然后执行下图所示的以下过程(修补,重新签名和安装)。 由于我们的动态库中有Swift类,因此请务必将标准Swift dylib库添加到修补过程中。
成功完成上述所有过程后,您应该能够看到添加到应用程序UIWindow上的自定义UIView。 您还将注意到,您的虚拟形象并不位于您的实际位置(该位置已在新加坡莱佛士城预设)。 通过点击黄色的控制按钮,您将能够将虚拟形象走到想要的任何地方。 令人失望的是,我们的“无处不在”功能不如PokeGO ++版本响应。 这是使用我们新烘焙的修改后的.ipa文件并通过收集戳球和捉住怪物(并获得经验)进一步进入游戏的视频证据。
终止描述:DYLD,库未加载: @ rpath / libswiftQuartzCore .dylib | 引用自:/var/containers/Bundle/Application/0965B9B7-ECAB-4AD6-8733-2DEF8A8153DC/pokemongo.app/Dylibs/LocationSpoofing
根据上面的屏幕截图,在应用启动期间引发了异常,因为原始PokemonGo ipa本身缺少必需的dylib依赖项。 解决方案很简单。 由于缺少的dylib是标准的swift xcode库,因此您可以简单地从以下位置复制libswiftQuartzCore.dylib文件:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos/libswiftQuartzCore.dylib
到在修补过程中使用的“ Dylibs ”文件夹。 如果缺少的依赖项在Xcode中不可用,则您可能需要扫描主.ipa文件本身。