0.前言
最近好奇这个充电保护程序为什么可以控制最高充电百分比,所以我想分析一下。
该程序适用于华硕飞行堡垒fx63vd7700型号,如果适用华硕其它型号的可以试试看。
注意该充电保护程序不适用于其它品牌、或华硕其它型号的笔记本电脑。
这个软件的界面如下图所示。
模式有三种:完整充电模式、平衡保养模式、最佳保养模式。三种模式限制充电百分比分别为100%,80%、和60%。
软件主界面
目录如下:
1.x64dbg动态调试
双击BhcApp.exe,启动充电保护软件。x64dbg附加“BhcMgr.exe”。
在DeviceIoControl处插入断点,这个函数用于和设备通信,随便选中一个模式然后点确定就会触发断点。
例如我选中的“平衡保养模式”。
调用堆栈如下图所示。
DeviceIoControl的参数如下:
[C] 纯文本查看 复制代码 BOOL DeviceIoControl(
[in] HANDLE hDevice,
[in] DWORD dwIoControlCode,
[in, optional] LPVOID lpInBuffer,
[in] DWORD nInBufferSize,
[out, optional] LPVOID lpOutBuffer,
[in] DWORD nOutBufferSize,
[out, optional] LPDWORD lpBytesReturned,
[in, out, optional] 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字节。
这个可以视为一个结构体。代码如下。
[C] 纯文本查看 复制代码 struct BatteryIOCtlInfo
{
DWORD head; // 头部
DWORD nextSize; // 后续结构体成员大小
DWORD num2; // 未知四字节数,固定为0x120057
DWORD perecent; // 充电百分比,0x50为80%,0x3C为60,0x64为100%
};
结构体各成员值填写为:
[C] 纯文本查看 复制代码 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参数如下:
[C] 纯文本查看 复制代码 HANDLE CreateFileW(
[in] LPCWSTR lpFileName,
[in] DWORD dwDesiredAccess,
[in] DWORD dwShareMode,
[in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes,
[in] DWORD dwCreationDisposition,
[in] DWORD dwFlagsAndAttributes,
[in, optional] 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++代码如下:
[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%。
|