打开微信老是提示:PC微信弹窗:当前客户端版本过低,请前往应用商店升级到最新版本客户端后再登录。
解决方案有好几种,比如硬改微信主程序exe文件的版本号,把版本号改成最新版本。这样做治标不治本,我在【吾爱破解】论坛看到了这么一篇帖子:https://www.52pojie.cn/thread-1673212-1-1.html
虽然是两年前的,原理都是一样的。硬改版本号非常容易出现环境异常的问题。

于是,又有了另一种方案,修改程序在内存中的地址数据。这个方法经过我自己实测是可行的,参照:https://blog.csdn.net/Scoful/article/details/139330910
这么做也有个弊端,不灵活。需要下载个cheat Engine软件,每次打开微信都要扫描电脑上运行的进程。然后搜索关键字,定位到具体的模块基址,然后手动选中对应的值进行修改然后保存。等到下次你还想用微信,又得从头这么操作一遍。哎,想想就头疼。尤其是这个微信版本号转换成十六进制值,估计都要难到很多人了。不过没关系,我写了个转换类帮你搞定。

进制转换器

package com.chaizhou.utils;

/**
 * @Author zF.
 * @ClassName BHDConverterUtil.java
 * @ProjectName NewBot-Nova
 * @Description 进制转换器
 */
public class BHDConverterUtil {

    public static String convertVersionToHex(String version) {
        // 将版本号按照"."进行分割
        String[] parts = version.split("\\.");

        // 使用StringBuilder来构建最终的转换结果
        StringBuilder result = new StringBuilder("6");

        // 遍历每个部分,转为16进制,并进行补位处理
        for (int i = 0; i < parts.length; i++) {
            // 将字符串转为整数
            int part = Integer.parseInt(parts[i]);

            // 将整数转为16进制字符串
            String hexPart = Integer.toHexString(part);

            // 根据索引决定补位长度,第一个部分不补,其他部分补2位
            if (i == 0) {
                result.append(hexPart); // 第一个部分不补位
            } else {
                result.append(String.format("%02x", part)); // 其他部分补足两位
            }
        }

        return result.toString();
    }

//    public static void main(String[] args) {
//        // 测试
//        String thisVersion = "3.9.8.15"; //当前微信版本
//        String thisVersionValue = convertVersionToHex(thisVersion);
//        System.out.println("当前微信版本转换后的数值: " + thisVersionValue);
//        String theVersion = "3.9.12.17"; //官网最新微信版本
//        String theVersionValue = convertVersionToHex(theVersion);
//        System.out.println("官网最新微信版本转换后的数值: " + theVersionValue);
//    }

    // 还原方法,将16进制字符串还原为版本号
    public static String convertHexToVersion(String hexValue) {
        // 去掉前缀 '6'
        String hex = hexValue.startsWith("0x") ? hexValue.substring(3) : hexValue.substring(1);

        // 构建一个数组来存储分割后的版本号部分
        int[] versionParts = new int[4];

        // 第一个部分对应的是第一个字符,长度1
        versionParts[0] = Integer.parseInt(hex.substring(0, 1), 16);

        // 其他部分每2个字符为一组
        versionParts[1] = Integer.parseInt(hex.substring(1, 3), 16);
        versionParts[2] = Integer.parseInt(hex.substring(3, 5), 16);
        versionParts[3] = Integer.parseInt(hex.substring(5, 7), 16);

        // 将每个部分拼接成点号分隔的版本号字符串
        return versionParts[0] + "." + versionParts[1] + "." + versionParts[2] + "." + versionParts[3];
    }

    public static void main(String[] args) {
        // 测试
        String hexValue = "0x6309080f";
        String version = convertHexToVersion(hexValue);
        System.out.println("还原后的版本号: " + version);
    }
}


你想用上面那种方法就运行我这个转换器,算出十六进制值,然后填到cheat Engine里面就可以啦。

那有没有更简单便捷的操作呢?当然有!我本来想用Java写个方法来操作的,结果Java不能直接操作内存(可能有,只是我做不到)。我用了JNA Platform尝试多次都没能成功,遂放弃。残缺版的代码也放出来吧,反正写都写了。

WeChatMemoryFixerUtil

package com.chaizhou.utils;

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Psapi;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.ptr.IntByReference;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @Author zF.
 * @ClassName WeChatMemoryFixerUtil.java
 * @ProjectName NewBot-Nova
 * @Description
 */
public class WeChatMemoryFixerUtil {

    // 官网最新版本
    private static final int TARGET_VERSION = 0x63090c11;  // 3.9.12.17
    private static final int ORIGINAL_VERSION = 0x6309080f;  // 3.9.8.15

    // 偏移地址列表(不同微信版本,版本号在内存中偏移地址不一样,需要通过CE工具定位。本代码仅针对3.9.8.15版本微信有效)
    private static final int[] ADDRESS = {0x3D8BB10, 0x3D8BB14, 0x3DC2F30, 0x3DC2F34, 0x3DF8DA8, 0x3DFFEE8};

    public static void main(String[] args) {
        try {
            WinNT.HANDLE processHandle = openProcess("WeChat.exe");
            if (processHandle == null) {
                throw new Exception("无法打开 WeChat.exe 进程,请确保微信正在运行。");
            }

            long weChatBaseAddress = getModuleBaseAddress(processHandle, "WeChatWin.dll");
            if (weChatBaseAddress == 0) {
                throw new Exception("未找到 WeChatWin.dll 模块!");
            }

            fixVersion(processHandle, weChatBaseAddress);
            System.out.println("好了,可以扫码登录了");

        } catch (Exception e) {
            System.err.println(e.getMessage() + ",请确认微信程序已经打开!");
        }
    }

    private static void fixVersion(WinNT.HANDLE processHandle, long weChatBaseAddress) throws Exception {
        for (int offset : ADDRESS) {
            long addr = weChatBaseAddress + offset;
            int value = readMemory(processHandle, addr);

            if (value == TARGET_VERSION) {
                continue; // 版本已经修复
            } else if (value != ORIGINAL_VERSION) {
                throw new Exception("版本不对,修复没有效果");
            }

            writeMemory(processHandle, addr, TARGET_VERSION); // 写入伪装版本
        }
    }

    private static WinNT.HANDLE openProcess(String processName) {
        int processId = getProcessId(processName);
        if (processId == -1) {
            return null;
        }
        return Kernel32.INSTANCE.OpenProcess(Kernel32.PROCESS_ALL_ACCESS, false, processId);
    }

    /**
     * @Description 获取进程ID
     * @param processName 进程名称
     */
    public static int getProcessId(String processName) {
        try {
            Process process = Runtime.getRuntime().exec("tasklist");
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.contains(processName)) {
                    String[] parts = line.trim().split("\\s+");
                    return Integer.parseInt(parts[1]);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return -1;
    }

    private static long getModuleBaseAddress(WinNT.HANDLE processHandle, String moduleName) {
        // 创建存储模块句柄的数组
        WinNT.HMODULE[] modules = new WinNT.HMODULE[1024];
        IntByReference cbNeeded = new IntByReference();

        // 获取当前进程的所有模块
        if (Psapi.INSTANCE.EnumProcessModules(processHandle, modules, modules.length * Native.getNativeSize(WinNT.HMODULE.class), cbNeeded)) {
            int moduleCount = cbNeeded.getValue() / Native.getNativeSize(WinNT.HMODULE.class);
            for (int i = 0; i < moduleCount; i++) {
                // 使用Memory来获取模块名
                Memory moduleNameBuffer = new Memory(1024); // 分配 1024 字节的内存
                IntByReference length = new IntByReference((int) moduleNameBuffer.size());

                // 这里确保传递正确的参数
                Psapi.INSTANCE.GetModuleFileNameEx(processHandle, modules[i], moduleNameBuffer, (int) moduleNameBuffer.size());

                String moduleFileName = Native.toString(moduleNameBuffer.getByteArray(0, 1024)).trim();
                if (moduleFileName.toLowerCase().endsWith(moduleName.toLowerCase())) {
                    return Pointer.nativeValue(modules[i].getPointer()); // 返回模块基地址
                }
            }
        }
        return 0; // 未找到模块
    }

    private static int readMemory(WinNT.HANDLE processHandle, long address) {
        IntByReference output = new IntByReference();
        Kernel32.INSTANCE.ReadProcessMemory(processHandle, new Pointer(address), output.getPointer(), 4, null);
        return output.getValue();
    }

    private static void writeMemory(WinNT.HANDLE processHandle, long address, int value) {
        Memory mem = new Memory(4);
        mem.setInt(0, value);
        Kernel32.INSTANCE.WriteProcessMemory(processHandle, new Pointer(address), mem, 4, null);
    }
}


既然Java做不到那有没有可以做到的?当然有,Python、C、C++……都可以操作内存。关键咱不会啊!
还好,有个东西稍微简单那么点。{易语言},还是初中的时候玩过它。没想到还得靠它救场啊。经过我通宵半宿,“百度 + CV”,终于搞出来了。[撒花] emmm,如果GPT会写易语言代码就好了。


问题来了,我们为什么非得用低版本的微信呢?当然是玩微信机器人啊。目前市面上的微信机器人实现原理无非是以下几种:网页版协议(最早期注册的部分微信号才支持) 、iPad协议(这个血贵买断版本得大几千上万块,按月也得200左右。)、安卓hook(很少,也很贵)、PC微信hook(这个经济成本低)。前面说的这个价格都是开发者收取的,这玩意儿相当于越狱,官方肯定不可能提供的。人家第三方私人开发者去研究这些东西肯定不是做慈善的。尤其是这些协议和hook那都是跟着版本走的。你必须安装指定版本的微信才能用,很好奇?那我推荐你看:https://blog.csdn.net/m6037843/article/details/140033449
看完这篇文章你大概能明白了吧?就像上面讲的修改版本号那样。不同版本的微信,每个字段在内存中的偏移地址都不一样。需要挨个去定位,然后不断调试,最后封装。所以,人家收点费也是应该的。现在原理你都已经知道了,你自己写个hook应该不难吧?什么?不想写?没关系,我正在做的微信机器人框架就是给你这种(帅哥)准备的。所以的东西全部封装好了,纯SpringBoot即可开发,会“HelloWorld”就能写自己的微信机器人,就像喝水一样简单。

本博客发布的内容仅供学习研究,禁止商用。如有侵权,请联系:hi@zhangfeng.cc

最后修改:2024 年 09 月 29 日
给我一点小钱钱也很高兴啦!o(* ̄▽ ̄*)ブ