Skip to content

Instantly share code, notes, and snippets.

@Skifary Skifary/main.m
Last active Oct 11, 2019

Embed
What would you like to do?
修改block的实现,先打印参数,再输出原有实现
#import <Foundation/Foundation.h>
#import "ffi.h"
NSMutableArray *g_allocations;
ffi_cif g_cif;
ffi_closure *g_closure;
void *g_replacement_invoke;
void *g_origin_invoke;
id g_block;
enum {
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
BLOCK_HAS_SIGNATURE = (1 << 30),
};
typedef struct __block_descriptor {
size_t reserved;
size_t Block_size;
void *rest[1];
}__block_descriptor;
typedef struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
__block_descriptor *descriptor;
}__block_impl;
const char *block_type_encode_string(id blk) {
__block_impl *block_impl = (__bridge void *)blk;
__block_descriptor *descriptor = block_impl->descriptor;
assert(block_impl->Flags & BLOCK_HAS_SIGNATURE);
int index = 0;
if(block_impl->Flags & BLOCK_HAS_COPY_DISPOSE)
index += 2;
return descriptor->rest[index];
}
void invoke_original_block(void* ret, void **args) {
if (g_origin_invoke) {
ffi_call(&g_cif, g_origin_invoke, ret, args);
}
}
static void ffi_clousure_func(ffi_cif *cif, void *ret, void **args, void *user_data) {
int i = *((int *)args[1]);
NSString *str = (__bridge NSString *)(*((void **)args[2]));
NSLog(@"%d,%@", i, str);
invoke_original_block(ret, args);
}
const char * size_and_alignment(const char *str, NSUInteger *sizep, NSUInteger *alignp, long *len) {
const char *out = NSGetSizeAndAlignment(str, sizep, alignp);
if(len)
*len = out - str;
while(isdigit(*out))
out++;
return out;
}
static int arg_count(const char *str) {
int argcount = -1; // return type is the first one
while(str && *str) {
str = size_and_alignment(str, NULL, NULL, NULL);
argcount++;
}
return argcount;
}
void * allocate(size_t howmuch) {
NSMutableData *data = [NSMutableData dataWithLength:howmuch];
[g_allocations addObject: data];
return [data mutableBytes];
}
ffi_type * ffi_arg_for_encode(const char *str) {
#define SINT(type) do { \
if(str[0] == @encode(type)[0]) \
{ \
if(sizeof(type) == 1) \
return &ffi_type_sint8; \
else if(sizeof(type) == 2) \
return &ffi_type_sint16; \
else if(sizeof(type) == 4) \
return &ffi_type_sint32; \
else if(sizeof(type) == 8) \
return &ffi_type_sint64; \
else \
{ \
NSLog(@"Unknown size for type %s", #type); \
abort(); \
} \
} \
} while(0)
#define UINT(type) do { \
if(str[0] == @encode(type)[0]) \
{ \
if(sizeof(type) == 1) \
return &ffi_type_uint8; \
else if(sizeof(type) == 2) \
return &ffi_type_uint16; \
else if(sizeof(type) == 4) \
return &ffi_type_uint32; \
else if(sizeof(type) == 8) \
return &ffi_type_uint64; \
else \
{ \
NSLog(@"Unknown size for type %s", #type); \
abort(); \
} \
} \
} while(0)
#define INT(type) do { \
SINT(type); \
UINT(unsigned type); \
} while(0)
#define COND(type, name) do { \
if(str[0] == @encode(type)[0]) \
return &ffi_type_ ## name; \
} while(0)
#define PTR(type) COND(type, pointer)
#define STRUCT(structType, ...) do { \
if(strncmp(str, @encode(structType), strlen(@encode(structType))) == 0) \
{ \
ffi_type *elementsLocal[] = { __VA_ARGS__, NULL }; \
ffi_type **elements = allocate(sizeof(elementsLocal)); \
memcpy(elements, elementsLocal, sizeof(elementsLocal)); \
\
ffi_type *structType = allocate(sizeof(*structType)); \
structType->type = FFI_TYPE_STRUCT; \
structType->elements = elements; \
return structType; \
} \
} while(0)
SINT(_Bool);
SINT(signed char);
UINT(unsigned char);
INT(short);
INT(int);
INT(long);
INT(long long);
PTR(id);
PTR(Class);
PTR(SEL);
PTR(void *);
PTR(char *);
PTR(void (*)(void));
COND(float, float);
COND(double, double);
COND(void, void);
ffi_type *CGFloatFFI = sizeof(CGFloat) == sizeof(float) ? &ffi_type_float : &ffi_type_double;
STRUCT(CGRect, CGFloatFFI, CGFloatFFI, CGFloatFFI, CGFloatFFI);
STRUCT(CGPoint, CGFloatFFI, CGFloatFFI);
STRUCT(CGSize, CGFloatFFI, CGFloatFFI);
#if !TARGET_OS_IPHONE
STRUCT(NSRect, CGFloatFFI, CGFloatFFI, CGFloatFFI, CGFloatFFI);
STRUCT(NSPoint, CGFloatFFI, CGFloatFFI);
STRUCT(NSSize, CGFloatFFI, CGFloatFFI);
#endif
NSLog(@"Unknown encode string %s", str);
abort();
}
ffi_type ** args_with_encode_string(const char *str, int *out_count) {
int count = arg_count(str);
ffi_type **arg_types = allocate(count * sizeof(*arg_types));
int i = -1; // 第一个是返回值,需要排除
while(str && *str) {
const char *next = size_and_alignment(str, NULL, NULL, NULL);
if(i >= 0)
arg_types[i] = ffi_arg_for_encode(str);
i++;
str = next;
}
*out_count = count;
return arg_types;
}
void prep_cif() {
int args_count;
const char *str = block_type_encode_string(g_block);
ffi_type **arg_types = args_with_encode_string(str, &args_count);
ffi_status status = ffi_prep_cif(&g_cif, FFI_DEFAULT_ABI, args_count, ffi_arg_for_encode(str), arg_types);
if(status != FFI_OK) {
NSLog(@"Got result %ld from ffi_prep_cif", (long)status);
abort();
}
}
void prep_closure() {
prep_cif();
g_closure = ffi_closure_alloc(sizeof(ffi_closure), &g_replacement_invoke);
ffi_status status = ffi_prep_closure_loc(g_closure, &g_cif, ffi_clousure_func, NULL, g_replacement_invoke);
if(status != FFI_OK) {
NSLog(@"ffi_prep_closure returned %d", (int)status);
abort();
}
g_origin_invoke = ((__bridge __block_impl *)g_block)->FuncPtr;
((__bridge __block_impl *)g_block)->FuncPtr = g_replacement_invoke;
}
void HookBlockToPrintArguments(id blk) {
g_block = blk;
prep_closure();
}
#pragma mark - 第二种实现方式
//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;
//}
int main(int argc, const char * argv[]) {
void (^blk)(int, NSString *) = ^void(int i, NSString *str) {
NSLog(@"original invoke");
};
HookBlockToPrintArguments(blk);
blk(1,@"aaa");
return 0;
}
@Skifary

This comment has been minimized.

Copy link
Owner Author

Skifary commented Jun 20, 2018

第二个问题
image

@Skifary

This comment has been minimized.

Copy link
Owner Author

Skifary commented Jun 20, 2018

解决原理,利用libffi hook block,保存参数信息并且切换函数实现,在最后打印参数信息后再调用原有的函数实现。

@victorylau

This comment has been minimized.

Copy link

victorylau commented Jun 21, 2018

前排膜拜大佬。

@lexrus

This comment has been minimized.

Copy link

lexrus commented Jun 28, 2018

太牛比了,膜拜,已粉。

@yoimhere

This comment has been minimized.

Copy link

yoimhere commented Jun 29, 2018

前排膜拜大佬。

@iStig

This comment has been minimized.

Copy link

iStig commented Jun 29, 2018

膜拜 不得不服

@songxing10000

This comment has been minimized.

Copy link

songxing10000 commented Jun 30, 2018

膜拜大神!!!

@Skifary

This comment has been minimized.

Copy link
Owner Author

Skifary commented Jun 30, 2018

新增第二种实现方式

@sunnyxx

This comment has been minimized.

Copy link

sunnyxx commented Jul 3, 2018

前排膜拜大佬。

@jueyingxx

This comment has been minimized.

Copy link

jueyingxx commented Jul 3, 2018

前排膜拜大佬。

@SiegeLeo

This comment has been minimized.

Copy link

SiegeLeo commented Jul 6, 2018

前排膜拜大佬。

@weiwanying

This comment has been minimized.

Copy link

weiwanying commented Jul 10, 2018

前排膜拜大佬。

@wqforever

This comment has been minimized.

Copy link

wqforever commented Aug 31, 2018

后排膜拜大佬。

@songxing10000

This comment has been minimized.

Copy link

songxing10000 commented Jan 25, 2019

再次膜拜大佬。

@paradiseduo

This comment has been minimized.

Copy link

paradiseduo commented Feb 19, 2019

但其实这只实现了特定的block替换,如果block的参数不确定,或者把int跟String一换,这个程序就崩了。我感觉提问者的意思应该是写一个通用的方法。而不是只能换这一种block。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.