iOS逆向記錄(三)

8.第一個逆向程序

  • 創建tweak工程

    ?  iOS /opt/theos/bin/nic.pl 
    NIC 2.0 - New Instance Creator
    ------------------------------
      [1.] iphone/activator_event
      [2.] iphone/application_modern
      [3.] iphone/cydget
      [4.] iphone/flipswitch_switch
      [5.] iphone/framework
      [6.] iphone/ios7_notification_center_widget
      [7.] iphone/library
      [8.] iphone/notification_center_widget
      [9.] iphone/preference_bundle_modern
      [10.] iphone/tool
      [11.] iphone/tweak
      [12.] iphone/xpc_service
     //選擇tweak工程  
    Choose a Template (required): 11  
     
     //工程名稱
    Project Name (required): MyFirstReProject  
     
    //deb包的名字(類似于bundle identifier)
    Package Name [com.yourcompany.myfirstreproject]: com.iosre.myfirstreproject  
     
    //tweak作者
    Author/Maintainer Name [System Administrator]: Flonger 
     
    //tweak作用對象的bundle identifier
    [iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.apple.springboard 
     
    //tweak安裝完成后需要重啟的應用
    [iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]: SpringBoard
    Instantiating iphone/tweak in myfirstreproject/...
    Done.
    
  • 工程文件結構介紹

  • Makefile

    //工程包含的通用頭文件
    include $(THEOS)/makefiles/common.mk
    
    //創建工程時指定的“Project Name,指定好之后一般不要再更改
    TWEAK_NAME = MyFirstReProject
     
    //tweak包含的源文件,指定多個文件時用空格隔開
    MyFirstReProject_FILES = Tweak.xm
    
    //tweak工程的頭文件,一般有application.mk、tweak.mk和tool.mk幾類
    include $(THEOS_MAKE_PATH)/tweak.mk
    
    //指定tweak安裝之后,需要做的事情,這里是殺掉SpringBoard進程 
    after-install::
        install.exec "killall -9 SpringBoard"
         
    補充:
    //編譯debug或者release
    DEBUG = 0
     
    //越獄iPhone的ip地址
    THEOS_DEVICE_IP = 192.168.1.113
     
    //指定支持的處理器架構
    ARCHS = armv7 arm64 
     
    //指定需要的SDK版本iphone:Base SDK:Deployment Target
    TARGET = iphone:latest:8.0  //最新的SDK,程序發布在iOS8.0以上
    
    //導入框架,多個框架時用空格隔開
    MyFirstReProject_FRAMEWORKS = UIKit 
    MyFirstReProject_PRIVATE_FRAMEWORKS = AppSupport
     
    //鏈接libsqlite3.0.dylib、libz.dylib和dylib1.o
    MyFirstReProject_LDFLAGS = -lz –lsqlite3.0 –dylib1.o
     
    //make clean
    clean::
        rm -rf ./packages/* 
    
    
  • tweak文件
    “xm”中的“x”代表這個文件支持Logos語法,如果后綴名是單獨一個“x”,說明源文件支持Logos和C語法;如果后綴名是“xm”
    ,說明源文件支持Logos和C/C++語法。

    /* How to Hook with Logos
    Hooks are written with syntax similar to that of an Objective-C @implementation.
    You don't need to #include <substrate.h>, it will be done automatically, as will
    the generation of a class list and an automatic constructor.
    
    %hook ClassName
    
    // Hooking a class method
    + (id)sharedInstance {
        return %orig;
    }
    
    // Hooking an instance method with an argument.
    - (void)messageName:(int)argument {
        %log; // Write a message about this call, including its class, name and arguments, to the system log.
    
        %orig; // Call through to the original function with its original arguments.
        %orig(nil); // Call through to the original function with a custom argument.
    
        // If you use %orig(), you MUST supply all arguments (except for self and _cmd, the automatically generated ones.)
    }
    
    // Hooking an instance method with no arguments.
    - (id)noArguments {
        %log;
        id awesome = %orig;
        [awesome doSomethingElse];
    
        return awesome;
    }
    
    // Always make sure you clean up after yourself; Not doing so could have grave consequences!
    %end
    */
    
    • %hook 指定需要hook的class,必須以%end結尾

    • %log 該指令在%hook內部使用,將函數的類名、參數等信息寫入syslog
      Cydia內搜索安裝syslogd

    • %orig該指令在%hook內部使用,執行被鉤?。╤ook)的函數的原始代碼。

  • control
    control文件記錄了deb包管理系統所需的基本信息,會被打包進deb包里。

  • 編譯工程

    • tweakxm 文件

      %hook SpringBoard 
      -  (void)applicationDidFinishLaunching:(id)application 
      { 
          %orig; 
          UIAlertView *alert = [[UIAlertView alloc]  
          initWithTitle:@"Hello,Tanzhou!" 
          message:nil 
          delegate:self cancelButtonTitle:@"OK"
          otherButtonTitles:nil]; 
          [alert show]; 
      }
      
      - (void)_menuButtonDown:(id)down  
      {  
          NSLog(@"x=%d, y=%d", 10, 20);
          %log((NSString *)@"iOSRE", (NSString *)@"Debug");  
          %orig; // call the original _menuButtonDown:
      }
      %end
      
      %hook SBLockScreenDateViewController
      - (void)setCustomSubtitleText:(id)arg1 withColor:(id)arg2
      {
      /*
         NSDate *date=[NSDate date];
         NSDateFormatter *format1=[[NSDateFormatter alloc]init];
         [format1 setDateFormat:@"yyyy/MM/dd HH:mm:ss"];   
         NSString *str1=[format1 stringFromDate:date];
      */
         struct tm *loctime;
         char timeBuf[1024] = {0};
         time_t now = time(NULL);
         loctime = localtime(&now);
         strftime(timeBuf, 30, "[%Y/%m/%d %H:%M:%S]", loctime);
         %orig([NSString stringWithUTF8String:timeBuf],arg2);   
      }
      %end
      
      
    • MakeFile文件

      DEBUG = 0
      THEOS_DEVICE_IP = 10.171.4.22 
      ARCHS = armv7 arm64 
      TARGET = iphone:latest:8.0  
      include $(THEOS)/makefiles/common.mk
      
      TWEAK_NAME = MyFirstReProject
      MyFirstReProject_FILES = Tweak.xm
      MyFirstReProject_FRAMEWORKS = UIKit 
      include $(THEOS_MAKE_PATH)/tweak.mk
      
      after-install::
          install.exec "killall -9 SpringBoard"
      clean::
          rm -rf ./packages/* 
      
    • control文件

      Package: com.iosre.myfirstreproject
      Name: MyFirstReProject
      Depends: mobilesubstrate
      Version: 1.0.1
      Architecture: iphoneos-arm
      Description: My first reproject!
      Maintainer: Flonger
      Author: Flonger
      Section: Tweaks
      Homepage: https://www.baidu.com
      
  • 編譯命令

    make  //編譯
    
    make package  //打包
     
    make install  //安裝
    
  • 驗證結果

9.deb包介紹

官網:http://www.debian.org/doc/debian-policy/

deb包本質是一個壓縮包文件。里面包含一些特定的目錄和文件。安裝過程就是dpkg程序按照指定的規則去拷貝文件和執行腳本。

dpkg -c  xxxx.deb //查看deb包的目錄結構
 
  • DEBIAN目錄
    存放control文件、及安裝和卸載時需要執行的腳本等

    • control文件導出。。
       //deb包的名字,卸載和查詢包信息都用這個名字
        Package: com.iosre.myfirstreproject
    
        //工程名字(產品名字)
        Name: MyFirstReProject
    
        //依賴包(可以指定多個,用','分割)
        Depends: mobilesubstrate, firmware  (>=8.0)
    
        //deb包版本號
        Version: 1.0.1
    
        //描述軟件所支持的平臺架構
        Architecture: iphoneos-arm
    
        //deb包簡介
        Description: My first reproject!
    
        //deb包維護人和聯系方式
        Maintainer: Flonger<xue@flonger.com>
    
        //軟件作者
        Author: Fonger
    
        //deb包歸屬類別
        Section: Tweaks
    
        //軟件主頁
        Homepage: https://www.baidu.com
    
    • 腳本文件
      preinst
      在Deb包文件解包之前,將會運行該腳本。許多“preinst”腳本的任務是停止作用于待升級軟件包的服務,直到軟件包安裝或升級完成。
      
      postinst
      該腳本的主要任務是完成安裝包時的配置工作。許多“postinst”腳本負責執行有關命令為新安裝或升級的軟件重啟服務。
      
      prerm
      該腳本負責停止與軟件包相關聯的daemon服務。它在刪除軟件包關聯文件之前執行。
      
      postrm
      該腳本負責修改軟件包鏈接或文件關聯,或刪除由它創建的文件。
      
  • dpkg打包時會復制當前目錄下layout目錄下的所有文件和目錄
    這些文件和目錄會鏡像到目標設備上(layout相對于設備的根目錄)

    //發布時的Makefile
    DEBUG = 0
    THEOS_DEVICE_IP = 10.171.4.22 
    ARCHS = armv7 arm64 
    TARGET = iphone:latest:8.0  
    include $(THEOS)/makefiles/common.mk
    
    TWEAK_NAME = MyFirstReProject
    MyFirstReProject_FILES = Tweak.xm
    MyFirstReProject_FRAMEWORKS = UIKit 
    include $(THEOS_MAKE_PATH)/tweak.mk
    
    clean::
        rm -rf ./packages/* 
    before-package::
        cp ./script/postinst ./.theos/_/DEBIAN/
        cp ./script/postrm ./.theos/_/DEBIAN/  
    

10. 常見Logos語法介紹

維基百科:http://iphonedevwiki.net/index.php/Logos

10.1 Block-level
  • %hook
    指定需要hook的class,必須以%end結尾。可以被%group包含

    %hook SBApplicationController
    -(void)uninstallApplication:(SBApplication *)application {
        NSLog(@"Hey, we're hooking uninstallApplication:!");
        %orig; // Call the original implementation of this method
        return;
    }
    %end
    
  • %group
    該指令用于將%hook分組,便于代碼管理及按條件初始化分組,必須以%end結尾。
    一個%group可以包含多個%hook,所有不屬于某個自定義group的%hook會被隱式歸類到%group_ungrouped中。

    %group iOS8
    %hook IOS8_SPECIFIC_CLASS
        // your code here
    %end // end hook
    %end // end group ios8
    
    %group iOS9
    %hook IOS9_SPECIFIC_CLASS
        // your code here
    %end // end hook
    %end // end group ios9
    
    %ctor {
        if (kCFCoreFoundationVersionNumber > 1200) {
            %init(iOS9);
        } else {
            %init(iOS8);
        }
    }
    
  • %new
    在%hook內部使用,給一個現有class添加新函數,功能與class_addMethod相同。
    注: Objective-C的category與class_addMethod的區別: 前者是靜態的而后者是動態的。

    %hook SBApplicationController
    -(void)uninstallApplication:(SBApplication *)application {
        NSLog(@"Hey, we're hooking uninstallApplication:!");
        %orig; // Call the original implementation of this method
        return;
    }
    
    %new
    - (void)namespaceNewMethod
    {
    NSLog(@"We've added a new method to SpringBoard.");
    }
    %end
    
10.2 Top level
  • %ctor
    tweak的構造函數,完成初始化工作;如果不顯示定義,Theos會自動生成一個%ctor,并在其中調用%init(_ungrouped)。

  • %dtor
    tweak的構造函數,完成收尾。如果不顯示定義,Theos會自動生成一個%dtor。

10.3 Function level
  • %init
    該指令用于初始化某個%group,必須在%hook或%ctor內調用;如果帶參數,則初始化指定的group,如果不帶參數,則初始化_ungrouped.
    注: 切記,只有調用了%ini,對應的%group才能起作用!
%ctor {
    if (kCFCoreFoundationVersionNumber > 1200) %init(iOS9);
     else %init(iOS8);
}
  • %c
    該指令的作用等同于objc_getClass或NSClassFromString,即動態獲取一個類的定義,在%hook或%ctor內使用 。
    %hook SpringBoard
    - (void)_menuButtonDown:(id)down
    {
    %orig;
    SBScreenShotter *shotter = [%c(SBScreenShotter) sharedInstance];
    [shotter saveScreenshot:YES]; 
    }
    %end@
    
  • %log
    該指令在%hook內部使用,將函數的類名、參數等信息寫入syslog,可以%log([(),…..])的格式追加其他打印信息。
tail -f /var/log/syslog | grep WeChat
  • %orig
    該指令在%hook內部使用,執行被hook的函數的原始代碼;也可以用%orig更改原始函數的參數。
//練習
@interface SBScreenshotter: NSObject
+ (id)sharedInstance;
- (void)saveScreenshot: (BOOL)arg1;
@end
 
@interface SpringBoard
+ (void)_AutoScreenSave2;
- (void)_AutoScreenSave;
@end
 
%hook SpringBoard 
-  (void)applicationDidFinishLaunching:(id)application 
{ 
    %orig; 
    UIAlertView *alert = [[UIAlertView alloc]  
    initWithTitle:@"Hello,Tanzhou!" 
    message:nil 
    delegate:self cancelButtonTitle:@"OK"
    otherButtonTitles:nil]; 
    [alert show]; 
}
 
%new
- (void)_AutoScreenSave
{
    NSLog(@"instance method");
    SBScreenShotter *shotter = [%c(SBScreenShotter) sharedInstance];
    [shotter saveScreenshot:YES]; 
}
 
%new
+ (void)_AutoScreenSave2
{
    NSLog(@"class method");
    SBScreenShotter *shotter = [%c(SBScreenShotter) sharedInstance];
    [shotter saveScreenshot:YES]; 
}
 
- (void)_menuButtonDown:(id)down  
{  
    //SBScreenShotter *shotter = [%c(SBScreenShotter) sharedInstance];
    //[shotter saveScreenshot:YES];
    //[self _AutoScreenSave]; 
    [%c(SpringBoard) _AutoScreenSave2];
    NSLog(@"x=%d, y=%d", 10, 20);
    %log((NSString *)@"iOSRE", (NSString *)@"Debug");  
    %orig; // call the original _menuButtonDown:
}
%end
 
%hook SBLockScreenDateViewController
- (void)setCustomSubtitleText:(id)arg1 withColor:(id)arg2
{
/*
   NSDate *date=[NSDate date];
   NSDateFormatter *format1=[[NSDateFormatter alloc]init];
   [format1 setDateFormat:@"yyyy/MM/dd HH:mm:ss"];   
   NSString *str1=[format1 stringFromDate:date];
*/
   struct tm *loctime;
   char timeBuf[1024] = {0};
   time_t now = time(NULL);
   loctime = localtime(&now);
   strftime(timeBuf, 30, "[%Y/%m/%d %H:%M:%S]", loctime);
   %orig([NSString stringWithUTF8String:timeBuf],arg2);   
}
%end
 
 
/*
%group HookTest
%hook SpringBoard
- (void)_lockButtonDown:(struct __IOHIDEvent *)arg1 fromSource:(int)arg2
{
  NSLog(@"_lockButtonDown");
}
 
- (void)_lockButtonUp:(struct __IOHIDEvent *)arg1 fromSource:(int)arg2
{
  NSLog(@"_lockButtonUp");
}
 
- (void)powerDownCanceled:(id)arg1
{
  NSLog(@"powerDownCanceled");
  %orig;
}
 
- (void)powerDown
{
  NSLog(@"powerDown");
}  
 
- (void)powerDownRequested:(id)arg1
{
  NSLog(@"powerDownRequested");
}
%end
%end
*/
 
%ctor
{
  %init(_ungrouped);
  //%init(HookTest);
}
 

11.Tweak工作原理

1.Cydia Substrate 和 Mobile Substrate

  • Cydia Substrate 原名為 Mobile Substrate 已經正式更名為 Cydia Substrate。

  • 它是越獄后cydia插件/軟件(主要指theos開發的tweak)運行的一個基礎依賴包。提供軟件運行的公共庫,可以用來動態替換內存中的代碼、數據等所以iOS系統越獄環境下安裝絕大部分插件,必須首先安裝Cydia Substrate。

  • Cydia Substrate主要由3部分組成:MobileHooker,MobileLoader 和 safe mode。

2.MobileHooker

  • MobileHooker用于替換覆蓋系統的方法,這個過程被稱為Hooking(掛鉤)
    它主要包含兩個函數:
    void MSHookMessageEx(Class class, SEL selector, IMP replacement, IMP *result);

    void MSHookFunction(voidfunction,void replacement,void** p_original);

    MSHookMessageEx 主要作用于Objective-C函數

    MSHookFunction 主要作用于C和C++函數

    Logos語法%hook就是對此函數做了一層封裝,讓編寫hook代碼變的更直觀,上面的例子用的就是logos語法。

  • MSHookMessageEx
    http://www.cydiasubstrate.com/api/c/MSHookMessageEx/

    void MSHookMessageEx(Class _class, SEL message, IMP hook, IMP *old);
    
    NSString *(*oldDescription)(id self, SEL _cmd);
     
    // implicit self and _cmd are explicit with IMP ABI
    NSString *newDescription(id self, SEL _cmd) {
        NSString *description = (*oldDescription)(self, _cmd);
        description = [description stringByAppendingString:@"!"];
        return description;
    }
    
    MSHookMessageEx(
        [NSObject class], @selector(description),&newDescription, &oldDescription
    );
    
  • MSHookFunction
    http://www.cydiasubstrate.com/api/c/MSHookFunction/

    void MSHookFunction(void *symbol, void *hook, void **old);
    
    void *(*oldConnect)(int, const sockaddr *, socklen_t);
    
    void *newConnect(
        int socket, const sockaddr *address, socklen_t length
    ) {
        if (address->sa_family == AF_INET) {
            sockaddr_in *address_in = address;
            if (address_in->sin_port == htons(6667)) {
                sockaddr_in copy = *address_in;
                address_in->sin_port = htons(7001);
                return oldConnect(socket, ?, length);
            }
        }
    
        return oldConnect(socket, address, length);
    }
    
    MSHookFunction(&connect, &newConnect, &oldConnect);
    

3.MobileLoader

  • MobileLoader 將tweak插件注入到第三方應用程序中(動態注入:ptrace)

  • 啟動時MobileLoader會根據/Library/MobileSubstrate/DynamicLibraries/目錄中plist文件指定的作用范圍,
    有選擇的在第三方進程空間里通過dlopen函數加載同名的dylib。

    每一個.dylib文件都會有一個同名的.plist文件。.plist文件的作用就是用來指定tweak插件的作用對象。

    Flongers-iphone:/Library/MobileSubstrate/DynamicLibraries root# pwd
    /Library/MobileSubstrate/DynamicLibraries
     
    Flongers-iphone:/Library/MobileSubstrate/DynamicLibraries root# ls
      AppList.dylib@         MFService.dylib*         MyFirstReProject.plist   afc2dService.dylib*
      AppList.plist          MFService.plist*         PreferenceLoader.dylib*  afc2dService.plist
      MFAccelerator.dylib*   MFServiceEx.dylib*       PreferenceLoader.plist   patcyh.dylib@
      MFAccelerator.plist*   MFServiceEx.plist*       RHRevealLoader.dylib*    patcyh.plist
      MFHongbaoRobot.dylib*  MobileSafety.dylib*      RHRevealLoader.plist
      MFHongbaoRobot.plist*  MobileSafety.plist       RocketBootstrap.dylib@
      MFService.bundle/      MyFirstReProject.dylib*  RocketBootstrap.plist
    

4.safe mode

  • 因為APP程序質量參差不齊崩潰再所難免,tweak本質是dylib,寄生在別人進程里,如果注入Springboard等。
    系統進程一旦出錯,可能導致整個進程崩潰,崩潰后就會造成iOS癱瘓。

  • 所以CydiaSubstrate引入了安全模式,在安全模式下所有基于CydiaSubstratede 的三方dylib都會被禁用,便于查錯與修復。

建議:

  • ssh到iPhone
  • dpkg -r com.iosre.myfirstreprojec 可以刪除對應的Tweak插件包

12. Tweak練習

1.定位目標文件

  • ps方法
  ps -e | grep WeChat
  • find方法

    find -name sshd
    
  • 固定目錄中查找

    AppStore App全部位于“/var/mobile/Containers/Bundle/Application/”下,
    系統App全部位于“/Applications/”下
    
    daemon的配置文件均位于
    “/System/Library/LaunchDaemons/”
    “/Library/LaunchDaemons”
    “/Library/LaunchAgents/”
    
    是一個plist格式的文件。其中的“ProgramArguments”字段,即是daemon可執行文件的絕對路徑
      Flongers-iphone:/Library/LaunchDaemons root# cat com.openssh.sshd.plist 
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    
    <dict>
        <key>Label</key>
        <string>com.openssh.sshd</string>
    
        <key>Program</key>
        <string>/usr/libexec/sshd-keygen-wrapper</string>
    
        <key>ProgramArguments</key>
        <array>
            <string>/usr/sbin/sshd</string>
            <string>-i</string>
        </array>
    
        <key>SessionCreate</key>
        <true/>
    
        <key>Sockets</key>
        <dict>
            <key>Listeners</key>
            <dict>
                <key>SockServiceName</key>
                <string>ssh</string>
            </dict>
        </dict>
    
        <key>StandardErrorPath</key>
        <string>/dev/null</string>
    
        <key>inetdCompatibility</key>
        <dict>
            <key>Wait</key>
            <false/>
        </dict>
    </dict>
    
    </plist>
    

2.獲取頭文件信息和bundleid

  • 砸殼
  • 通過class-dump獲取頭文件
  • 獲取bundleid
    codesign -dvvv WeChat
    

3.分析頭文件編寫tweak代碼

  • Makefile文件

    THEOS_DEVICE_IP = 192.168.1.113
    DEBUG = 1
    ARCHS = armv7 arm64 
    TARGET = iphone:latest:8.0  
    include $(THEOS)/makefiles/common.mk
    
    TWEAK_NAME = WeChatReProject
    WeChatReProject_FILES = Tweak.xm
    WeChatReProject_FRAMEWORKS = UIKit 
    include $(THEOS_MAKE_PATH)/tweak.mk
    
    after-install::
        install.exec "killall -9 WeChat"
    
    clean::
        rm -rf ./packages/* 
    
  • control文件

    Package: com.iosre.wechatreproject
    Name: WeChatReProject
    Depends: mobilesubstrate
    Version: 0.0.1
    Architecture: iphoneos-arm
    Description: WeChat Tweak
    Maintainer: FLonger
    Author: Flonger
    Section: Tweaks
    Homepage: https://www.baidu.com
    
  • plist文件

{ Filter = { Bundles = ( "com.tencent.xin" ); }; }
  • tweak.xm文件
    #import<UIKit/UIKit.h>
    #import <CoreLocation/CoreLocation.h>
    #import <CoreLocation/CLLocation.h>
    
    @interface SeePeopleNearByLogicController
    - (void)onRetrieveLocationOK:(id)arg1;
    @end
    
    %hook SeePeopleNearByLogicController
    - (void)onRetrieveLocationOK:(id)arg1
    {
        CLLocation *location = [[CLLocation alloc] initWithLatitude:31.154352 longitude:121.42562];
        %orig(location);
    
        UIAlertView *alertView = [[UIAlertView alloc] 
        initWithTitle:[@"onRetrieveLocationOK" 
        stringByAppendingString:[[NSString alloc] 
        initWithFormat:@"location is %@", location]] 
        message:nil 
        delegate:self 
        cancelButtonTitle:@"ok" 
        otherButtonTitles:nil];
    
        [alertView show];
    }
    %end
    
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容