iOS_frida-trace修改函数参数和返回值

7,609 阅读3分钟

1、使用frida-trace启动app并追踪方法:

frida-trace -U -f cn.testapp.main -m "*[Global *]"

cn.testapp.main 是APP的bundleID ,frida-trace以此判断要启动哪个app

2、frida-trace追踪app的方法时,修改方法的参数和返回值

iOS测试项目代码:

#import "ViewController.h"
@interface ViewController ()<UIWebViewDelegate>
@property(nonatomic,strong)UIButton * testBtn;
@end

@implementation ViewController
- (void)viewDidLoad {    
    [super viewDidLoad];
}

-(void)viewDidAppear:(BOOL)animated{    
    [super viewDidAppear:animated];
     [self addButton];
}

-(void)addButton{    
    UIButton * btn = [UIButton buttonWithType:UIButtonTypeSystem];
    btn.frame = CGRectMake(100, 100, 100, 100);    
    btn.backgroundColor = [UIColor orangeColor];
    [btn setTitle:@"点击" forState:UIControlStateNormal];
    [btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
    self.testBtn = btn;
}

-(void)btnClick{    
    NSLog(@"点击成功");

    int age = [self testSendInt:18];
    NSString * name = [self testSendString:@"jack"];
    NSLog(@"\n%@\n%d",name,age);
}
-(int)testSendInt:(int)age{
    int result = age+10;
    return result;
}
-(NSString *)testSendString:(NSString *)name{
    NSString * result = [name stringByAppendingString:@"--2"];
    return result;
}
@end

使用frida-trace测试 testSendInt 和 testSendString 这两个方法

-[ViewController testSendInt:]方法对应的js脚本:

{
  /**
   * Called synchronously when about to call -[ViewController testSendInt:].
   *
   * @this {object} - Object allowing you to store state for use in onLeave.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {array} args - Function arguments represented as an array of NativePointer objects.
   * For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
   * It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
   * @param {object} state - Object allowing you to keep state across function calls.
   * Only one JavaScript function will execute at a time, so do not worry about race-conditions.
   * However, do not use this to store function arguments across onEnter/onLeave, but instead
   * use "this" which is an object for keeping state local to an invocation.
   */
  onEnter: function (log, args, state) {
    log('-[ViewController testSendInt:' + args[2] + ']');
    // 修改参数为 20
    args[2] = ptr("20");
  },

  /**
   * Called synchronously when about to return from -[ViewController testSendInt:].
   *
   * See onEnter for details.
   *
   * @this {object} - Object allowing you to access state stored in onEnter.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {NativePointer} retval - Return value represented as a NativePointer object.
   * @param {object} state - Object allowing you to keep state across function calls.
   */
  onLeave: function (log, retval, state) {
    //修改返回值为 99
    retval2 = ptr("99");
    retval.replace(retval2);
  }
}

-[ViewController testSendString:]方法对应的js脚本:

{
  /**
   * Called synchronously when about to call -[ViewController testSendString:].
   *
   * @this {object} - Object allowing you to store state for use in onLeave.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {array} args - Function arguments represented as an array of NativePointer objects.
   * For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
   * It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
   * @param {object} state - Object allowing you to keep state across function calls.
   * Only one JavaScript function will execute at a time, so do not worry about race-conditions.
   * However, do not use this to store function arguments across onEnter/onLeave, but instead
   * use "this" which is an object for keeping state local to an invocation.
   */
  onEnter: function (log, args, state) {
    log('-[ViewController testSendString:' + args[2] + ']');
    //修改参数为 “逆向APP”
    args[2] = ObjC.classes.NSString.stringWithString_("逆向APP")

  },

  /**
   * Called synchronously when about to return from -[ViewController testSendString:].
   *
   * See onEnter for details.
   *
   * @this {object} - Object allowing you to access state stored in onEnter.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {NativePointer} retval - Return value represented as a NativePointer object.
   * @param {object} state - Object allowing you to keep state across function calls.
   */
  onLeave: function (log, retval, state) {
    //修改返回值为 "逆向APP---666"
    newretval = ObjC.classes.NSString.stringWithString_("逆向APP---666")
    retval.replace(newretval)
  }
}

打开终端,输入frida-trace命令:

frida-trace -U 23745 -m "*[ViewController *]"

“23745”是我当前iOS APP 的pid,改成你自己的。

当点击 APP 中的按钮触发这两个方法的调用:

APP打印信息被修改了,以下是打印对比:

2020-05-26 10:56:12.583483+0800 testUIWebView[23745:2779627] 点击成功
2020-05-26 10:56:12.592081+0800 testUIWebView[23745:2779627] 
jack--2
28
2020-05-26 10:58:29.192116+0800 testUIWebView[23745:2779627] 点击成功
2020-05-26 10:58:29.251267+0800 testUIWebView[23745:2779627] 
逆向APP
99
2020-05-26 10:59:43.744645+0800 testUIWebView[23745:2779627] 点击成功
2020-05-26 10:59:43.791268+0800 testUIWebView[23745:2779627] 
逆向APP--2
99

====================================================

修改返回值为bool的函数返回值:

onLeave(log, retval, state) {
    retval.replace(0x0);//修改返回值为false
  }