Kotani bald collection
1. The introduction
-
Kotani’s company can be late three times a month, and Kotani was late for work four times in May. Very afflictive. To put an end to that. Resolutely study a wave of secretly clocked ๐
-
Kotani is using an iPhone XS Max, iOS 14.3 (jailbroken), and the latest update: 6.0.16.
-
IDA, Reveal and Terminal DebugServer add-on processes are often used in reverse Windows. Xcode and Hopper are preferred by iOS developers today. ๐ (in fact, both are about the same.)
-
Look at the renderings first
2. Nail punch card plug-in
2.1. Debug the application
The first step to ravaging is to act cool
- Break the nail into the shell and take it off. I’m using
frida-ios-dump
“Xiao Gu wrote an articleShell and FridaThe blog.
That’s the nail in the shell. Ipa comes out. Let’s leave it there. Let’s leave it there
- Has begun!
iOS
The guys love it so much,Xcode
Debugging (have brothers asked me how to attach. Let me draw a flow chart here.
That’s a lot clearer
- If we can debug it, let’s just
Positioning punching
Find the punch screen,viewdebug
Debugging)
Oh, my God. It is a WKWebview, unable to locate!
Is that the end of it? How is it possible, after that xiaogu if late, there is no way to make up ~ยท
2.1.1. The train of thought
Gather your thoughts and clues
- Clues:
- The punch in interface is a
WKWebview
interface - When we clocked in
H5
There’s a change, which means there’s a placeTell the H5
Positioning success - If it’s native positioning
Tell the H5
Yes, then they must haveInteraction code
- The punch in interface is a
- Ideas:
- If they have
interaction
We knowHook to live
thisinteraction
Just look insideComes back
, possible by changing the value) - If it is an iOS location, it will definitely go
locationManager: didUpdateLocations:
- It could be,
H5 interaction starts positioning
And thenCallback location information
- If they have
Then our next task is to locate the interactive code and print the message back!! Play, play
2.2. Location code
-
So we just started exporting the tacks. Ipa, unzip, get the MachO file
-
Then fetch the header through class-dump
class-dump -H DingTalk -o dingHeader
- Drag the binaries in
Hopper
(searchlocationManager: didUpdateLocations:
)
There are only 5 in total, we hook these several, look at the log, I guess should be able to locate (if he calls the native)
- We’ll use it this time
Monkey
writeTweak the plugin
You can also use itTHEOS
This time we may need several debugging before positioning, I will useMonkey
Convenient point ~)
- To obtain
The APPID nailing
And the configuration
- The one we found up there
5
A,hook
the
#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
Copy the code
And then let’s install the plugin and look at the log
- We found this
AMapLocationCLMDelegate
andAMapLocationManager
They all came in pairs. None of the others left
- And then let’s see
class-dump
Out of theheader
File. foundAMapLocationCLMDelegate
It’s filled with proxy callbacks
At this point, Kotani can guess the location of the AMapLocationManager fetch, and then the parameter passes the parameter to the H5 interaction
- We put the
AMapLocationManager
Type everything in therelog
, the use oflogify.pl
- Then we’ll install the plugin and take a look
log
I see good information. We’re going to get back to Xcode debugging attachments
- from
Hopper
Find the offset position
Xcode
If I add it, I can find itASLR
- Locate the offset and set the breakpoint
0x104e70000 + 0x36b4a8 = 0x1051DB4A8
- When I clicked the time clock, it stopped
- The way we think about it, we’re going to watch
Function call stack
!!
(If there is no symbol, it doesn’t matter, we will use the Hopper address to locate!)
- we
hook
Let’s do this function
%hook LAPluginInstanceCollector
- (void)handleJavaScriptRequest:(id)arg1 callback:(id)arg2{
%log;
%orig;
}
%end
Copy the code
- Guys, we can get a clue. This
callback
Is ablock
,arg1
Is a parameter,arg2
Is the argument to call back
- Want to know this
block
The parameter type of. I need to see hisThe signature
The ~
Get his signature ~ by memory pan
- Old way,
Hopper
Take the address. thenXcode attaches a breakpoint
0x100f50000 + 0x488f110 = 0x1057DF110
b 0x1057DF110
Cut it off and analyze it
- At this point we can continue
hook
Oh, look at himParameters inside
What is
%hook LAPluginInstanceCollector
- (void)handleJavaScriptRequest:(id)arg1 callback:(void (^) (id))arg2{
// We can create a block.
id xg_callback = ^(id argCb){
// Print the parameters to see if there are any triggers
NSLog(@"xg_callback arg1:%@",arg1);
// Then print the parameter that is passed, and see what type it is
NSLog(@"xg_callback argCbClass:%@, argCb:%@",[argCb class],argCb);
arg2(argCb);
};
//xg_callback replaces arg2. (Just one transfer)
%orig(arg1,xg_callback);
}
%end
Copy the code
- And look at the effect
I think I found it, but there’s a lot of other information about him in here. (address, city, latitude and longitude, etc.)
2.3. Code for the punch card plug-in
We know that the other type is a dictionary. Triggered when action=start
- Go straight to code (latest version)
%hook LAPluginInstanceCollector
- (void)handleJavaScriptRequest:(id)arg1 callback:(void (^) (id))arg2{
id xg_callback = ^(id argCb){
// Xiaogu actually hit a lot of logs while doing it.
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 replaces arg2. (Just one transfer)
%orig(arg1,xg_callback);
}
%end
Copy the code
- Take a look at the renderings
3. Set the punch switch
The main functions are almost written. Let’s set another switch to control: if the switch is on, go with the card plug-in logic, if the switch is off, go with the original logic.
- We secretly add a button in the Settings ~
Xcode is so powerful
- Then find the
dataSource
!
- That would be easy. (Brothers, this is a
tableview
Ah, put his code onehook
Add linecell
, not veryeasy
?)
@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 it is the last group, add a line
if([tableView.nextResponder .nextResponder isKindOfClass:%c(DTSettingListViewController)] && (section == [self numberOfSectionsInTableView:tableView]- 1)) {return 1;
}
return %orig;
}
- (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// Last group, last line, set a 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 = @" Secretly clocked open!!";
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{
// Set the height of the last row of the last group
if([tableView.nextResponder .nextResponder isKindOfClass:%c(DTSettingListViewController)] && ([indexPath section] == [self numberOfSectionsInTableView:tableView]- 1)) {return 45;
}
return %orig;
}
- (long long)numberOfSectionsInTableView:(UITableView *)tableView {
// Add a group
if([tableView.nextResponder .nextResponder isKindOfClass:%c(DTSettingListViewController)]){
return %orig + 1;
}
return %orig;
}
%end
Copy the code
- Then add a judgment in the place where you punched in before, and you’re done
if([arg1Dic[@"action"] isEqualToString:@"start"] && [XGDefaults boolForKey:XGSWITCHKEY]){
- See the effect
4. To summarize
-
Commercial use of this blog is prohibited. Pure for study, if have legal responsibility to have nothing to do with oneself!!
-
This blog is created by Xiaogu, if reprinted please indicate the source!
-
– Kotani wanted to change the value of the HOOK-iOS callback directly, but felt it would be a bit of an error
-
All right, guys. A wave of reverse plug-in development. Kogu is going to write about basic security for his next article
-
But I can’t write it this long. The blog is too long for my brothers to read. I’m trying to keep it simple
-
Finally wish brothers, more and more handsome ๏ผ๏ผ๏ผ๏ผ And never be late