/** * system_control.js - Frida系统控制扩展 * 功能:截图、UI导航、页面检测、输入模拟 * 通过Frida直接调用Android内部API,不依赖ADB */ 'use strict'; rpc.exports = { // ==================== 截图 ==================== takeScreenshot: function (params) { /** * 通过Android Shell命令截图并返回base64 * 使用Runtime.exec执行screencap(需要Root或同进程权限) */ try { return Java.performNow(function () { var savePath = (params && params.path) || '/sdcard/frida_screenshot.png'; var Runtime = Java.use('java.lang.Runtime'); var runtime = Runtime.getRuntime(); // 方案1: 直接用screencap命令 var process = runtime.exec(['sh', '-c', 'screencap -p ' + savePath]); process.waitFor(); // 读取文件并转base64 var File = Java.use('java.io.File'); var file = File.$new(savePath); if (!file.exists()) { return { success: false, error: '截图文件不存在' }; } var fileSize = file.length(); var FileInputStream = Java.use('java.io.FileInputStream'); var fis = FileInputStream.$new(file); var bytes = Java.array('byte', new Array(parseInt(fileSize)).fill(0)); fis.read(bytes); fis.close(); var Base64 = Java.use('android.util.Base64'); var b64 = Base64.encodeToString(bytes, 2); // NO_WRAP return { success: true, path: savePath, size: parseInt(fileSize), base64_length: b64.length, base64: b64.substring(0, 200) + '...(truncated)', full_base64: b64, }; }); } catch (e) { return { success: false, error: String(e) }; } }, takeScreenshotToFile: function (params) { /** * 截图保存到指定路径(不返回base64,避免传输大数据) */ try { return Java.performNow(function () { var savePath = (params && params.path) || '/sdcard/frida_sc_' + Date.now() + '.png'; var Runtime = Java.use('java.lang.Runtime'); var runtime = Runtime.getRuntime(); var process = runtime.exec(['sh', '-c', 'screencap -p ' + savePath]); process.waitFor(); var File = Java.use('java.io.File'); var file = File.$new(savePath); if (file.exists()) { return { success: true, path: savePath, size: parseInt(file.length()) }; } return { success: false, error: '截图失败' }; }); } catch (e) { return { success: false, error: String(e) }; } }, // ==================== 页面检测 ==================== getCurrentActivity: function () { /** * 获取当前前台Activity名称 */ try { return Java.performNow(function () { var ActivityThread = Java.use('android.app.ActivityThread'); var currentApp = ActivityThread.currentApplication(); var activities = []; // 遍历所有Activity Java.choose('android.app.Activity', { onMatch: function (activity) { if (!activity.isFinishing() && !activity.isDestroyed()) { activities.push({ class: activity.getClass().getName(), title: activity.getTitle() ? activity.getTitle().toString() : '', visible: activity.hasWindowFocus(), }); } }, onComplete: function () {}, }); return { success: true, activities: activities, foreground: activities.length > 0 ? activities[activities.length - 1].class : 'unknown', }; }); } catch (e) { return { success: false, error: String(e) }; } }, // ==================== UI导航 ==================== navigateToChat: function (params) { /** * 导航到指定聊天窗口 * 通过微信内部Intent跳转 */ try { return Java.performNow(function () { var wxid = (params && params.wxid) || 'filehelper'; var ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext(); var Intent = Java.use('android.content.Intent'); var Uri = Java.use('android.net.Uri'); // 微信内部跳转到聊天页面 var intent = Intent.$new(); intent.setClassName('com.tencent.mm', 'com.tencent.mm.ui.chatting.ChattingUI'); intent.putExtra('Chat_User', wxid); intent.addFlags(0x10000000); // FLAG_ACTIVITY_NEW_TASK ctx.startActivity(intent); return { success: true, navigated_to: 'ChattingUI', wxid: wxid }; }); } catch (e) { return { success: false, error: String(e) }; } }, navigateToContacts: function () { /** * 导航到通讯录页面 */ try { return Java.performNow(function () { var ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext(); var Intent = Java.use('android.content.Intent'); var intent = Intent.$new(); intent.setClassName('com.tencent.mm', 'com.tencent.mm.ui.LauncherUI'); intent.putExtra('LauncherUI.From.Shortcut.Msg', true); intent.addFlags(0x10000000); ctx.startActivity(intent); return { success: true, navigated_to: 'Contacts' }; }); } catch (e) { return { success: false, error: String(e) }; } }, navigateToMe: function () { /** * 导航到"我"页面 */ try { return Java.performNow(function () { var ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext(); var Intent = Java.use('android.content.Intent'); var intent = Intent.$new(); intent.setClassName('com.tencent.mm', 'com.tencent.mm.ui.LauncherUI'); intent.addFlags(0x10000000); ctx.startActivity(intent); return { success: true, navigated_to: 'Me' }; }); } catch (e) { return { success: false, error: String(e) }; } }, navigateToMoments: function () { /** * 导航到朋友圈 */ try { return Java.performNow(function () { var ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext(); var Intent = Java.use('android.content.Intent'); var intent = Intent.$new(); intent.setClassName('com.tencent.mm', 'com.tencent.mm.plugin.sns.ui.SnsTimeLineUI'); intent.addFlags(0x10000000); ctx.startActivity(intent); return { success: true, navigated_to: 'Moments' }; }); } catch (e) { return { success: false, error: String(e) }; } }, // ==================== 输入模拟 ==================== simulateTap: function (params) { /** * 模拟点击(通过shell input tap) */ try { return Java.performNow(function () { var x = (params && params.x) || 0; var y = (params && params.y) || 0; var Runtime = Java.use('java.lang.Runtime'); var runtime = Runtime.getRuntime(); var process = runtime.exec(['sh', '-c', 'input tap ' + x + ' ' + y]); process.waitFor(); return { success: true, tapped: { x: x, y: y } }; }); } catch (e) { return { success: false, error: String(e) }; } }, simulateInput: function (params) { /** * 模拟文本输入 */ try { return Java.performNow(function () { var text = (params && params.text) || ''; var Runtime = Java.use('java.lang.Runtime'); var runtime = Runtime.getRuntime(); // 需要对特殊字符转义 var escaped = text.replace(/ /g, '%s').replace(/'/g, "\\'"); var process = runtime.exec(['sh', '-c', "input text '" + escaped + "'"]); process.waitFor(); return { success: true, input: text }; }); } catch (e) { return { success: false, error: String(e) }; } }, simulateKeyEvent: function (params) { /** * 模拟按键事件(返回键=4, Home=3, 回车=66) */ try { return Java.performNow(function () { var keycode = (params && params.keycode) || 4; var Runtime = Java.use('java.lang.Runtime'); var runtime = Runtime.getRuntime(); var process = runtime.exec(['sh', '-c', 'input keyevent ' + keycode]); process.waitFor(); return { success: true, keycode: keycode }; }); } catch (e) { return { success: false, error: String(e) }; } }, // ==================== 文件操作 ==================== readFileBase64: function (params) { /** * 读取手机上的文件并返回base64 */ try { return Java.performNow(function () { var filePath = (params && params.path) || ''; if (!filePath) return { success: false, error: '缺少path参数' }; var File = Java.use('java.io.File'); var file = File.$new(filePath); if (!file.exists()) return { success: false, error: '文件不存在: ' + filePath }; var fileSize = file.length(); if (fileSize > 5 * 1024 * 1024) { return { success: false, error: '文件太大(>5MB): ' + fileSize }; } var FileInputStream = Java.use('java.io.FileInputStream'); var fis = FileInputStream.$new(file); var bytes = Java.array('byte', new Array(parseInt(fileSize)).fill(0)); fis.read(bytes); fis.close(); var Base64 = Java.use('android.util.Base64'); var b64 = Base64.encodeToString(bytes, 2); return { success: true, path: filePath, size: parseInt(fileSize), base64: b64 }; }); } catch (e) { return { success: false, error: String(e) }; } }, listFiles: function (params) { /** * 列出目录下的文件 */ try { return Java.performNow(function () { var dirPath = (params && params.path) || '/sdcard/'; var File = Java.use('java.io.File'); var dir = File.$new(dirPath); if (!dir.exists() || !dir.isDirectory()) { return { success: false, error: '目录不存在: ' + dirPath }; } var files = dir.listFiles(); var result = []; var len = files ? files.length : 0; for (var i = 0; i < Math.min(len, 50); i++) { result.push({ name: files[i].getName(), is_dir: files[i].isDirectory(), size: files[i].isFile() ? parseInt(files[i].length()) : 0, }); } return { success: true, path: dirPath, count: len, files: result }; }); } catch (e) { return { success: false, error: String(e) }; } }, // ==================== 连接状态 ==================== getConnectionStatus: function () { return { success: true, mode: 'frida_wireless', transport: 'tcp', pid: Process.id, arch: Process.arch, timestamp: Date.now(), }; }, };