
Thick client penetration testing targets desktop applications that run real logic on the user's machine instead of in a browser. Think trading terminals, ERP front-ends, healthcare apps, and admin consoles built in .NET, Java, or native C/C++. Because the binary, its config, and often credentials all sit on the host, you get a much larger local attack surface than a typical web app.
This guide walks the methodology end to end: mapping two-tier versus three-tier architecture, intercepting both proxy-aware and proxy-unaware traffic, digging through local storage and the registry, decompiling managed binaries, and abusing DLL search order. It names the exact tools for each step so you can build a repeatable workflow.
Thick client penetration testing is the security assessment of a fat or rich desktop application that executes business logic locally and communicates with one or more backend services. Unlike a thin client (a browser rendering server-side pages), a thick client ships compiled code, local config, and sometimes an embedded database to the endpoint.
That changes your scope. You are testing the binary, the data it writes to disk and the registry, the memory it holds at runtime, and the network protocol it speaks, which is frequently a custom TCP protocol rather than plain HTTP. The discipline overlaps with both application and host testing, and it sits alongside other specialized engagements you can read about in our overview of types of penetration testing.
The architecture decides how data flows and where you intercept it. A two-tier (client-server) app talks directly to a database. The client holds the DB connection string and often the SQL, so a decompile or a memory dump can hand you database credentials and let you query the backend directly, bypassing application-layer controls entirely.
A three-tier app inserts an application server between the client and the database. The client calls an API or a middleware service, and the DB credentials live server-side. Here your tampering happens at the API boundary, which is closer to web and API testing. The same broken-object-level-authorization issues you would hunt in network and service testing apply once you reach that tier.
Start by classifying the traffic, then pick the right interception method. If the app speaks HTTP/HTTPS and honors the system proxy, point it at Burp Suite and install Burp's CA so you can read TLS. Many thick clients ignore proxy settings, so you need lower-level tools.
For proxy-unaware or non-HTTP protocols, Echo Mirage and Wireshark earn their keep. Echo Mirage hooks the application's socket calls and lets you view and edit raw traffic, including custom TCP protocols. Wireshark captures everything on the wire for protocol analysis. When the app pins or uses non-HTTP transport, Frida lets you hook the TLS or send/recv functions at runtime to dump and modify payloads before encryption.
Insecure local storage is where thick clients leak the most, because developers assume the user's machine is trusted. You routinely find credentials, API keys, and connection strings sitting in cleartext config files, INI files, the Windows registry, or an embedded SQLite database. Sometimes they are base64-encoded and called encryption.
Enumerate everything the app writes. Use Process Monitor to watch file and registry activity at launch and login, then inspect each artifact. Check %APPDATA%, %LOCALAPPDATA%, ProgramData, and HKCU/HKLM registry hives. CFF Explorer and a hex editor help you pull strings and resources out of the binary itself, where hardcoded secrets love to hide.
Your decompiler depends on the runtime. For .NET (managed) binaries, dnSpy and ILSpy decompile assemblies back to near-original C# or VB, so you can read logic, patch checks, and find secrets. For Java thick clients, JD-GUI or CFR recover source from class files. For native C/C++ binaries, IDA Pro or the free Ghidra give you disassembly and decompilation to pseudo-C.
Reverse engineering exposes client-side authentication, license checks, hidden features, and crypto routines you can then attack. When obfuscation gets in the way, attach Frida or a debugger to read values at runtime instead of statically. This same instrument-at-runtime mindset shows up across modern offensive work, including the AI-driven approach in our guide to agentic pentesting.
DLL hijacking abuses the Windows library search order: if an application loads a DLL by name without a full path, and an attacker can drop a malicious DLL earlier in the search path, the app loads attacker code with its own privileges. In a thick client install that writes to a world-writable directory, this is a fast path to code execution and privilege escalation.
Hunt for it with Process Monitor filtered on CreateFile or LoadImage events ending in NAME NOT FOUND for .dll files. Each missing DLL in a writable path is a candidate. Confirm by planting a proof-of-concept DLL that pops calc or logs to a file. Also check for unquoted service paths and insecure file permissions on the install directory, which compound the impact.
A good engagement delivers reproducible findings mapped to impact, not just a tool dump. Each issue should include the artifact (file, registry key, packet, or function), the steps to reproduce, the privilege or data it exposes, and a concrete fix. Group them by the categories above so the client can prioritize.
Tie remediation to standards where you can: OWASP ASVS for storage and crypto controls, and CWE references for DLL hijacking (CWE-427) and cleartext storage (CWE-312). For teams that want this validation running continuously rather than once a year, see how we frame ongoing network and host testing and feed results into a single remediation queue.