代碼注入及其拓展--逆向開發

今天繼續講述逆向開發中另外一個比較重要的課程是代碼注入內容,本篇篇幅比較長,但仍是有不少乾貨的,但願你們經過此篇文章更加了解逆向開發中的要點和知識點.咱們將分解幾個內容,進行講解:html

  1. Framework注入
  2. Dylib注入
  3. MethodSwizzle
  4. 微信示例講解
  5. 總結

讓代碼執行本身的代碼,總體方案以下:ios

如何讓別人的app來執行本身的代碼呢? 這就要經過代碼注入的方式來達到,而代碼注入的方式有兩種: 一種是經過framework, 一種是dylib方式,另種方案,能夠經過Runtime機制git

代碼注入思路:github

DYLD會動態加載動態庫Framework中全部動態庫,在frameworks中加入本身的一個動態庫,而後在動態庫中hook和注入代碼.編程

1、FrameWork注入

 1.準備工做

  • 微信6.6.5(越獄應用)
  • MachOView軟件

  MachOView的下載地址:http://sourceforge.net/projects/machoview/微信

  若是想看源碼以下:MachOView源碼:https://github.com/gdbinit/MachOViewapp

  • yololib工具(給MachOView注入framework)

  yololib工具下載地址:https://github.com/KJCracks/yololib?spm=a2c4e.11153940.blogcont63256.9.5126420eAJpqBD函數

  • 簽名文件appsign文件

2.流程

2.1 加入準備工做,導入微信6.6.5版本以及腳本appSign.sh重簽名文件

2.2 將appSign導入到項目腳本中

 

 

 2.3 有了上面的兩個步驟後,而後編譯一下工程,會出現一個temp工程,裏面包含了payload文件

2.4 顯示包內容,查看可執行文件

 2.5 咱們經過MachOView軟件查看WeChat

咱們看到有不少的DYLIB,表明的是加載動態庫工具

2.6  咱們在項目中新建framework

 

2.7 新建文件用於驗證

2.8 想要達到剛加載就運行,代碼要寫在load方法

 2.9 編譯一下,查看app包位置會多出一個framework

2.10 顯示包內容,在framework查看

由上可知,WJHookFrameWork已經加入成功。ui

2.11 可是運行並無成功,沒有執行load裏的代碼

緣由:用MachOView打開可執行的WeChat,沒有找到WJHookFrameWork

下面咱們講述怎麼將WJHookFramework寫入到MachoView文件中?

3. WJHookFramework寫入到MachOView文件中

須要使用yololib工具,建議將yololib放到 /usr/local/bin

3.1 解壓越獄包

3.2 將WeChat.app顯示包內容,找到WeChat可執行的文件

須要增長執行權限: chmod +x WeChat

3.3 寫入WeChat可執行文件

yololib WeChat Frameworks/WJHookFrameWork.framework/WJHookFrameWork

經過上面的過程,查看MachOView文件Load commands中是否有WJHookFrameWork

上面圖顯示已經加入成功。

3.4 刪除原有的ipa,打包payload

zip -ry WeChat.ipa Payload

將WeChat.ipa放入App目錄中,刪除其餘的文件夾。

 

3.5 再次運行,發現成功!!!

上面就是framework方式代碼注入。你們能夠私信我,若有不懂!!!

 2、Dylib注入

2.1 新建工程,添加腳本到build phases 


加入腳本文件

2.2添加第三方庫dylib(mac os的,非ios)

2.3 添加依賴

2.4 修改第三方類庫僅限mac使用,修改Base SDK

2.5 修改signing 

2.6 腳本中注入動態庫的代碼

# ${SRCROOT} 它是工程文件所在的目錄
TEMP_PATH="${SRCROOT}/Temp"
#資源文件夾,咱們提早在工程目錄下新建一個APP文件夾,裏面放ipa包
ASSETS_PATH="${SRCROOT}/APP"
#目標ipa包路徑
TARGET_IPA_PATH="${ASSETS_PATH}/*.ipa"
#清空Temp文件夾
rm -rf "${SRCROOT}/Temp"
mkdir -p "${SRCROOT}/Temp"

#----------------------------------------
# 1. 解壓IPA到Temp下
unzip -oqq "$TARGET_IPA_PATH" -d "$TEMP_PATH"
# 拿到解壓的臨時的APP的路徑
TEMP_APP_PATH=$(set -- "$TEMP_PATH/Payload/"*.app;echo "$1")
# echo "路徑是:$TEMP_APP_PATH"

#----------------------------------------
# 2. 將解壓出來的.app拷貝進入工程下
# BUILT_PRODUCTS_DIR 工程生成的APP包的路徑
# TARGET_NAME target名稱
TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$TARGET_NAME.app"
echo "app路徑:$TARGET_APP_PATH"

rm -rf "$TARGET_APP_PATH"
mkdir -p "$TARGET_APP_PATH"
cp -rf "$TEMP_APP_PATH/" "$TARGET_APP_PATH"

#----------------------------------------
# 3. 刪除extension和WatchAPP.我的證書無法簽名Extention
rm -rf "$TARGET_APP_PATH/PlugIns"
rm -rf "$TARGET_APP_PATH/Watch"

#----------------------------------------
# 4. 更新info.plist文件 CFBundleIdentifier
#  設置:"Set : KEY Value" "目標文件路徑"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TARGET_APP_PATH/Info.plist"

#----------------------------------------
# 5. 給MachO文件上執行權限
# 拿到MachO文件的路徑
APP_BINARY=`plutil -convert xml1 -o - $TARGET_APP_PATH/Info.plist|grep -A1 Exec|tail -n1|cut -f2 -d\>|cut -f1 -d\<`
#上可執行權限
chmod +x "$TARGET_APP_PATH/$APP_BINARY"

#----------------------------------------
# 6. 重簽名第三方 FrameWorks
TARGET_APP_FRAMEWORKS_PATH="$TARGET_APP_PATH/Frameworks"
if [ -d "$TARGET_APP_FRAMEWORKS_PATH" ];
then
for FRAMEWORK in "$TARGET_APP_FRAMEWORKS_PATH/"*
do

#簽名
/usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORK"
done
fi

#注入
yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/libHankHook.dylib"

2.7 編譯運行成功(也和上面同樣在類中加入load代碼)

 

上面就是dylib方式代碼注入,但願對你們有所幫助!!!

 經過上面的兩種方式實現代碼注入,讓別人的app運行本身的app,下面總結以下:

 3、MethodSwizzle

3.1 概念

iOS 中實現AOP編程思想的方式其中之一是Method Swizzling,而 Method Swizzling 是利用Runtime特性把一個方法和另個方法的實現作替換,程序運行時修改Dispatch Table裏SEL和IMP之間的映射關係.

經過swizzling method改變目標函數selector所指向實現,在新的實現中來實現所要改的內容便可.

3.2 特色

  • 繼承: 修改較多,沒法敢保證他人必定繼承基類
  • 類別: 類別中重寫方法會覆蓋到原有的實現,其實,在真實的開發中,重寫方法並非爲了取代它,而是爲了添加一些實現; 若是幾個類別實現了一樣的方法, 但只有一個類別的方法會被調用.
  • AOP優點: 減小了重複代碼

3.3 代碼

@implementation NSURL (HKURL)

+(void)load
{
    Method URLWithStr = class_getClassMethod(self, @selector(URLWithString:));
    
    Method HKURL = class_getClassMethod(self, @selector(HKURLWithStr:));
    
    //交換
    method_exchangeImplementations(URLWithStr, HKURL);
}

+(instancetype)HKURLWithStr:(NSString *)str{
    //調用系統原來的方法
    NSURL * url = [NSURL HKURLWithStr:str];
    if (url == nil) {
        str = @"https://www.blog.com";
    }
    url = [NSURL HKURLWithStr:str];
    
    return url;
}

在上面的代碼中,利用method swizzling的交換方法.其餘Runtime的使用方法,以及爲何寫在load方法中,請參考本人另篇博客http://www.javashuo.com/article/p-mbmitvyi-dv.html

拓展: 爲何寫在load中?

  • load方法在源文件被裝載到程序中會被自動調用,不須要手動調用,也不須要該類使用不使用無關,在main()前被執行.
  • 當子類重寫了load,假如子類的類別重寫了load,load的調用順序會這樣: 父類、子類、子類類別
  • 可是若是有多個子類category都重寫了load,每一個子類category中load都會調用一次
  • 假如子類沒有重寫load,子類的默認load也不會去調用父類的load.此與正常繼承不太同樣.
  • 在正常的開發中, 除了method swizzle ,其餘的邏輯代碼儘可能不放在load,load方法中的代碼邏輯要儘可能簡單

 

4、微信示例Demo

4.1 微信--破壞註冊

4.1.1 將微信程序運行出來,以下圖所示

4.1.2 根據上面紅色找出類名,方法名

4.1.3 經過插件class-dump導出微信的.h文件

class-dump是將OC運行時聲明的信息導出來的工具, 其實能夠導出.h文件. 用此工具將未通過加密的app的頭文件導出來.

使用它一樣也要講此工具拷貝到MAC的目錄下/usr/local/bin下.

4.1.4 通過sublime text來找出對應的文件

4.1.5 經過第三部分講解,利用runtime交換方法

4.1.6 結果

 

4.2 竊取微信密碼

4.2.1 找到輸入密碼框的內容

從上面看出,登陸按鈕爲一個FixTitleColorButton對象,Target名字存放的地址爲0x280afaa40,Action名字存放地址是0x280afac00。

4.2.2 查看帳號密碼的輸入框

發現帳號密碼輸入框對象屬於都一個對象,叫作WCUITextField

4.2.3 利用LLDB查看登陸具體的Target和Action

從上面卡出,登陸按鈕在WCAccountMainLoginViewController頁面中;

登陸點擊方法叫作onNext

4.2.4 利用Sublime查看WeChat文件

發現確實有onNext()方法,並從中看出帳號輸入框和密碼輸入框都是WCAccountTextFieldItem中,可是並無發現textFileld,可是能夠看到WCAccountTextFieldItem是繼承於WCBaseTextFieldItem,咱們再看看WCBaseTextFieldItem文件內容

看出一個m_textField對象,經過tex字段取出string。

4.2.5 在帳號欄中輸入帳號和密碼

po [(WCAccountMainLoginViewController *)0x1128bbc00 valueForKey:@"_textFieldUserPwdItem"]
po [(WCAccountTextFieldItem *)0x28328e880 valueForKey:@"m_textField"]
po [(WCUITextField *)0x112163a00 text]

經過LLDB調試輸入的密碼是123456。

4.2.6 Hook登陸,獲取密碼

+ (void)load {
    NSLog(@"來了,老弟");
    Method onNext = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), sel_registerName("onNext"));
    //1.保存原始的IMP
    old_onNext = method_getImplementation(onNext);
    //2.SET
    method_setImplementation(onNext, (IMP)my_next);
}

IMP (*old_onNext)(id self,SEL _cmd);

void my_next(id self,SEL _cmd){
    // 獲取密碼
    NSString *pwd = [[[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"] performSelector:@selector(text)];
    NSString *accountTF = [[[self valueForKey:@"_textFieldUserNameItem"] valueForKey:@"m_textField"] performSelector:@selector(text)];
    NSLog(@"密碼是!%@",pwd);
    // 將密碼追加在帳號欄的後面
    [[[self valueForKey:@"_textFieldUserNameItem"] valueForKey:@"m_textField"] performSelector:@selector(setText:) withObject:[NSString stringWithFormat:@"%@+%@",accountTF,pwd]];
    //調用原來的方法
    old_onNext(self,_cmd);
}

上面用的是setIMP和getIMP的方式,對原方法進行Hook,也能夠用class_replaceMethod(),method_exchangeImplementations()。

 

5、總結

首先從代碼注入的方式:framework和dylib兩種方式,而後講到Method swizzling方式嘗試Hook,最後又以demo的方式來闡述代碼注入和Hook,但願對你們理解逆向開發的代碼注入有所幫助!!!,歡迎你們繼續關注!!!

相關文章
相關標籤/搜索