Skip to content

Instantly share code, notes, and snippets.

@Skifary
Last active October 11, 2019 08:35
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Skifary/497ad1ee4bf7f57d8093463cfabd1c1f to your computer and use it in GitHub Desktop.
Save Skifary/497ad1ee4bf7f57d8093463cfabd1c1f to your computer and use it in GitHub Desktop.
替换所有block的实现
//
// 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;
}
@Skifary
Copy link
Author

Skifary commented Jun 30, 2018

第三题:image

@Skifary
Copy link
Author

Skifary commented Jun 30, 2018

原理,block在每次赋值的时候都会调用retain函数,所以说,利用fishhook hook了block的retain函数objc_retainBlock,在第二题的基础上在hook每一个block对象即可

@karosLi
Copy link

karosLi commented Oct 10, 2018

static void (*orig_func)(void *v ,int i, NSString *str);

应该是下面的声明把

static void (* orig_objc_retainBlock)(void *v ,int i, NSString *str);

@paradiseduo
Copy link

paradiseduo commented Feb 20, 2019

这里可以给blk添加一个属性 如果被hook过就不用继续hook,那么问题来了。。如何给一个void *添加属性呢?

@paradiseduo
Copy link

paradiseduo commented Feb 20, 2019

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