逆向学习实战之--替换哈罗单车图片

逆向学习实战之–替换哈罗单车图片 最近学习iOS逆向知识也有一段时间了,今天就找了一个App练下手,来检测这段时间的学习效果。
逆向的APP是哈罗单车,目的是实现替换地图上面单车的定位图片,之前好像在网上看到过有人实现过这个效果。

  • 明确目的,梳理思路
既然是替换原有单车的图片,那么只需要找到初始化设置图片的地方即可,然后hook处理成我们需要的图片。
  • 准备工作
1、越狱手机4S,iOS8.0系统,4S是armv7的架构,目前iPhone从5S开始都是arm64架构,奈何自己很穷,买不起好手机,哎o(╥﹏╥)o ,但是逆向的思路是一样的,区别只是汇编语言有点差异。
2、利用dumpdecrypted对应用砸壳获取EasyBike.decrypted备用,利用class-dump导出APP的头文件备用
  • 分析开始
1、从界面入手,利用cycript或者Reveal找出单车所在的视图 MAAnnotationContainerView
逆向学习实战之--替换哈罗单车图片
文章图片

2、查看 MAAnnotationContainerView.h 文件分析该类中的方法
根据方法命名来初步猜测添加AnnotationView的方法。
- (void)addAnnotationView:(id)arg1;

3、利用lldb来动态调试目标程序
a、利用lldb命令 image list -o -f 获取目标APP的偏移地址0x0005e000
b、将之前砸壳的EasyBike.decrypted文件放入IDA分析获取addAnnotationView方法的基地址:__text:0x0050578C
c、设置断点 br s -a ‘0x0050578C+0x0005e000’ ,查看添加单车图片的时候是否会触发
当拖动地图,地图添加AnnotationView便会触发该方法,所以这个方法就是我们需要找的方法。
(lldb) br s -a '0x0050578C+0x0005e000' Breakpoint 1: where = EasyBike`_mh_execute_header + 5230748, address = 0x0056378c (lldb) c error: Process is running.Use 'process interrupt' to pause execution. Process 2231 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0056378c EasyBike`_mh_execute_header + 5248908 EasyBike`_mh_execute_header: ->0x56378c <+5248908>: svcge#0x3b5f0 0x563790 <+5248912>: stceqp9, c14, [r0, #-180] 0x563794 <+5248916>: pkhbtmi r4, r3, r2, lsl #13 0x563798 <+5248920>: .long0xf25b4650; unknown opcode Target 0: (EasyBike) stopped. (lldb) c

d、那么现在利用IDA查看addAnnotationView方法的实现,确认这里是否有添加图片的操作呢
初略的过一遍该方法的汇编代码(汇编代码就不贴出了),并没有相关图片的操作,关键的几个方法如下:
[self addSubview:] [self annotation] setSelected: setObject:forKey:

这个时候就要考虑,是否在其他地方就已经处理过了,那么接下来先看看addAnnotationView的参数类型了。
e、在之前设置的断点中,添加一些自定义的命令
br com add 1 po $r2 c DONE// 断点打印参数类型 JYAroundBikeAnnoView JYNearlyBikeAnnoView 选中其中一个AnnotationView打印 JYStartPointAnnoView

所以addAnnotationView的参数类型可以是JYStartPointAnnoView、JYAroundBikeAnnoView、JYNearlyBikeAnnoView
f、利用导出的头文件查看这三个类的内容
结果是这三个类中都没有ImageView或者Image的影子,但是在这三个类的父类MAAnnotationView中存在UIImageView的属性,此时猜想界面上的单车图片就是这个ImageView来决定的
g、在IDA中搜索MAAnnotationView,查找有Image信息的方法,发现有一个[MAAnnotationView setImage:]的方法,查看这个方法的汇编实现。不难发现这个方法就是设置图片的方法。
// 关键代码 __text:0051A246MOVR5, R0 __text:0051A248MOVR0, R2 __text:0051A24ABLX.W_objc_retain __text:0051A24EMOVR8, R0 __text:0051A250MOVR0, #(_OBJC_IVAR_$_MAAnnotationView._image - 0x51A25C) ; UIImage *_image; __text:0051A258ADDR0, PC; UIImage *_image; __text:0051A25ALDRR6, [R0] ; UIImage *_image; __text:0051A25CLDRR4, [R5,R6] __text:0051A25ECMPR4, R8 __text:0051A260BEQ.Wloc_51A396 __text:0051A264MOVR0, R8 __text:0051A266BLX.W_objc_retain __text:0051A26ASTRR0, [R5,R6] __text:0051A26CMOVR0, R4 __text:0051A26EBLX.W_objc_release __text:0051A272MOVR0, #(selRef_imageView - 0x51A27E) __text:0051A27AADDR0, PC; selRef_imageView __text:0051A27CLDR.WR10, [R0] ; "imageView" __text:0051A280MOVR0, R5; void * __text:0051A282MOVR1, R10 ; char * __text:0051A284BLX.W_objc_msgSend// 伪代码 UIIMageView * imageView = [self imageView]; __text:0051A288MOVR7, R7 __text:0051A28ABLX.W_objc_retainAutoreleasedReturnValue __text:0051A28EMOVR4, R0 __text:0051A290MOVR0, #(selRef_setImage_ - 0x51A29E) __text:0051A298LDRR2, [R5,R6] __text:0051A29AADDR0, PC; selRef_setImage_ __text:0051A29CLDRR1, [R0] ; "setImage:" __text:0051A29EMOVR0, R4; void * __text:0051A2A0BLX.W_objc_msgSend __text:0051A2A4MOVR0, R4// 伪代码 [imageView setImage:_image];

h、通过上面的分析终于找到设置图片的方法了,后面通过hook setImage:方法就可以将图片替换成自己的方法了
  • 编写Tweak验证
@interface MAAnnotationView: UIView @property(readonly, nonatomic) UIImageView *imageView; @end%hook MAAnnotationView - (void)setImage:(UIImage *)image { %orig; // JYNearlyBikeAnnoViewJYAroundBikeAnnoViewJYStartPointAnnoView // JYStartPointAnnoView 选中之后的这种类型不做处理 if ([self isKindOfClass:%c(JYNearlyBikeAnnoView)] || [self isKindOfClass:%c(JYAroundBikeAnnoView)]) { self.imageView.image = [UIImage imageWithContentsOfFile:@"/mv.png"]; } } %end

  • 查看结果
    逆向学习实战之--替换哈罗单车图片
    文章图片

  • 总结
【逆向学习实战之--替换哈罗单车图片】这个是这段时间学习以来完成的一个比较完善的逆向实战了,虽然比较简单,但也实现了从零到一开始,刚开始的分析是不像上面那样简单的,分析过程中还是遇到了很多问题,但是多花时间去研究就会越来越窥探到逆向开发的门路。

    推荐阅读