Files
Gamemax-linux-apps/docs/reverse-engineering.md
T
oxpoeandREA (managed-code analysis) f58a011f4d GAMEMAX IceBurg LCD Linux bridge: sender + tray app
Reverse-engineered Linux driver for the LCD panel of the GAMEMAX IceBurg
Digital AIO cooler (HID 5131:2007). Includes:

- src/gamemax_report.py  pure-stdlib sender: reads hwmon/proc sensors and
  streams the 65-byte HID report the firmware understands (no deps)
- src/gamemax_gui.py     PySide6 tray app: animated monitor, fan/temperature
  channel pickers, autostart, blank mode, single instance, crash log
- packaging/             AppImage build script, udev rule, systemd user unit
- tools/                 IL dump helpers used to read the vendor MSIL
- docs/                  full reverse-engineering analysis
- DISCLAIMER.md          Linux-compatibility project, not affiliated with vendor

Co-authored-by: REA (managed-code analysis)
2026-10-13 06:26:52 +07:00

10 KiB
Raw Permalink Blame History

GAMEMAX PcInfoMonitorPro — Recon & HID Protocol

Target: GAMEMAX_V1.0.0/app/ (installer GAMEMAX_V1.0.0.04(1).exe) Analisis: 2026-10-13, REA 6.4.0 + Ghidra 12.1.2 (managed static provider), IL dumper lokal.

1. Isi target

File Peran Teknologi
PcInfoMonitorPro.exe Aplikasi utama (GUI) PE32 mixed-mode C++/CLI + Qt5, logika = MSIL (457 method body)
allComputerInfoGetPro.exe Helper console (dipanggil terpisah) mixed-mode C++/CLI, sebagian besar CRT
WitmodHardwareInfoLibrary.dll Model data sensor (CPU/GPU/mobo) .NET Framework, CIL murni
LibreHardwareMonitorLib.dll Sumber data sensor OSS pihak ketiga (bukan kode vendor)
HidSharp.dll HID library .NET OSS pihak ketiga (tidak dipakai jalur utama)
hidapi.dll I/O HID OSS, dipakai untuk buka/tulis device
Qt5*.dll, opengl32sw.dll, D3Dcompiler_47.dll Framework UI Qt 5 native
configDir/appConfig.ini Konfigurasi app [AppInfo] AppName=GAMEMAX, AppVersion=V_1.0.0.04, AppID=ABCDEF6543A1, warna tema, font Microsoft YaHei

Catatan: vendor internal tampil sebagai MyCompanyWitmod / WITMOD; GAMEMAX adalah merek OEM-nya.

2. Arsitektur logika

Semua logika aplikasi dikompilasi ke MSIL (mixed-mode /clr), sehingga decompile native (Ghidra) pada metode aplikasi menghasilkan sampah. Metode dideklarasikan sebagai fungsi global bernama bertitik, mis. MainHidInterFace.hidApi_Write, DMainWidget.onGetPcInfoOk, di bawah tipe <Module>. Native hanya: Qt DLL, hidapi, CRT.

Alur HID:

DMainWidget.onGetPcInfoOk   (bangun report 65 byte dari sensor)
  -> MainHidInterFace.hidApi_Write   (mutex + copy 65 B + QList enqueue)
      -> MainHidInterFace.run        (thread: QList.takeFirst -> hid_write, poll 500 us)

3. Device target & pembukaan

MainHidInterFace.getuUsbHidDeviceList:

  1. hid_enumerate(0, 0) — semua HID
  2. filter vendor_id == 20785 (0x5131) dan product_id == 8199 (0x2007)
  3. ambil path (offset 0, string ASCII) → hid_open_path
  4. daftar device aktif dimuat via RegisterDeviceNotificationW (plug/unplug, sinyal sigHidDeviceConnectChanging_Into/Remove, sigOpenHidSuccessful)

Tulis satu arah: tidak ada hid_read* yang diimpor — app hanya mengirim.

4. Protokol tulis (terverifikasi dari IL)

  • Transfer hid_write(handle, buf, 65): 65 byte = 1 byte report ID + 64 byte payload
  • buf[0] = 0 (report ID 0)
  • buf[1] = 64 (0x40, panjang payload)
  • Nilai 16-bit big-endian (high byte dulu)
  • Suhu: jika checkbox unit tercentang → nilai dipakai apa adanya; jika tidak → round((v - 32) / 1.8) | 0x80. Bit 0x80 menandakan nilai Fahrenheit.
  • Pengiriman berulang tiap 500 us selama device terbuka

Layout report (dari DMainWidget.onGetPcInfoOk)

Offset Isi Sumber
0 0 report ID
1 64 panjang payload
2 CPU temp GetCpu_Temperature (+flag 0x80 bila °F)
3 CPU load GetCpu_Load
4..5 CPU clock (MHz, BE16) GetCpu_Clock
6..7 CPU fan (RPM, BE16) GetCpu_Fan
8..9 BE16 dari struct lokal belum dipetakan
10 GPU temp GetGpu_Temperature (+flag 0x80)
11 GPU load GetGpu_CoreLoad
12..13 GPU clock (BE16) GetGpu_CoreClock
14..15 GPU fan (BE16) GetGpu_Fan
16..17 GPU power (BE16) GetGpu_Power
18 u8 dari struct lokal belum dipetakan
19..20 BE16 dari struct lokal belum dipetakan
21 u8 dari struct lokal belum dipetakan
22..23 BE16 dari struct lokal belum dipetakan
24..64 0 tidak ditulis jalur ini

Nilai sensor berasal dari WitmodHardwareInfoLibrary.Monitor (wrapper tipis di atas LibreHardwareMonitor): CPU/GPU Temperature, Load, CoreLoad, Clock, Clock_Max, Fan, Fan_Max, Power, Power_Max.

5. Bukti & artefak

  • analysis/evidence/hid-write-protocol.json — Evidence bundle REA (12 records, 5.5 MB)
  • analysis/snapshots/pcinfomonitorpro.json — snapshot Ghidra (bisa dibuka ulang tanpa import)
  • analysis/tools/ildump.py — disassembler IL (dnfile+dncil) untuk membaca MSIL dengan operand terselesaikan; venv: uv venv ilenv && uv pip install --python ilenv/bin/python dnfile dncil

6. Hasil lanjutan

6.1 Hanya ada satu jenis perintah HID

Seluruh IL (457 body) dipindai: setiap fungsi hidapi dipanggil tepat sekali (hid_init, hid_enumerate, hid_free_enumeration, hid_open_path, hid_set_nonblocking, hid_write, hid_close, hid_exit) dan hidApi_Write hanya punya satu pemanggil (DMainWidget.onGetPcInfoOk). Tidak ada hid_read*/hid_get_feature_report — tidak ada perintah lain (brightness, mode, dll.) di jalur ini.

6.2 Auto-start + self-elevation (Task Scheduler)

DMainWidget.initThemeData (fungsi startup besar, offset IL ~4380-4520):

  1. Menulis penanda ke QSettings: StartupTaskOKver---
  2. ShellExecuteW(verb="runas", file="schtasks", params=
    /create /tn "%1" /tr "\"%2\" %3" /sc onlogon /rl highest
    • %2 = QCoreApplication.applicationFilePath() (path exe sendiri)
    • %3 = ---StartupByTaskMinWindow (penanda argumen)
    • verb runas → UAC sekali di awal, task berjalan dengan token tertinggi tiap logon
  3. main memindai argv untuk ---StartupByTaskMinWindow, lalu mencetak "Program was started by Task Scheduler." / "Program was not started by Task Scheduler." dan memulai aplikasi terminimalkan
  4. Manifest exe: requestedExecutionLevel level='requireAdministrator'

Efek: aplikasi otomatis berjalan sebagai admin tanpa prompt UAC di setiap logon.

6.3 allComputerInfoGetPro.exe = stub test

main: new Monitor(); GetComputerInfo(); Sleep(500); printf("Over ... ..."); getchar(); — harness uji developer untuk WitmodHardwareInfoLibrary, bukan bagian alur runtime. Nama file ini tidak dirujuk oleh PcInfoMonitorPro.exe (ASCII maupun UTF-16) dan tidak ada di installer.

6.4 Layout report — LENGKAP (terverifikasi di device)

Offset Isi Sumber di aplikasi Terverifikasi
0 0 report ID ✅
1 64 panjang payload ✅
2 CPU temp (0..127) GetCpu_Temperature ✅ tampil di layar
3 CPU load % GetCpu_Load ✅
4..5 CPU clock MHz (BE16) GetCpu_Clock ✅ — device merender byte ini di slot "RPM"
6..7 CPU fan RPM (BE16) GetCpu_Fan ✅ (device tidak menampilkannya di halaman ini)
8..9 CPU power W (BE16) GetCpu_Power ✅
10 GPU temp (0..127) GetGpu_Temperature ✅
11 GPU load % GetGpu_CoreLoad ✅
12..13 GPU clock MHz (BE16) GetGpu_CoreClock ✅
14..15 GPU fan RPM (BE16) GetGpu_Fan ✅
16..17 GPU power W (BE16) GetGpu_Power ✅
18 RAM usage % GlobalMemoryStatusEx → dwMemoryLoad ✅
19..20 total RAM MiB (BE16) ullTotalPhys × 2⁻²⁰ ✅
21 disk free % GetDiskFreeSpaceExW (free/total × 100) ✅
22..23 total disk GB (BE16) total bytes >> 30 ✅
24..64 nol tidak dipakai ✅

Catatan pembalikan dari dugaan awal: byte 8..9 bukan counter waktu melainkan CPU power; 19..20 dan 22..23 adalah RAM total dan ukuran disk, bukan waktu.

6.5 Perilaku firmware yang ditemukan saat pengujian

  1. Nilai ≥ 128 ditolak. Aplikasi asli menulis suhu Celsius dengan bit 0x80 aktif. Firmware IceBurg mengabaikan field itu dan mempertahankan nilai terakhir yang valid (pengujian: 99 °C mentok sampai nilai tanpa flag dikirim). Jadi kirim suhu 0..127 tanpa flag.
  2. Kedip = indikator "nilai tidak berubah". Saat semua field statis, angka tengah berkedip ~1×/detik; saat nilai berubah (suhu naik 40→90) kedip hilang. Bukan efek laju kirim — kedip tetap ada walau kita berhenti mengirim.
  3. Plafon laju ~8 report/detik. Endpoint interrupt OUT bInterval 160 ms; setiap write() hidraw menunggu URB selesai (~125 ms). Aplikasi asli menumpuk antrean dari loop 500 µs (QTimer.setInterval(10) + QThread.usleep(500)), efektifnya sama.
  4. Selalu "streaming", tidak ada handshake/init: buka lalu tulis 64 byte.
  5. Slot RPM salah byte. Diuji silang di hardware: kirim clock=4000 dan fan=1500 → layar menampilkan 4000 di slot RPM. Jadi firmware memakai byte 4..5 untuk slot itu, padahal aplikasi asli menaruh clock CPU di sana (bug pasangan app/firmware). Implementasi pengganti menukar clock/fan agar layar menampilkan RPM fan sungguhan.
  6. Akurasi dibandingkan system monitor: suhu cocok (selisih hanya pembulatan ke integer), load cocok; keduanya tampil dengan delay beberapa detik akibat jendela sampling dan laju device.

7. Implementasi pengganti (jalan di host ini)

analysis/tools/gamemax_report.py — Python murni, tanpa dependensi:

  • auto-detect node hidraw dari VID:PID (0x5131:0x2007)
  • baca sensor Linux: hwmon (CPU = maksimum Tctl/Tccd*, GPU, fan, power), /proc/stat, cpufreq, /proc/meminfo, statvfs("/")
  • bangun report 65 byte sesuai tabel di 6.4, tulis 64 byte payload ke hidraw
  • --dry-run mencetak report + nilai; --listen N membaca pesan device→host (device ini tidak pernah mengirim apa pun); --count, --interval, --unit c|f, --flag-celsius (fidelitas ke aplikasi asli), override tiap field via --cpu-temp dll.
  • self_check() mengunci header, urutan big-endian, dan semantik satuan

analysis/tools/70-gamemax.rules — udev rule TAG+="uaccess" untuk node hidraw. analysis/tools/gamemax-report.service — unit systemd user (padanan schtasks /sc onlogon aplikasi asli), sudah aktif di mesin ini:

systemctl --user status gamemax-report.service
journalctl --user -u gamemax-report -f
systemctl --user disable --now gamemax-report.service   # matikan

Uji yang sudah lolos: dry-run + assert, kirim nyata, device menampilkan load/RPM/suhu sesuai kiriman, dan tampilan mengikuti perubahan nilai.

8. Device: GameMax IceBurg 240 Digital BK

Ditemukan di mesin ini sebagai Bus 001 Device 005: ID 5131:2007 (usb.ids salah menamainya "MSR-101U card reader" — descriptor-nya vendor-defined 0xFF00, 64 byte IN

  • 64 byte OUT, tanpa report ID). Produknya: GameMax IceBurg 240 Digital BK, AIO 240 mm dengan blok LCD; "IceBurg 240 Digital Software" dari halaman produk (gamemaxpc.com/cpu-liquid-cooler/1550.html) adalah PcInfoMonitorPro.exe yang kita bongkar. Layar menampilkan halaman CPU (ikon CPU + load %, suhu besar, RPM, 6 titik indikator halaman) dan menganimasikan busur kiri/kanan.

Verifikasi: setelah gamemax-report.service aktif, device menampilkan suhu/load/RPM dari sensor Linux, mengikuti perubahan nilai, dan berkedip hanya saat nilai statis (perilaku firmware, disepakati dibiarkan apa adanya).