commit 7ac5c0320dc3da16ffa13ae0b0cb82a6e4d48ff0 Author: Marco Date: Wed Mar 25 16:41:55 2026 +0100 first decomp and analysis diff --git a/Surveillance-Client.gpr b/Surveillance-Client.gpr new file mode 100644 index 0000000..e69de29 diff --git a/Surveillance-Client.rep/idata/00/00000000.prp b/Surveillance-Client.rep/idata/00/00000000.prp new file mode 100644 index 0000000..df524f4 --- /dev/null +++ b/Surveillance-Client.rep/idata/00/00000000.prp @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Surveillance-Client.rep/idata/00/~00000000.db/db.2.gbf b/Surveillance-Client.rep/idata/00/~00000000.db/db.2.gbf new file mode 100644 index 0000000..2bf9afd Binary files /dev/null and b/Surveillance-Client.rep/idata/00/~00000000.db/db.2.gbf differ diff --git a/Surveillance-Client.rep/idata/00/~00000000.db/db.3.gbf b/Surveillance-Client.rep/idata/00/~00000000.db/db.3.gbf new file mode 100644 index 0000000..5d2abc7 Binary files /dev/null and b/Surveillance-Client.rep/idata/00/~00000000.db/db.3.gbf differ diff --git a/Surveillance-Client.rep/idata/~index.bak b/Surveillance-Client.rep/idata/~index.bak new file mode 100644 index 0000000..b1e697f --- /dev/null +++ b/Surveillance-Client.rep/idata/~index.bak @@ -0,0 +1,4 @@ +VERSION=1 +/ +NEXT-ID:0 +MD5:d41d8cd98f00b204e9800998ecf8427e diff --git a/Surveillance-Client.rep/idata/~index.dat b/Surveillance-Client.rep/idata/~index.dat new file mode 100644 index 0000000..ab3e57b --- /dev/null +++ b/Surveillance-Client.rep/idata/~index.dat @@ -0,0 +1,5 @@ +VERSION=1 +/ + 00000000:Surveillance_client.exe:c0a86480f39a29301594652600 +NEXT-ID:1 +MD5:d41d8cd98f00b204e9800998ecf8427e diff --git a/Surveillance-Client.rep/idata/~journal.bak b/Surveillance-Client.rep/idata/~journal.bak new file mode 100644 index 0000000..781ea1b --- /dev/null +++ b/Surveillance-Client.rep/idata/~journal.bak @@ -0,0 +1,2 @@ +IADD:00000000:/Surveillance_client.exe +IDSET:/Surveillance_client.exe:c0a86480f39a29301594652600 diff --git a/Surveillance-Client.rep/project.prp b/Surveillance-Client.rep/project.prp new file mode 100644 index 0000000..d7d126d --- /dev/null +++ b/Surveillance-Client.rep/project.prp @@ -0,0 +1,6 @@ + + + + + + diff --git a/Surveillance-Client.rep/projectState b/Surveillance-Client.rep/projectState new file mode 100644 index 0000000..2275ee1 --- /dev/null +++ b/Surveillance-Client.rep/projectState @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/Surveillance-Client.rep/user/00/00000000.prp b/Surveillance-Client.rep/user/00/00000000.prp new file mode 100644 index 0000000..8acdd40 --- /dev/null +++ b/Surveillance-Client.rep/user/00/00000000.prp @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Surveillance-Client.rep/user/00/~00000000.db/db.1.gbf b/Surveillance-Client.rep/user/00/~00000000.db/db.1.gbf new file mode 100644 index 0000000..b6b2e14 Binary files /dev/null and b/Surveillance-Client.rep/user/00/~00000000.db/db.1.gbf differ diff --git a/Surveillance-Client.rep/user/~index.dat b/Surveillance-Client.rep/user/~index.dat new file mode 100644 index 0000000..b1e697f --- /dev/null +++ b/Surveillance-Client.rep/user/~index.dat @@ -0,0 +1,4 @@ +VERSION=1 +/ +NEXT-ID:0 +MD5:d41d8cd98f00b204e9800998ecf8427e diff --git a/Surveillance-Client.rep/user/~journal.dat b/Surveillance-Client.rep/user/~journal.dat new file mode 100644 index 0000000..4526d56 --- /dev/null +++ b/Surveillance-Client.rep/user/~journal.dat @@ -0,0 +1,2 @@ +IADD:00000000:/udf_c0a86480f39a29301594652600 +IDSET:/udf_c0a86480f39a29301594652600:c0a86480c18d30858376112400 diff --git a/Surveillance-Client.rep/versioned/~index.bak b/Surveillance-Client.rep/versioned/~index.bak new file mode 100644 index 0000000..b1e697f --- /dev/null +++ b/Surveillance-Client.rep/versioned/~index.bak @@ -0,0 +1,4 @@ +VERSION=1 +/ +NEXT-ID:0 +MD5:d41d8cd98f00b204e9800998ecf8427e diff --git a/Surveillance-Client.rep/versioned/~index.dat b/Surveillance-Client.rep/versioned/~index.dat new file mode 100644 index 0000000..b1e697f --- /dev/null +++ b/Surveillance-Client.rep/versioned/~index.dat @@ -0,0 +1,4 @@ +VERSION=1 +/ +NEXT-ID:0 +MD5:d41d8cd98f00b204e9800998ecf8427e diff --git a/docs/surveillance-client-dpi-analysis.md b/docs/surveillance-client-dpi-analysis.md new file mode 100644 index 0000000..3f79b10 --- /dev/null +++ b/docs/surveillance-client-dpi-analysis.md @@ -0,0 +1,234 @@ +# 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 \ No newline at end of file diff --git a/docs/surveillance-client-dpi-next-steps.md b/docs/surveillance-client-dpi-next-steps.md new file mode 100644 index 0000000..c890f57 --- /dev/null +++ b/docs/surveillance-client-dpi-next-steps.md @@ -0,0 +1,152 @@ +# Surveillance Client DPI Next Steps + +Date: 2026-03-25 + +## Goal + +Find the lowest-risk path to make the legacy client usable on high-resolution monitors without breaking multi-window video layout behavior. + +## Recommended Work Plan + +### Phase 1: Establish Runtime Baseline + +1. Test the current executable under Windows with no compatibility overrides. +2. Test with external manifest variants or compatibility settings that force: + - DPI unaware + - System DPI aware + - Per-monitor aware +3. Capture screenshots and note: + - overall UI size + - text crispness + - icon scaling + - video view scaling + - behavior when moving between monitors with different DPI + +Reason: + +- This determines whether the practical answer is an OS-scaling solution or a true binary patch. +- For a Qt 4-era application, this experiment can save a lot of unnecessary reverse engineering. + +### Phase 2: Finish Startup Mapping In Ghidra + +1. Trace `0x004c7260` in more detail until the `QApplication` constructor call is isolated. +2. Identify the first top-level widget or main window constructor. +3. Identify where `show`, `showNormal`, or `showFullScreen` is first invoked for the main UI. +4. Identify where `window_status` data is applied back onto live windows after `load_window_status_from_settings`. + +Reason: + +- If a binary patch is needed, the ideal injection point is after `QApplication` exists but before the first user-visible window is shown. + +### Phase 3: Decide On Patch Strategy + +#### Option A: Keep The App DPI-Unaware And Let Windows Scale It + +Use this if: + +- the UI becomes acceptably sized +- video rendering remains correct +- visual blur is acceptable + +Advantages: + +- lowest engineering risk +- no need to understand all custom Qt painting and layout code +- least likely to break camera preview surfaces + +Risks: + +- text and controls may remain blurry +- behavior may vary by Windows version + +#### Option B: System-DPI-Aware Patch Plus Geometry Reset/Migration + +Use this if: + +- the app looks tiny now because it is already treated as DPI aware in some configuration +- Qt scales fonts and base metrics acceptably at startup when system DPI is exposed + +Required work: + +1. Add or patch early DPI-awareness setup before UI creation. +2. Clear or rescale persisted `windowGeometry` and related layout state. +3. Verify icons, toolbars, tab metrics, and preview panes at 125%, 150%, and 200%. + +Risks: + +- still no clean per-monitor behavior +- custom pixel-sized controls may remain too small + +#### Option C: Application-Side Qt Scaling Retrofit + +Use this if: + +- Windows scaling is visually unacceptable +- a crisp interface is required + +Required work: + +1. Patch after `QApplication` creation. +2. Scale fonts globally. +3. Scale icon sizes and style metrics. +4. Scale or invalidate stored `QRect` window geometry. +5. Verify custom widgets and video panes. + +Likely implementation ideas: + +- patching application font defaults +- patching style pixel metrics through an existing proxy style path +- scaling saved geometry before it is applied +- forcing a first-run reset of `window_status` + +Risks: + +- highest reverse-engineering effort +- most likely to require multiple iteration cycles + +## Specific Reverse-Engineering Targets + +The next Ghidra pass should answer these exact questions: + +1. Where is `QApplication` constructed? +2. What function creates the main window? +3. Where does the program apply `windowGeometry` from `QSettings`? +4. Are there custom widgets using hardcoded pixel sizes? +5. Are video preview surfaces tied to raw pixel assumptions that could regress under scaling? + +## Settings To Watch Closely + +These keys are likely to interfere with a DPI patch and should be considered for migration or reset: + +- `mainwindow/size` +- `mainwindow/fullscreen` +- `window_status` +- `view_status` +- `mainview_status` +- `screenIndex` +- `screenBeginIndex` +- `isScreenEnlarge` + +## Practical Recommendation + +Start with a runtime experiment matrix before editing the binary. + +If Windows-side scaling already produces acceptable results, stop there. + +If it does not, the next best path is: + +1. isolate `QApplication` creation +2. isolate main-window show +3. patch startup before show +4. neutralize or migrate persisted geometry +5. validate video panes and multi-monitor layout behavior + +## Exit Criteria For A Successful Fix + +The fix should only be considered successful if all of the following hold: + +1. Main UI is readable at common desktop scales such as 125%, 150%, and 200%. +2. Camera preview panes are not clipped or distorted. +3. Multi-window layouts still restore correctly. +4. Moving the app between monitors does not make it unusably small. +5. Saved geometry does not trap the app in an old tiny layout after restart. \ No newline at end of file