CModule是frida提供的一种在javascript环境中直接运行C代码的机制
什么时候使用CModule?
需要更高的执行效率
处理复杂的数据结构和内存操作
需要访问Frida内部API进行高级操作
与Stalker结合使用进行指令级追踪
javaScript调用CModule函数
var cm = new CModule(`
void hello(void) {
frida_log("Hello World from CModule");
}
`);
const hello = new NativeFunction(cm.hello, 'void', []);
hello();var cm = new CModule(`
int add(int a, int b) {
return a + b;
}
`);
// 这里就和frida调用navite函数是一样的,我们通过CModule构造了一个native函数然后用frida去调用它
const add = new NativeFunction(cm.add, 'int', ['int', 'int']);
const result = add(1, 2);
console.log(result);CModule调用javaScript函数
var cm = new CModule(`
extern void onMessage(const char * message);
void hello(void) {
onMessage("Hello World from CModule");
}
`, {
onMessage: new NativeCallback(function (messagePtr) {
const message = messagePtr.readUtf8String();
console.log('[*] Message: ', message);
}, 'void', ['pointer'])
});
const hello = new NativeFunction(cm.hello, 'void', []);
hello();extern表明这个函数或者变量是在外部声明的
NativeCallback创建一个c调用js的函数,NativeFunction是创建一个js调用c的函数
CModule与javaScript的数据交换
// 申请4字节的内存
var shared_memory = Memory.alloc(4);
// 往内存中写入值
shared_memory.writeS32(123);
var cm = new CModule(`
#include <stdio.h> // 定义printf
extern volatile int shared_from_js;
void hello(void) {
printf("Value from JS: %d\\n", shared_from_js);
// 修改shared_memory的实际值
shared_from_js = 456;
}
`, {
"shared_from_js": shared_memory
});
const hello = new NativeFunction(cm.hello, 'void', []);
hello();
console.log('New Value: ' + shared_memory.readS32()); // 输出 456CModule Hook示例(拦截open函数并修改文件路径)
// 创建一个 CModule 对象
var cm = new CModule(`
#include <gum/guminterceptor.h>
#include <string.h>
typedef struct _IcState IcState;
struct _IcState { // 类似 js hook native 时的 this 指针,用于传递上下文,可以自己添加想传递的数据
const char *path;
};
static void frida_log (const char * format, ...);
extern void onMessage(const gchar * message); // 从 CModule 中调用 frida js 的例子
// CModule加载的时候执行一次
void init (void)
{
frida_log("init()");
}
// CModule销毁的时候执行一次
void finalize (void)
{
frida_log("finalize()");
}
void
onEnter (GumInvocationContext * ic) // for libc open
{
const char *path;
IcState *state;
gpointer arg0;
const char *redirect_path = NULL;
state = GUM_IC_GET_INVOCATION_DATA (ic, IcState); // 获取上下文
path = gum_invocation_context_get_nth_argument (ic, 0); // 获取第 0 个参数
state->path = path;
// 判断两个字符串是否相等如果想等则返回0
if (strcmp(path, "/proc/self/status") == 0) {
redirect_path = "/data/local/tmp/status.txt";
frida_log("Redirecting: %s -> %s", path, redirect_path);
state->path = redirect_path;
}
// 如果设置了重定向路径,则替换参数
if (redirect_path != NULL) {
// 替换第 1 个参数
gum_invocation_context_replace_nth_argument(ic, 0, (gpointer)redirect_path);
}
frida_log("on_enter() open path=%s", path);
}
void
onLeave (GumInvocationContext * ic) // for libc open
{
gpointer retval;
IcState *state;
retval = gum_invocation_context_get_return_value (ic); // 读取返回值
// gum_invocation_context_replace_return_value: 替换返回值
state = GUM_IC_GET_INVOCATION_DATA (ic, IcState); // 获取上下文
const char *path = state->path;
frida_log("on_leave() retval=%p open path=%s", retval, path);
}
static void
frida_log (const gchar * format,
...)
{
gchar * message;
va_list args;
va_start (args, format);
message = g_strdup_vprintf (format, args);
va_end (args);
onMessage (message); // 调用 frida 的 onMessage 函数
g_free (message);
}
`, {
onMessage: new NativeCallback(function(messagePtr) {
// 提供一个 NativeCallback 函数,用于调用 frida 的 onMessage 函数
const message = messagePtr.readUtf8String();
console.log('[*] message from cmodule: ' + message);
}, 'void', ['pointer'])
});
console.log(JSON.stringify(cm));
var openImpl = Module.findExportByName(null, 'open');
console.log('[*] open: ' + openImpl);
Interceptor.attach(openImpl, cm);CModule Hook示例(Hook open函数并修改返回值)
var cm = new CModule(`
#include <gum/guminterceptor.h>
#include <string.h>
#include <stddef.h>
typedef struct _IcState IcState;
struct _IcState {
const char *path;
int should_block; // 记录文件是否需要阻止
};
static void frida_log(const char *format, ...);
extern void onMessage(const gchar *message);
void init(void) {
frida_log("CModule initialized");
}
void finalize(void) {
frida_log("CModule finalized");
}
void onEnter(GumInvocationContext *ic) {
IcState *state = GUM_IC_GET_INVOCATION_DATA(ic, IcState);
// 初始化状态
state->should_block = 0;
// 获取参数
const char *path = gum_invocation_context_get_nth_argument(ic, 0);
state->path = path;
// 检查是否需要阻止
if (path != NULL && strcmp(path, "/data/user/0/cn.binary.frida/files/test_hack.txt") == 0) {
state->should_block = 1;
frida_log("Will block: %s", path);
}
frida_log("on_enter() open path=%s", path);
}
void onLeave(GumInvocationContext *ic) {
IcState *state = GUM_IC_GET_INVOCATION_DATA(ic, IcState);
gpointer retval = gum_invocation_context_get_return_value(ic);
if (state->should_block) {
// gum_invocation_context_replace_return_value修改返回值
// 这里将返回值改成-1文件将会打开失败
gum_invocation_context_replace_return_value(ic, (gpointer)(gssize)-1);
frida_log("BLOCKED: %s (returned -1)", state->path);
} else {
frida_log("on_enter() open path=%s retval=%p", state->path, retval);
}
}
static void frida_log(const gchar *format, ...) {
gchar *message;
va_list args;
va_start(args, format);
message = g_strdup_vprintf(format, args);
va_end(args);
onMessage(message);
g_free(message);
}
`, {
onMessage: new NativeCallback(function(messagePtr) {
console.log('[CModule]', messagePtr.readUtf8String());
}, 'void', ['pointer'])
});
console.log(JSON.stringify(cm));
var openImpl = Module.findExportByName(null, 'open');
console.log('[*] open: ' + openImpl);
Interceptor.attach(openImpl, cm);frida CModule
http://8.134.212.132:8090/archives/frida-cmodule
评论