preface

During the epidemic period, it is troublesome to clock in when working at home, so THE author thought of realizing this need. This paper is long because it describes the process from thinking to a complete analysis demonstration, and basically introduces the knowledge points involved, so students who are familiar with relevant knowledge can skip by themselves.

This article will demonstrate the complete process of actually reversing an application from Idea -> explore -> Debug -> injection. The effect is to modify the Wi-Fi and GPS position punching rules, to meet the requirements of not required Wi-Fi environment or GPS range can also be normal punching.

(This article uses the latest version 5.0.6 of The current nail, and subsequent updates may change the code logic and make the plug-in no longer applicable, just for communication and learning)

Disclaimer: This demo plugin has no commercial purpose and does not engage in any commercial activities.

Tip:

  • This paper is based on the jailbreak environment plug-in to achieve.
  • Modify the re-sign application in a non-jailbreak environmentBundleIDNail nail has corresponding monitoring, greater risk.
  • There are some modifications to the virtual location of mobile phones in another way, which is not covered in this article.

Leading knowledge

  • 1️, RSA encryption principle & cryptography &HASH

  • 2️ principle of application signature and re-signature (re-signing wechat application practice)

  • 3️, shell script automatic re-signature and code injection

  • 4️, resigning application debugging and code modification (Hook)

  • 5️, Mach-O file

  • 6️ principle and symbol table of Hook/fishHook

  • 7️ LLDB from shallow to deep

  • 8️, LLDB Advanced on Chisel and Cycript

  • 9️, prison break

  • As for the reverse leading knowledge, the article introduced by the author still lacks the knowledge of smashing shells and assembling instructions, which will be continued in the subsequent updates to form a complete set of chapters and columns.
  • Cracking shells and assembling parts of the content does not affect what we are going to do today with the nail plugin.

The preparatory work

  • Perfect jailbreak cell phone (used in this articleiPhone 5s , IOS 9.0.1, the perfect jailbreak version,Xcode 10.1 )
  • AppStroeInstall legitimate nails, this article uses the latest version (5.0.6)
  • RevealAbout theRevealThis article will cover it in detail
  • frida-ios-dumpPlease refer to the installation of this shell smashing toolgit – frida-ios-dump (About the shell, the author will update the article on the dynamic shell, static shell principle and the use and principle of different shell tools)
  • HopperMach-OAnalysis tool to extract password:x07n.dmgUnzip passwordxclient.info .
  • Sublime Text – Lightweight Text editing tool with high global search efficiency.
  • MonkeyDev and Theos, re-signed applications and tools essential for writing jailbreak plugins.
  • Jailbreak environment LLDB use, LLDB plug-in – loadCommands

Reveal page debugging tool

A lot of reverse must start from the page, find the corresponding button method to hook, can help us clear the code and business logic.

As we all know, there is no encryption for projects that have been cracked or run by code on the phone. For such applications, we can directly Attach to the running application by Xcode -> Debug -> Attach to Process. This allows you to achieve view-debug.

(For how to determine whether MachO application shell, use otool -l + MachO file name).

So for the legitimate application, that is, there is no shell application, how to carry out page debugging. Here’s the question Reveal addresses.

The installation

1.MacEnd tool installation

Reveal-for-mac: iv3j, DMG Installation package password: xclient.info

Download and install.

2. Jailbreak phone add-on

Search for Reveal Loader in Cydia and install it.

3. Mobile phone Settings

Open permissions according to the following figure.

4. Environment configuration

SSH
usb
Prison break a preliminary

  • Port mapping

  • The login

  • Copy files from Mac to mobile phone Create a RHRevealLoader folder in the phone root directory /Library/.

Make a copy of the RevealServer in the RevealServer.framework on the computer side, rename it Libreveal. dylib, and then copy it to the phone /Library/RHRevealLoader/ directory.

SCP - 12345 - P r/Users/libin/Desktop/reverse/libReveal dylib root @ localhost: / Library/RHRevealLoader /Copy the code

You can also use iFunBox to visualize action files.

  • Restart PCReveal, restart the phone, open the nail, it will display as follows.

5, prompt

The Reveal on the computer side did not detect the opened application, please check the following questions:

  • 1️ discount: Check itRevealServerHas it been changed tolibReveal.dylib.
  • 2 ️ ⃣ : checklibReveal.dylibHave no execution permission. No+xCan.
  • 3️ retail: mobile phone and computer terminalRevealWhether to restart.
  • 4️ : Mobile phone should be kept on the same LOCAL area network with computer after restart.

The final result is as follows:

Second, the shell

Here we use Frida-ios-dump for shell smashing. (I will update the article on dynamic shell smashing, static shell smashing principle and the use and principle of different shell smashing tools.)

For USB port mapping, log in to the phone, and then use the crack shell.

Frida’s dump.py can be used in any directory, so you don’t have to CD it to the directory every time. The application ipA is stored in the current directory. If you are interested, you can refer to 2.5.3 Configuring shell to automatically connect USB mapping and login in Jailbreak Preliminary.

After the shell is smashed, ipA is obtained, which is changed to ZIP, decompressed, and the package content is displayed. Then the mach-O source file can be found after the shell is smashed.

Class-dump header file:

Link password: PJTT

View the application encryption status:

Three, class – the dump

Use class-dump to export the headers of the application after breaking the shell. If you are not familiar with class-dump, you can refer to the article debugging and code modification of the re-checkout application.

Enter the command:

class-dump -H DingTalk -o ./headers/

  • DingTalkIs in the current directoryMach-OThe file name
  • -o ./headers/That means output to the same pathheadersFolder.

The results are as follows:

At this point, the preparation is complete, which is the first thing we need to do to reverse an application.

  • 1️ retail: running application, page debugging (Reveal, smash shell application re-signature attached toXcode , View-Debug , ChiselCycriptAnd so on, the referenceLLDB Advanced chapter Chisel with Cycript).
  • 2️ retail: application of shell smashing
  • 3 ️ ⃣ :class-dump

Iv. Summary of preparatory work

In actual reverse development, it is not recommended to debug the code directly. In line with the principle that time is cost, we should deal with the process as follows.

First clear ideas and source development logic, can static analysis on static analysis (static analysis generally includes class-dump view header files, Macho analysis, assembly code analysis and so on. Of course, is not forced to do not need to analyze assembly, for assembly is very familiar with the students can ignore), as little dynamic debugging, after we have a full grasp of the start of the code.

So with all the tools in place, let’s think about business requirements and logic.

Train of thought

Requirements:

  • When using the siteGPSWhen punching in rules:
    • We want to be able to punch in without being in the designated position.
  • Specify when using the connectionWi-FiWhen the clock:
    • We want to be able to not connect to the specifiedWi-FiThey can also punch in normally.

So the first thing we can think of is the following:

Idea 1

From the punch button and click method, the methodhookOr view the assembly for static analysis, view its processing logic, modify the judgment logic, when the conditions do not meet the normal execution of the punch.

Therefore, go to the punch in page and use the Reveal view button method.

Come here and see the unfortunate news that the entire page is a WebView. Even if we can guess how the WebView interacts with the OC and what fixed methods will be called to continue the search, the time cost is too great.

So let’s switch gears.

Idea 2

First of all, let’s consider the situation of GPS clocking. Due to the requirements of iOS system, GPS location of any map is almost packaged with the native CLLocationManager.

So we thought of modifying the proxy method that gets the GPS so that it always gets the latitude and longitude that the address returns.

Wi-fi is the same idea as above. In general, it should be able to meet the needs. Next, we will try.

Debugging process

First, static analysis

Use Hopper to open mach-O after shell smashing.

locationManager:didUpdateLocations:
Copy the code

The search results are as follows:

Search to the whole project, there are several classes that implement this method. Then what should we do, to see the compilation of these methods for analysis? I do not recommend this approach here.

Since usage habits tell us that the GPS position will be obtained every time the page is opened.

So I think we can handle it this way:

Using dynamic debugging, Hook the method of these classes, keep calling the original method in Hook, but add a print, to find out which class gets the GPS position when the page is opened. To narrow down the analysis.

Using logos to hook the method is very efficient and convenient. (For those unfamiliar, you can read the actual reverse hook method — Logos)

Therefore, you go straight to the dynamic debugging phase.

Second, dynamic debugging

1. New construction

After installing the MonkeyDev plugin, select the following new project:

Change the file type to Objective-C++ Source and keep only one UIKit import for the file content.

(If the file type is not refreshed after modification, you can select other files on the left and then select back.)

2. Obtain the Bundle ID of the target project

There are several ways to do this. You can go directly to the app info.plist.

To mention the use of CYcript in jailbreak environments, as well as custom CY directives (also see LLDB advanced Chisel and CYcript)

We use this way:

  • ① : Port mapping and SSH login to mobile phones
  • ② : Mobile phone operation and ensure the front desk active state
  • ③ : Check the nailing processID
  • (4) :cycriptAttach current process
  • ⑤ : Import customcyinstruction
  • 6: getBundle ID

Fill the Bundle ID into the project configuration file.

2. SSH configuration

Writing plug-ins using MonkeyDev requires configuring SSH login information in the project.

The authors have configured the relevant environment variables in.zshrc so that they do not need to be filled in every time.

SSH port mapping and login reference jailbreak

Here is a brief explanation of why a successful plug-in installation requires the process to be killed and restarted.

  • Actually,MonkeyDevtweakThe use ofTheosThe principle is usedDYLD_INSERT_LIBRARYPrinciple.
  • dyldAs you can see in the source code,dyldDepending on theDYLD_INSERT_LIBRARYThis environment variable determines whether to load the inserted dynamic library.
  • Some protection is done by addition__RESTRICTSection,_restrictTo implement the protection of the jailbreak plugin. (we will discuss and demonstrate this in the following jailbreak environment attack and defense).
  • The jailbreak plugin package actually generatesdylibLibrary, and then throughsshCopy it to the phone, and when the app loads, thedyldTo load thehookCode. (this is why plug-in installation requires killing the process to reload).

Dyld source code:

const char* const *           DYLD_INSERT_LIBRARIES;
// load any inserted libraries   
if( sEnv.DYLD_INSERT_LIBRARIES ! =NULL ) {
  for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib ! =NULL; ++lib) 
      loadInsertedDylib(*lib);
}
Copy the code

2. Write the Logos

This code and nothing to say, it is respectively the hooks in the hopper above we search out the implementation of the locationManager: didUpdateLocations: this method of several classes.

#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 DTCLocationManager
- (void)locationManager:(id)arg1 didUpdateLocations:(id)arg2{
    %log;
    %orig;
}
%end

%hook LALocationManager
- (void)locationManager:(id)arg1 didUpdateLocations:(id)arg2{
    %log;
    %orig;
}
%end


%hook LAPLocationInfo
- (void)dt_locationManager:(id)arg1 didUpdateLocations:(id)arg2{
    %log;
    %orig;
}
%end


%hook DTLocationJSAPIHandler
- (void)dt_locationManager:(id)arg1 didUpdateLocations:(id)arg2{
    %log;
    %orig;
}
%end

%hook VILocationManager
- (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

Make sure local port 12345 is mapped to port 22 on the other end of the USB phone. The compilation succeeded and the running spikes were found to have been killed.

3. Check the print

Since we add printing to the hook method, we can run the nail, go to the punch page, and see which class positioning method is called.

CMD + Shift + 2 open the Devices page, open the console. Enter search DingTalk to select process.

  • And what we found through our search results is,AMapLocationCLMDelegateAMapLocationManagerdidUpdateLocationsThe calls are the most frequent and always come in pairs.
  • So we can speculate,ManagerdelegateThere is an agency relationship betweenManagerOnce the location information is retrieved, it is called back to the protocol implementer via the proxy. That is, a method nesting.
  • theAMapLocationCLMDelegateAMapLocationManagerThe address record is saved.

4. Memory breakpoints

Since the production package is unsigned, breakpoints by class and method names are not possible, so we use memory addresses for breakpoints.

  • After SSH mapping and login, enter:

    debugserver *:12346 -a DingTalk
    Copy the code
  • Enter LLDB on the MAC to enter the breakpoint state, and then enter

    process connect connect://localhost:12346
    Copy the code

(Above is the jailbreak environment using USB LLDB debugging).

Use methods + class memory address to get the list of methods and address of the class (this instruction comes from the LLDB plug-in – loadCommands).

The didUpdateLocations method of the AMapLocationCLMDelegate class can be broken using the b + method memory address.

Note:

Some students will often use this method to add breakpoints to the environment. Normally this is fine, but remember what we did? We’re going to do the methodhookThat is, method implementationimpHas been replaced by our own method, therefore, the above method is wrong!! .

Let’s go to the next call to AMapLocationCLMDelegate’s didUpdateLocations method.

logos hook

So how do we break the original method without hook?

  • Obtain the offset of the first address based on Mach -O.

  • Gets the mach-O first address

The calculation principle involves ALSR and pageZero knowledge, refer to LLDB from shallow to deep at the end of the article.

Calculate the method address of AMapLocationCLMDelegate 0x100267EE8 and the method address of AMapLocationManager 0x1002786E4. So let’s add breakpoints separately.

After adding the breakpoint, go to the next call:

It can be found that the hook method is not entered this time. OK, the two methods memory breakpoints are added.

Using BT, we can see the function nested call relationship, which verifies our previous conjecture:

After the above debugging, we found that the location of AMapLocationManager was called in the punch card page. So, next, let’s look at the header file of this class.

5. View the header file

Sublime opens the class-dump header and CMD + Shift + F searches @interface AMapLocationManager.

hook

Because this class has many methods, it is too troublesome to write by hand. In fact, when we configure Theos, there is a script inside.

Copy the amaplocationManager. h we dumped to the project directory. Enter the command:

After execution, drag the generated logamapManager. xm into the project, select Objective-C++ Source as the type, and compile the project. At this time, generate an additional logamapManager. mm in the project folder, and drag the project.

Cxx_destruct: () {cxx_destruct: () {cxx_destruct: () {cxx_destruct: () {cxx_destruct: () {cxx_destruct: () {cxx_destruct: () {cxx_destruct: ();

The author here added four classes of declaration, students need to directly copy the use can be.

@interface CLLocationManager
@end
@interface AMapNetworkManager
@end
@interface CLLocation
@end
@interface AMapLocationReGeocode
@end
Copy the code

Comment out the positioning methods of those classes of our previous hook to prevent too much printing from affecting judgment.

Rebuild and view the console print.

Here we see that the manager calls startUpdatingLocation, followed by didUpdateLocations. So again, we find the address breakpoint for startUpdatingLocation.

Once the breakpoint has been successfully placed, enter the punch page again. At the breakpoint, BT looks at the function call stack.

6. Locate the function call flow

Analysis:

  • In the figure above, we see that the function name is not displayed for symbolic reasons, so we want to know the function name, again, we can calculate. The actual address of the process function is shown in the figure.
  • Then subtractMach-ORandom offset value of first address:ALSR, can be based onMach-OFirst address offset, so we can goHopperSearch for class and function names.
  • Pay attention to considerpageZeroThe actual physical address and offset are includedpageZero , arm 64Subtract one from the calculation in0x10000000).

For example, #2 in the function call stack, the actual function address is 0x00000001024eaad8, Subtract the Mach-O header address (ALSR) obtained from the image list and remove the first 1 (page zero) as 0x94000 to get 0x102456AD8.

Go to Hopper, press G and enter the memory address to find the following:

(Hopper on the Mac terminal is too slow.)

The startUpdatingLocation function call stack is translated unsigned as follows:

frame #1: 0x00000001085250e8 [AMapLocationManager startUpdatingLocation]
frame #2: 0x102456AD8 DingTalk` [DTALocationManager dt_startUpdatingLocation] ? DingTalk + 248
frame #3: 0x1039148B0 DingTalk` [LAPLocationInfo start:to:]?DingTalk  + 1980
frame #4: 0x103959010 DingTalk` [LAPluginInstanceCollector handleJavaScriptRequest:callback:]?DingTalk  + 52
Copy the code

Here we find the call starting point: webView js interaction callback with OC. That is, the webView page loads, communicates with the OC, and calls up the starting location.

So next, hook the method and add print.

%hook LAPluginInstanceCollector
- (void)handleJavaScriptRequest:(id)arg1 callback:(id)arg2{
    %orig;
    NSLog(@"LBHook\n\n\n\n\n"
          "arg1Class = %@\n"
          "arg1 = %@\n"
          "arg2Class = %@\n"
          "arg2 = %@\n"
          ,[arg1 class],arg1,[arg2 class],arg2);
}
%end
Copy the code

By adding print, we see that parameter 1 is an NSDictionary parameter. Parameter 2 is a stack block. The latitude and longitude information is not found in the first parameter, so we need to look at this block.

7. Block obtains the signature

Since we need to know what the parameters and return values of the Block are, we need to look at the Block’s signature to see what it is.

This is the process of getting the Block_descriptor_3 signature based on the memory offset at the flags flag.

Block data structure source code:

struct Block_layout {
    void *isa;
    volatile int32_t flags; // contains ref count
    int32_t reserved;
    BlockInvokeFunction invoke;// Implement the address!
    struct Block_descriptor_1 *descriptor;
    // imported variables
};

#define BLOCK_DESCRIPTOR_1 1
struct Block_descriptor_1 {
    uintptr_t reserved;
    uintptr_t size;
};

#define BLOCK_DESCRIPTOR_2 1
struct Block_descriptor_2 {
    // requires BLOCK_HAS_COPY_DISPOSE
    BlockCopyFunction copy;
    BlockDisposeFunction dispose;
};

#define BLOCK_DESCRIPTOR_3 1
struct Block_descriptor_3 {
    // requires BLOCK_HAS_SIGNATURE
    const char *signature;
    const char *layout;     // contents depend on BLOCK_HAS_EXTENDED_LAYOUT
};
Copy the code

Then according to the above about the same way, we can give [LAPluginInstanceCollector handleJavaScriptRequest: callback:] add breakpoints. Run to the breakpoint after successful addition.

Once we get the block address, we’re going to get its signature.

through

po [NSMethodSignature signatureWithObjCTypes:"v16@? 0 @ 8"]
Copy the code

blockIs a zero return value, oneidType parameterblock
id

8. The block parameter type is determined

To clarify the type of the block argument, we nested a block and called the original method in our custom block. We called the original block in our custom block and added a print.

Therefore, we rewrite the hook code as follows:

%hook LAPluginInstanceCollector
- (void)handleJavaScriptRequest:(NSDictionary *)arg1 callback:(void(^)(id))arg2{
    id myCallBack = ^(id block_arg){
        NSLog(@"arg1 %@\n block_argClass: %@\nblock_arg:%@\n",arg1,[block_arg class],block_arg); // Keep the original use!! arg2(block_arg); }; %orig(arg1,myCallBack); } %endCopy the code

Compile the installation, reopen the pins, and view the console printout.

block
NSDictionary
GPS

⚠️ Analysis completed:

Therefore, we can definitely assume that the startUpdatingLocation of AMapLocationManager is called in this method and a dictionary is called back into the block after the location is obtained. Therefore, in this method, the longitude and latitude are written directly as the longitude and latitude of the desired location. It’s perfect for our needs.

Of course, we can see that there are many different conditions and states of parameter 1 and parameter 2. Through checking, we can find that when the action in parameter 1 is start and the keep in parameter 2 is 1, it means that the longitude and latitude need to be obtained again.

Therefore, modify the code.

9. Modify the original code logic

%hook LAPluginInstanceCollector
- (void)handleJavaScriptRequest:(NSDictionary *)arg1 callback:(void(^)(id))arg2{
    if([arg1[@"action"] isEqualToString:@"start"] {// You may need to modify the location information! // define a myBlock id myCallBack = ^(NSDictionary * block_arg){if([block_arg[@"keep"] isEqualToString:@"1"]) {/ / need to modify the GPS NSMutableDictionary * tempDic = [NSMutableDictionary dictionaryWithDictionary: block_arg]; // Change the value of the dictionary in block! tempDic[@"result"] [@"latitude"] = @"28.1924070001";
                tempDic[@"result"] [@"longitude"] = @"112.9788130003"; // Use the modified! arg2(tempDic); }else{// Keep the original use!! arg2(block_arg); }}; %orig(arg1,myCallBack); }else{
        %orig;
    }
}
%end
Copy the code

10. View the effect

  • No plug-in installed: Punch in to display remote.
  • Compile and install the plug-in.

WiFi and GPS punch card plug-in complete version

WiFi clocking exploration ideas and GPS position clocking exactly the same.

After exploration, we found that it was also the method of interaction between JS of our final hook and OC to obtain whether the current connected WiFi information is consistent with the macIp of WiFi set by the administrator.

Hook code complete version:

%hook LAPluginInstanceCollector
- (void)handleJavaScriptRequest:(NSDictionary *)arg1 callback:(void(^)(id))arg2{
    if([arg1[@"action"] isEqualToString:@"start"] {// You may need to modify the location information! // define a myBlock id myCallBack = ^(NSDictionary * block_arg){if([block_arg[@"keep"] isEqualToString:@"1"]) {/ / need to modify the GPS NSMutableDictionary * tempDic = [NSMutableDictionary dictionaryWithDictionary: block_arg]; // Change the value of the dictionary in block! Here modify the GPS position set for your company to allow clocking"result"] [@"latitude"] = @"31.8567980000";
                tempDic[@"result"] [@"longitude"] = @"118.8274580000"; // Use the modified! arg2(tempDic); }else{// Keep the original call!! arg2(block_arg); }}; %orig(arg1,myCallBack); }else if([arg1[@"action"] isEqualToString:@"getInterface"]) {/ / modify WIFI!!!!! // define a myBlock id myCallBack = ^(NSDictionary * block_arg){NSMutableDictionary * tempDic = [NSMutableDictionary dictionaryWithDictionary:block_arg]; // Change the value of the dictionary in block! , here modify the WiFi macIP tempDic set for your company"result"] [@"macIp"] = @"f0:b4:29:6b:fe:51"; // Use the modified! arg2(tempDic); }; %orig(arg1,myCallBack); }else{
        %orig;
    }
}
%end
Copy the code

WiFi effect is not demonstrated, and THE SAME as GPS rules.

At this point, you can take a jailbreak device at home from the comfort of the clock 😆.

conclusion

  • 1️ : This paper shows in detail how to make a prison break plug-in from scratch, and most of the debugging tools and knowledge points involved are introduced. I encourage those of you who are interested to practice.

  • 2️ : In the reverse process, clear thinking is very important, while to master cycript, shell breaking, jailbreak environment LLDB debugging, Theos, Chisel, and other static analysis and dynamic debugging tools, the underlying principle is also essential.

  • 3️ : After sorting out ideas, try to use static analysis (assembly also belongs to static analysis, depending on personal situation). When the general idea is sorted out, dynamic debugging can be carried out, hook code and breakpoint debugging, cycript and other tools to help straighten out the source code logic.

  • 4️ : Finally, we find that in fact, real hook injection modification code is very simple, the reverse way is such, combing and derivation often take a lot of time.

Finally, to reiterate:

The demo plug-in does not serve any commercial purpose, nor does it engage in any commercial activity.

Pure original article, reproduced please indicate the source.