引言
tweak: 在越獄環(huán)境,我要去修改,玩玩某個(gè)App,需要做的就是用theos創(chuàng)建一個(gè)tweak的項(xiàng)目,然后去修改App
反tweak: 當(dāng)我知道tweak去將動(dòng)態(tài)庫(kù)臨時(shí)插入進(jìn)程從而修改我的App的時(shí)候,這么搞那可不行萬一懷孕了吶?,插入進(jìn)程需要的DYLD的宏的環(huán)境變量DYLD_INSTER_LIBRARIES,查看dyld的源代碼,我知道了在MachO文件中添加一個(gè)section其中segmentname、sectionname分別為__RESTRICT、__restrict從而達(dá)到我要的防治進(jìn)程使用DYLD臨時(shí)插入動(dòng)態(tài)庫(kù)
反反tweak: 前幾天玩的好好的App,突然之間tweak插入進(jìn)程插不進(jìn)去,我擦,這怎么回事? 經(jīng)過反復(fù)搜索,各種途徑的努力,原來App在項(xiàng)目打包的時(shí)候,在MachO文件中添加了一個(gè)section其中segmentname、sectionname分別為__RESTRICT、__restrict,那么我只要修改MachO文件中的這個(gè)section,使它的segmentname、sectionname任意字段修改不等于__RESTRICT、__restrict,那么我的目的就達(dá)到了,然后我還是可以爆你。
反反反 tweak
負(fù)面情緒+10086
mmp的,我聽說在某dia、某手又有爆我的App,你說氣不氣,你TM修改我的MachO文件,你這是犯規(guī)擦
既然你做初一,也別怪我做十五。
你既然修改我的MachO文件,那么我每次運(yùn)行App的時(shí)候我會(huì)檢測(cè)我的MachO文件中的section,它是否包含segmentname、sectionname分別為__RESTRICT、__restrict,如果沒有這個(gè)section就直接閃退,哥么你想干哈?
分析
static bool hasRestrictedSegment(const macho_header* mh)
{
const uint32_t cmd_count = mh->ncmds;
const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(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;
}
dyld的源碼 dyld.cpp
根據(jù)上述代碼,我們可以判斷MachO文件中是否有我們提到的section。
我們調(diào)用這個(gè)方法,需要一個(gè)參數(shù)macho_header* mh
在系統(tǒng)的頭文件,#import <mach-o/loader.h>存在 macho_header
、mach_header_64
struct mach_header {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
};
struct mach_header_64 {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
uint32_t reserved; /* reserved */
};
在#import <mach-o/dyld.h> 存在一段代碼
//可以直接拿到`mach_header`
extern const struct mach_header* _dyld_get_image_header(uint32_t image_index)
//uint32_t image_index 是的角標(biāo)MachO、dylib等的前面的標(biāo)示
//lldb調(diào)試的時(shí)候 image list
//MachO的索引是0
防護(hù)代碼在你的App中調(diào)用
// ARM and x86_64 are the only architecture that use cpu-sub-types
#define CPU_SUBTYPES_SUPPORTED ((__arm__ || __arm64__ || __x86_64__) && !TARGET_IPHONE_SIMULATOR)
#if __LP64__
#define macho_header mach_header_64
#define LC_SEGMENT_COMMAND LC_SEGMENT_64
#define macho_segment_command segment_command_64
#define macho_section section_64
#else
#define macho_header mach_header
#define LC_SEGMENT_COMMAND LC_SEGMENT
#define macho_segment_command segment_command
#define macho_section section
#endif
+ (void)load{
//dyld啟動(dòng)app最先加載的是自己的MachO 通過lldb:image list
const struct macho_header *header = (const struct macho_header *)_dyld_get_image_header(0);
if(hasRestrictedSegment(header)){
NSLog(@"反tweak正常");
}else{
NSLog(@"兄弟是不是找事?");
exit(0);
}
}
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;
printf("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;
}
以上