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 usingfrida-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!iOSThe guys love it so much,XcodeDebugging (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 justPositioning punchingFind the punch screen,viewdebugDebugging)

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 aWKWebviewinterface
    • When we clocked inH5There’s a change, which means there’s a placeTell the H5Positioning success
    • If it’s native positioningTell the H5Yes, then they must haveInteraction code
  • Ideas:
    • If they haveinteractionWe knowHook to livethisinteractionJust look insideComes back, possible by changing the value)
    • If it is an iOS location, it will definitely golocationManager: didUpdateLocations:
    • It could be,H5 interaction starts positioningAnd thenCallback location information

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 inHopper(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 timeMonkeywriteTweak the pluginYou can also use itTHEOSThis time we may need several debugging before positioning, I will useMonkeyConvenient point ~)

  • To obtainThe APPID nailingAnd the configuration

  • The one we found up there5A,hookthe
#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 thisAMapLocationCLMDelegateandAMapLocationManagerThey all came in pairs. None of the others left

  • And then let’s seeclass-dumpOut of theheaderFile. foundAMapLocationCLMDelegateIt’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 theAMapLocationManagerType everything in therelog, the use oflogify.pl

  • Then we’ll install the plugin and take a looklog

I see good information. We’re going to get back to Xcode debugging attachments

  • fromHopperFind the offset position

  • XcodeIf 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 watchFunction call stack!!

(If there is no symbol, it doesn’t matter, we will use the Hopper address to locate!)

  • wehookLet’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. ThiscallbackIs ablock,arg1Is a parameter,arg2Is the argument to call back

  • Want to know thisblockThe parameter type of. I need to see hisThe signatureThe ~

Get his signature ~ by memory pan

  • Old way,HopperTake the address. thenXcode attaches a breakpoint

0x100f50000 + 0x488f110 = 0x1057DF110

  • b 0x1057DF110Cut it off and analyze it

  • At this point we can continuehookOh, look at himParameters insideWhat 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 thedataSource!

  • That would be easy. (Brothers, this is atableviewAh, put his code onehookAdd 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