Frida相关脚本代码样例(Windows下经过测试)

一、追踪malloc以及free的调用地址(不含调用栈)

import sys
import frida

def on_message(message, data):
    if message['type'] == 'send':
        print(message['payload'])

pid = int(input("请输入目标进程的PID: "))

session = frida.attach(pid)

print("attach suscess")

script = session.create_script("""
Interceptor.attach(Module.findExportByName(null, "malloc"), {
  onEnter: function(args) {
    send("malloc called with: " + args[0]);
  }  
});

Interceptor.attach(Module.findExportByName(null, "free"), {
  onEnter: function(args) {
    send("free called with: " + args[0]); 
  }
});
""")

script.on('message', on_message)
script.load()
print("js load failed")

sys.stdin.read()
session.detach()

二、追踪malloc以及free的函数调用栈

import sys
import frida

def on_message(message, data):
    if message['type'] == 'send':
        print(message['payload'])

pid = int(input("请输入目标进程的PID: "))

session = frida.attach(pid)

print("attach success")

script = session.create_script("""
Interceptor.attach(Module.findExportByName(null, "malloc"), {
  onEnter: function(args) {
    send("malloc called with: " + args[0]);
    send("Call stack: " + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\\n"));
  }  
});

Interceptor.attach(Module.findExportByName(null, "free"), {
  onEnter: function(args) {
    send("free called with: " + args[0]);
    send("Call stack: " + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\\n"));
  }
});
""")

script.on('message', on_message)
script.load()
print("js load success")

sys.stdin.read()
session.detach()

三、追踪malloc以及free调用栈(输出到文件中)

import sys
import frida

pid = int(input("请输入目标进程的PID: "))
session = frida.attach(pid)

print("attach success")

# 打开文件并将标准输出重定向到该文件
f_output = open('output.txt', 'w')
f_stdout = sys.stdout
sys.stdout = f_output

script = session.create_script("""
Interceptor.attach(Module.findExportByName(null, "malloc"), {
  onEnter: function(args) {
    send("malloc called with: " + args[0]);
    send("Call stack: " + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\\n"));
  }  
});

Interceptor.attach(Module.findExportByName(null, "free"), {
  onEnter: function(args) {
    send("free called with: " + args[0]);
    send("Call stack: " + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\\n"));
  }
});
""")

def on_message(message, data):
    if message['type'] == 'send':
        print(message['payload'])

script.on('message', on_message)
script.load()

try:
	sys.stdin.read()
except KeyboardInterrupt:
	f_stdout.write(f" exit\n")
	f_output.flush()
	session.detach()


四、统计调用栈次数与详细信息并输出到文件中:

import sys
import frida

pid = int(input("请输入目标进程的PID: "))
session = frida.attach(pid)

print("attach success")

call_stacks = []

def on_message(message, data):
    if message['type'] == 'send':
        print(message['payload'])
        if "Call stack" in message['payload']:
            call_stacks.append(message['payload'])

script = session.create_script("""
Interceptor.attach(Module.findExportByName(null, "malloc"), {
  onEnter: function(args) {
    send("Call stack: \\n" + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\\n"));
  }  
});

Interceptor.attach(Module.findExportByName(null, "free"), {
  onEnter: function(args) {
    send("Call stack: \\n" + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\\n"));
  }
});
""")

script.on('message', on_message)
script.load()
print("js load success")

try:
    sys.stdin.read()
except KeyboardInterrupt:
    # 打开文件并将标准输出重定向到该文件
    f_output = open('output.txt', 'w')
    f_stdout = sys.stdout
    sys.stdout = f_output
    # 将调用栈信息整理成火焰图格式
    flamegraph_data = {}
    for stack in call_stacks:
        stack_lines = stack.split("\n")
        for line in stack_lines:
            if line.startswith("0x"):
                if line in flamegraph_data:
                    flamegraph_data[line] += 1
                else:
                    flamegraph_data[line] = 1
    # 输出火焰图格式数据
    for addr, count in flamegraph_data.items():
        print(f"次数:{count} 详细信息:{addr}")
    f_stdout.write(" exit\n")
    f_output.flush()
    session.detach()

关于Frida目前研究的总结:
1、在Windows下无论是Release还是Debug都可以分析malloc以及free的调用栈,只不过Debug信息更详细,如果将Release的优化关闭两者信息基本一致。
2、在Windows下符号信息仍需要pdb文件协助,这不同于Linux,好消息是只需要将pdb与测试的PE文件放在同一目录Frida可以自动搜寻到符号信息。

目前时间只够我研究到上面四个情况,第四种已经基本满足需求了,如果后续需要转换为火焰图的话还需要加以改进,但是整体脚本框架无需很大变动了,可以参考内存增长与火焰图这篇文章。

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-30 01:08:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-30 01:08:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-30 01:08:01       82 阅读
  4. Python语言-面向对象

    2024-03-30 01:08:01       91 阅读

热门阅读

  1. 前端通用命名规范和Vue项目命名规范

    2024-03-30 01:08:01       41 阅读
  2. GIT使用小结

    2024-03-30 01:08:01       39 阅读
  3. 面试宝典:PHP中的Yac技术深度分析

    2024-03-30 01:08:01       42 阅读
  4. 什么是FLV

    2024-03-30 01:08:01       39 阅读
  5. 正则表达式

    2024-03-30 01:08:01       36 阅读
  6. 正则匹配/正则表达式

    2024-03-30 01:08:01       53 阅读
  7. Rust引用借用 vs 原始指针

    2024-03-30 01:08:01       37 阅读
  8. 库函数的模拟实现

    2024-03-30 01:08:01       42 阅读
  9. uniapp踩坑细节

    2024-03-30 01:08:01       45 阅读
  10. Element-UI中el-time-picker时间选择器无法选择

    2024-03-30 01:08:01       37 阅读