引言
tweak: 在越狱环境,我要去修改,玩玩某个App,需要做的就是用theos创建一个tweak的项目,然后去修改App
反tweak: 当我知道tweak去将动态库临时插入进程从而修改我的App的时候,这么搞那可不行万一怀孕了呐?,插入进程需要的DYLD的宏的环境变量DYLD_INSTER_LIBRARIES,查看dyld的源代码,我知道了在MachO文件中添加一个section其中segmentname、sectionname分别为__RESTRICT、__restrict从而达到我要的防治进程使用DYLD临时插入动态库
反反tweak: 前几天玩的好好的App,突然之间tweak插入进程插不进去,我擦,这怎么回事? 经过反复搜索,各种途径的努力,原来App在项目打包的时候,在MachO文件中添加了一个section其中segmentname、sectionname分别为__RESTRICT、__restrict,那么我只要修改MachO文件中的这个section,使它的segmentname、sectionname任意字段修改不等于__RESTRICT、__restrict,那么我的目的就达到了,然后我还是可以爆你。
反反反 tweak
负面情绪+10086
mmp的,我听说在某dia、某手又有爆我的App,你说气不气,你TM修改我的MachO文件,你这是犯规擦
既然你做初一,也别怪我做十五。
你既然修改我的MachO文件,那么我每次运行App的时候我会检测我的MachO文件中的section,它是否包含segmentname、sectionname分别为__RESTRICT、__restrict,如果没有这个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
根据上述代码,我们可以判断MachO文件中是否有我们提到的section。
我们调用这个方法,需要一个参数macho_header* mh
在系统的头文件,#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 是的角标MachO、dylib等的前面的标示
//lldb调试的时候 image list
//MachO的索引是0
防护代码在你的App中调用
// 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启动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;
}
以上