华硕fx63vd7700充电保护程序“ASUS Battery Health Charging”逆向分析
0.前言最近好奇这个充电保护程序为什么可以控制最高充电百分比,所以我想分析一下。
该程序适用于华硕飞行堡垒fx63vd7700型号,如果适用华硕其它型号的可以试试看。
注意该充电保护程序不适用于其它品牌、或华硕其它型号的笔记本电脑。
这个软件的界面如下图所示。
模式有三种:完整充电模式、平衡保养模式、最佳保养模式。三种模式限制充电百分比分别为100%,80%、和60%。
目录如下:
1.x64dbg动态调试
双击BhcApp.exe,启动充电保护软件。x64dbg附加“BhcMgr.exe”。
在DeviceIoControl处插入断点,这个函数用于和设备通信,随便选中一个模式然后点确定就会触发断点。
例如我选中的“平衡保养模式”。
调用堆栈如下图所示。
DeviceIoControl的参数如下:
BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
);
回到DeviceIoControl上层函数“sub_321C90”。观察DeviceIoControl的入参:
HANDLE hDevice = 0x274
DWORD dwIoControlCode = 0x22240C
LPVOID lpInBuffer = 0xB7F010
DWORD nInBufferSize = 0x10
LPVOID lpOutBuffer = 0x93F238
DWORD nOutBufferSize = 0x400
LPDWORD lpBytesReturned = 0x93F234
LPOVERLAPPED lpOverlapped = 0
1.1 查看缓冲区lpInBuffer: 0xB7F010
如下图所示为缓冲区内容,大小0x10字节。
这个可以视为一个结构体。代码如下。
struct BatteryIOCtlInfo
{
DWORD head; // 头部
DWORD nextSize; // 后续结构体成员大小
DWORD num2; // 未知四字节数,固定为0x120057
DWORD perecent; // 充电百分比,0x50为80%,0x3C为60,0x64为100%
};
结构体各成员值填写为:
BatteryIOCtlInfo btinfo;
btinfo.head = 0x53564544;
btinfo.nextSize=8;
btinfo.num2 = 0x120057;
// 0x3c 60%
// 0x50 80%
// 0x64 100%
btinfo.perecent = 0x3c;
1.2 输出缓冲区lpOutBuffer: 0x93F238
只有头四节被填充0x1,剩余的0x400 - 4个字节均为0.
输出缓冲区里的内容没有什么特别的,只需保证有输出缓冲区,以及该缓冲区有0x400字节大小即可。
2.IDA静态分析
以上分析了DeviceIoControl的入参,但是还不知道设备句柄是怎么获取的。
进入sub_321C90的代码段,在IDA为“sub_401C90”,00401D0C为调用DeviceIoControl的语句。
选中"hDevice",按下X键看看哪个语句写入了这个hDevice。如下图所示。(Type:r表示读取read,w表示写入write)
进入了函数sub_401D70。
原来是CreateFileW打开(电池)设备的句柄。
CreateFileW参数如下:
HANDLE CreateFileW(
LPCWSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
LPCWSTR lpFileName:"\\.\ATKACPI"
DWORD dwDesiredAccess: 0xC0000000 ( GENERIC_READ | GENERIC_WRITE == 0xC0000000 )
DWORD dwShareMode: 0x3 (FILE_SHARE_READ | FILE_SHARE_WRITE == 0x3)
LPSECURITY_ATTRIBUTES lpSecurityAttributes: NULL
DWORD dwCreationDisposition: 0x3 (OPEN_EXISTING == 3)
DWORD dwFlagsAndAttributes: NULL
HANDLE hTemplateFile: NULL
3. 代码复现
因此控制笔记本最高充电百分比的C++代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
struct BatteryIOCtlInfo
{
DWORD head;
DWORD nextSize;
DWORD num2;
DWORD perecent;
};
int main(int argc, char** argv, char** envp)
{
// GENERIC_READ | GENERIC_WRITE == 0xC0000000
// FILE_SHARE_READ | FILE_SHARE_WRITE == 0x3
// OPEN_EXISTING == 3
HANDLE hhh = CreateFileW
(
L"\\\\.\\ATKACPI",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
NULL,
NULL
);
//
BatteryIOCtlInfo btinfo;
btinfo.head = 0x53564544;
btinfo.nextSize=8;
btinfo.num2 = 0x120057;
// 0x3c 60%
// 0x50 80%
// 0x64 100%
btinfo.perecent = 0x3c;// 修改此处数值
// out buffer
void* out_buf = malloc(0x400);
DWORD returnBytes = 0;
//
DeviceIoControl(
hhh,
0x22240C,
&btinfo,
sizeof(btinfo),
out_buf,
0x400,
&returnBytes,
NULL);
CloseHandle(hhh);
free(out_buf);
return 0;
}
经测试可以修改最高充电百分比,但是只能有60%,80%和100%三种数值。如果修改为其它数值,则默认最高充电百分比为100%。
Wobuaishangban 发表于 2024-3-18 08:49
技术很niubi,但问个小白问题:改这个的目的是什么?
我想分析一下这个华硕的充电保护程序是怎么控制最高充电电量的,然后用c++代码复现出来。这个工具感觉不太好找,所以试着分析一下它的原理:lol 本帖最后由 Chenda1 于 2024-3-20 09:15 编辑
大佬我是华硕天选看了您的文章只知道用这个代码在可支持机型可以使用代码调整。不过我看不懂
我有一个问题: 这个电池控制是比如控制到80就涓流充电 (很慢的速度 让他与80%消耗的成互补关系)还是它冲到80%后就将电引到电脑主板而开机的耗电不再消耗电池,电池只是在慢慢的维持80%,因为我长时间插着他会从80%慢慢到达82%当然过程可能是一个月, 我总结一下1.是否高功率充电入电池然后 电脑消耗电池的电量2.到达80%后涓流充电池,电脑直接从充电器取电。 感谢分享原创作品! {:1_921:}原创必顶一个
感谢分享原创作品! 感谢,学到了 来试试看 我的笔记本正好也是华硕的飞行堡垒系列,但型号不一样。不知道能不能适用 感谢分享,很有用 支持一下