Hook ObjC的不定参数方法

今天群里有朋友问怎么Hook ObjC的不定参数方法,比如NSDictionary的+ [NSDictionary dictionaryWithObjectsAndKeys:]

于是稍微研究了一下,其实和普通的ObjC的Hook差不多的。

#include <Foundation/Foundation.h>
#include <Cocoa/Cocoa.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#include <stdarg.h>
 
/*!
 *  @brief  用于替换不定参数方法的实现
 *
 *  @param self self
 *  @param op   selector
 *  @param obj1 first param
 *  @param ...  other params
 *
 *  @return for this case, returns an instance of NSDictionary
 */

id dictionaryWithObjectsAndKeys(id self, SEL op,id obj1, ...);
id dictionaryWithObjectsAndKeys(id self, SEL op,id obj1, ...)
{

    /*!
     *  @brief  用于保存Key和Value
     */

    NSMutableArray *keys = [[NSMutableArray alloc] init];
    NSMutableArray *values = [[NSMutableArray alloc] init];

    /*!
     *  @brief  使用stdarg提供的函数获取参数
     */

    va_list args;
    va_start(args, obj1);
    id obj = obj1;
    int flag = 0;
    while (obj != nil) {

    /*!
     *  @brief  因为这里演示的是NSDictionary的dictionaryWithObjectsAndKeys方法
     * 所以判断一下现在获取的是Key还是Value
     */

        if (flag % 2 == 0) {
            [keys addObject:obj];
            printf("[Hook] Key: %sn",[obj description].UTF8String);
        } else {
            [values addObject:obj];
            printf("[Hook] Value: %sn",[obj description].UTF8String);
        }
        obj = va_arg(args, id);
        flag++;
    }
    va_end(args);

    /*!
     *  @brief  自己实现一下等价的功能, 对于不定参数方法有时不一定方便调用%orig;
     */

    NSMutableDictionary * result = [[NSMutableDictionary alloc] init];
    for (int index = 0; index < keys.count; index++)
        [result setValue:[values objectAtIndex:index] forKey:[keys objectAtIndex:index]];
    return result;
}
 
int main(int argc, const char * argv[])
{
 
    /*!
     *  @brief  替换原来NSDictionary的实现
     */
 
    method_setImplementation( class_getClassMethod( NSClassFromString( @"NSDictionary" ), NSSelectorFromString( @"dictionaryWithObjectsAndKeys:" ) ), (IMP)dictionaryWithObjectsAndKeys );
 
    NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys : @"Name"@"[data deleted]"@"Info"@{@"Blog" @"Blog.[data deleted].com"}nil];
    NSLog(@"%@",dict);
    return 0;
}

最后得到,
屏幕快照 2015-03-31 下午4.28.04

3 thoughts on “Hook ObjC的不定参数方法”

  1. 感觉这种应该是有汇编级的库支持才对

    跟msg_send类似,把栈复位就可以了吧?

  2. 我想了一下,调用原函数是个比较让人恼火的地方,你举的例子恰好可以找到比较方便的代替函数,但对于NSLog,objc_msgSend这样的函数,你要怎么调用原函数?通过va_list系列函数拿到的参数,要怎么传给原函数?

Leave a Reply

Your email address will not be published. Required fields are marked *

4 − three =