These are very disorganized because I wrote these as I reversed various bits and pieces. If I'm wrong about something, please let me know so I can forget to update this.
For me this was the Achilles' heel, Crackproof creates a debug log if a certain folder in %temp% is present. The folder name is 12 hex characters long, and different between executables. The easiest way to find it is to break on/hook CreateFileW.
Once you create it, any Crackproofed modules will spit out logs as they unpack. Lines contain status codes, indicating roughly what the unpacker is doing at a given time (see below). Lines with additional debug information are also included, sometimes they can be very handy.
Crackproof will also send an encrypted log to \\.\mailslot\ErrLog-Pec<number>, but it's not as useful. Both share a common 9-digit error code format:
AAA-BBB-CCC
- AAA - Corresponds to status code of the unpacker during failure
- BBB - Sub-stage
- CCC - ?
You can create a mailslot, decrypt these logs, then convert the 9-digit code to a status code, but why bother?
If you break as soon as status code is written, then search for (WORD)(status_code << 4 | 1) as bytes in the binary, you will easily find the corresponding stage of the unpacker. Knowing this made my life 10000x easier, thank you Hypertech.
This isn't a comprehensive list, there are a ton of stages and each is configurable by the various options passed to Crackproof's obfuscator, sometimes you may not see ones that are in this list. I only chose to highlight ones that are notable/important for this reason.
| Code | Note |
|---|---|
| 200 | Startup |
| 210 | Check Host Architecture |
| 52F | Check for Kernel Debugger |
| 540 | Check VMWare Backdoor (and/or processor flags) |
| C00 | OS Minimum Version Check |
| C01 | Check for testsigning or disableintegritychecks boot options |
| C03 | Initialize new Htsysm driver |
| C04 | Set Protected Process flag, add hooks |
| A0F | Check for injected DLLs |
| A09 | Check hardware registry for VM |
| A08 | Copy ntdll/kernel32 code from disk to memory |
| A04 | Copy ntdll/kernel32 code from disk to memory, die if patched |
| A07 | Kill injected threads |
| A01 | Die if injected threads found |
| A03 | Check if parent process is cmd.exe or explorer.exe |
| A11 | Check if host process of DLL has peC section or imports from KeRnEl32.dLl |
| B00 | OS Compatible Version Check |
| B21 | Load HtsyskNT.dll |
| BD0 | Ensure that C:\Windows\msc.log.log does not exist |
| BE0 | Check for SoftICE/Syser debugger |
| BB0 | Load HtpecmNT.dll |
| 5C0 | Load Runtime DLLs (will log missing DLLs) |
| 640 | Decrypt executable pages |
| 655 | Relocation |
| 840 | Install SEH hook, encrypt executable pages again |
| 280 | Jump to OEP |
Crackproof manual maps DLLs for some of its extended functionality. The function HtdpsCmnGetFileInfo is called with a 2-letter module code, and this loads the DLL into memory along with retrieving its entrypoint from the PE header. These DLLs are a bit difficult to find in memory, as they can have the MZ and PE magic values zeroed out, but they are otherwise very easy to extract and examine. Using the struct passed to the internal module loader is the easiest way to locate them.
| Module Code | Name | Status Code | Notes |
|---|---|---|---|
it |
HtpecIt.dll |
Axx |
Anti-tamper, anti-injection, anti-VM |
dt |
HtdpStub2.dll |
Additional loader code | |
cm |
Bxx |
Old Htsysm driver usermode init code | |
dm |
Cxx |
New Htsysm driver usermode init code |
This driver's main feature is allowing any process to run kernel-mode shellcode with an unauthenticated IOCTL. Crackproof uses this to manual-map kernel-mode DLLs, as well as to call the _FarEntry@0 export in these DLLs, which run code to implement the rest of its kernel-mode functionality.
| Module Code | Name | Notes |
|---|---|---|
sk |
HtsyskNT.dll |
Set up manual mapper for future modules, provide basic kernel I/O and memory functions |
pm |
HtpecmNT.dll |
Something to do with monitoring for and terminating processes (kill analysis tools?) |
New Htsysm is much more restricted, it just lets processes write to their EPROCESS, allowing them to edit any information about themselves.
Only thing that is done with this is setting Protected Process flag to prevent usermode tampering. You can undo it with kernel/HV debugger, PPLcontrol, or hooking DeviceIoControl.
Only problem is, any program that can correctly encrypt its process ID can also edit its EPROCESS, or any kernel memory for that matter. You can also inject a DLL, wait to gain PP status and then do fun things to the system. Despite this glaring vulnerability, it still manages to be WHQL signed. Thanks Bill Gates for the free BYOVD.
It also seems like some functions like NtCreateSection wouldn't work in PP mode, so they hook these functions to disable PP, call the original function, and re-enable. The list of these hooked functions is given in the debug log.
The following registry values are checked:
HKLM\Hardware\Description\SystemSystemBiosVersion
HKLM\SYSTEM\CurrentControlSet\Control\SystemInformationSystemProductName
HKLM\Hardware\Description\System\BIOSSystemProductName
The following strings are searched for only at the beginning of these values:
Virtual
VMware
Bochs
VBOX
VRTUAL
Microsoft Hyper-V
Only problem is that VMWare has VMWare string at the end of its BIOS version, so this check fails to catch it if you set SMBIOS.reflectHost = "TRUE".
Another earlier check is for VMWare backdoor, used by VMWare Tools. Set monitor_control.restrict_backdoor = "TRUE" in the .vmx file to get around this and don't install Tools in the VM. CPU flags are also sometimes checked at this stage, so make sure that VT-x is enabled in the VM and check that you don't see Virtual Machine: Yes in Task Manager.
You can also set SMBIOS and BIOS information in QEMU to similarly get around this check. As for other VM software, I don't use them so I have no idea.
Executable sections are protected with per-page encryption. Page access is set to PAGE_NOACCESS, when execution jumps to one of these pages then ACCESS_VIOLATION exception is handled to decrypt the page then resume execution.
Exception handling is done by patching ntdll!KiUserExceptionDispatcher to jump to Crackproof's exception handler. Once it finishes, it returns to allow normal SEH. This technique allows the exception handler to hide from any SEH detection tools, and it gains maximal priority over SEH hooks, since the kernel jumps directly here when passing exceptions to usermode.
Since this is an optional feature, Crackproof decrypts the protected section first, then if this feature is enabled, it re-encrypts the section page-by-page. Presumably, they realized that you could just dump the binary before this happens, so they added a feature to randomly XOR certain bytes so your dump would be ruined, but it's not terribly difficult to undo.