金山护眼大师实现原理
2024-03-17 17:33:41

软件下载

https://pc.qq.com/detail/19/detail_25499.html

软件设置保存在注册表

HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\khealtheye

护眼原理

原理是利用 SetDeviceGammaRamp 函数设置色温
关键位置在keyeprotect.dll文件中,关键函数 sub_100A8C10
IDA静态分析

1
2
3
4
5
6
7
8
9
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
char __usercall sub_100A8C10@<al>(unsigned __int16 per@<ax>, int context@<ecx>, int healthMode@<edi>)
{
int v3; // esi
unsigned __int16 blueStep; // ST24_2
unsigned __int16 v5; // ax
double multiplier; // st7
double v7; // st6
unsigned __int16 v8; // ax
int redStep; // [esp+10h] [ebp-8h]
WORD redStepa; // [esp+10h] [ebp-8h]
WORD greenStep; // [esp+12h] [ebp-6h]

switch ( healthMode )
{
case 0: // 智能模式
v3 = per;
redStep = *(_DWORD *)(context + 20);
blueStep = *(_WORD *)(context + 24);
v5 = (signed int)((double)per * 1.28);
goto LABEL_10;
case 1: // 办公模式
v3 = per;
multiplier = (double)per;
v7 = 0.4 * multiplier + 88.0;
v8 = (signed int)v7;
redStepa = (signed int)v7;
if ( v8 < 88u )
redStepa = 88;
greenStep = (signed int)v7;
if ( v8 < 88u )
greenStep = 88;
SetGamma((_DWORD *)context, redStepa, greenStep, (signed int)(multiplier * 1.28));
goto LABEL_11;
case 2: // 影视模式
v3 = per;
v5 = (signed int)((double)per * 1.28);
break;
case 3: // 游戏模式
v3 = per;
v5 = (signed int)((double)per * 1.28);
break;
}
LOWORD(redStep) = v5;
HIWORD(redStep) = v5;
LABEL_10:
SetGamma((_DWORD *)context, redStep, HIWORD(redStep), v5);
LABEL_11:
sub_100A4AE0(healthMode);
sub_100A4AE0(v3);
return 1;
}

得出设置公式

1
2
3
4
5
6
7
8
9
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
54
55
56
57
58
59
60
61
62
enum class HealthMode
{
Smart,
Office,
Movie,
Game
};

bool SetGamma(double redStep, double greenStep, double blueStep)
{
auto success = false;
HDC hDevice = ::GetDC(nullptr);
if (hDevice)
{
WORD ramp[3][256];
for (auto i = 0; i < 256; ++i)
{
const auto r = i * (redStep + 128);
const auto g = i * (greenStep + 128);
const auto b = i * (blueStep + 128);
ramp[0][i] = (WORD)(min(0xFFFF, r));
ramp[1][i] = (WORD)(min(0xFFFF, g));
ramp[2][i] = (WORD)(min(0xFFFF, b));
}
success = ::SetDeviceGammaRamp(hDevice, ramp);
::ReleaseDC(nullptr, hDevice);
}
return success;
}

/// <summary>
/// 护眼
/// </summary>
/// <param name="brightness">亮度百分比(0 ~ 100)</param>
/// <param name="mode">护眼模式</param>
/// <returns></returns>
bool EyeProtect(double brightness, HealthMode mode)
{
auto success = false;
const auto multiplier = brightness;
double r = 0;
double g = 0;
double b = std::round(multiplier * 1.28);

switch (mode)
{
case HealthMode::Smart:
r = g = 128;
break;

case HealthMode::Office:
r = g = max(88, 0.4 * multiplier + 88.0);
break;

case HealthMode::Movie:
case HealthMode::Game:
r = g = b;
break;
}
success = SetGamma(r, g, b);
return success;
}

任何模式下将亮度设置为100都会变为系统默认值,等同于关闭护眼功能。
其中影视模式和游戏模式的公式是同一个,效果相同。

智能模式默认亮度为75%
办公模式默认亮度为30%
影视模式默认亮度为59%
游戏模式默认亮度为78%

配置文件解密

data目录下有部分.dat文件,是xml加密后的数据。
解密方法就是去掉头4字节,就是字符串”.tmp”,然后把余下的数据与0xD8异或,最后从末尾搜索0xFDFDFDFD,找到并删除其之后的数据

1
2
3
4
5
6
7
8
9
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
54
55
56
57
58
59
60
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <iostream>
#include <fstream>
#include <string>
#include <memory>
#include <filesystem>

namespace fs = std::filesystem;

std::string Decrypt(char* pData, int size)
{
std::string s;
for (auto i = 0; i < size; ++i)
{
pData[i] ^= 0xD8;
}
return s;
}

int main()
{
auto dir = fs::current_path();
auto iter = fs::recursive_directory_iterator(dir);
auto end = fs::recursive_directory_iterator();

while (iter != end)
{
if (fs::is_regular_file(*iter))
{
auto path = iter->path();
if (path.extension() == ".dat")
{
std::ifstream in(path, std::ios::binary | std::ios::ate);
if (in.is_open())
{
auto size = in.tellg();
in.seekg(0, std::ios::beg);
auto buf = std::make_unique<char[]>(size);
auto p = buf.get();
in.read(p, size);
if (_strnicmp(p, ".tmp", 4) == 0)
{
p += 4;
Decrypt(p, (int)size - 4);

std::ofstream out("out.xml", std::ios::binary | std::ios::trunc);
if (out.is_open())
{
out << p;
out.close();
}
}
in.close();
}
}
}
iter++;
}
}
2024-03-17 17:33:41
下一页