打开微信老是提示: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