吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2977|回复: 4
收起左侧

[求助] 求指导小程序云函数逆向

[复制链接]
毛_毛熊 发表于 2025-5-21 11:18

求论坛大佬指导小程序云函数逆向思路
已尝试步骤和思路

  • fiddler抓包,发现有些包抓不到
  • github搜索到相关工具对小程序反编译,发现代码中有 wx.cloud.callFunction wx.request 相关调用
  • github搜索到相关工具对特定版本小程序开启控制台后,调试js发现数据是通过wx.request调用得来

目前碰到几个问题

  • 小程序自动升级,开启控制台调试后关闭再打开就不能开启了。只能重新安装特定版本
  • 尝试使用frida进行hook,没有使用frida经验,使用ai写的frida脚本测试发现脚本正常运行,但是获取不到wx.cloud.callFunction wx.request 相关信息
# frida_loader.py
import frida
import sys
import json

# ----- 配置 -----
TARGET_PROCESS_NAME_OR_PID = "WeChatAppEx.exe"

HOOK_SCRIPT_FILE = "hook_wx_cloud.js"
# ----- 配置结束 -----

def on_message(message, data):
    """
    处理从 Frida JavaScript 脚本发送回来的消息
    """
    if message['type'] == 'send':
        payload = message['payload']
        print(f"
  • Message from JS: {payload.get('type', 'unknown')}")         if payload.get('type') == 'status':             print(f"    Status: {payload.get('message')}")         elif payload.get('type') == 'request':             print(f"    Function Name: {payload.get('functionName')}")             print(f"    Timestamp: {payload.get('timestamp')}")             print(f"    Request Data:\n{json.dumps(payload.get('requestData'), indent=4, ensure_ascii=False)}")             print("-" * 50)         elif payload.get('type') == 'response':             print(f"    Function Name: {payload.get('functionName')}")             print(f"    Timestamp: {payload.get('timestamp')}")             if payload.get('isError'):                 print(f"    Error Response Data:\n{json.dumps(payload.get('responseData'), indent=4, ensure_ascii=False)}")             else:                 print(f"    Success Response Data:\n{json.dumps(payload.get('responseData'), indent=4, ensure_ascii=False)}")             print("=" * 50)     elif message['type'] == 'error':         print(f"[!] JavaScript Error: {message.get('description')}")         print(f"    Stack: {message.get('stack')}")     else:         print(f"
  • Unknown message: {message}") def find_target_process(device, name_or_pid):     """     查找目标进程,如果指定的是名字,可能会有多个实例,需要用户选择。     """     try:         # 如果是PID         if isinstance(name_or_pid, int) or name_or_pid.isdigit():             print(f"
  • Trying to attach to PID: {name_or_pid}")             return device.attach(int(name_or_pid))         # 如果是进程名         else:             print(f"
  • Searching for process name: {name_or_pid}")             processes = [p for p in device.enumerate_processes() if p.name.lower() == name_or_pid.lower()]             if not processes:                 print(f"[!] No process found with name: {name_or_pid}")                 return None             if len(processes) == 1:                 print(f"
  • Found one process: {processes[0].name} (PID: {processes[0].pid})")                 return device.attach(processes[0].pid)             else:                 print(f"
  • Found multiple processes with name '{name_or_pid}':")                 for i, p in enumerate(processes):                     # 尝试获取命令行参数或窗口标题来帮助区分 (这部分比较依赖系统和Frida能力)                     try:                         print(f"  [{i}] PID: {p.pid}, Name: {p.name}")                     except Exception:                         print(f"  [{i}] PID: {p.pid}, Name: {p.name}")                 while True:                     try:                         choice = input("  Please select the process index to attach to: ")                         selected_process = processes[int(choice)]                         print(f"
  • Attaching to selected process: {selected_process.name} (PID: {selected_process.pid})")                         return device.attach(selected_process.pid)                     except (ValueError, IndexError):                         print("  Invalid input. Please enter a valid index number.")                     except KeyboardInterrupt:                         print("\n
  • Attachment cancelled by user.")                         return None     except frida.ProcessNotFoundError:         print(f"[!] Process {name_or_pid} not found.")         return None     except Exception as e:         print(f"[!] Error finding/attaching to process: {e}")         return None def main():     session = None     try:         device = frida.get_local_device()  # PC端使用 local_device         print(f"
  • Attached to local device (PC).")         # 附加到目标进程 (关键步骤)         print(f"
  • Please open the target WeChat Mini Program now if it's not already open.")         print(f"
  • The script will try to attach to '{TARGET_PROCESS_NAME_OR_PID}'.")         session = find_target_process(device, TARGET_PROCESS_NAME_OR_PID)         if not session:             print("[!] Failed to attach to any process. Exiting.")             return         print("
  • Attached successfully to target process!")         with open(HOOK_SCRIPT_FILE, "r", encoding="utf-8") as f:             js_code = f.read()         script = session.create_script(js_code)         script.on('message', on_message)  # 设置消息回调函数         print("
  • Loading script...")         script.load()         print("
  • Script loaded. Waiting for cloud function calls... (Press Ctrl+C to detach)")         # 如果JS脚本中有RPC导出,可以在这里调用         # script.exports.init() # 假设JS中有 rpc.exports.init         sys.stdin.read()  # 阻塞,直到用户按任意键或Ctrl+C     except frida.ProcessNotFoundError:         print(f"[!] Process {TARGET_PROCESS_NAME_OR_PID} not found.")         print(f"    Ensure the WeChat PC application and the target Mini Program are running.")         print(f"    Use 'frida-ps -Ua' or Task Manager to find the PID and update TARGET_PROCESS_NAME_OR_PID.")         sys.exit(1)     except frida.TransportError as e:         print(f"[!] Frida transport error: {e}.")     except KeyboardInterrupt:         print("
  • Detaching and exiting...")     except Exception as e:         print(f"[!] Could not attach to target. Error: {e}")         sys.exit(1)     finally:         if session:             print("
  • Detaching from process...")             session.detach()             print("
  • Detached.") if __name__ == '__main__':     main()
  • // hook_wx_cloud.js
    
    // 尝试多次,直到 wx 对象和云函数API可用
    function tryHookCloudFunction() {
        if (typeof wx !== 'undefined' && wx.cloud && typeof wx.cloud.callFunction === 'function') {
            console.log('[Frida] Found wx.cloud.callFunction. Attempting to hook...');
    
            const originalCallFunction = wx.cloud.callFunction;
    
            wx.cloud.callFunction = function(options) {
                console.log('[Frida] wx.cloud.callFunction CALLED');
                console.log('[Frida] Request Name:', options.name);
                console.log('[Frida] Request Data:', JSON.stringify(options.data, null, 2));
    
                // 发送请求数据到 Python 控制端
                send({
                    type: 'request',
                    functionName: options.name,
                    requestData: options.data,
                    timestamp: new Date().toISOString()
                });
    
                // 调用原始函数
                const promise = originalCallFunction.apply(this, arguments);
    
                // Intercept the promise resolution/rejection
                promise.then(function(res) {
                    console.log('[Frida] wx.cloud.callFunction SUCCESS');
                    console.log('[Frida] Response Data:', JSON.stringify(res, null, 2));
                    // 发送响应数据到 Python 控制端
                    send({
                        type: 'response',
                        functionName: options.name,
                        responseData: res,
                        isError: false,
                        timestamp: new Date().toISOString()
                    });
                }).catch(function(err) {
                    console.log('[Frida] wx.cloud.callFunction ERROR');
                    console.error('[Frida] Error Data:', JSON.stringify(err, null, 2));
                    // 发送错误数据到 Python 控制端
                    send({
                        type: 'response',
                        functionName: options.name,
                        responseData: err, // 或者 err.message, err.stack
                        isError: true,
                        timestamp: new Date().toISOString()
                    });
                });
                return promise;
            };
    
            console.log('[Frida] wx.cloud.callFunction hooked successfully!');
            send({ type: 'status', message: 'Hooked wx.cloud.callFunction successfully!' });
    
        } else {
            console.log('[Frida] wx.cloud.callFunction not found yet or wx object not ready. Retrying in 1 second...');
            setTimeout(tryHookCloudFunction, 1000); // 1秒后重试
        }
    }
    
    // Frida RPC 导出,允许 Python 端调用此函数(可选,如果需要在Python端控制何时开始hook)
    /*
    rpc.exports = {
        init: function () {
            tryHookCloudFunction();
        }
    };
    */
    
    // 脚本加载时立即尝试Hook
    tryHookCloudFunction();

    目前想不到有其他什么好的思路或者方法,请大佬们指导指导!!!

    发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

    坦然 发表于 2025-5-21 13:56
    1.先抓到云函数的包(HOOK)。
    2.wx协议发送包或者hook发包。
    仅提供思路,仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途。
     楼主| 毛_毛熊 发表于 2025-5-21 14:17
    坦然 发表于 2025-5-21 13:56
    1.先抓到云函数的包(HOOK)。
    2.wx协议发送包或者hook发包。
    仅提供思路,仅限用于学习和研究目的;不得 ...

    HOOK这步我还不太清楚怎么做,第一次接触frida
    上面的代码是Gemini写的,可以运行但是不能替换wx.cloud.callFunction 也就无法获取云函数通信的数据,如果可以打印点相关信息或者调试的话就好点。但是HOOK的这个js我打断点也没用= =
    大佬能详细讲讲吗?或者有什么文章推荐我去看看。

    xoyi 发表于 2025-5-21 15:51
    https://github.com/FourTwooo/Hook_WeChat_FaaS
    可以参考下
    heifengye 发表于 2025-6-13 16:06
    回复你第一个小问题,小程序特定版本,可以删除其他版本后 只保留特定的版本,并给上级文件设置用户组写入权限拒绝,这样微信就没办法写入新的小程序版本

    第二个问题就不是一两句能说清楚的了,建议你找一下相关教程,有点耐心的看完。
    您需要登录后才可以回帖 登录 | 注册[Register]

    本版积分规则

    返回列表

    RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

    GMT+8, 2026-8-7 12:48

    Powered by Discuz!

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表