Some time ago, my friend Jupiter suggested we take apart Total’s licensing algorithm. After some brainstorming, we wrote a license key file generator. Everything would have been fine, if not for the fact that the licensing scheme is built on a public‑key cryptosystem—LUC. And of course, to get through the licensing check, you need the keys.
LUC is an RSA-like cryptosystem. Its key difference from RSA is that it uses Lucas sequences instead of modular exponentiation. As with RSA, generating the private key requires knowing the factors (P and Q), which you can obtain by factoring the modulus (N). In our case, the modulus is 832 bits long. Naturally, neither I nor Jupiter have that kind of computational power. And we haven’t saved up for a quantum computer yet. 🙂
To address this problem, we’ll generate our own LUC key pair. We’ll encrypt the license with the private key, and the program will decrypt it using the public key. To ensure the public key is accepted, we’ll patch it in memory.
Besides LUC, Total also includes self‑protection mechanisms, including anti‑tampering of the executable. You can, of course, brute‑force patch the binary, but that’s just a kludge that won’t generalize and defeats a universal bypass.
warning
This article is published for educational purposes only. The editors accept no responsibility for any harm resulting from the materials in this publication. The article intentionally does not cover the licensing algorithm itself; instead, it demonstrates the practical aspects of implementing a protection bypass using the proxy DLL technique.
What’s the plan?
Our goal is to replace the (N) module in the program’s executable without compromising its integrity. That way, our generated key file will decrypt correctly and the program will be registered.
There are two ways to solve this problem:
- Implement loaders for the program’s x86 and x64 builds.
- Develop proxy DLLs that perform the same function as the loaders.
Both approaches let you update the program without hassle. I prefer the second one—it’s more convenient. With this approach, you don’t need to edit the program shortcuts to change the target from Total’s executable to our loader. You just copy the DLLs and the key file into the program’s installation folder.
Tools
- x64dbg — debugger
- MASM (x86) — assembler
- MASM (x64) — assembler
- wincmd.key — a license key file for the program, generated by the keygen that Jupiter and I made
Process
I downloaded the latest beta from the official site, which includes both 32-bit and 64-bit versions. Installed it to the directory suggested by the installer (C:\
).

Now launch either TOTALCMD.
or TOTALCMD64.
—it doesn’t matter which. You’ll get a window like this.

As expected. 😉 Now run Total under a debugger and open the Symbols tab.

On the left side of the window, you can see the modules (DLLs) loaded into the process’s memory. Of all the modules, we’re only interested in two dynamic libraries: version.
and winspool.
.
Don’t be confused by the fact that winspool.
doesn’t have a .
extension; internally it’s structured like a standard dynamic library. These two modules will be the candidates for creating same-name proxy DLLs for Total.
info
We’re building two modules because the program has both x86 and x64 versions. Each one will use a proxy DLL that matches its bitness.
How the Proxy DLL Mechanism Works
The proxy DLL technique hinges on a specific behavior of the Windows loader (NTLDR or NT Loader) when it maps DLL modules into a process’s memory.
In the Windows loader, this is handled by the LdrLoadDll
API, which resides in ntdll.
. Higher-level wrappers around this API include LoadLibrary
and LoadLibraryEx
.
One of the steps in loading an executable (an EXE module in our case) is populating its import table with the addresses of the APIs it needs from DLLs. At the start of this process, LdrLoadDll
looks up each module (DLL) by its file name—e.g., version.
—which appears in the import table as an ASCII string. LdrLoadDll
first searches the current directory of the newly created process, in our example C:\
. If the module isn’t found there, it continues based on the process bitness (x86 or x64) by searching the system directory (C:\
or C:\
). If the DLL still isn’t found, an error is raised.
LdrLoadDll
lets you load modules with the same name from different directories into the address space of a process you’ve created. For example, in our case the proxy DLL loads NTDLL.
from the directory where TOTALCMD.
resides, while the original DLL (from the system directory) is loaded by the proxy DLL via the LoadLibrary
API, passing the absolute path to the original DLL. This is another detail that makes a proxy-DLL mechanism possible. You’ll see how it works from the proxy DLL code below. 🙂
Continuing. In the TOTALCMD.
and TOTALCMD64.
processes, both DLLs are present. For TOTALCMD.
we’ll use version.
, and for TOTALCMD64.
we’ll use winspool.
.
In Total Commander, the module (N) involved in decrypting the key file (wincmd.
) is represented as a string literal encoded in ASCII.
AAD4474DC8387E81BB095D810F4F4F21D5D7CCC756E3D6E5DEE48AC000C25AA0EFAD0AD3A5AC46F15B50249597461BBB87CDC3F1BA37C17A9A207A3603E38E718F9927A5EB38005D8B72EAFDC63931C3D93C1FAD457A17CA85BEB40F3FA9152770DAC12E8E3B912D
To properly decrypt our key, replace it with our modulus (N):
E813039FB5F248DDA582F1C411D3B5B7A4C97CBB6982388EB354A8B78324A6A7B494ABAB4A0A97728BAC585FCD856D2173F4C3ADE89E8176AE53F7BF7AEC39FCACEC907829B31FE1C3BB3E2E4C30925525655F967B52A0318FCE0BA0BAE065D8A68DBE86167F67A1
Now once again, run both builds under the debugger one at a time to determine where the target module (N) is located—that is, in which section of the executable.
Launch the x86 version and go to the Memory Map tab. Press Ctrl + B to open the binary search window for the process memory, copy the original module name (N), and paste it into the ASCII field.

Click OK, and the References tab will open with the search results.

We can see the address where module (N) was found — 0x004E219C.

Navigate to the memory dump view at the given address and scroll up.


We see the address 0x00401000. This is the starting address of the section that contains module (N).
Go back to the Memory Map tab and you’ll see that the address 0x00401000 corresponds to the first section of the executable TOTALCMD.
— CODE
.

For the x64 build, repeat the same steps with the debugger.
As a result, we determine that the module’s ASCII string (N) for the x86 build is located in the CODE
section (0x00401000
), while for the x64 build it’s in the .
section (0x0000000000AD9000
).
Alright, we’ve got everything we need to build a proxy DLL. Let’s start coding. 🙂
Implementation
We’ll walk through the code for the x86 version, specifically version.
. The x64 build is analogous. The proxy DLL’s entry point (EntryPoint
). Everything here is standard.

Using the DisableThreadLibraryCalls API isn’t strictly necessary. I used it to disable the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications, just in case.
Next, we proceed to MainProc.

Here I declare global variables to hold pointers to the original API functions.
I allocate memory to store the retrieved path to the original version.dll.

Here I’ve annotated every step of the MainProc routine’s execution.

Right below MainProc, I declare exported functions that make unconditional jumps (JMP) from the proxy DLL to the original DLL. The version.def file specifies the names of the proxy DLL’s exported functions, matching the function names in the original DLL.
LIBRARY version
EXPORTS
GetFileVersionInfoA=__GetFileVersionInfoA@0
GetFileVersionInfoByHandle=__GetFileVersionInfoByHandle@0
GetFileVersionInfoExW=__GetFileVersionInfoExW@0
GetFileVersionInfoSizeA=__GetFileVersionInfoSizeA@0
GetFileVersionInfoSizeExW=__GetFileVersionInfoSizeExW@0
GetFileVersionInfoSizeW=__GetFileVersionInfoSizeW@0
GetFileVersionInfoW=__GetFileVersionInfoW@0
VerFindFileA=__VerFindFileA@0
VerFindFileW=__VerFindFileW@0
VerInstallFileA=__VerInstallFileA@0
VerInstallFileW=__VerInstallFileW@0
VerLanguageNameA=__VerLanguageNameA@0
VerLanguageNameW=__VerLanguageNameW@0
VerQueryValueA=__VerQueryValueA@0
VerQueryValueW=__VerQueryValueW@0
And the proxy DLL’s main function is ReplaceModulus.

In the proxy DLL’s data section, I have the original module (Original) and the module (New) that should replace the original.

Here too, every step of the code’s execution is commented.
Conclusion
The result of all the steps above is a registered version of the program. And in this setup, you can update the app without worrying that the registration will get wiped. 🙂
Copy three files into the Total Commander folder: your license key wincmd.
and the DLLs version.
and winspool.
. Then start the program.

Task Manager shows that both DLLs are loaded into the process.

We’re happy. 🙂
Summary
As you can see, the proxy DLL mechanism is a convenient and powerful tool. It lets you seamlessly emulate original functions while easily modifying data and code in the process’s memory.
[ Source Code and KeyYou can download the program’s source code and a key for hands-on practice at this link. Please note that all materials are provided for educational purposes only. The editorial team is not responsible for any harm caused by the materials in this article.
Password: the site’s domain name.