小谷禿頭合集ios
小谷的公司每月能夠遲到3次,小谷5月的時候考勤居然遲到了4次。很難受。爲了杜絕這種狀況。毅然決然的研究一波偷偷打卡😃
git
小谷用的設備是iPhone XS Max
,iOS 14.3(越獄
),目前最新的釘釘:6.0.16
。markdown
用Windows
作逆向
的兄弟們,常常使用IDA和Reveal
還有終端debugserver附加進程
,今天小谷要用iOS開發的兄弟們都比較喜歡的Xcode和hopper
。😆(其實都差很少。)函數
先看效果圖post
蹂躪第一步,首先要裝酷學習
frida-ios-dump
,小谷寫過一篇砸殼和Frida的博客.這樣
砸過殼
的釘釘.ipa
就出來了,先放這,咱們先無論他ui
iOS
兄弟們超級喜歡的,Xcode
調試(曾經有兄弟問過我怎麼附加的。我這裏畫下流程圖)這樣就清晰不少了spa
定位打卡
的代碼了啊 (找到打卡界面,viewdebug
調試)我滴天啊。是個
WKWebview
,定位不到!!插件
這樣就結束了嗎?怎麼可能呢,那之後小谷要是遲到,沒有辦法彌補了~·
debug
整理下思路和線索
WKWebview
界面H5
會有變化,說明是有地方告訴H5
定位成功告訴H5
的,那麼他們就必定有交互代碼
交互
,咱們知道hook住
這個交互
就能夠了(看裏面的回傳
,經過改變值可能作到)locationManager: didUpdateLocations:
H5交互的時候開始定位
,而後回調定位信息
那麼咱們接下來的任務就是
定位交互的代碼
和打印回傳的信息
了!! 搞起,搞起~
咱們剛開始導出了釘釘.ipa
,解壓
,拿MachO
文件
而後經過class-dump
取出header
class-dump -H DingTalk -o dingHeader
Hopper
(搜索locationManager: didUpdateLocations:
)一共就
5
個,咱們就把這幾個hook
一下,看下log
了,我猜想應該就能夠定位到了(若是他調用的原生的
)
Monkey
寫Tweak插件
了(固然也能夠用THEOS
,主要咱們此次可能要好幾回調試才能定位,我就用Monkey
方便點~)釘釘的APPID
,並配置5
個,hook
一下#import <UIKit/UIKit.h>
%hook AMapLocationCLMDelegate
- (void)locationManager:(id)arg1 didUpdateLocations:(id)arg2{
%log;
%orig;
}
%end
%hook AMapLocationManager
- (void)locationManager:(id)arg1 didUpdateLocations:(id)arg2{
%log;
%orig;
}
%end
%hook LALocationManager
- (void)locationManager:(id)arg1 didUpdateLocations:(id)arg2{
%log;
%orig;
}
%end
%hook DTCLocationManager
- (void)locationManager:(id)arg1 didUpdateLocations:(id)arg2{
%log;
%orig;
}
%end
%hook MAMapView
- (void)locationManager:(id)arg1 didUpdateLocations:(id)arg2{
%log;
%orig;
}
%end
複製代碼
而後咱們安裝插件,看下
log
AMapLocationCLMDelegate
和AMapLocationManager
都是成對出現的,其餘的都沒有走class-dump
出來的header
文件。發現AMapLocationCLMDelegate
裏面都是一些代理回調這個時候,小谷又能夠推測一波了: 在
AMapLocationManager
獲取的位置,而後參數在把參數傳給H5交互
AMapLocationManager
裏面的方法都打一遍log
,使用logify.pl
log
看到了不錯的信息。咱們要繼續開始
Xcode調試附加
了
Hopper
找到偏移位置Xcode
附加下,能夠找到ASLR
0x104e70000 + 0x36b4a8 = 0x1051DB4A8
函數調用棧
了!!有沒有那麼一丟丟爽歪歪~ (若是沒有符號也沒有關係,咱們就經過
Hopper
地址定位!)
hook
下這個函數%hook LAPluginInstanceCollector
- (void)handleJavaScriptRequest:(id)arg1 callback:(id)arg2{
%log;
%orig;
}
%end
複製代碼
callback
是個block
,說明arg1
是參數,arg2
是回調回去的參數block
的參數類型。就要看看他的簽名
了~經過
內存平移
來拿他的簽名
~
Hopper
拿地址。而後Xcode附加下斷點
0x100f50000 + 0x488f110 = 0x1057DF110
b 0x1057DF110
斷住它,而後分析他
hook
了,看看他裏面的參數
是啥%hook LAPluginInstanceCollector
- (void)handleJavaScriptRequest:(id)arg1 callback:(void (^) (id))arg2{
//咱們能夠自定義個block看下。
id xg_callback = ^(id argCb){
//能夠先把傳入的參數打印下,看看有沒有啥觸發器
NSLog(@"xg_callback arg1:%@",arg1);
//而後把傳入的參數打印下,也看下他是什麼類型的
NSLog(@"xg_callback argCbClass:%@, argCb:%@",[argCb class],argCb);
arg2(argCb);
};
//xg_callback替換arg2。(只作了一個轉接的過程)
%orig(arg1,xg_callback);
}
%end
複製代碼
我好像找到了,可是這裏面還有好多其餘跟他相關連的信息。(好比地址,城市,經緯度啥的)
咱們知道他類型是個字典。
action=start
的時候觸發
%hook LAPluginInstanceCollector
- (void)handleJavaScriptRequest:(id)arg1 callback:(void (^) (id))arg2{
id xg_callback = ^(id argCb){
//小谷作的時候其實打了好多log。。
NSDictionary *arg1Dic = (NSDictionary *)arg1;
if([arg1Dic[@"action"] isEqualToString:@"start"]){
NSLog(@"xg_callback text:start");
NSMutableDictionary * CbDic = [NSMutableDictionary dictionaryWithDictionary:argCb];
if (CbDic[@"result"][@"latitude"] && CbDic[@"result"][@"longitude"]){
NSLog(@"xg_callback text:result");
NSMutableDictionary * resultDic = [NSMutableDictionary dictionaryWithDictionary:CbDic[@"result"]];
resultDic[@"latitude"] = @"40.0361208767361";
resultDic[@"longitude"] = @"116.4161067708333";
[CbDic setValue:resultDic forKey:@"result"];
}
arg2(CbDic);
}else{
arg2(argCb);
}
};
//xg_callback替換arg2。(只作了一個轉接的過程)
%orig(arg1,xg_callback);
}
%end
複製代碼
主要功能寫的差很少了。咱們再來設置一個開關來控制一下:若是
開關開啓
,就走打卡插件邏輯
,若是開關關閉
,走原來的邏輯
。
Xcode
好強大~
dataSource
吧tableview
啊,把他的代碼一hook
加行cell
,不是很easy
嗎)@interface DTTableViewHandler : NSObject
- (long long)numberOfSectionsInTableView:(UITableView *)tableView;
@end
%hook DTTableViewHandler
%new
-(void)xg_switchChang:(UISwitch *)switchView{
[XGDefaults setBool:switchView.isOn forKey:XGSWITCHKEY];
[XGDefaults synchronize];
}
- (long long)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
// 若是是最後一組,增長一行
if([tableView.nextResponder .nextResponder isKindOfClass:%c(DTSettingListViewController)] && (section == [self numberOfSectionsInTableView:tableView]-1)){
return 1;
}
return %orig;
}
- (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//最後一組,最後一行,設置一個cell
if([tableView.nextResponder .nextResponder isKindOfClass:%c(DTSettingListViewController)] && ([indexPath section] == [self numberOfSectionsInTableView:tableView]-1)){
UITableViewCell * cell = nil;
if([indexPath row] == 0){
static NSString * swCell = @"SWCELL";
cell = [tableView dequeueReusableCellWithIdentifier:swCell];
if(!cell){
cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:nil];
}
cell.textLabel.text = @"偷偷打卡開啓!!";
UISwitch * switchView = [[UISwitch alloc] init];
switchView.on = [XGDefaults boolForKey:XGSWITCHKEY];
[switchView addTarget:self action:@selector(xg_switchChang:) forControlEvents:(UIControlEventValueChanged)];
cell.accessoryView = switchView;
cell.backgroundColor = [UIColor whiteColor];
return cell;
}
return nil;
}else{
return %orig;
}
}
- (double)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
//設置最後一組最後一行的行高
if([tableView.nextResponder .nextResponder isKindOfClass:%c(DTSettingListViewController)] && ([indexPath section] == [self numberOfSectionsInTableView:tableView]-1)){
return 45;
}
return %orig;
}
- (long long)numberOfSectionsInTableView:(UITableView *)tableView {
//增長一組
if([tableView.nextResponder .nextResponder isKindOfClass:%c(DTSettingListViewController)]){
return %orig + 1;
}
return %orig;
}
%end
複製代碼
if([arg1Dic[@"action"] isEqualToString:@"start"] && [XGDefaults boolForKey:XGSWITCHKEY]){
這篇博客禁止作商業用途。純屬爲了學習,若是有法律責任與本人無關!!
這篇博客是小谷自創的,若是轉載請標明出處!
小谷原本想直接HOOK
-iOS回調
的那個函數
改值,不過感受會有誤傷
好了兄弟們。逆向插件
開發了一波。小谷準備下一篇寫個基礎安防
的
不過不能寫這麼長了。博客寫太長,兄弟們估計不想看。我儘可能精簡
最後祝兄弟們,愈來愈帥!!!! 還有你們永不遲到~