追踪iOS某APP的验证签名过程
利用反汇编追踪iOS某APP的验证签名过程
环境需求
-
越狱iOS设备一台,
-
Openssh
-
Cycript
-
Hopper Disassembler v4*
-
iProxy
对iOS APP进行砸壳
首先用USB连接越狱手机,使用USB进行端口映射到本机
iproxy 2222 22
新开终端
ssh root@127.0.0.1 -p 2222
开始砸壳
DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /var/mobile/Containers/Bundle/Application/1999C8D2-58C1-43C0-A717-A44B55CC1FEA/***.app/***
得到砸壳后的文件
Testerde-iPhone:~/decrypted root# ls
cf.decrypted
Testerde-iPhone:~/decrypted root#
使用Hopper载入砸壳后的文件同时使用class-dump导出头文件
class-dump -H ./cf.decrypted -o ./header --arch arm64
注意在砸壳手机上运行的是什么CPU架构的,我们这里是arm64
在使用charles抓包时发现URL中使用auth_key参数传递了验证签名,所以在hopper 中搜索auth_key
得到以下片段
00000001011436a9 db "WSOpenMemberViewController", 0 ; DATA XREF=cfstring_WSOpenMemberViewController
00000001011436c4 db "loadedTimeRanges", 0 ; DATA XREF=cfstring_loadedTimeRanges
00000001011436d5 db "v32@?0{?=qiIq}8", 0
00000001011436e5 db "mm:ss", 0 ; DATA XREF=cfstring_mm_ss
00000001011436eb db "%@-%.f-0-0-%@", 0 ; DATA XREF=cfstring______f_0_0___
00000001011436f9 db "%@?auth_key=%.f-0-0-%@", 0 ; DATA XREF=cfstring____auth_key___f_0_0___
0000000101143710 db "player", 0 ; DATA XREF=0x10138cc60, 0x1013d6b60, 0x1013e1218, 0x101484138, 0x1014e82c8, 0x1014f6400, 0x10155c500, 0x101592bb8, 0x101593f18
0000000101143717 db "T@\"AVPlayer\",&,N,V_player", 0 ; DATA XREF=0x10138cc60, 0x1013d6b60, 0x101484138, 0x1014f6400, 0x101592bb8, 0x101593f18
0000000101143731 db "playerItem", 0 ; DATA XREF=0x10138cc70, 0x1013d6b70
000000010114373c db "T@\"AVPlayerItem\",&,N,V_playerItem", 0 ; DATA XREF=0x10138cc70, 0x1013d6b70
000000010114375e db "playerLayer", 0 ; DATA XREF=0x10138cc80, 0x1013d6b80, 0x1013e1228, 0x1014f6410, 0x10155c510
000000010114376a db "T@\"AVPlayerLayer\",&,N,V_playerLayer", 0 ; DATA XREF=0x10138cc80, 0x1013d6b80, 0x1014f6410
双击
00000001011436f9 db "%@?auth_key=%.f-0-0-%@", 0 ; DATA XREF=cfstring____auth_key___f_0_0___
查看到
cfstring____auth_key___f_0_0___:
00000001012e7760 dq ___CFConstantStringClassReference, 0x7c8, 0x1011436f9, 0x16 ; "%@?auth_key=%.f-0-0-%@", DATA XREF=-[WSAVPlayerView encryptionUrl:andVideoKey:]+368, -[WSSpecialColumPlayerView encryptionUrl:andVideoKey:]+368
这可以可以得出auth_key这个字符串在
- [WSAVPlayerView encryptionUrl:andVideoKey:]+368
- [WSSpecialColumPlayerView encryptionUrl:andVideoKey:]+368
这两个地方使用过,这查看使用class_dump导出的头文件
WSAVPlayerView.h
//
// Generated by class-dump 3.5 (64 bit).
//
// class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard.
//
#import "UIView.h"
@class AVPlayer, AVPlayerItem, AVPlayerLayer, NSString, NSTimer, UIButton, UIImageView, UILabel, UIProgressView, UISlider, UITapGestureRecognizer;
@interface WSAVPlayerView : UIView
{
_Bool _isPortraitShow;
_Bool _isVIP;
_Bool _isNetWorkWiFi;
_Bool _isSeeking;
_Bool _isShowingTool;
NSString *_currentUrlString;
NSString *_videoKey;
double _time;
id <WSAVPlayerViewDelegate> _delegate;
AVPlayer *_player;
AVPlayerItem *_playerItem;
AVPlayerLayer *_playerLayer;
UISlider *_progressSlider;
UIView *_topToolView;
UIView *_bottomToolView;
UIView *_vipView;
UILabel *_vipLabel;
UIButton *_vipButton;
UIButton *_continueButton;
UIImageView *_vipBgImageView;
UIButton *_backButton;
UIButton *_lockButton;
UIButton *_playButton;
UILabel *_progressTimeLabel;
UILabel *_restTimeLabel;
UIButton *_expandOrShrinkButton;
AVPlayerItem *_currentPlayerItem;
NSTimer *_progressTimer;
UIProgressView *_progressView;
UITapGestureRecognizer *_tapGesture;
NSTimer *_toolControlTimer;
}
+ (Class)layerClass;
@property(nonatomic) _Bool isShowingTool; // @synthesize isShowingTool=_isShowingTool;
@property(nonatomic) _Bool isSeeking; // @synthesize isSeeking=_isSeeking;
@property(retain, nonatomic) NSTimer *toolControlTimer; // @synthesize toolControlTimer=_toolControlTimer;
@property(retain, nonatomic) UITapGestureRecognizer *tapGesture; // @synthesize tapGesture=_tapGesture;
@property(retain, nonatomic) UIProgressView *progressView; // @synthesize progressView=_progressView;
@property(retain, nonatomic) NSTimer *progressTimer; // @synthesize progressTimer=_progressTimer;
@property(retain, nonatomic) AVPlayerItem *currentPlayerItem; // @synthesize currentPlayerItem=_currentPlayerItem;
@property(retain, nonatomic) UIButton *expandOrShrinkButton; // @synthesize expandOrShrinkButton=_expandOrShrinkButton;
@property(retain, nonatomic) UILabel *restTimeLabel; // @synthesize restTimeLabel=_restTimeLabel;
@property(retain, nonatomic) UILabel *progressTimeLabel; // @synthesize progressTimeLabel=_progressTimeLabel;
@property(retain, nonatomic) UIButton *playButton; // @synthesize playButton=_playButton;
@property(retain, nonatomic) UIButton *lockButton; // @synthesize lockButton=_lockButton;
@property(retain, nonatomic) UIButton *backButton; // @synthesize backButton=_backButton;
@property(retain, nonatomic) UIImageView *vipBgImageView; // @synthesize vipBgImageView=_vipBgImageView;
@property(retain, nonatomic) UIButton *continueButton; // @synthesize continueButton=_continueButton;
@property(retain, nonatomic) UIButton *vipButton; // @synthesize vipButton=_vipButton;
@property(retain, nonatomic) UILabel *vipLabel; // @synthesize vipLabel=_vipLabel;
@property(retain, nonatomic) UIView *vipView; // @synthesize vipView=_vipView;
@property(retain, nonatomic) UIView *bottomToolView; // @synthesize bottomToolView=_bottomToolView;
@property(retain, nonatomic) UIView *topToolView; // @synthesize topToolView=_topToolView;
@property(retain, nonatomic) UISlider *progressSlider; // @synthesize progressSlider=_progressSlider;
@property(retain, nonatomic) AVPlayerLayer *playerLayer; // @synthesize playerLayer=_playerLayer;
@property(retain, nonatomic) AVPlayerItem *playerItem; // @synthesize playerItem=_playerItem;
@property(retain, nonatomic) AVPlayer *player; // @synthesize player=_player;
@property(nonatomic) _Bool isNetWorkWiFi; // @synthesize isNetWorkWiFi=_isNetWorkWiFi;
@property(nonatomic) _Bool isVIP; // @synthesize isVIP=_isVIP;
@property(nonatomic) _Bool isPortraitShow; // @synthesize isPortraitShow=_isPortraitShow;
@property(nonatomic) __weak id <WSAVPlayerViewDelegate> delegate; // @synthesize delegate=_delegate;
@property(readonly, nonatomic) double time; // @synthesize time=_time;
@property(retain, nonatomic) NSString *videoKey; // @synthesize videoKey=_videoKey;
@property(readonly, copy, nonatomic) NSString *currentUrlString; // @synthesize currentUrlString=_currentUrlString;
- (void).cxx_destruct;
- (void)layoutSubviews;
- (void)dealloc;
- (id)getPrivateKey:(id)arg1;
- (id)encryptionUrl:(id)arg1 andVideoKey:(id)arg2;
- (void)seekTime:(double)arg1;
- (id)convertTime:(double)arg1;
- (double)availableDuration;
- (void)observeValueForKeyPath:(id)arg1 ofObject:(id)arg2 change:(id)arg3 context:(void *)arg4;
- (void)playerDidFinishPlaying:(id)arg1;
- (void)prepareToPlay;
- (void)removeSystemNotifications;
- (void)addSystemNotifications;
- (void)removeTimeObserver;
- (void)addTimeObserver;
- (void)removePlayerItemStatusObserver;
- (void)addPlayerItemStatusObserver;
- (void)refreshProgessUI;
- (void)showVIPView:(_Bool)arg1;
- (void)hideVIPView;
- (void)hideToolView;
- (void)showToolView;
- (void)continuePlayVideo;
- (void)openVIPAction;
- (void)expandOrShrinkAction:(id)arg1;
- (void)playAction:(id)arg1;
- (void)lockAction:(id)arg1;
- (void)backAction:(id)arg1;
- (void)resumeRefreshing;
- (void)pauseRefreshing;
- (void)seek:(id)arg1;
- (void)addExternToolView;
- (void)playWithUrlString:(id)arg1;
- (void)clean;
- (void)pause;
- (void)play;
@property(readonly, nonatomic) _Bool isPlaying;
- (void)initializeAVPlayer;
- (id)initWithFrame:(struct CGRect)arg1;
- (id)initWithFrame:(struct CGRect)arg1 playUrl:(id)arg2;
@end
通过查看头文件可以看到
[WSAVPlayerView encryptionUrl:andVideoKey:]
方法中的VideoKey会保存在view的属性里面,我们来看看这个VideoKey是什么?
在终端查看进程id
ps -e
5507 ?? 0:14.64 /var/mobile/Containers/Bundle/Application/3912B0D8-705D-42E0-A087-D7A9711CB464/QQ.app/QQ
5703 ?? 0:05.17 /var/mobile/Containers/Bundle/Application/30C91D48-B9A6-4CA2-9669-A76073893084/WeChat.app/WeChat
5830 ?? 0:00.30 /usr/libexec/rtcreportingd
5976 ?? 0:00.64 /System/Library/Frameworks/SystemConfiguration.framework/SCHelper
6030 ?? 1:01.96 /var/mobile/Containers/Bundle/Application/1999C8D2-58C1-43C0-A717-A44B55CC1FEA/***.app/***
这时使用cycript附加上去
cycript -p 6030
cy#
我们先让这个播放器初始化完成并传入数据,这时需要在手机上进入到响应页面点击播放按钮
查看当前的视图层次
UIApp.keyWindow.recursiveDescription().toString()
<WSAVPlayerView: 0x12688de50; frame = (0 0; 320 201); hidden = YES; gestureRecognizers = <NSArray: 0x170846180>; layer = <AVPlayerLayer: 0x1748221a0>>
发现 WSAVPlayerView的内存地址为0x12688de50
这时为了方便下次的调用我们声明一个变量
cy# var pv = #0x12688de50
#"<WSAVPlayerView: 0x12688de50; frame = (0 0; 320 201); hidden = YES; gestureRecognizers = <NSArray: 0x170846180>; layer = <AVPlayerLayer: 0x1748221a0>>"
查看属性VideoKey
cy# pv.videoKey
@"NnVpU1VEc2drMTIzQVB4dDY="
通过对比发现NnVpU1VEc2drMTIzQVB4dDY=的值是在请求视频资料中传入的
我们把输入带入[WSAVPlayerView encryptionUrl:andVideoKey:]
这个方法需要传入两个参数,第一个为url,第二个为key
cy# [pv encryptionUrl:@"http://www.baidu.com/class/18007651/454eae93a1963d7c31b1076b7c5a6e58_18007651_480.mp4" andVideoKey:@"NnVpU1VEc2drMTIzQVB4dDY="]
@"http://www.baidu.com/class/18007651/454eae93a1963d7c31b1076b7c5a6e58_18007651_480.mp4?auth_key=1503547268-0-0-077178daad75b10032af437b1d5d4cfb"
这里返回了正确的auth_key说明我们找的函数对了
那么我们来看看hopper这个函数大致做了一些什么
00000001000ee4b4 mov x23, x0
00000001000ee4b8 adrp x8, #0x101615000 ; @selector(setStarImage:highlightedStarImage:)
00000001000ee4bc ldr x1, [x8, #0x948] ; "timeIntervalSince1970",@selector(timeIntervalSince1970)
00000001000ee4c0 bl imp___stubs__objc_msgSend
00000001000ee4c4 mov v8, v0
00000001000ee4c8 adrp x28, #0x101643000 ; @selector(wifiReachability)
00000001000ee4cc ldr x0, [x28, #0x9d0] ; objc_cls_ref_WOWSUtils,__objc_class_WOWSUtils_class
00000001000ee4d0 adrp x8, #0x101617000 ; @selector(defaultManager)
00000001000ee4d4 ldr x1, [x8, #0x660] ; "base64Decode:",@selector(base64Decode:)
00000001000ee4d8 mov x2, x20
00000001000ee4dc bl imp___stubs__objc_msgSend
00000001000ee4e0 mov x29, x29
00000001000ee4e4 bl imp___stubs__objc_retainAutoreleasedReturnValue
00000001000ee4e8 mov x25, x0
00000001000ee4ec adrp x8, #0x101617000 ; @selector(defaultManager)
00000001000ee4f0 ldr x1, [x8, #0x668] ; "getPrivateKey:",@selector(getPrivateKey:)
00000001000ee4f4 mov x0, x24
00000001000ee4f8 mov x2, x25
00000001000ee4fc bl imp___stubs__objc_msgSend
00000001000ee500 mov x29, x29
00000001000ee504 bl imp___stubs__objc_retainAutoreleasedReturnValue
00000001000ee508 mov x24, x0
00000001000ee50c adrp x21, #0x101643000 ; @selector(wifiReachability)
00000001000ee510 ldr x0, [x21, #0xab0] ; objc_cls_ref_NSString,_OBJC_CLASS_$_NSString
00000001000ee514 adrp x8, #0x101612000
00000001000ee518 ldr x26, [x8, #0xad0] ; "stringWithFormat:",@selector(stringWithFormat:)
00000001000ee51c str x24, [sp, #0x10]
00000001000ee520 str d8, [sp, #0x8]
00000001000ee524 str x22, sp
00000001000ee528 adrp x2, #0x1012e7000
00000001000ee52c add x2, x2, #0x740 ; @"%@-%.f-0-0-%@"
00000001000ee530 mov x1, x26
00000001000ee534 bl imp___stubs__objc_msgSend
00000001000ee538 mov x29, x29
00000001000ee53c bl imp___stubs__objc_retainAutoreleasedReturnValue
00000001000ee540 mov x27, x0
00000001000ee544 ldr x0, [x28, #0x9d0] ; objc_cls_ref_WOWSUtils,__objc_class_WOWSUtils_class
00000001000ee548 adrp x8, #0x101617000 ; @selector(defaultManager)
00000001000ee54c ldr x1, [x8, #0x670] ; "getMD5String:",@selector(getMD5String:)
00000001000ee550 mov x2, x27
00000001000ee554 bl imp___stubs__objc_msgSend
00000001000ee558 mov x29, x29
00000001000ee55c bl imp___stubs__objc_retainAutoreleasedReturnValue
00000001000ee560 mov x28, x0
00000001000ee564 ldr x0, [x21, #0xab0] ; objc_cls_ref_NSString,_OBJC_CLASS_$_NSString
00000001000ee568 str x28, [sp, #0x10]
00000001000ee56c str d8, [sp, #0x8]
00000001000ee570 str x19, sp
00000001000ee574 adrp x2, #0x1012e7000
00000001000ee578 add x2, x2, #0x760 ; @"%@?auth_key=%.f-0-0-%@"
00000001000ee57c mov x1, x26
00000001000ee580 bl imp___stubs__objc_msgSend
00000001000ee584 mov x29, x29
00000001000ee588 bl imp___stubs__objc_retainAutoreleasedReturnValue
00000001000ee58c mov x26, x0
00000001000ee590 mov x0, x28
00000001000ee594 bl imp___stubs__objc_release
00000001000ee598 mov x0, x27
00000001000ee59c bl imp___stubs__objc_release
00000001000ee5a0 mov x0, x24
00000001000ee5a4 bl imp___stubs__objc_release
00000001000ee5a8 mov x0, x25
00000001000ee5ac bl imp___stubs__objc_release
00000001000ee5b0 mov x0, x23
00000001000ee5b4 bl imp___stubs__objc_release
00000001000ee5b8 mov x0, x22
00000001000ee5bc bl imp___stubs__objc_release
00000001000ee5c0 ldr x0, [sp, #0x18]
00000001000ee5c4 bl imp___stubs__objc_release
00000001000ee5c8 b loc_1000ee5d8
loc_1000ee5cc:
00000001000ee5cc mov x0, x19 ; CODE XREF=-[WSAVPlayerView encryptionUrl:andVideoKey:]+68, -[WSAVPlayerView encryptionUrl:andVideoKey:]+72
00000001000ee5d0 bl imp___stubs__objc_retain
00000001000ee5d4 mov x26, x0
loc_1000ee5d8:
00000001000ee5d8 mov x0, x20 ; CODE XREF=-[WSAVPlayerView encryptionUrl:andVideoKey:]+448
00000001000ee5dc bl imp___stubs__objc_release
00000001000ee5e0 mov x0, x19
00000001000ee5e4 bl imp___stubs__objc_release
00000001000ee5e8 mov x0, x26
00000001000ee5ec ldp x29, x30, [sp, #0x80]
00000001000ee5f0 ldp x20, x19, [sp, #0x70]
00000001000ee5f4 ldp x22, x21, [sp, #0x60]
00000001000ee5f8 ldp x24, x23, [sp, #0x50]
00000001000ee5fc ldp x26, x25, [sp, #0x40]
00000001000ee600 ldp x28, x27, [sp, #0x30]
00000001000ee604 ldp d9, d8, [sp, #0x20]
00000001000ee608 add sp, sp, #0x90
00000001000ee60c b imp___stubs__objc_autoreleaseReturnValue
; endp
用hopper查看得出大致流程
- 解密base64的VideoKey
- 格式化需要签名的字符串
- 生成效验字符串MD5
- 格式化成最终URL,也就是上面返回值
解密base64的VideoKey
那现在我们来看看怎么解密VideoKey的
服务器传下来的
VideoKey是NnVpU1VEc2drMTIzQVB4dDY=
base64解码以后的字符为
6uiSUDsgk123APxt6
00000001000ee4cc ldr x0, [x28, #0x9d0] ; objc_cls_ref_WOWSUtils,__objc_class_WOWSUtils_class
00000001000ee4d0 adrp x8, #0x101617000 ; @selector(defaultManager)
00000001000ee4d4 ldr x1, [x8, #0x660] ; "base64Decode:",@selector(base64Decode:)
00000001000ee4d8 mov x2, x20
00000001000ee4dc bl imp___stubs__objc_msgSend
00000001000ee4e0 mov x29, x29
00000001000ee4e4 bl imp___stubs__objc_retainAutoreleasedReturnValue
00000001000ee4e8 mov x25, x0
00000001000ee4ec adrp x8, #0x101617000 ; @selector(defaultManager)
00000001000ee4f0 ldr x1, [x8, #0x668] ; "getPrivateKey:",@selector(getPrivateKey:)
在反汇编中可以看到解码以后调用了getPrivateKey方法
那么我们这里在cycript中带入看看
cy# [pv getPrivateKey:@"6uiSUDsgk123APxt6"]
@"sgk123"
发现这个结果是正确的
这是在hopper中查看[WSAVPlayerView getPrivateKey:]方法
00000001000ee610 stp x24, x23, [sp, #-0x40]! ; Objective C Implementation defined at 0x10138c348 (instance method), DATA XREF=0x10138c348
00000001000ee614 stp x22, x21, [sp, #0x10]
00000001000ee618 stp x20, x19, [sp, #0x20]
00000001000ee61c stp x29, x30, [sp, #0x30]
00000001000ee620 add x29, sp, #0x30
00000001000ee624 mov x20, x2
00000001000ee628 adrp x8, #0x101615000 ; @selector(setStarImage:highlightedStarImage:)
00000001000ee62c ldr x21, [x8, #0x1c8] ; "substringToIndex:",@selector(substringToIndex:)
00000001000ee630 mov x0, x20
00000001000ee634 bl imp___stubs__objc_retain
00000001000ee638 mov x19, x0
00000001000ee63c orr w2, wzr, #0x1
00000001000ee640 mov x0, x20
00000001000ee644 mov x1, x21
00000001000ee648 bl imp___stubs__objc_msgSend
00000001000ee64c mov x29, x29
00000001000ee650 bl imp___stubs__objc_retainAutoreleasedReturnValue
00000001000ee654 mov x21, x0
00000001000ee658 adrp x8, #0x101612000
00000001000ee65c ldr x22, [x8, #0x8c8] ; "integerValue",@selector(integerValue)
00000001000ee660 mov x1, x22
00000001000ee664 bl imp___stubs__objc_msgSend
00000001000ee668 mov x23, x0
00000001000ee66c mov x0, x21
00000001000ee670 bl imp___stubs__objc_release
00000001000ee674 adrp x8, #0x101612000
00000001000ee678 ldr x1, [x8, #0xa98] ; "length",@selector(length)
00000001000ee67c mov x0, x20
00000001000ee680 bl imp___stubs__objc_msgSend
00000001000ee684 sub x2, x0, #0x1
00000001000ee688 adrp x8, #0x101614000 ; @selector(setReturnKeyType:)
00000001000ee68c ldr x1, [x8, #0x460] ; "substringFromIndex:",@selector(substringFromIndex:)
00000001000ee690 mov x0, x20
00000001000ee694 bl imp___stubs__objc_msgSend
00000001000ee698 mov x29, x29
00000001000ee69c bl imp___stubs__objc_retainAutoreleasedReturnValue
00000001000ee6a0 mov x21, x0
00000001000ee6a4 mov x1, x22
00000001000ee6a8 bl imp___stubs__objc_msgSend
00000001000ee6ac mov x22, x0
00000001000ee6b0 mov x0, x21
00000001000ee6b4 bl imp___stubs__objc_release
00000001000ee6b8 adrp x8, #0x101617000 ; @selector(defaultManager)
00000001000ee6bc ldr x1, [x8, #0x678] ; "substringWithRange:",@selector(substringWithRange:)
00000001000ee6c0 mov x0, x20
00000001000ee6c4 mov x2, x23
00000001000ee6c8 mov x3, x22
00000001000ee6cc bl imp___stubs__objc_msgSend
00000001000ee6d0 mov x20, x0
00000001000ee6d4 mov x0, x19
00000001000ee6d8 bl imp___stubs__objc_release
00000001000ee6dc mov x0, x20
00000001000ee6e0 bl imp___stubs__objc_retainAutoreleasedReturnValue
00000001000ee6e4 ldp x29, x30, [sp, #0x30]
00000001000ee6e8 ldp x20, x19, [sp, #0x20]
00000001000ee6ec ldp x22, x21, [sp, #0x10]
00000001000ee6f0 ldp x24, x23, [sp]!, #0x40
00000001000ee6f4 b imp___stubs__objc_autoreleaseReturnValue
; endp
字符串6uiSUDsgk123APxt6得出sgk123的过程为
第一个字符和最后一个字符为字符串需要截取的开始和结尾
比如
6uiSUDsgk123APxt6 => 6uiSUD sgk123 APxt6
9TFQUz4wN sgk123 7ltDvfB6 => 9TFQUz4wN sgk123 7ltDvfB6
格式化需要签名的字符串
00000001000ee508 mov x24, x0
00000001000ee50c adrp x21, #0x101643000 ; @selector(wifiReachability)
00000001000ee510 ldr x0, [x21, #0xab0] ; objc_cls_ref_NSString,_OBJC_CLASS_$_NSString
00000001000ee514 adrp x8, #0x101612000
00000001000ee518 ldr x26, [x8, #0xad0] ; "stringWithFormat:",@selector(stringWithFormat:)
00000001000ee51c str x24, [sp, #0x10]
00000001000ee520 str d8, [sp, #0x8]
00000001000ee524 str x22, sp
00000001000ee528 adrp x2, #0x1012e7000
00000001000ee52c add x2, x2, #0x740 ; @"%@-%.f-0-0-%@"
00000001000ee530 mov x1, x26
00000001000ee534 bl imp___stubs__objc_msgSend
00000001000ee538 mov x29, x29
00000001000ee53c bl imp___stubs__objc_retainAutoreleasedReturnValue
00000001000ee540 mov x27, x0
00000001000ee544 ldr x0, [x28, #0x9d0] ; objc_cls_ref_WOWSUtils,__objc_class_WOWSUtils_class
00000001000ee548 adrp x8, #0x101617000 ; @selector(defaultManager)
00000001000ee54c ldr x1, [x8, #0x670] ; "getMD5String:",@selector(getMD5String:)
[WSAVPlayerView encryptionUrl:andVideoKey:]方法反汇编中可以看到
format的格式为%@-%.f-0-0-%@,这里有三个参数,怎么取获取这三个参数的值?
格式化完成以后传入getMD5String:方法
直接在getMD5String中查看传入的值就好了,这里使用lldb 的debugserver查看
debugserver默认没有task_for_pid权限
我们先把越狱手机/Developer/usr/bin/debugserver复制到mac
先创建一个ent.xml
然后保存一下内容
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.springboard.debugapplications</key>
<true/>
<key>get-task-allow</key>
<true/>
<key>task_for_pid-allow</key>
<true/>
<key>run-unsigned-code</key>
<true/>
</dict>
</plist>
执行签名
ldid -Sent.xml debugserver
然后复制到越狱设备的/usr/bin/
开启调试***为进程名称
Testerde-iPhone:~/ root# debugserver *:1234 -a "***"
debugserver-@(#)PROGRAM:debugserver PROJECT:debugserver-320.2.89
for arm64.
Attaching to process ***...
Listening to port 1234 for a connection from *..
这时调试服务器已经监听开启了1234端口等候处理
这里我们再使用iProxy映射一个端口
iproxy 1234 1234
新开一个终端
启动lldb建立和debugserver的连接
➜ ~ lldb
(lldb) process connect connect://127.0.0.1:1234
Process 6254 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
frame #0: 0x00000001965d4e7c libsystem_kernel.dylib`mach_msg_trap + 8
libsystem_kernel.dylib`mach_msg_trap:
-> 0x1965d4e7c <+8>: ret
libsystem_kernel.dylib`mach_msg_overwrite_trap:
0x1965d4e80 <+0>: mov x16, #-0x20
0x1965d4e84 <+4>: svc #0x80
0x1965d4e88 <+8>: ret
(lldb)
查看基址
(lldb) image list -o -f
[ 0] 0x0000000000084000 /private/var/mobile/Containers/Bundle/Application/1999C8D2-58C1-43C0-A717-A44B55CC1FEA/***.app/***(0x0000000100084000)
[ 1] 0x0000000000094000 /Users/charley/Library/Developer/Xcode/iOS DeviceSupport/8.1.3 (12B466)/Symbols/usr/lib/dyld
[ 2] 0x000000010182c000 /Library/MobileSubstrate/MobileSubstrate.dylib(0x000000010182c000)
[ 3] 0x0000000003aac000 /Users/charley/Library/Developer/Xcode/iOS DeviceSupport/8.1.3 (12B466)/Symbols/usr/lib/libc++.1.dylib
[ 4] 0x0000000003aac000 /Users/charley/Library/Developer/Xcode/iOS DeviceSupport/8.1.3 (12B466)/Symbols/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics
[ 5] 0x0000000003aac000 /Users/charley/Library/Developer/Xcode/iOS DeviceSupport/8.1.3 (12B466)/Symbols/System/Library/Frameworks/Foundation.framework/Foundation
[ 6] 0x0000000003aac000 /Users/charley/Library/Developer/Xcode/iOS DeviceSupport/8.1.3 (12B466)/Symbols/System/Library/Frameworks/ImageIO.framework/ImageIO
[ 7] 0x0000000003aac000 /Users/charley/Library/Developer/Xcode/iOS DeviceSupport/8.1.3 (12B466)/Symbols/System/Library/Frameworks/MobileCoreServices.framework/MobileCoreServices
[ 8] 0x0000000003aac000 /Users/charley/Library/Developer/Xcode/iOS DeviceSupport/8.1.3 (12B466)/Symbols/System/Library/Frameworks/QuartzCore.framework/QuartzCore
[ 9] 0x0000000003aac000 /Users/charley/Library/Developer/Xcode/iOS DeviceSupport/8.1.3 (12B466)/Symbols/System/Library/Frameworks/Security.framework/Security
[ 10] 0x0000000003aac000 /Users/charley/Library/Developer/Xcode/iOS DeviceSupport/8.1.3 (12B466)/Symbols/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration
这里可以看到基址为0x0000000000084000
[ 0] 0x0000000000084000 /private/var/mobile/Containers/Bundle/Application/1999C8D2-58C1-43C0-A717-A44B55CC1FEA/***.app/***(0x0000000100084000)
lldb命令c让程序继续运行
(lldb) c
Process 6254 resuming
(lldb)
我们在getMD5String这个方法的第一行下断点,也就是
下面的第一行
0000000100493b48 sub sp, sp, #0x60 ; Objective C Implementation defined at 0x10143f320 (class method), DATA XREF=0x10143f320
0000000100493b4c stp x24, x23, [sp, #0x20]
0000000100493b50 stp x22, x21, [sp, #0x30]
0000000100493b54 stp x20, x19, [sp, #0x40]
0000000100493b58 stp x29, x30, [sp, #0x50]
0000000100493b5c add x29, sp, #0x50
0000000100493b60 mov x19, x2
那么程序在手机内存中的地址怎么计算?
其实就是上面查看到的基址0x0000000000084000 +第一行的偏移量0000000100493b48 = 0x100517B48
那么我就在0x100517B48下断点
(lldb) br s -a 0x100517B48
Breakpoint 6: where = *** `_mh_execute_header + 4772212, address = 0x0000000100517b48
手机点击界面进行播放,lldb会断下来执行po $x2查看传入的参数
Process 6254 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 6.1
frame #0: 0x0000000100517b48 ***`_mh_execute_header + 4799304
***`_mh_execute_header:
-> 0x100517b48 <+4799304>: sub sp, sp, #0x60 ; =0x60
0x100517b4c <+4799308>: stp x24, x23, [sp, #0x20]
0x100517b50 <+4799312>: stp x22, x21, [sp, #0x30]
0x100517b54 <+4799316>: stp x20, x19, [sp, #0x40]
(lldb)po $x2
/class/17426404/2dbe0a6c9077e5aa969196faf047be2b_17426404_480.mp4-1503551940-0-0-sgk123
(lldb)
是不是很清楚了
%@-%.f-0-0-%@格式化的三个参数
- url路径
- 时间戳
- PrivateKey
后面的就比较容易了
生成效验字符串MD5
使用格式化的字符做MD5结果
f62b7278787782d900497c498d7271b2
格式化成最终URL
格式
@"%@?auth_key=%.f-0-0-%@"
参数如下
- url地址
- 时间戳
- md5签名
格式化的结果
http://www.baidu.com/class/18007651/454eae93a1963d7c31b1076b7c5a6e58_18007651_480.mp4?auth_key=1503552405-0-0-f62b7278787782d900497c498d7271b2