Last active
October 11, 2019 08:35
-
-
Save Skifary/497ad1ee4bf7f57d8093463cfabd1c1f to your computer and use it in GitHub Desktop.
替换所有block的实现
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.m | |
// TestObjc | |
// | |
// Created by Skifary on 14/03/2018. | |
// Copyright © 2018 skifary. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
#import "fishhook.h" | |
typedef struct __block_impl { | |
void *isa; | |
int Flags; | |
int Reserved; | |
void *FuncPtr; | |
}__block_impl; | |
static void (*orig_func)(void *v ,int i, NSString *str); | |
void hookFunc(void *v ,int i, NSString *str) { | |
NSLog(@"%d,%@", i, str); | |
orig_func(v,i,str); | |
} | |
void HookBlockToPrintArguments(id blk) { | |
__block_impl *ptr = (__bridge __block_impl *)blk; | |
orig_func = ptr->FuncPtr; | |
ptr->FuncPtr = &hookFunc; | |
} | |
#pragma mark - 第三题实现部分 | |
static id (*orig_objc_retainBlock)(id); | |
id hook_objc_retainBlock(id blk) { | |
id retainBlk = orig_objc_retainBlock(blk); | |
// 因为retain会多次调动 | |
// 这里可以给blk添加一个属性 如果被hook过就不用继续hook | |
// 因为这里只是一个测试例子 就不做这么麻烦了 | |
if (true) { | |
HookBlockToPrintArguments(blk); | |
} | |
return retainBlk; | |
} | |
void HookEveryBlockToPrintArguments() { | |
rebind_symbols((struct rebinding[1]){{"objc_retainBlock", hook_objc_retainBlock, (void *)&orig_objc_retainBlock}}, 1); | |
} | |
int main(int argc, const char * argv[]) { | |
HookEveryBlockToPrintArguments(); | |
void (^blk)(int, NSString *) = ^void(int i, NSString *str) { | |
NSLog(@"original invoke"); | |
}; | |
blk(1,@"aaa"); | |
return 0; | |
} |
原理,block在每次赋值的时候都会调用retain函数,所以说,利用fishhook hook了block的retain函数objc_retainBlock,在第二题的基础上在hook每一个block对象即可
static void (*orig_func)(void *v ,int i, NSString *str);
应该是下面的声明把
static void (* orig_objc_retainBlock)(void *v ,int i, NSString *str);
这里可以给blk添加一个属性 如果被hook过就不用继续hook,那么问题来了。。如何给一个void *添加属性呢?
objc_retainBlock实际上就是_Block_Copy方法,这个方法是这么定义的:
void *_Block_copy(const void *arg) {
struct Block_layout *aBlock;
if (!arg) return NULL;
// The following would be better done as a switch statement
aBlock = (struct Block_layout *)arg;
if (aBlock->flags & BLOCK_NEEDS_FREE) {
// latches on high
latching_incr_int(&aBlock->flags);
return aBlock;
}
else if (aBlock->flags & BLOCK_IS_GLOBAL) {
return aBlock;
}
else {
// Its a stack block. Make a copy.
struct Block_layout *result = malloc(aBlock->descriptor->size);
if (!result) return NULL;
memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
// reset refcount
result->flags &= ~(BLOCK_REFCOUNT_MASK|BLOCK_DEALLOCATING); // XXX not needed
result->flags |= BLOCK_NEEDS_FREE | 2; // logical refcount 1
_Block_call_copy_helper(result, aBlock);
// Set isa last so memory analysis tools see a fully-initialized object.
result->isa = _NSConcreteMallocBlock;
return result;
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
第三题: