一、Tweak原理分析
1、獲取APPID,com.tencent.xin
2、theos創建
3、cd進來,
make
編譯一下,生成隱藏文件.theos
,最后是把theosDemo.dylib
注入到手機4、
make package
一下,生成packages
文件。make package
打包,打包成deb
的包。安裝的時候其實就是安裝的這個.deb
的包5、
make install
注入。微信重啟了,Cydia
中出現theosDemo
6、打開
iFunBox
,在Device/Library/MobileSubstrate/DynamicLibraries
中會出現theosDemo.dylib
和theosDemo.plist
注意點:正常情況下這里是會出現的
theosDemo.dylib
和theosDemo.plist
,但是我這里用theos它沒有出現,用Monkey寫Tweak,他就出現了。這是為什么了? 待解決中7、打開Xcode,可以看到打印
8、把手機上的MachO拷貝出來,用
MachOView
打開,Load Commands
中并沒有theosDemo
。所以咋們的越獄插件是通過DYLD_INSERT_LIBRARIES
環境變量插入的。
兩種方式
1、Framework注入、修改了MachO
2、DYLD_INSERT_LIBRARIES
環境變量插入,MachO沒有改變
二、DYLD源碼分析找到防護突破口
搜索
DYLD_INSERT_LIBRARIES
command+shift+j
來到5693行;
pruneEnvironmentVariables(envp, &apple);
移除環境變量; gLinkContext.processIsRestricted
保證這個為真,就可以移除環境變量processIsRestricted
搜索一下,看這個屬性是在那里賦值的。processIsRestricted = true
搜索一下
hasRestrictedSegment
。所以如果MachO中segname
有__RESTRICT
和sectname
有__restrict
,則hasRestrictedSegment(mainExecutableMH)
為ture,則gLinkContext.processIsRestricted
為true,則環境變量移除,則不會插入動態庫三、修改RESTRICT段防護Tweak
1、創建一個普通的工程
2、
theos
創建一個Tweak3、把Tweak拖入
Sublime Text
。編寫logos,然后保存一下4、
theos
執行make
和make package;make install
。應用重新啟動了5、
command+shift+2
、Open Console
注意:正常情況下這里是會打印
不好意思我把你干掉了
,但是我這里用theos它沒有出現,用Monkey寫Tweak,它就打印了。這是為什么了? 待解決中(同上面的問題)下面的是用Monkey寫的Tweak。成功了。
6、
Other Linker Flags
添加-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null
。然后編譯一下查看MachO,如圖所示,生成了
Section64(__RESTRICT,__restrict)
7、
command+R
運行項目。打印點擊了屏幕
,防住了。8、把App拷貝下來,查看MachO。
9、修改二進制,破壞防護
保存,退出MachOView,在此打開MachOView
Snip20191223_24.png
10、再把MachO拷貝回手機,
scp -P 12345 -r ~/Desktop/antiTweak.app root@localhost:/var/mobile/Containers/Bundle/Application/07DDF178-A970-4227-A3B4-644944E25E9F/
注意:此時的app啟動不了,因為破壞了簽名
11、重簽名。創建一個MonkeyApp項目,項目名隨便取,
Bundle Identifier
也隨便取,我這里取了一個和原工程一樣的。然后重新運行MonkeyApp項目。打印
不好意思我把你干掉了
,說明成功了。四、參考dyld源碼防護
1、dyld源碼
2、原項目按如下方式修改。并且
Other Linker Flags
中也添加了-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null
。
#import "ViewController.h"
#import <mach-o/loader.h>
#import <mach-o/dyld.h>
#if __LP64__
#define LC_SEGMENT_COMMAND LC_SEGMENT_64
#define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT
#define LC_ENCRYPT_COMMAND LC_ENCRYPTION_INFO
#define macho_segment_command segment_command_64
#define macho_section section_64
#define macho_header mach_header_64
#else
#define LC_SEGMENT_COMMAND LC_SEGMENT
#define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64
#define LC_ENCRYPT_COMMAND LC_ENCRYPTION_INFO_64
#define macho_segment_command segment_command
#define macho_section section
#define macho_header mach_header
#endif
@interface ViewController ()
@end
@implementation ViewController
+ (void)load {
//根據imagelist可以看出,imagelist 里面第0個是我們自己的可執行文件
const struct mach_header * header = _dyld_get_image_header(0);
if (hasRestrictedSegment(header)) {
NSLog(@"沒毛病");
} else {
NSLog(@"請刪除插件!!!");
}
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UIAlertController *ac = [UIAlertController alertControllerWithTitle:@"提示" message:@"點擊了屏幕" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
[ac addAction:action];
[self presentViewController:ac animated:true completion:nil];
NSLog(@"點擊了屏幕");
}
static bool hasRestrictedSegment(const struct macho_header* mh)
{
const uint32_t cmd_count = mh->ncmds;
const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(struct macho_header));
const struct load_command* cmd = cmds;
for (uint32_t i = 0; i < cmd_count; ++i) {
switch (cmd->cmd) {
case LC_SEGMENT_COMMAND:
{
const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
//dyld::log("seg name: %s\n", seg->segname);
if (strcmp(seg->segname, "__RESTRICT") == 0) {
const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects];
for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
if (strcmp(sect->sectname, "__restrict") == 0)
return true;
}
}
}
break;
}
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
}
return false;
}
@end
3、修改二進制,用MachOView修改,方法如上。
4、重簽名。使用MonkeyApp重簽名。方法如上。打印請刪除插件!!!
,說明又防住了,??。