0.前言
最近好奇这个充电保护程序为什么可以控制最高充电百分比,所以我想分析一下。
该程序适用于华硕飞行堡垒fx63vd7700型号,如果适用华硕其它型号的可以试试看。
注意该充电保护程序不适用于其它品牌、或华硕其它型号的笔记本电脑。
这个软件的界面如下图所示。
模式有三种:完整充电模式、平衡保养模式、最佳保养模式。三种模式限制充电百分比分别为100%,80%、和60%。
软件主界面
目录如下:
1.x64dbg动态调试
双击BhcApp.exe,启动充电保护软件。x64dbg附加“BhcMgr.exe”。
在DeviceIoControl处插入断点,这个函数用于和设备通信,随便选中一个模式然后点确定就会触发断点。
例如我选中的“平衡保养模式”。
调用堆栈如下图所示。
DeviceIoControl的参数如下:
[C] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 | 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] 纯文本查看 复制代码 1 2 3 4 5 6 7 | struct BatteryIOCtlInfo
{
DWORD head;
DWORD nextSize;
DWORD num2;
DWORD perecent;
};
|
结构体各成员值填写为:
[C] 纯文本查看 复制代码 1 2 3 4 5 6 7 8 | BatteryIOCtlInfo btinfo;
btinfo.head = 0x53564544;
btinfo.nextSize=8;
btinfo.num2 = 0x120057;
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] 纯文本查看 复制代码 1 2 3 4 5 6 7 8 9 | 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++] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #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)
{
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;
btinfo.perecent = 0x3c;
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%。
|