iOS逆向工程——非越狱调试

其实iOS的逆向分析业界已经十分成熟了,网上也有许多有趣的尝试(一步一步实现iOS微信自动抢红包(非越狱)。本文着重于如何在非越狱机器上进行调试,出于学习及总结的目的,记录于此。

本文以破解游戏梦幻西游为例,逐步讲解整个调试流程。

->工具

完成整个过程需要准备以下几个必要工具:

1、iOSOpenDev,用于允许在Xcode上创建Dylib工程;

2、yololib,用于为二进制文件注入Dylib;

3、class-dump,用于导出 decrypted 的二进制文件的头文件;

4、CaptainHook,这是一个头文件,引入工程后,我们可以通过宏快速地 Hook 任意方法;

5、一台越狱机器,安装 cycriptopenssh

非必要工具:

1、dumpdecrypted,用于为AppStore包的二进制文件破壳;

注:dumpdecrypted 之所以非必要,是因为一般情况下可以从越狱市场下到已经 decrypted 后的app!如果下到的包不是 decrypted 的,请自行百度 decrypted。

->定位

首先我们要解决的问题是,在哪里注入我们的调试入口。这个定位过程必须要有越狱机器的配合。我们会通过在越狱机器(已安装应用)上运行 cycript 确定应用视图层级。

在MAC命令行运行:

    ->ssh root@192.168.10.11 #你的越狱手机的IP,默认越狱机器密码为 alpine->ps -e #关掉其它应用,从进程列表中找到应用对应的进程号,一般路径带了一串MD5值的就是了->cycript -p 2231 #进行cycript

当 cycript 运行后,就可以通过命令行运行objc代码:

    cy#[[UIApplication sharedApplication].keyWindow recursiveDescription]

这里用到了私有方法 recursiveDescription ,会返回整个层级的描述。

<UIWindow: 0x15cd9de50; frame = (0 0; 667 375); autoresize = W+H; gestureRecognizers = <NSArray: 0x15e08c260>; layer = <UIWindowLayer: 0x15cd79f50>>| <CCEAGLView: 0x15e08d2a0; frame = (0 0; 667 375); autoresize = W+H; gestureRecognizers = <NSArray: 0x15cdc2290>; layer = <CAEAGLLayer: 0x15e08c8f0>>

到这,我们定位了主View对应的类,现在我们需要写点代码Hook这个类。

->编写Dylib

通过 iOSOpenDev 创建一个Dylib工程,把主工程文件由.m 改为.mm,引入头文件 CaptainHook.h,把主工程文件.mm替换为以下内容:

#import "CaptainHook.h"__attribute__((constructor)) static void entry() {[[BQInjectToolHelper sharedInstance] injectToolsToMY];
}static BQInjectToolsNavigationController *sharedMainNav = nil;CHDeclareClass(CCEAGLView);CHMethod(7, id, CCEAGLView, initWithFrame, CGRect, frame, pixelFormat, id, arg2, depthFormat, unsigned int, arg3, preserveBackbuffer, _Bool, arg4, sharegroup, id, arg5, multiSampling, _Bool, arg6, numberOfSamples, unsigned int, arg7)
{//调用原来的AsyncOnAddMsg:MsgWrap:方法id v = CHSuper(7, CCEAGLView, initWithFrame, frame, pixelFormat, arg2, depthFormat, arg3, preserveBackbuffer, arg4, sharegroup, arg5, multiSampling, arg6, numberOfSamples, arg7);if (sharedMainNav == nil) {BQInjectToolsMainViewController *mainVc = [[BQInjectToolsMainViewController alloc] init];BQInjectToolsNavigationController *mainNav = [[BQInjectToolsNavigationController alloc] initWithRootViewController:mainVc];sharedMainNav = mainNav;}[sharedMainNav injectToSuperView:v];BQLog(@"BQ Inject initWithFrame:pixelFormat:depthFormat:preserveBackbuffer:sharegroup:multiSampling:numberOfSamples: success!");return v;
}@implementation BQInjectToolHelper+ (BQInjectToolHelper *)sharedInstance
{static BQInjectToolHelper *sharedInsatnce = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{sharedInsatnce = [[BQInjectToolHelper alloc] init];});return sharedInsatnce;
}- (void)injectToolsToMY
{CHLoadLateClass(CCEAGLView);CHClassHook(0, CCEAGLView, init);CHClassHook(1, CCEAGLView, initWithFrame);CHClassHook(2, CCEAGLView, initWithFrame, pixelFormat);CHClassHook(3, CCEAGLView, initWithFrame, pixelFormat, depthFormat);CHClassHook(7, CCEAGLView, initWithFrame, pixelFormat, depthFormat, preserveBackbuffer, sharegroup, multiSampling, numberOfSamples);BQLog(@"BQ Injected!");
}@end@implementation BQInjectToolsNavigationController- (void)injectToSuperView:(UIView *)view
{if (view == nil || self.view.superview == view) return;[self.view removeFromSuperview];self.view.frame = CGRectMake((view.frame.size.width - _injectToolsContentSize.width) / 2, -_injectToolsContentSize.height, _injectToolsContentSize.width, _injectToolsContentSize.height);[view addSubview:self.view];[self addGestureRecognizerToView:view];
}@end

这里做了几件事:

1、申明了CCEAGLView 类,并Hook了方法 -(id)initWithFrame:(struct CGRect)arg1 pixelFormat:(id)arg2 depthFormat:(unsigned int)arg3 preserveBackbuffer:(_Bool)arg4 sharegroup:(id)arg5 multiSampling:(_Bool)arg6 numberOfSamples:(unsigned int)arg7 方法;

2、在补始化CCEAGLView 时,为该View添加子View以及Pan手势响应;

后续我们就可以通过手势,呼出我们注入的页面了。

这里有个小技巧,在cycript下,输入 [[CCEAGLView alloc] init ,并按两下 tab 键,cycript会为你联想方法,你可以把方法列表里的方法全Hook了(事实上我就是这么做的)

编写完代码后运行,这里注意保证生成的dylib的目标架构包含(armv7&arm64)。

->注入

在命令行运行:

    ->yololib MY.app/MY libJDYTest.dylib #注意文件的相对路径,dylib文件不能带前置目录

如果你的应用包含多个架构支持,那么yololib会分别为你的每一个架构注入dylib。运行后如下:

    Reading binary: libJDYTest.dylib2016-06-08 21:26:50.944 yololib[47766:1342053] FAT binary!2016-06-08 21:26:50.944 yololib[47766:1342053] Injecting to arch 92016-06-08 21:26:50.944 yololib[47766:1342053] Patching mach_header..2016-06-08 21:26:50.945 yololib[47766:1342053] Attaching dylib..2016-06-08 21:26:50.945 yololib[47766:1342053] Injecting to arch 112016-06-08 21:26:50.945 yololib[47766:1342053] Patching mach_header..2016-06-08 21:26:50.945 yololib[47766:1342053] Attaching dylib..2016-06-08 21:26:50.945 yololib[47766:1342053] Injecting to arch 02016-06-08 21:26:50.945 yololib[47766:1342053] 64bit arch wow2016-06-08 21:26:50.946 yololib[47766:1342053] dylib size wow 562016-06-08 21:26:50.946 yololib[47766:1342053] mach.ncmds 232016-06-08 21:26:50.946 yololib[47766:1342053] mach.ncmds 242016-06-08 21:26:50.946 yololib[47766:1342053] Patching mach_header..2016-06-08 21:26:50.946 yololib[47766:1342053] Attaching dylib..2016-06-08 21:26:50.946 yololib[47766:1342053] size 542016-06-08 21:26:50.946 yololib[47766:1342053] complete!

看到上面的提示就表示注入完成了。注入的地址是 @executable_path/libJDYTest.dylib ,因此最终要把dylib放到和app可执行文件相同的目录下。

->重签名

重签名需要以下三个东西:

1、libJDYTest.dylib,这个是我们已经注入到二进制的动态库;

2、配对的证书和.mobileprovision文件;

3、Entitlements.plist文件;

1我们已经生成。2的获取方式如下:

1、从 https://developer.apple.com 申请开发者证书,证书名如下iPhone Developer: YourName (YYYYYYYYY),记下证书名YYYYYYYYY;

[2]、创建一个新应用工程,在工程 Build-Setting 中,把 Code signing 的Profile和证书指定为开发者证书;

[3]、运行起新工程,在Product里点app右键,找到app的目录,在app目录下有.mobileprovision文件(第三步其实可以不必做,这么做是为了保险起见);

Entitlement.pist 是用于申明应用权限的文件,会在签名中使用到,3的获取方式如下:

1、在 https://developer.apple.com 查找到证书的TeamID;

2、按如下模板生成 Entitlement.plist;

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict><key>application-identifier</key><string>XXXXXXXXXX.as.your.wish.name</string><key>com.apple.developer.team-identifier</key><string>XXXXXXXXXX</string><key>get-task-allow</key><true/><key>keychain-access-groups</key><array><string>XXXXXXXXXX.as.your.wish.name</string></array>
</dict>
</plist>

以上文件准备好后,运行如下命令:

    ->cp libJDYTest.dylib MY.app/->cp embedded.mobileprovision MY.app/->rm -rf MY.app/_CodeSignature  # 如果你的应用有ext或都watch,需要对Watch和ext中的_CodeSignature同样删了,或者干脆把Watch和ext删了->codesign -f -s YYYYYYYYY MY.app/libJDYTest.dylib->codesign -f -s YYYYYYYYY --entitlements Entitlements.plist MY.app->xcrun -sdk iphoneos PackageApplication -v MY.app -o $(pwd)/MYFinish.ipa

运行完后,MYFinish.ipa就是我们的最终成果,用itools装到非越狱的iphone上吧。

这里签名需要注意以下两点:

1、签名的开发者证书,在钥匙串中的 属性->信任->使用此证书时 ,必须要选择<系统默认>否则签名不成功;

2、Apple Worldwide Developer Relations CA - G2证书同上;

验证是否正确答名成功使用以下命令:

    ->codesign -vvvvv MYFinish.app/libJDYTest.dylib MYFinish.app/libJDYTest.dylib: valid on diskMYFinish.app/libJDYTest.dylib: satisfies its Designated Requirement

->调试

MYFinish.ipa 安装好后,后续重复以上步骤就可以在自己的面板上开发功能了。当然我们可以把上面的操作写成脚本,并保存为 fastPack.sh,方便快速的签名和打包,代码如下。

## 1、move yololib to /usr/local/bin/ by your self;
## 2、copy app dylib mobileprovision plist to the same path with this shell;
## 3、the all name will not support any space;
##
##                                                                 ——Zhiqiang.bzq
##                                                                    2016.06.04## Functions ##
function makeFinishName() {# appname=$1# name=${appname%.*}# ext=${appname##*.}# finishname="${name}Finish.$ext"echo $1;
}function checkArgument() {if [ $# != 5 ]; thenecho "use like this : $0 appname.app libname.dylib embedded.mobileprovision entitlement.plist cername"exit 1fiappname=$1libname=$2profile=$3entitlement=$4echo "checking arguments..."if [ ! -d $appname ]; thenecho "app $appname no exist"exit 2fiif [ ! -f $libname ]; thenecho "dylib $libname no exist"exit 3fiif [ ! -f $profile ]; thenecho "profile $profile no exist"exit 4fiif [ ! -f $entitlement ]; thenecho "entitlement $entitlement no exist"exit 5fi
}function doCopy() {echo "copying file..."finishname=$(makeFinishName $1)# if [ -d $finishname ]; then#     rm -rf $finishname# fi# cp -rf $1 $finishnamecp $2 "${finishname}/"cp $3 "${finishname}/"
}function doInjectAtPath() {echo "injecting..."finishname=$(makeFinishName $1)name=${1%.*}yololib "${finishname}/${name}" "$2"
}function findExtFilesAtPath () {ext=$1path=$2result=$(find $2/. -name "*.$1")echo $result
}function removeCodeSignAtPath () {rm -rf "$1/_CodeSignature"
}function doCodeSign() {echo "code signning..."finishname=$(makeFinishName $1)removeCodeSignAtPath "${finishname}/_CodeSignature"# find appex extensionappeses=$(findExtFilesAtPath "appex" "${finishname}/")for appex in $appeses; doremoveCodeSignAtPath $appexcodesign -f -s $5 $appexdone# for sub appapps=$(findExtFilesAtPath "app" "${finishname}/")for app in $apps; doremoveCodeSignAtPath $appcodesign -f -s $5 $appdone# resign dylibdylibs=$(findExtFilesAtPath "dylib" "${finishname}/")for dylib in $dylibs; docodesign -f -s $5 $dylibdone# sign the whole app by entitlementcodesign -f -s $5 --entitlements $4 $finishname
}function doGenerateIPA() {echo "packing ipa..."finishname=$(makeFinishName $1)name=${finishname%.*}path=$(pwd)xcrun -sdk iphoneos PackageApplication -v $finishname -o ${path}/${name}.ipa
}function main() {checkArgument $*doCopy $*doInjectAtPath $*doCodeSign $*# doGenerateIPA $*echo "done!"
}## Script ##
main $*

但这样远远不够,至少无法快速的进行断点调试。打开我们之前为了获取.mobileprofile文件创建的工程,添加新的Target,并改为MY(和目标可执行文件名相同即可)。

在MY的Build Phases中添加Run Script,Run Script添加如下脚本:

    lib_path="${BUILT_PRODUCTS_DIR}/lib${TARGET_NAME}.dylib"local_workspace="/Users/zhiqiangbao/Desktop/HackMH"rm -rf "${BUILT_PRODUCTS_DIR}/MY.app"cp -rf "${local_workspace}/MY.app" "${BUILT_PRODUCTS_DIR}/"chmod 777 "${BUILT_PRODUCTS_DIR}/MY.app/MY" #注意,这一步必须cp -rf "${local_workspace}/embedded.mobileprovision" "${BUILT_PRODUCTS_DIR}/"cp -rf "${local_workspace}/Entitlements.plist" "${BUILT_PRODUCTS_DIR}/"cp -rf "${local_workspace}/fastPack.sh" "${BUILT_PRODUCTS_DIR}/"cd $BUILT_PRODUCTS_DIR./fastPack.sh MY.app libJDYTest.dylib embedded.mobileprovision     Entitlements.plist "XXXXXXXX"cd -

这里做了个小trick,在Xcode为新工程生成完app后,我们用自己签名过的app替换了它。所以最终被安装上手机的是被我们cracked的应用。

CMD+R运行工程试试,哈哈,大功告成。PS:游戏内的原生Log也可以看哦。

附图:

ResultDebug
log
HackMY

另附上开发工具dylib的git地址,别忘了改Run Script中的地址信息哦!

梦幻西游开发工具:git@gitlab.alibaba-inc.com:zhiqiang.bzq/MY_Cracked.git

用以下命令初始化:

    ->git submodule init->git submodule update

如有不正之处,欢迎指正~!^ ^

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/284454.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[转]2022 Flutter 宣布发布 Windows 正式版

原文链接&#xff1a; https://medium.com/flutter/announcing-flutter-for-windows-6979d0d01fed 自从推出 Flutter 以来&#xff0c;我们一直专注于为漂亮的定制应用提供跨平台解决方案&#xff0c;这些应用被编译为机器代码并充分利用设备的底层图形硬件功能。 今天这一愿景…

电脑经常弹出“不支持的硬件”解决办法

电脑经常弹出“不支持的硬件”解决办法。 通过微软官方查证,这是由于以上处理器需要最新的Windows10系统才会这样子的,而大多出现该提示的都安装了Win7或是Win8.1系统。 来至微软官方的说明 此错误出现的原因是各代新处理器要求最新Windows版本以获得支持。 例如,Windows 1…

使用 Web API 上传和下载多个文件

原文作者&#xff1a;Jay Krishna Reddy原文链接&#xff1a;https://www.c-sharpcorner.com/article/upload-and-download-multiple-files-using-web-api/翻译&#xff1a;沙漠尽头的狼&#xff08;谷歌翻译加持&#xff0c;文中版本使用.NET 6升级&#xff09;---正文开始---…

【MapGIS精品教程】002:GDB本地数据库的使用

本文主要内容为MapGISGDB本地数据库的使用&#xff0c;包括&#xff1a;GDB企业管理器的认识、GDB本地数据库的创建方法、GDB本地数据库的备份和恢复。 1. GDB企业管理器的认识 GDB是地理数据的资源管理器&#xff0c;主要对空间数据进行有序组织与管理。 GDB数据管理包括&…

RabbitMQ学习3----运行和管理RabbitMQ

1.服务为管理 Erlang天生就是为了让应用程序无需知道对方是否存在同一台机器上即可互相通信。 Erlang节点&#xff1a;Erlang虚拟机的每个实例。多个Erlang应用程序可以运行在同一个节点之上。节点之间可以进行本地通信&#xff08;不管他们是运行在同一台服务器之上&#xff0…

各代移动网络性能

摘自《中国元宇宙白皮书》 下载整书完整版https://www.aliyundrive.com/s/gXQvRLM22kD

EFCore高级Saas系统下单DbContext如何支持不同数据库的迁移

前言随着系统的不断开发和迭代默认的efcore功能十分强大&#xff0c;但是随着Saas系统的引进efcore基于表字段的多租户模式已经非常完美了&#xff0c;但是基于数据库的多租户也是可以用的&#xff0c;但是也存在缺点&#xff0c;缺点就是没有办法支持不同数据库&#xff0c;mi…

51. Python 数据处理(2)

1.Python 修改excel文件import xlrd import xlutils.copy excelr xlrd.open_workbook("hello.xlsx") excelw xlutils.copy.copy(excelr) sheet1 excelw.get_sheet(0) sheet1.write(3, 5, "xlutils.copy test test") excelw.save("hello.xlsx"…

人工智能十大流行算法

导读&#xff1a;本文为有志于成为数据科学家或对此感兴趣的读者们介绍最流行的机器学习算法。 作者&#xff1a;Fahim ul Haq 译者&#xff1a;刘志勇&#xff0c;策划&#xff1a;赵钰莹 来源&#xff1a;InfoQ&#xff08;ID&#xff1a;infoqchina&#xff09; 机器学习是…

Win7+Win10双系统安装全攻略

安装双系统,不仅能给你非凡的体验,还可以满足工作中因系统版本,兼容性,处理器等原因带来的不便。本文讲解Win7+Win10双系统安装全攻略,亲测可用。 1. 硬盘分区 本文讲解利用固态硬盘+机械硬盘的分区方式。 固态硬盘:为了绝对提高系统运行的速度,将固态硬盘作为双系统的…

聊聊研发团队中的“人”

大家好&#xff0c;我是Z哥。汉字博大精深&#xff0c;很多时候我们可以通过拆字来更形象地理解一个词的含义。比如“团队”这个词的两个字"团"和“队”单独看也都是表示一种由多人组成的组织。再做一下拆字就是“口”“才”和“耳”“人”。前者表示一个人才如果没有…

[转]【分布式系统】唯一ID生成策略总结

文章目录 全局唯一id介绍 全局唯一id特点:常见全局唯一id生成策略 1、数据库自增长序列或字段生成id 2、UUID 3、Redis生成ID 4、zookeeper生成ID 5、Twitter的snowflake算法全局唯一id介绍 系统唯一id是我们在设计阶段常常遇到的问题。在复杂的分布式系统中&#…

超全的开源Winform UI库,满足你的一切桌面开发需求!

本文有dotnet9站长整理 网址&#xff1a;https://dotnet9.com/本站曾介绍过一款Winform开源控件库HZHControls&#xff0c;Winform在大家心中的地位还是挺高的&#xff0c;今天小编再分享一款新鲜出炉的 Winform UI库——SunnyUI&#xff0c;一起跟 Dotnet9 往下看吧。项目名称…

告别国外 IDE,阿里 蚂蚁自研 IDE 研发框架 OpenSumi 正式开源

经历近 3 年时间&#xff0c;在阿里集团及蚂蚁集团共建小组的努力下&#xff0c;OpenSumi 作为国内首个强定制性、高性能&#xff0c;兼容 VS Code 插件体系的 IDE 研发框架&#xff0c;今天正式对外开源。 一 OpenSumi 是什么&#xff1f; OpenSumi 是一款面向垂直领域&#…

window-memcache技术随笔

memcached.exe软件放置到非中文,非空格的目录,把MSVCR71.DLL文件放在memcached.exe同目录下启动,控制面板中打开window功能-Telnet客户端memcache服务方法一:管理员身份打开黑窗口 d:(mem的所在盘)cd memmemcached.exe -p 11211方法二: 安装为Windows的系统服务memcached.exe -…

将不确定变为确定~老赵写的CodeTimer是代码性能测试的利器

首先&#xff0c;非常感谢赵老大的CodeTimer&#xff0c;它让我们更好的了解到代码执行的性能&#xff0c;从而可以让我们从性能的角度来考虑问题&#xff0c;有些东西可能我们认为是这样的&#xff0c;但经理测试并非如何&#xff0c;这正应了我之前的那名话&#xff1a;“机器…

聊聊 C++ 中的几种智能指针(下)

一&#xff1a;背景 上一篇我们聊到了C 的 auto_ptr &#xff0c;有朋友说已经在 C 17 中被弃用了&#xff0c;感谢朋友提醒&#xff0c;今天我们来聊一下 C 11 中引入的几个智能指针。unique_ptrshared_ptrweak_ptr看看它们都怎么玩。二&#xff1a;三大智能指针详解 1. uniq…

iOS回顾笔记( 02 ) -- 由九宫格布局引发的一系列“惨案”

iOS回顾笔记&#xff08; 02 &#xff09; -- 由九宫格布局引发的一系列“惨案” 前言&#xff08;扯几句淡先&#xff09; 回顾到学习UI过程中的九宫格布局时&#xff0c;发现当时学的东西真是不少。 这个阶段最大的特点就是&#xff1a;知识点繁多且琐碎。 我们的目标就是要将…

【GlobalMapper精品教程】007:如何加载谷歌卫星影像?

“Global Mapper支持所有OGC标准数据源类型,例如用于流式栅格地图的WMS / WMTS,用于矢量数据集的WFS和用于为指定区域下载单个数据文件的WCS。预先切片的图像和地形数据集也可以使用OSM(OpenStreetMaps)、TMS(Tiled Map Service)和Google Maps瓦片架构支持。您只需要选择适当…

Mysql清空表(truncate)与删除表中数据(delete)的区别

2019独角兽企业重金招聘Python工程师标准>>> 为某基于wordpress搭建的博客长久未除草&#xff0c;某天升级的时候发现已经被插入了几万条垃圾留言&#xff0c;如果一条条删除那可真是累人的活。遂考虑直接进入mysql直接清空表或者删除表中数据。 本文记录一下这2种操…