frida将自己注入到Firefox中,hook了recv 和read函数

sudo /Users/snappyjack/Library/Python/3.8/bin/frida-trace -i "recv*" -i "read*" firefox

test in MacOS

cp /bin/cat /tmp/cat
/tmp/cat

在另一个终端运行如下python(macOS需关闭SIP)

import frida

def on_message(message, data):
    print("[on_message] message:", message, "data:", data)

session = frida.attach("cat")

script = session.create_script("""
rpc.exports.enumerateModules = function () {
  return Process.enumerateModules();
};
""")
script.on("message", on_message)	# 这个暂时没有用
script.load()

print([m["name"] for m in script.exports.enumerate_modules()])

其中SIP状态查看如下

snappyjack@snappyjack /tmp % csrutil status
System Integrity Protection status: disabled.

输出的结果如下

snappyjack@snappyjack frida-morty % python3 example.py
['cat', 'libSystem.B.dylib', 'libcache.dylib', 'libcommonCrypto.dylib', 'libcompiler_rt.dylib', 'libcopyfile.dylib', 'libcorecrypto.dylib', 'libdispatch.dylib', 'libdyld.dylib', 'libkeymgr.dylib', 'liblaunch.dylib', 'libmacho.dylib', 'libquarantine.dylib', 'libremovefile.dylib', 'libsystem_asl.dylib', 'libsystem_blocks.dylib', 'libsystem_c.dylib', 'libsystem_collections.dylib', 'libsystem_configuration.dylib', 'libsystem_containermanager.dylib', 'libsystem_coreservices.dylib', 'libsystem_darwin.dylib', 'libsystem_dnssd.dylib', 'libsystem_featureflags.dylib', 'libsystem_info.dylib', 'libsystem_m.dylib', 'libsystem_malloc.dylib', 'libsystem_networkextension.dylib', 'libsystem_notify.dylib', 'libsystem_product_info_filter.dylib', 'libsystem_sandbox.dylib', 'libsystem_secinit.dylib', 'libsystem_kernel.dylib', 'libsystem_platform.dylib', 'libsystem_pthread.dylib', 'libsystem_symptoms.dylib', 'libsystem_trace.dylib', 'libunwind.dylib', 'libxpc.dylib', 'libc++abi.dylib', 'libobjc.A.dylib', 'liboah.dylib', 'libc++.1.dylib', 'dyld']

Functions

#include <stdio.h>
#include <unistd.h>

void
f (int n)
{
  printf ("Number: %d\n", n);
}

int
main (int argc,
      char * argv[])
{
  int i = 0;

  printf ("f() is at %p\n", f);

  while (1)
  {
    f (i++);
    sleep (1);
  }
}

编译

gcc -Wall hello.c -o hello

运行后的效果如下

snappyjack@snappyjack frida-morty % ./hello
f() is at 0x1017aeee0
Number: 0
Number: 1
Number: 2
Number: 3
创建hook.py
from __future__ import print_function
import frida
import sys

session = frida.attach("hello")
script = session.create_script("""
Interceptor.attach(ptr("%s"), {
    onEnter: function(args) {
        send(args[0].toInt32());
    }
});
""" % int(sys.argv[1], 16))#onEnter提供了args参数,可以用来读取参数列表
def on_message(message, data):	
    print(message)
script.on('message', on_message)	# monitor for any messages from the injected process
script.load()
sys.stdin.read()

运行后如下

snappyjack@snappyjack frida-morty % python hook.py 0x106760ee0
{u'type': u'send', u'payload': 12}
{u'type': u'send', u'payload': 13}
{u'type': u'send', u'payload': 14}
{u'type': u'send', u'payload': 15}
{u'type': u'send', u'payload': 16}
{u'type': u'send', u'payload': 17}

或者这样

snappyjack@snappyjack ~ % sudo /Users/snappyjack/Library/Python/3.8/bin/frida-trace -i "f" hello
Password:
Instrumenting...
f: Auto-generated handler at "/Users/snappyjack/__handlers__/hello/f.js"
Started tracing 1 function. Press Ctrl+C to stop.
           /* TID 0x307 */
   711 ms  f()
  1712 ms  f()
  2715 ms  f()

修改js

  onEnter(log, args, state) {
    log('f()');
    send(args[0].toInt32());
  },

结果如下

103338 ms  f()
{'type': 'send', 'payload': 285}
104342 ms  f()
{'type': 'send', 'payload': 286}
105345 ms  f()
{'type': 'send', 'payload': 287}
106350 ms  f()
{'type': 'send', 'payload': 288}
107352 ms  f()
{'type': 'send', 'payload': 289}
108356 ms  f()
{'type': 'send', 'payload': 290}
创建modify.py
import frida
import sys

session = frida.attach("hello")
script = session.create_script("""
Interceptor.attach(ptr("%s"), {
    onEnter: function(args) {
        args[0] = ptr("1337");
    }
});
""" % int(sys.argv[1], 16))	#args[0] = ptr("1337")表示将1337指针赋予给args[0],达到修改参数的目的
script.load()
sys.stdin.read()

运行python modify.py 0x1042a0ee0后效果如下

snappyjack@snappyjack frida-morty % ./hello
f() is at 0x1042a0ee0
Number: 0
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
Number: 6
Number: 7
Number: 8
Number: 1337
Number: 1337
Number: 1337
Number: 1337

或者

sudo /Users/snappyjack/Library/Python/3.8/bin/frida-trace -i "f" hello

修改js脚本

  onEnter(log, args, state) {
    log('f()');
    send(args[0].toInt32());
    args[0] = ptr("1337");
  },

结果如下

Number: 53
Number: 54
Number: 1337
Number: 1337
Number: 1337
Number: 1337
Number: 1337
Number: 1337
Number: 1337
Number: 1337
创建call.py
import frida
import sys

session = frida.attach("hello")
script = session.create_script("""
var f = new NativeFunction(ptr("%s"), 'void', ['int']);
f(1911);
f(1911);
f(1911);
""" % int(sys.argv[1], 16))	#原型如下new NativeFunction(address, returnType, argTypes[, abi]),其中第一个参数是函数地址,第二个参数是返回值的类型,第三个参数是输入参数的类型
script.load()

运行后有如下效果

Number: 18
Number: 19
Number: 20
Number: 21
Number: 1911
Number: 1911
Number: 1911
Number: 22
Number: 23
Number: 24
Number: 25
Injecting Strings and Calling a Function

创建hi.c如下

#include <stdio.h>
#include <unistd.h>

int
f (const char * s)
{
  printf ("String: %s\n", s);
  return 0;
}

int
main (int argc,
      char * argv[])
{
  const char * s = "Testing!";

  printf ("f() is at %p\n", f);
  printf ("s is at %p\n", s);

  while (1)
  {
    f (s);
    sleep (1);
  }
}

编译

gcc -Wall hi.c -o hi

运行如下

snappyjack@snappyjack frida-morty % ./hi
f() is at 0x10a3b6eb0
s is at 0x10a3b6f88
String: Testing!
String: Testing!
String: Testing!

同样建立stringhook.py

from __future__ import print_function
import frida
import sys

session = frida.attach("hi")
script = session.create_script("""
var st = Memory.allocUtf8String("TESTMEPLZ!");//在堆空间申请一块
var f = new NativeFunction(ptr("%s"), 'int', ['pointer']);//创建了一个方法
    // In NativeFunction param 2 is the return value type,
    // and param 3 is an array of input types
f(st);//执行了这个方法,并将之前TESTMEPLZ!地址传入其中
""" % int(sys.argv[1], 16))
def on_message(message, data):
    print(message)
script.on('message', on_message)
script.load()

运行后结果如下

String: Testing!
String: Testing!
String: TESTMEPLZ!
String: Testing!
String: Testing!
String: Testing!

修改参数

snappyjack@snappyjack ~ % sudo /Users/snappyjack/Library/Python/3.8/bin/frida-trace -i "f" hi
Password:
Instrumenting...
f: Loaded handler at "/Users/snappyjack/__handlers__/hi/f.js"
  onEnter(log, args, state) {
  var buf = Memory.allocUtf8String('mystring');
  this.buf = buf;
  args[0] = buf;
},

结果如下

snappyjack@snappyjack frida-morty % ./hi
f() is at 0x10337beb0
s is at 0x10337bf88
String: Testing!
String: Testing!
String: Testing!
String: Testing!
String: Testing!
String: Testing!
String: Testing!
String: mystring
String: mystring
String: mystring

查看参数

修改js

sudo vim /Users/snappyjack/__handlers__/hi/f.js
onEnter(log, args, state) {
                  console.log("args[0]:",hexdump(args[0]));
                console.log("args[1]:",args[0].readCString());
                console.log("args[2]:",args[0].toInt32());
},

结果如下

args[0]:             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
105636f88  61 61 61 61 62 62 62 62 63 63 63 63 64 64 64 64  aaaabbbbccccdddd
105636f98  00 66 28 29 20 69 73 20 61 74 20 25 70 0a 00 73  .f() is at %p..s
105636fa8  20 69 73 20 61 74 20 25 70 0a 00 00 01 00 00 00   is at %p.......
105636fb8  1c 00 00 00 00 00 00 00 1c 00 00 00 00 00 00 00  ................
105636fc8  1c 00 00 00 02 00 00 00 b0 3e 00 00 34 00 00 00  .........>..4...
105636fd8  34 00 00 00 4a 3f 00 00 00 00 00 00 34 00 00 00  4...J?......4...
105636fe8  03 00 00 00 0c 00 01 00 10 00 01 00 00 00 00 00  ................
105636ff8  00 00 00 01 00 00 00 00 5c 82 60 20 ff 7f 00 00  ........\.` ....
105637008  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
105637018  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
105637028  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
105637038  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
105637048  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
105637058  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
105637068  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
105637078  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
args[1]: aaaabbbbccccdddd
args[2]: 90402696
sockaddr_in的一个案例

Client.c如下

#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

int
main (int argc,
      char * argv[])
{
  int sock_fd, i, n;
  struct sockaddr_in serv_addr;
  unsigned char * b;
  const char * message;
  char recv_buf[1024];

  if (argc != 2)		// 验证参数
  {
    fprintf (stderr, "Usage: %s <ip of server>\n", argv[0]);
    return 1;
  }

  printf ("connect() is at: %p\n", connect);

  if ((sock_fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)	// 验证是否可以建立socket
  {
    perror ("Unable to create socket");
    return 1;
  }

  bzero (&serv_addr, sizeof (serv_addr));

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons (5000);

  if (inet_pton (AF_INET, argv[1], &serv_addr.sin_addr) <= 0)//验证地址
  {
    fprintf (stderr, "Unable to parse IP address\n");
    return 1;
  }
  printf ("\nHere's the serv_addr buffer:\n");
  b = (unsigned char *) &serv_addr;
  for (i = 0; i != sizeof (serv_addr); i++)
    printf ("%s%02x", (i != 0) ? " " : "", b[i]);

  printf ("\n\nPress ENTER key to Continue\n");
  while (getchar () == EOF && ferror (stdin) && errno == EINTR)
    ;

  if (connect (sock_fd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
  {
    perror ("Unable to connect");
    return 1;
  }

  message = "Hello there!";
  if (send (sock_fd, message, strlen (message), 0) < 0)//发送一条
  {
    perror ("Unable to send");
    return 1;
  }

  while (1)
  {
    n = recv (sock_fd, recv_buf, sizeof (recv_buf) - 1, 0);//接受数据并打印数据
    if (n == -1 && errno == EINTR)
      continue;
    else if (n <= 0)
      break;
    recv_buf[n] = 0;

    fputs (recv_buf, stdout);
  }

  if (n < 0)
  {
    perror ("Unable to read");
  }

  return 0;
}

编译如下

gcc -Wall client.c -o client

分别运行如下

snappyjack@snappyjack frida-morty % nc -l 5000
Hello there!
daf
aaa
bbb
ccc
snappyjack@snappyjack frida-morty % ./client 127.0.0.1
connect() is at: 0x7fff205d63dc

Here's the serv_addr buffer:
00 02 13 88 7f 00 00 01 00 00 00 00 00 00 00 00

Press ENTER key to Continue


daf
aaa
bbb
ccc

修改struct.py

from __future__ import print_function
import frida
import sys

session = frida.attach("client")
script = session.create_script("""
// First, let's give ourselves a bit of memory to put our struct in:
send('Allocating memory and writing bytes...');//首先发送一个字符串
var st = Memory.alloc(16); //然后申请一块空间


// Now we need to fill it - this is a bit blunt, but works...
st.writeByteArray([0x02, 0x00, 0x13, 0x89, 0x7F, 0x00, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30]);//将申请的空间填入一些数据


// Module.getExportByName() can find functions without knowing the source
// module, but it's slower, especially over large binaries! YMMV...
// 下面这句话是查找connect函数的地址,然后传入
Interceptor.attach(Module.getExportByName(null, 'connect'), {
    onEnter: function(args) {
        send('Injecting malicious byte array:');// 再发一个字符串
        args[1] = st;	// 修改connect的第一个参数
    }
    //, onLeave: function(retval) {
    //   retval.replace(0); // Use this to manipulate the return value
    //}
});
""")

# Here's some message handling..
# [ It's a little bit more meaningful to read as output :-D
#   Errors get [!] and messages get [i] prefixes. ]
def on_message(message, data):
    if message['type'] == 'error':
        print("[!] " + message['stack'])
    elif message['type'] == 'send':		# 如果种类是send,那么打印这个消息
        print("[i] " + message['payload'])
    else:
        print(message)		# 打印这个消息
script.on('message', on_message)
script.load()
sys.stdin.read()

运行如下命令

./client 127.0.0.1
nc -lp 5001
./struct_mod.py

可以看到端口已经被改成了5001

Messages

首先创建hello.c

#include <stdio.h>
#include <unistd.h>

void
f (int n)
{
  printf ("Number: %d\n", n);
}

int
main (int argc,
      char * argv[])
{
  int i = 0;

  printf ("f() is at %p\n", f);

  while (1)
  {
    f (i++);
    sleep (1);
  }
}

创建一个send.py

from __future__ import print_function
import frida
import sys

session = frida.attach("hello")
script = session.create_script("send(1337);")	# 创建一个script
def on_message(message, data):
    print(message)
script.on('message', on_message)
script.load()
sys.stdin.read()

如果你将send(1337)改为send(a),将报如下错误

{u'type': u'error', u'description': u'ReferenceError: a is not defined', u'lineNumber': 1}
收取消息(异步的方式)

创建pingpong.py

from __future__ import print_function
import frida
import sys

session = frida.attach("hello")
script = session.create_script("""
    recv('poke', function onMessage(pokeMessage) { send('pokeBack'); });
""")
def on_message(message, data):
    print(message)
script.on('message', on_message)		#打印 message
script.load()
script.post({"type": "poke"})		#应该是发了一个数据
sys.stdin.read()
阻塞的方式接受消息
from __future__ import print_function
import frida
import sys

session = frida.attach("hello")
script = session.create_script("""
Interceptor.attach(ptr("%s"), {
    onEnter: function(args) {
        send(args[0].toString());	//发送函数的参数
        var op = recv('input', function(value) {
            args[0] = ptr(value.payload);
        });
        op.wait();	//阻塞等待
    }
});
""" % int(sys.argv[1], 16))
def on_message(message, data):
    print(message)		#打印发送过来的消息
    val = int(message['payload'], 16)	#获取发送过来的消息参数
    script.post({'type': 'input', 'payload': str(val * 2)})	#将消息参数*2,发送给主程序
script.on('message', on_message)
script.load()
sys.stdin.read()

命令

Frida

snappyjack@snappyjack frida-morty % /usr/local/Cellar/python@3.9/3.9.2/Frameworks/Python.framework/Versions/3.9/bin/frida 计算器
     ____
    / _  |   Frida 14.2.13 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://www.frida.re/docs/home/

[Local::计算器]-> Object.keys(ObjC.classes).slice(0, 10)
[
    "NSLeafProxy",
    "Object",
    "__NSGenericDeallocHandler",
    "__NSAtom",
    "_NSZombie_",
    "__NSMessageBuilder",
    "NSVB_AnimationFencingSupport",
    "JSExport",
    "NSProxy",
    "FPFrameworkOverridesIterator"
]

frida-trace

snappyjack@snappyjack frida-morty % /usr/local/Cellar/python@3.9/3.9.2/Frameworks/Python.framework/Versions/3.9/bin/frida-trace --decorate -i "recv*" -i "send*" Firefox
Instrumenting...
...
...
sendUserActivityMsg: Auto-generated handler at "/Users/snappyjack/pycharmProjects/frida-morty/__handlers__/IOKit/sendUserActivityMsg.js"
sendAsyncReleaseMsg: Auto-generated handler at "/Users/snappyjack/pycharmProjects/frida-morty/__handlers__/IOKit/sendAsyncReleaseMsg.js"
Started tracing 24 functions. Press Ctrl+C to stop.
           /* TID 0x993f */
  2243 ms  recvmsg(socket=0x86, message=0x70000d940af0, flags=0x80) [libsystem_kernel.dylib]
  2243 ms  recvmsg(socket=0x86, message=0x70000d940af0, flags=0x80) [libsystem_kernel.dylib]

其中--decorate参数会自动添加类似如下方法

onEnter(log, args, state) {
  log('memcpy()');
},

frida_ssl_logger(无法使用)

snappyjack@snappyjack frida_ssl_logger % python3 ssl_logger.py -verbose 22927

经过尝试

对wechat进行hook

下载class-dump:https://github.com/AloneMonkey/MonkeyDev/blob/master/bin/class-dump

首先生成头文件

class-dump -H /Applications/WeChat.app

结果如下

total 41864
drwxr-xr-x  4924 snappyjack  staff  157568  3  1 16:31 .
drwx------@   18 snappyjack  staff     576  3  1 16:30 ..
-rw-r--r--     1 snappyjack  staff    1267  3  1 16:31 A2BlockInvocation.h
-rw-r--r--     1 snappyjack  staff    1112  3  1 16:31 A2DynamicBKURLConnectionInformalDelegate.h
-rw-r--r--     1 snappyjack  staff     820  3  1 16:31 A2DynamicClassDelegate.h
-rw-r--r--     1 snappyjack  staff    1667  3  1 16:31 A2DynamicDelegate.h
-rw-r--r--     1 snappyjack  staff     618  3  1 16:31 A2DynamicNSCacheDelegate.h
-rw-r--r--     1 snappyjack  staff    1446  3  1 16:31 A2DynamicNSURLConnectionDelegate.h
-rw-r--r--     1 snappyjack  staff    1739  3  1 16:31 ABTestItem.h
-rw-r--r--     1 snappyjack  staff     432  3  1 16:31 ABTestListWrap.h
-rw-r--r--     1 snappyjack  staff     729  3  1 16:31 AFCompoundResponseSerializer.h
-rw-r--r--     1 snappyjack  staff    1842  3  1 16:31 AFHTTPBodyPart.h
-rw-r--r--     1 snappyjack  staff    3858  3  1 16:31 AFHTTPRequestSerializer.h
-rw-r--r--     1 snappyjack  staff    1389  3  1 16:31 AFHTTPResponseSerializer.h

缩小查找范围

snappyjack@snappyjack wechathead % ls -al |grep Message|grep Service
-rw-r--r--     1 snappyjack  staff    5221  3  1 16:31 FTSFileMessageService.h
-rw-r--r--     1 snappyjack  staff     382  3  1 16:31 IMessageServiceAppExt-Protocol.h
-rw-r--r--     1 snappyjack  staff     980  3  1 16:31 IMessageServiceFileExt-Protocol.h
-rw-r--r--     1 snappyjack  staff     381  3  1 16:31 IMessageServiceFileReTransferExt-Protocol.h
-rw-r--r--     1 snappyjack  staff     755  3  1 16:31 IMessageServiceImageExt-Protocol.h
-rw-r--r--     1 snappyjack  staff     780  3  1 16:31 IMessageServiceVideoExt-Protocol.h
-rw-r--r--     1 snappyjack  staff     407  3  1 16:31 IMessageServiceVideoReTransferExt-Protocol.h
-rw-r--r--     1 snappyjack  staff    3144  3  1 16:31 MMFTSMessageService.h
-rw-r--r--     1 snappyjack  staff   20481  3  1 16:31 MessageService.h

查看MessageService.h

- (id)SendLocationMsgFromUser:(id)arg1 toUser:(id)arg2 withLatitude:(double)arg3 longitude:(double)arg4 poiName:(id)arg5 label:(id)arg6;
- (id)SendNamecardMsgFromUser:(id)arg1 toUser:(id)arg2 containingContact:(id)arg3;
- (id)SendStickerStoreEmoticonMsgFromUsr:(id)arg1 toUsrName:(id)arg2 md5:(id)arg3 productID:(id)arg4;
- (id)SendEmoticonMsgFromUsr:(id)arg1 toUsrName:(id)arg2 md5:(id)arg3 emoticonType:(unsigned int)arg4;
- (id)SendImgMessage:(id)arg1 toUsrName:(id)arg2 thumbImgData:(id)arg3 midImgData:(id)arg4 imgData:(id)arg5 imgInfo:(id)arg6;
- (id)SendTextMessage:(id)arg1 toUsrName:(id)arg2 msgText:(id)arg3 atUserList:(id)arg4;
- (id)SendAppMusicMessageFromUser:(id)arg1 toUsrName:(id)arg2 withTitle:(id)arg3 url:(id)arg4 description:(id)arg5 thumbnailData:(id)arg6;
- (id)SendAppURLMessageFromUser:(id)arg1 toUsrName:(id)arg2 withTitle:(id)arg3 url:(id)arg4 description:(id)arg5 thumbnailData:(id)arg6;
- (id)SendAppURLMessageFromUser:(id)arg1 toUsrName:(id)arg2 withTitle:(id)arg3 url:(id)arg4 description:(id)arg5 thumbUrl:(id)arg6 sourceUserName:(id)arg7 sourceDisp

尝试hook这些方法

sudo /Users/snappyjack/Library/Python/3.8/bin/frida-trace -m "-[MessageService Send*]" 微信

自动生成的js脚本如下

/*
 * Auto-generated by Frida. Please modify to match the signature of -[MessageService SendTextMessageWithString:toUser:].
 * This stub is currently auto-generated from manpages when available.
 *
 * For full API reference, see: https://frida.re/docs/javascript-api/
 */

{
  /**
   * Called synchronously when about to call -[MessageService SendTextMessageWithString:toUser:].
   *
   * @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(log, args, state) {
    log(`-[MessageService SendTextMessageWithString:${args[2]} toUser:${args[3]}]`);
  },

  /**
   * Called synchronously when about to return from -[MessageService SendTextMessageWithString:toUser:].
   *
   * 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(log, retval, state) {
  }
}

尝试发送几条数据后如下

Started tracing 18 functions. Press Ctrl+C to stop.
           /* TID 0x307 */
115543 ms  -[MessageService SendTextMessage:0x600001ff5560 toUsrName:0x9c2e0e36855403e1 msgText:0x9e0f1e68f7157201 atUserList:0x60000015f390]
134465 ms  -[MessageService SendTextMessage:0x600001ff5560 toUsrName:0x9c2e0e36855403e1 msgText:0x600000214450 atUserList:0x6000002175a0]

修改onEnter信息如下

sudo vim /Users/snappyjack/__handlers__/MessageService/SendTextMessage_toUsrName_msgTex_34aa5a1f.js
  onEnter(log, args, state) {
    console.log(`-[我的消息测试 SendTextMessage:${args[2]} toUsrName:${args[3]} msgText:${args[4]} atUserList:${args[5]}]`);
    console.log("arg[1] -> " + new ObjC.Object(args[2]))
    console.log("arg[2] -> " + new ObjC.Object(args[3]))
    console.log("arg[3] -> " + new ObjC.Object(args[4]))
    console.log("arg[4] -> " + new ObjC.Object(args[5]))
},

运行如下

snappyjack@snappyjack ~ % sudo /Users/snappyjack/Library/Python/3.8/bin/frida-trace -m "-[MessageService SendTextMessage*]" 微信

结果如下

  3541 ms  -[MessageService SendTextMessage:0x600001c98f60 toUsrName:0xdc73374b7235993 msgText:0xfe6235eb6366d13 atUserList:0x600001e4a370]
-[我的消息测试 SendTextMessage:0x600001c98f60 toUsrName:0xdc73374b7235993 msgText:0xfe6235e85346f03 atUserList:0x60000005d680]
arg[1] -> wxid_6984249843912
arg[2] -> filehelper
arg[3] -> 333
arg[4] ->

修改发送的信息

  onEnter(log, args, state) {
    //log(`-[MessageService SendTextMessage:${args[2]} toUsrName:${args[3]} msgText:${args[4]} atUserList:${args[5]}]`);
    //console.log(`-[我的消息测试 SendTextMessage:${args[2]} toUsrName:${args[3]} msgText:${args[4]} atUserList:${args[5]}]`);
    console.log("arg[1] -> " + new ObjC.Object(args[2]));
    console.log("arg[2] -> " + new ObjC.Object(args[3]));
    console.log("arg[3] -> " + new ObjC.Object(args[4]));
    args[4] = ObjC.classes.NSString.stringWithString_("MacOS微信分析")
  },

主动调用信息,将一下信息保存为wechattest.js

console.log("init success");
function SendTextMessage(wxid, msg) {
    var message = ObjC.chooseSync(ObjC.classes.MessageService)[0]
    var username = ObjC.classes.CUtility.GetCurrentUserName();
    console.log(username)
    console.log("Type of arg[0] -> " + message)
    var toUsrName = ObjC.classes.NSString.stringWithString_(wxid);
    var msgText = ObjC.classes.NSString.stringWithString_(msg);
    message["- SendTextMessage:toUsrName:msgText:atUserList:"](username, toUsrName, msgText, null);
}
SendTextMessage("filehelper","主动调用发送信息!")

运行/Users/snappyjack/Library/Python/3.8/bin/frida 微信 --debug --runtime=v8 --no-pause -l wechattest.js,此时可以主动的发送消息

监听接收消息

/Users/snappyjack/Library/Python/3.8/bin/frida-trace -m "-[MessageService notifyAddMsgOnMainThread*]" 微信

直接修改js代码

var MessageData = new ObjC.Object(args[3]).$ivars;
console.log("fromUsrName -> " + MessageData.fromUsrName)
console.log("toUsrName -> " + MessageData.toUsrName)
console.log("msgContent -> " + MessageData.msgContent)

结果如下

Instrumenting...
-[MessageService notifyAddMsgOnMainThread:msgData:]: Loaded handler at "/Users/snappyjack/pycharmProjects/frida-morty/__handlers__/MessageService/notifyAddMsgOnMainThread_msgData_.js"
Started tracing 1 function. Press Ctrl+C to stop.
fromUsrName -> xxxx
toUsrName -> wxxxx
msgContent -> jxlxxxx7:
我记忆出现了混乱
           /* TID 0x2c7f07 */
 10044 ms  -[MessageService notifyAddMsgOnMainThread:0x600002b925b0 msgData:0x7fa557609970]
fromUsrName -> 19xxxxm
toUsrName -> wxixxxx12
msgContent -> mxxxxxi:
外国明星名字太难记了

参考:https://bbs.pediy.com/thread-266041.htm