前言
Logos 是 Theos 的一個(gè)組件,它允許程序員使用一組特殊的預(yù)處理器指令來編寫鉤子拢驾,簡潔高效。
做過 iOS 逆向開發(fā)的朋友應(yīng)該非常熟悉拾并,這里筆者將介紹如何在 Mac app 上使用 Logos概疆。
可能用到的工具
- Theos
- optool/insert_dylib
- unsign (optional)
一個(gè)簡單的例子
-
編寫一個(gè)簡單的 demo逗威,大概就是 軟件正中一個(gè)按鈕,點(diǎn)擊之后 alert("hi!")岔冀。核心代碼如下:
#import "ViewController.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } - (IBAction)sayHi:(NSButton *)sender { NSAlert *alert = NSAlert.new; alert.messageText = @"hi!"; alert.alertStyle = NSAlertStyleInformational; [alert runModal]; } - (void)setRepresentedObject:(id)representedObject { [super setRepresentedObject:representedObject]; // Update the view, if already loaded. } @end
我們的目標(biāo)是注入 sayHi 這個(gè)方法凯旭,使點(diǎn)擊按鈕之后不再說“hi!”,而是“hello world!”
-
編寫 Logos
%config(generator=internal) // 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. #import <Foundation/Foundation.h> %hook ViewController // Hooking an instance method with an argument. - (void)sayHi:(id)argument { NSAlert *r15 = [[NSAlert alloc] init]; [r15 setMessageText:@"hello world!"]; [r15 setAlertStyle:0x1]; [r15 runModal]; } // Always make sure you clean up after yourself; Not doing so could have grave consequences! %end %ctor { NSLog(@"!!!!!!inject success!!!!!!!"); }
將以上代碼保存為一個(gè) Tweak.xm 文件(名字后綴名隨意)使套,放在與 SayHi.app 同級(jí)目錄下罐呼,便于后續(xù)操作。
然后我們使用 Theos 的語法分析來把 Logos 轉(zhuǎn)換成普通代碼
$THEOS/bin/logos.pl Tweak.xm > abc.mm
注意 abc 應(yīng)該有 mm 作為后綴名侦高,用于告訴 clang 目標(biāo)語言類型使用 clang 編譯轉(zhuǎn)換后的普通代碼嫉柴,并將結(jié)果放到 app 包內(nèi)
clang -shared -undefined dynamic_lookup -o ./SayHi.app/Contents/MacOS/lib.dylib ./abc.mm
使用 optool/insert_dylib 往 SayHi 的 MachO 頭部添加我們剛剛編譯的 lib.dylib
optool install -c load -p @executable_path/lib.dylib -t ./SayHi.app/Contents/MacOS/SayHi
如果你的 Mac app 沒有簽名的話,此時(shí)應(yīng)該已經(jīng)達(dá)成我們的需求了奉呛。但是實(shí)踐中我們肯定不是對(duì)自己導(dǎo)出的未簽名 Mac app 下黑手计螺。所以需要去掉這個(gè)簽名或重簽名。因?yàn)楣P者沒有錢買開發(fā)者賬號(hào)瞧壮,故不知道如何重簽名登馒。
- 使用 codesign 去除簽名
codesign --remove-signature SayHi.app
此時(shí)我們的需求已經(jīng)達(dá)成
但是 codesign 有一個(gè) bug,在刪除代碼簽名之后沒有修復(fù) MachO Header 的偏移咆槽,會(huì)導(dǎo)致生成的 MachO 文件畸形陈轿。筆者曾經(jīng)就遇見一個(gè)不到 1m 的小程序在移除簽名后膨脹到 2g 大小。
所以筆者建議使用開源社區(qū)的代替方案——unsign
后記
筆者把上面的繁瑣命令行操作整合為一個(gè)腳本秦忿,在這里也順便分享出來
#!/usr/bin/env bash
#將xm和文件app包放在同一個(gè)目錄麦射,運(yùn)行本腳步進(jìn)行注入
path=`ls | grep *.app | head -1`
tweak=`ls | grep *.xm | head -1`
temp='x11901'
name=${path%.app}
$THEOS/bin/logos.pl "./${tweak}" > "./${temp}.m"
clang -shared -undefined dynamic_lookup -o "./${path}/Contents/MacOS/lib.dylib" "./${temp}.mm"
optool install -c load -p @executable_path/lib.dylib -t "./${path}/Contents/MacOS/${name}"
rm -f ${temp}.m
# 使用unsign效果可能更好,codesign --remove-signature 在刪除代碼簽名之后沒有修復(fù)MachO Header的偏移灯谣,導(dǎo)致生成的MachO文件畸形
# codesign --remove-signature ${name}
if [ ! -e "./${path}/Contents/MacOS/${name}.ori" ]; then
unsign "./${path}/Contents/MacOS/${name}"
mv "./${path}/Contents/MacOS/${name}" "./${path}/Contents/MacOS/${name}.ori"
mv "./${path}/Contents/MacOS/${name}.unsigned" "./${path}/Contents/MacOS/${name}"
fi
open "./${path}/Contents/MacOS/${name}"