234 lines
8.1 KiB
Markdown
234 lines
8.1 KiB
Markdown
|
|
# Surveillance Client DPI Analysis
|
||
|
|
|
||
|
|
Date: 2026-03-25
|
||
|
|
|
||
|
|
Target binary: `Surveillance_client.exe`
|
||
|
|
|
||
|
|
Analysis method: Ghidra MCP against the already-imported and analyzed program database.
|
||
|
|
|
||
|
|
## Objective
|
||
|
|
|
||
|
|
Determine how the client initializes its UI, whether it already contains any DPI-awareness logic, and what practical patch points exist for making the application usable on high-resolution displays.
|
||
|
|
|
||
|
|
## Executive Summary
|
||
|
|
|
||
|
|
- The binary is a Qt Widgets desktop application, and the available imports strongly suggest an older Qt 4-era codebase.
|
||
|
|
- No direct static use of Windows DPI-awareness APIs was found.
|
||
|
|
- No obvious embedded DPI manifest strings were found in the loaded program strings.
|
||
|
|
- The application persists window geometry and display layout state through `QSettings`, including explicit `QRect` geometry records.
|
||
|
|
- That persistence layer is likely to matter for any DPI patch, because old pixel-based geometry can become incorrect or visually tiny once DPI behavior changes.
|
||
|
|
|
||
|
|
## Confirmed Entry Flow
|
||
|
|
|
||
|
|
The startup chain currently identified is:
|
||
|
|
|
||
|
|
1. `___tmainCRTStartup` at `0x00708d44`
|
||
|
|
2. `qt_startup_dispatch` at `0x00709b00`
|
||
|
|
3. `qWinMain` thunk at `0x00709c02`
|
||
|
|
4. Application main routine at `0x004c7260`
|
||
|
|
|
||
|
|
Notes:
|
||
|
|
|
||
|
|
- `qt_startup_dispatch` converts `GetCommandLineW()` output into a local 8-bit argv-style buffer and forwards execution into Qt startup.
|
||
|
|
- This is a useful early patch region if a future binary modification needs to happen before the first top-level window is created.
|
||
|
|
|
||
|
|
## Evidence This Is An Older Qt Widgets Application
|
||
|
|
|
||
|
|
The import table and strings include multiple indicators that this is not a modern Qt high-DPI-aware build:
|
||
|
|
|
||
|
|
- `QApplication`
|
||
|
|
- `QPlastiqueStyle`
|
||
|
|
- `QProxyStyle`
|
||
|
|
- `QStyleOptionViewItemV4`
|
||
|
|
- `desktop`
|
||
|
|
- `screenGeometry`
|
||
|
|
- `availableGeometry`
|
||
|
|
- `primaryScreen`
|
||
|
|
|
||
|
|
Why that matters:
|
||
|
|
|
||
|
|
- `QPlastiqueStyle` and `QStyleOptionViewItemV4` are strong Qt 4-era signals.
|
||
|
|
- A Qt 4-era app is much less likely to support automatic per-monitor DPI scaling cleanly.
|
||
|
|
- If DPI awareness is turned on without additional UI scaling work, the usual failure mode is a crisp but very small interface.
|
||
|
|
|
||
|
|
## What Was Not Found
|
||
|
|
|
||
|
|
The following searches did not produce evidence of a built-in DPI implementation:
|
||
|
|
|
||
|
|
- `SetProcessDPIAware`
|
||
|
|
- `SetProcessDpiAwareness`
|
||
|
|
- `SetThreadDpiAwarenessContext`
|
||
|
|
- `WM_DPICHANGED`
|
||
|
|
- `devicePixelRatio`
|
||
|
|
- `HighDpi`
|
||
|
|
- `QT_AUTO_SCREEN_SCALE_FACTOR`
|
||
|
|
- `AA_EnableHighDpiScaling`
|
||
|
|
|
||
|
|
I also searched program strings for common manifest content such as:
|
||
|
|
|
||
|
|
- `dpiAware`
|
||
|
|
- `asmv3`
|
||
|
|
- `requestedExecutionLevel`
|
||
|
|
- `trustInfo`
|
||
|
|
|
||
|
|
None of those were found in the loaded strings.
|
||
|
|
|
||
|
|
## Resource Layout
|
||
|
|
|
||
|
|
The PE section layout includes a resource section:
|
||
|
|
|
||
|
|
- `.rsrc: 0x00dd7000 - 0x00df05ff`
|
||
|
|
|
||
|
|
Even with a resource section present, no obvious manifest or DPI-related XML strings surfaced through the Ghidra string search during this pass.
|
||
|
|
|
||
|
|
## Settings And Geometry Findings
|
||
|
|
|
||
|
|
Several settings-related functions were isolated and renamed in the Ghidra database for future work.
|
||
|
|
|
||
|
|
### `init_app_settings_defaults` at `0x0059ca30`
|
||
|
|
|
||
|
|
This function initializes many application settings keys and default values.
|
||
|
|
|
||
|
|
Relevant confirmed keys:
|
||
|
|
|
||
|
|
- `mainwindow/fullscreen`
|
||
|
|
- `mainwindow/size`
|
||
|
|
- `window_status`
|
||
|
|
- `gen/liveviewstatus`
|
||
|
|
- `gen/autolive`
|
||
|
|
- `screenAutoSwitch/interval`
|
||
|
|
- `screenAutoSwitch/forceSync`
|
||
|
|
- `screenAutoSwitch/isOn`
|
||
|
|
|
||
|
|
Relevant confirmed defaults:
|
||
|
|
|
||
|
|
- `mainwindow/size = 0x400 x 0x300` which is `1024 x 768`
|
||
|
|
- `mainwindow/fullscreen = false`
|
||
|
|
|
||
|
|
Interpretation:
|
||
|
|
|
||
|
|
- The main window has a fixed persisted default size in pixels.
|
||
|
|
- That is a strong warning sign for DPI patching, because a legacy saved size can remain visually small after changing DPI behavior.
|
||
|
|
|
||
|
|
### `load_window_status_from_settings` at `0x005a72b0`
|
||
|
|
|
||
|
|
This function reads a `QSettings` array named `window_status` and loads nested UI state.
|
||
|
|
|
||
|
|
Confirmed per-window fields:
|
||
|
|
|
||
|
|
- `windowGeometry`
|
||
|
|
- `isCurWindow`
|
||
|
|
- `isFullScreen`
|
||
|
|
- `isMainWindow`
|
||
|
|
- `maxTabIndex`
|
||
|
|
|
||
|
|
Confirmed nested view/screen fields:
|
||
|
|
|
||
|
|
- `view_status`
|
||
|
|
- `mainview_status`
|
||
|
|
- `screenIndex`
|
||
|
|
- `screenBeginIndex`
|
||
|
|
- `isScreenEnlarge`
|
||
|
|
- `autoSwitchInterval`
|
||
|
|
- `autoSwitchIndependent`
|
||
|
|
- `autoSwitchIsOn`
|
||
|
|
- `stream_status`
|
||
|
|
- `groupChannelID`
|
||
|
|
- `videoIndex`
|
||
|
|
- `isCurSelected`
|
||
|
|
- `isSoundOn`
|
||
|
|
- `Emap_status`
|
||
|
|
- `emapIDIndex`
|
||
|
|
|
||
|
|
Interpretation:
|
||
|
|
|
||
|
|
- The application stores a substantial amount of layout state in settings.
|
||
|
|
- `windowGeometry` is especially important because it appears to be persisted as a `QRect`.
|
||
|
|
- If the process DPI mode changes, previously stored geometry may need migration, scaling, deletion, or selective reset.
|
||
|
|
|
||
|
|
### `save_window_status_to_settings` at `0x005a6170`
|
||
|
|
|
||
|
|
This function writes back the same structures into `QSettings`.
|
||
|
|
|
||
|
|
Interpretation:
|
||
|
|
|
||
|
|
- Even if a DPI hack works visually at first launch, the application can overwrite the new layout with old pixel-based assumptions on exit.
|
||
|
|
- Any durable solution should consider both the load and save side of geometry persistence.
|
||
|
|
|
||
|
|
### `apply_mainwindow_fullscreen_setting` at `0x0047c1f0`
|
||
|
|
|
||
|
|
This function compares a key against `mainwindow/fullscreen` and activates the matching `QAction` when the value is true.
|
||
|
|
|
||
|
|
Interpretation:
|
||
|
|
|
||
|
|
- The UI state is driven through Qt actions, not direct Win32 window management.
|
||
|
|
- That reinforces the view that DPI fixes will likely need to be applied at Qt startup or Qt widget/layout level rather than through a narrow Win32 patch alone.
|
||
|
|
|
||
|
|
## Implications For A DPI Fix
|
||
|
|
|
||
|
|
### Most likely current problem model
|
||
|
|
|
||
|
|
Based on the evidence, the binary looks like a legacy Qt Widgets application with no obvious modern DPI-awareness implementation. That creates two realistic scenarios:
|
||
|
|
|
||
|
|
1. The process is effectively DPI-unaware and Windows bitmap scaling is not being applied in the way the user wants.
|
||
|
|
2. The process is being made DPI-aware somewhere outside the obvious static import path, causing the UI to render at legacy pixel sizes and appear tiny.
|
||
|
|
|
||
|
|
This analysis did not prove which of those two runtime cases is active on the target system. It did establish that the executable itself does not appear to contain a straightforward built-in high-DPI implementation.
|
||
|
|
|
||
|
|
### Why a simple `SetProcessDPIAware` patch is risky
|
||
|
|
|
||
|
|
For an older Qt Widgets app:
|
||
|
|
|
||
|
|
- enabling DPI awareness alone often produces a sharp but tiny UI
|
||
|
|
- stored `QRect` geometry may restore undersized windows
|
||
|
|
- icon sizes, style metrics, and custom-painted controls may remain pixel-based
|
||
|
|
- there is no evidence yet of `WM_DPICHANGED` handling for per-monitor updates
|
||
|
|
|
||
|
|
### What a workable solution will probably require
|
||
|
|
|
||
|
|
At minimum, a successful patch likely needs one of these paths:
|
||
|
|
|
||
|
|
1. A compatibility-style solution that lets Windows scale the app acceptably.
|
||
|
|
2. An early startup patch plus application-wide Qt scaling adjustments before top-level widgets are shown.
|
||
|
|
3. A deeper patch that also normalizes saved geometry and possibly icon/font/style metrics.
|
||
|
|
|
||
|
|
## Ghidra Database Changes Made During Analysis
|
||
|
|
|
||
|
|
The following functions were renamed in the active program database:
|
||
|
|
|
||
|
|
- `0x00709b00` -> `qt_startup_dispatch`
|
||
|
|
- `0x0059ca30` -> `init_app_settings_defaults`
|
||
|
|
- `0x005a72b0` -> `load_window_status_from_settings`
|
||
|
|
- `0x005a6170` -> `save_window_status_to_settings`
|
||
|
|
- `0x0047c1f0` -> `apply_mainwindow_fullscreen_setting`
|
||
|
|
|
||
|
|
Decompiler comments were also added at those entrypoints summarizing their purpose.
|
||
|
|
|
||
|
|
## Current Confidence Level
|
||
|
|
|
||
|
|
High confidence:
|
||
|
|
|
||
|
|
- Qt-based GUI application
|
||
|
|
- older Qt lineage is likely
|
||
|
|
- no obvious static DPI-awareness implementation exists
|
||
|
|
- window geometry persistence is real and important
|
||
|
|
|
||
|
|
Medium confidence:
|
||
|
|
|
||
|
|
- the best durable fix will require more than a manifest-only change
|
||
|
|
- geometry migration/reset will likely be necessary for a clean result
|
||
|
|
|
||
|
|
Low confidence without runtime testing:
|
||
|
|
|
||
|
|
- whether the best final mode is DPI-unaware with OS scaling, system-DPI-aware, or a custom Qt-side scaling patch
|
||
|
|
|
||
|
|
## Recommended Direction
|
||
|
|
|
||
|
|
Treat this as a legacy-Qt DPI retrofit problem, not just a missing API call problem.
|
||
|
|
|
||
|
|
The next pass should focus on:
|
||
|
|
|
||
|
|
- locating the `QApplication` construction site inside `0x004c7260`
|
||
|
|
- locating first top-level window creation/show
|
||
|
|
- tracing where `windowGeometry` is applied to the main window
|
||
|
|
- deciding whether to pursue an OS-scaling strategy or a real application-side scaling patch
|