第一次提交

This commit is contained in:
2025-02-05 15:02:27 +08:00
commit d06b32a92f
44 changed files with 3219 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
package org.tzd.frida;
import org.tzd.frida.windows.CallbackMessage;
import org.tzd.frida.windows.Frida;
import org.tzd.frida.windows.FridaRunnable;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Main 类用于启动和执行 Frida 注入操作。
*
* <p>此类主要包含一个入口方法 <code>main</code>,用于加载必要的本地库并初始化 Frida 对象。</p>
* <p>它会通过调用 <code>getProcessPid</code> 方法获取指定进程的 PID并将 JavaScript 代码注入到目标进程中。</p>
*
* @author tzdwindows 7
*/
public class Main {
/**
* 程序入口方法。
*
* <p>此方法加载本地 DLL 库并创建一个 <code>Frida</code> 实例。接着通过 <code>run</code> 和 <code>execute</code> 方法执行指定的任务。</p>
* <p>执行期间,会将回调函数添加到 <code>Frida</code> 实例中,接收并打印消息。</p>
*
* @param args 命令行参数
*/
public static void main(String[] args) {
// 加载本地 DLL 文件
System.load("C:\\Users\\Administrator\\source\\repos\\FridaNative\\x64\\Release\\FridaNative.dll");
// 创建 Frida 实例并传入 JavaScript 代码及进程 PID
Frida frida = new Frida("console.log('Hello, Frida!');", getProcessPid("java.exe"));
// 执行 Frida 任务,注入代码并注册回调函数
frida.run(new Runnable() {
@Override
public void run() {
// 在此处添加要执行的代码
}
}).execute(new FridaRunnable() {
@Override
public void run(Frida frida) {
// 注册回调消息,接收到消息时打印
frida.addCallbackMessage(new CallbackMessage() {
@Override
public void onMessage(String message) {
System.out.println(message); // 打印收到的消息
}
});
}
}).start(); // 启动线程
}
/**
* 获取指定进程的 PID。
*
* <p>此方法通过运行 Windows 命令 <code>tasklist</code> 获取系统中所有正在运行的进程,并查找指定进程名。</p>
* <p>一旦找到匹配的进程,它将提取进程的 PID 并返回。</p>
*
* @param processName 要查找的进程名称。
* @return 目标进程的 PID如果未找到则返回 -1。
*/
public static long getProcessPid(String processName) {
long pid = -1;
try {
ProcessBuilder builder = new ProcessBuilder("tasklist");
builder.redirectErrorStream(true);
Process process = builder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
if (line.contains(processName)) {
String[] parts = line.split("\\s+");
pid = Long.parseLong(parts[1]);
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return pid;
}
}

View File

@@ -0,0 +1,12 @@
package org.tzd.frida.windows;
/**
* @author tzdwindows 7
*/
public interface CallbackMessage {
/**
* 回调消息
* @param message 消息
*/
void onMessage(String message);
}

View File

@@ -0,0 +1,126 @@
package org.tzd.frida.windows;
/**
* @author tzdwindows 7
*/
public class Frida {
private final String jsCode;
private FridaThread thread;
boolean isRunning;
long pid;
/**
* 构造一个新的 <code>Frida</code> 实例。
*
* @param jsCode 需要注入的 JavaScript 代码。
* @param pid 目标进程的进程ID。
*
* <p>此构造函数用于初始化一个新的 <code>Frida</code> 对象,指定要注入的 JavaScript 代码及目标进程ID。</p>
*/
public Frida(String jsCode, long pid) {
this.jsCode = jsCode;
this.pid = pid;
isRunning = false;
}
/**
* 启动并返回一个新的线程用于执行JavaScript注入。
*
* @return 返回一个线程管理类 <code>FridaThread</code>,方便对线程进行统一管理。
*
* <p>该方法的工作流程如下:</p>
* <ol>
* <li<code>new FridaThread(() -> { ... })</code>: 创建一个新的线程,该线程执行 JavaScript 注入操作。线程内部会设置 <code>isRunning = true</code> 并调用 <code>Frida0.injection(jsCode, this)</code> 来注入 JavaScript 代码。</li>
* </ol>
*
* <p>示例用法:</p>
* <pre>
* FridaThread thread = frida.run();
* thread.setStart(true)
* thread.start(); // 启动线程
* </pre>
*/
public FridaThread run() {
thread = new FridaThread(() -> {
isRunning = true;
Frida0.injection(jsCode,this);
},this);
return thread;
}
/**
* 启动并返回一个新的线程用于执行JavaScript注入。
*
* @param callback 在循环中的回调函数
* @return 一个线程管理类,方便对线程进行统一管理
*
* <p>该方法的工作流程如下:</p>
* <ol>
* <li><code>run(Runnable... callback)</code>: 首先创建一个新的 <code>FridaThread</code>,并传入一个 <code>Runnable</code> 任务,任务会在新线程中执行。任务内会调用 <code>Frida0.injection(jsCode, this, callback)</code>,注入并执行 JavaScript 代码。</li>
* <li><code>execute(FridaRunnable runnable)</code>: <code>execute</code> 方法允许你定义在 <code>FridaThread</code> 中执行的额外任务。<code>FridaRunnable</code> 接口的 <code>run</code> 方法会被调用,允许你与 <code>Frida</code> 对象交互,添加回调消息或其他操作。</li>
* <li><code>start()</code>: 启动线程,执行上述所有任务。</li>
* </ol>
*
* <p>示例用法:</p>
* <pre>
* frida.run(new Runnable() {
* @Override
* public void run() {
* // 在此处添加需要执行的代码
* }
* }).execute(new FridaRunnable() {
* @Override
* public void run(Frida frida) {
* // 注册回调消息,接收信息
* frida.addCallbackMessage(new CallbackMessage() {
* @Override
* public void onMessage(String message) {
* System.out.println(message); // 打印收到的消息
* }
* });
* }
* }).start(); // 启动线程
* </pre>
*
* <p>在这个示例中,<code>run()</code> 方法首先创建并配置一个新的线程,<code>execute()</code> 方法为线程添加了一个回调函数,接收到消息时会触发该回调函数。最后,调用 <code>start()</code> 启动线程的执行。</p>
* <p>当然你如果非要在FridaThread中直接使用start而不经过execute的话我们会抛出异常 throw new RuntimeException("Basic information is not configured"); </p>
*/
public FridaThread run(Runnable... callback) {
thread = new FridaThread(() -> {
isRunning = true;
Frida0.injection(jsCode, this, callback);
}, this);
return thread;
}
/**
* 将回调消息添加到消息列表中。
*
* @param callbackMessage 要添加的回调消息对象。
*
* <p>此方法会将传入的 <code>callbackMessage</code> 对象添加到 <code>Frida0.CALLBACK_MESSAGE_LIST</code> 中。</p>
*/
public void addCallbackMessage(CallbackMessage callbackMessage) {
Frida0.CALLBACK_MESSAGE_LIST.add(callbackMessage);
}
/**
* 从消息列表中移除指定的回调消息。
*
* @param callbackMessage 要移除的回调消息对象。
*
* <p>此方法会将传入的 <code>callbackMessage</code> 对象从 <code>Frida0.CALLBACK_MESSAGE_LIST</code> 中移除。</p>
*/
public void clearCallbackMessage(CallbackMessage callbackMessage) {
Frida0.CALLBACK_MESSAGE_LIST.remove(callbackMessage);
}
/**
* 清空所有回调消息。
*
* <p>此方法会清空 <code>Frida0.CALLBACK_MESSAGE_LIST</code> 中的所有回调消息。</p>
*/
public void clearCallbackMessage() {
Frida0.CALLBACK_MESSAGE_LIST.clear();
}
}

View File

@@ -0,0 +1,85 @@
package org.tzd.frida.windows;
import java.util.ArrayList;
import java.util.List;
/**
* Frida0 类用于处理 Frida 注入相关的操作和消息传递。
*
* <p>此类包括注入 JavaScript 代码到目标进程、消息的发送与接收处理等功能。</p>
* <p>通过该类,用户可以与 Frida 注入的进程进行交互,并通过回调函数获取日志或错误信息。</p>
*
* @author tzdwindows 7
*/
public class Frida0 {
// 存储回调消息的列表
static final List<CallbackMessage> CALLBACK_MESSAGE_LIST = new ArrayList<>();
/**
* 注入 JavaScript 代码到指定的 Frida 实例,并执行回调任务。
*
* <p>该方法调用本地代码注入 JavaScript并执行传入的回调函数。在 Frida 进程运行期间,回调函数将不断被执行。</p>
* <p>方法会在 Frida 进程完成后释放资源,并设置 Frida 的运行状态为 `false`。</p>
*
* @param jsCode 注入的 JavaScript 代码。
* @param frida 当前的 Frida 实例,包含进程 PID 等信息。
* @param callback 运行中的回调任务列表,多个任务可以同时执行。
*/
static void injection(String jsCode, Frida frida, Runnable... callback) {
// 调用本地方法进行 JavaScript 注入
FridaNative.injection(frida.pid, jsCode);
// 如果有回调任务,循环执行回调
if (callback != null) {
while (FridaNative.isRunning()) {
FridaNative.update();
for (Runnable runnable : callback) {
runnable.run();
}
}
}
// 释放本地资源
FridaNative.release();
frida.isRunning = false;
}
/**
* 发送消息给所有已注册的回调消息对象。
*
* <p>此方法会遍历 <code>CALLBACK_MESSAGE_LIST</code> 列表,并触发每个回调对象的 <code>onMessage</code> 方法。</p>
*
* @param message 需要发送的消息内容。
*/
private static void sendMessage(String message) {
CALLBACK_MESSAGE_LIST.forEach(callbackMessage -> callbackMessage.onMessage(message));
}
/**
* 处理接收到的消息,并根据消息类型做出响应。
*
* <p>根据消息中的 `type` 字段,如果是 `error` 类型,抛出运行时异常;如果是 `log` 类型,打印日志。</p>
* <p>其他类型的消息直接通过回调发送。</p>
*
* @param message 接收到的消息内容。
*/
private static void onMessage(String message) {
// 获取消息类型
String type = FridaNative.getStringMember(message, "type");
// 处理错误类型的消息
if (!type.isEmpty()) {
if ("error".equals(type)) {
sendMessage(FridaNative.getStringMember(message, "payload"));
throw new RuntimeException(FridaNative.getStringMember(message, "description"));
} else if ("log".equals(type)) {
sendMessage(FridaNative.getStringMember(message, "payload"));
}
return;
}
// 处理普通消息
sendMessage(message);
}
}

View File

@@ -0,0 +1,71 @@
package org.tzd.frida.windows;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;
/**
* FridaJsInjector 类负责通过 Frida 向目标进程注入 JavaScript 代码。
* <p>此类提供了一个方法,允许通过读取指定的 JS 文件,并将其中的代码注入到指定的进程中。</p>
* <p>如果注入过程中发生错误,类会抛出相应的异常。</p>
*
* @author tzdwindows 7
* @since 1.0
* @version 1.0
*/
public class FridaJsInjector {
private Frida frida;
/**
* 构造方法,通过传入 PID 和 JavaScript 文件路径来初始化 Frida 实例。
*
* @param pid 目标进程的 PID。
* @param jsFilePath JavaScript 文件的路径。
*/
public FridaJsInjector(long pid, String jsFilePath) {
String jsCode = readJsFile(jsFilePath);
this.frida = new Frida(jsCode, pid);
}
/**
* 读取指定路径的 JavaScript 文件内容。
*
* @param jsFilePath JavaScript 文件路径。
* @return 文件内容的字符串表示。
*/
private String readJsFile(String jsFilePath) {
String jsCode = null;
try {
jsCode = new String(Files.readAllBytes(Paths.get(jsFilePath)));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Failed to read the JavaScript file: " + jsFilePath, e);
}
return jsCode;
}
/**
* 向目标进程注入 JavaScript 代码。
* <p>该方法会使用 Frida 将 JavaScript 代码注入到指定的目标进程,并执行相关操作。</p>
* <p>方法会启动一个线程,并在该线程中执行注入操作。可以通过提供回调函数来接收注入过程中的消息。</p>
* <p>此方法会检查 Frida 实例是否已经初始化,并在初始化完成后执行 JavaScript 注入。</p>
*
* @param callback 传入的回调消息,当接收到来自 Frida 的消息时,该回调会被触发。
* @param callbackMessage 可选的额外回调函数,用于处理 JavaScript 注入的过程中的操作。
* @return 返回一个线程对象,用于统一管理和控制线程执行。
*
* @throws RuntimeException 如果 Frida 实例未初始化,则抛出运行时异常。
*/
public Thread injectJs(CallbackMessage callback, Runnable... callbackMessage) {
if (frida == null) {
throw new RuntimeException("Frida instance is not initialized.");
}
return frida.run(callbackMessage).execute(new FridaRunnable() {
@Override
public void run(Frida frida) {
frida.addCallbackMessage(callback);
}
});
}
}

View File

@@ -0,0 +1,54 @@
package org.tzd.frida.windows;
/**
* FridaNative 类封装了与本地 Frida 库的交互方法。
* <p>该类提供了几个静态本地方法,用于将 JavaScript 代码注入到目标进程并进行管理。</p>
* <p>所有方法都通过 JNI 调用本地代码实现与 Frida 库的交互。</p>
*/
public class FridaNative {
/**
* 使用 Frida 将 JavaScript 代码注入到指定进程。
*
* <p>该方法通过 JNI 调用本地 Frida 函数,将 JavaScript 代码注入到指定的进程中。</p>
*
* @param pid 目标进程的 PID通常是目标程序的进程 ID例如QQ 进程)。
* @param jsCode 要注入的 JavaScript 代码字符串。
* @return 返回注入是否成功,成功返回 `true`,失败返回 `false`。
*/
native static boolean injection(long pid, String jsCode);
/**
* 更新 Frida 的状态,保持与注入进程的交互。
* <p>此方法调用本地 Frida 函数以保持与注入的进程进行通信和交互。</p>
*
* @return 返回更新是否成功,成功返回 `true`,失败返回 `false`。
*/
native static boolean update();
/**
* 判断 Frida 是否正在运行。
* <p>此方法用于检查 Frida 是否正在执行并保持与目标进程的交互。</p>
*
* @return 如果 Frida 正在运行,返回 `true`,否则返回 `false`。
*/
native static boolean isRunning();
/**
* 释放 Frida 的资源。
* <p>该方法调用本地函数释放与 Frida 进程的所有资源。</p>
*
* @return 如果资源释放成功,返回 `true`,否则返回 `false`。
*/
native static boolean release();
/**
* 从消息中提取指定的字符串成员。
* <p>该方法通过 JNI 调用本地函数获取消息中的指定成员,并返回其字符串值。</p>
*
* @param message 输入的消息字符串,通常是 Frida 的 JSON 格式的响应消息。
* @param member 要获取的成员名称。
* @return 返回指定成员的字符串值。
*/
native static String getStringMember(String message, String member);
}

View File

@@ -0,0 +1,8 @@
package org.tzd.frida.windows;
/**
* @author tzdwindows 7
*/
public interface FridaRunnable {
void run(Frida frida);
}

View File

@@ -0,0 +1,62 @@
package org.tzd.frida.windows;
/**
* FridaThread 类继承自 {@link Thread},用于封装与 Frida 相关的线程操作。
* <p>此类用于创建并启动线程,以便在新的线程中执行与 Frida 相关的任务。</p>
* <p>它允许在启动线程之前执行额外的操作,例如调用 `FridaRunnable` 的 `run` 方法来配置与 Frida 的交互。</p>
*
* @author tzdwindows 7
*/
public class FridaThread extends Thread {
private boolean isStart = false; // 用于标记线程是否已配置正确
private final Frida frida; // 与线程相关联的 Frida 实例
/**
* 构造一个新的 FridaThread 实例。
* <p>该构造函数接受一个任务和一个 Frida 实例,创建一个线程并传入任务。</p>
*
* @param task 线程执行的任务,类型为 {@link Runnable}。
* @param frida 与该线程关联的 {@link Frida} 实例。
*/
public FridaThread(Runnable task, Frida frida) {
super(task); // 调用父类构造器
this.frida = frida;
setName("Frida Thread"); // 设置线程名称
}
/**
* 执行与 Frida 相关的额外任务。
* <p>此方法会执行传入的 {@link FridaRunnable} 任务,并传入当前的 Frida 实例。</p>
*
* @param runnable 执行任务的 {@link FridaRunnable} 实例。
* @return 返回当前的 {@link FridaThread} 实例,以便链式调用。
*/
public FridaThread execute(FridaRunnable runnable) {
runnable.run(frida); // 执行任务
isStart = true; // 标记线程配置完成
return this; // 返回当前线程实例
}
/**
* 设置线程是否已经开始执行。
* <p>此方法可用于手动控制线程的启动配置。</p>
*
* @param start 设置线程是否已配置完成。
*/
public void setStart(boolean start) {
isStart = start;
}
/**
* 启动线程。
* <p>重写了 `Thread` 类的 `start()` 方法,首先检查线程是否已正确配置。</p>
* <p>如果未正确配置,则抛出一个运行时异常,避免线程未准备好就启动。</p>
*/
@Override
public void start() {
if (!isStart) {
throw new RuntimeException("Basic information is not configured");
}
super.start(); // 调用父类的 `start()` 方法启动线程
}
}

View File

@@ -0,0 +1,31 @@
package org.tzd.frida.windows;
/**
* 当 JavaScript 代码执行或语法出错时抛出此异常。
* <p>此异常用于处理与 JavaScript 代码相关的错误,例如代码执行失败或语法错误。</p>
* <p>通过该异常,程序能够捕获并处理 JavaScript 代码运行过程中可能出现的问题。</p>
*
* @author tzdwindows 7
* @since 1.0
* @version 1.0
*/
public class JsCodeError extends Exception {
/**
* 默认构造方法。
* <p>调用父类 {@link Exception} 的默认构造方法。</p>
*/
public JsCodeError() {
super();
}
/**
* 带有错误信息的构造方法。
* <p>使用传入的错误信息来初始化异常。</p>
*
* @param message 错误信息,用于描述异常的具体内容。
*/
public JsCodeError(String message) {
super(message); // 调用父类构造器,传入错误信息
}
}