今天繼續講述逆向開發中另外一個比較重要的課程是代碼注入內容,本篇篇幅比較長,但仍是有不少乾貨的,但願你們經過此篇文章更加了解逆向開發中的要點和知識點.咱們將分解幾個內容,進行講解:html
讓代碼執行本身的代碼,總體方案以下:ios
如何讓別人的app來執行本身的代碼呢? 這就要經過代碼注入的方式來達到,而代碼注入的方式有兩種: 一種是經過framework, 一種是dylib方式,另種方案,能夠經過Runtime機制git
代碼注入思路:github
DYLD會動態加載動態庫Framework中全部動態庫,在frameworks中加入本身的一個動態庫,而後在動態庫中hook和注入代碼.編程
MachOView的下載地址:http://sourceforge.net/projects/machoview/微信
若是想看源碼以下:MachOView源碼:https://github.com/gdbinit/MachOViewapp
yololib工具下載地址:https://github.com/KJCracks/yololib?spm=a2c4e.11153940.blogcont63256.9.5126420eAJpqBD函數
咱們看到有不少的DYLIB,表明的是加載動態庫工具
由上可知,WJHookFrameWork已經加入成功。ui
緣由:用MachOView打開可執行的WeChat,沒有找到WJHookFrameWork
下面咱們講述怎麼將WJHookFramework寫入到MachoView文件中?
須要使用yololib工具,建議將yololib放到 /usr/local/bin
須要增長執行權限: chmod +x WeChat
yololib WeChat Frameworks/WJHookFrameWork.framework/WJHookFrameWork
經過上面的過程,查看MachOView文件Load commands中是否有WJHookFrameWork
上面圖顯示已經加入成功。
zip -ry WeChat.ipa Payload
將WeChat.ipa放入App目錄中,刪除其餘的文件夾。
上面就是framework方式代碼注入。你們能夠私信我,若有不懂!!!
加入腳本文件
# ${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"
上面就是dylib方式代碼注入,但願對你們有所幫助!!!
經過上面的兩種方式實現代碼注入,讓別人的app運行本身的app,下面總結以下:
iOS 中實現AOP編程思想的方式其中之一是Method Swizzling,而 Method Swizzling 是利用Runtime特性把一個方法和另個方法的實現作替換,程序運行時修改Dispatch Table裏SEL和IMP之間的映射關係.
經過swizzling method改變目標函數selector所指向實現,在新的實現中來實現所要改的內容便可.
@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中?
class-dump是將OC運行時聲明的信息導出來的工具, 其實能夠導出.h文件. 用此工具將未通過加密的app的頭文件導出來.
使用它一樣也要講此工具拷貝到MAC的目錄下/usr/local/bin下.
從上面看出,登陸按鈕爲一個FixTitleColorButton對象,Target名字存放的地址爲0x280afaa40,Action名字存放地址是0x280afac00。
發現帳號密碼輸入框對象屬於都一個對象,叫作WCUITextField
從上面卡出,登陸按鈕在WCAccountMainLoginViewController頁面中;
登陸點擊方法叫作onNext
發現確實有onNext()方法,並從中看出帳號輸入框和密碼輸入框都是WCAccountTextFieldItem中,可是並無發現textFileld,可是能夠看到WCAccountTextFieldItem是繼承於WCBaseTextFieldItem,咱們再看看WCBaseTextFieldItem文件內容
看出一個m_textField對象,經過tex字段取出string。
po [(WCAccountMainLoginViewController *)0x1128bbc00 valueForKey:@"_textFieldUserPwdItem"] po [(WCAccountTextFieldItem *)0x28328e880 valueForKey:@"m_textField"] po [(WCUITextField *)0x112163a00 text]
經過LLDB調試輸入的密碼是123456。
+ (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()。
首先從代碼注入的方式:framework和dylib兩種方式,而後講到Method swizzling方式嘗試Hook,最後又以demo的方式來闡述代碼注入和Hook,但願對你們理解逆向開發的代碼注入有所幫助!!!,歡迎你們繼續關注!!!