top of page

Software Cracking

Software Cracking | Black Hat HQ

Software Cracking For Hackers


Software cracking means bypassing license/registration checks, trial limitations, or copy protection to assess the security of software protection mechanisms. This is an article/guide on the art of software cracking, cracking software.


  1. Reconnaissance Phase (Before Cracking)


Identify Protection Type


bash

# Check packer/protector
exiftool target_setup.exe | grep -i "packer\|compiler\|protector"
exiftool target_setup.exe | grep -i "UPX\|Themida\|VMProtect\|Enigma\|Obsidium\|Armadillo"

# Section analysis (commercial protectors have telltale sections)
objdump -p target_setup.exe | grep -E "\.text|\.vmp|\.themida|\.enigma|\.packed"

# Entropy check (high = packed/protected)
binwalk -E target_setup.exe

Common Protectors & Cracking Difficulty


Protector

Difficulty

Detection

Bypass Technique

Time

None (native)

Easy

Standard PE

Patch comparison

10 min

UPX

Very Easy

UPX0/UPX1 sections

upx -d

1 min

Enigma

Medium

enigma section

API hooking

2-4 hrs

VMProtect

Hard

vmp0/vmp1 sections

Memory dump + rebuild

8+ hrs

Themida

Hard

themida section

Advanced unpacking tools

8+ hrs

Obsidium

Medium-Hard

Custom sections

Debugging + patching

4-6 hrs


  1. Unpacking


UPX (Most Common)


bash

# Simple unpack
upx -d packed.exe -o unpacked.exe

# Manual unpack if UPX modified
# Dump from memory via OllyDbg/x64dbg at OEP

Manual Unpack (Generic)


bash

# Tools needed:
# - x64dbg (Windows) or GDB (Linux)
# - Scylla (import reconstructor)
# - Process Dumper

# Workflow:
# 1. Load in debugger → break at OEP (Original Entry Point)
# 2. Memory dump at OEP
# 3. Fix imports with Scylla
# 4. Rebuild PE

Finding OEP (pushad/popad pattern):


# In x64dbg, look for:
popad         ; Restore registers
jmp OEP       ; Jump to original code
# Set breakpoint on popad → step to OEP → dump

Automated Unpacking


bash

# Generic unpacker
sudo apt install de4dot

# .NET unpacking
de4dot -f protected_app.exe -o unpacked_app.exe

# Universal unpacker
# Use: UniExtract 2

  1. Static Analysis: Finding License Checks


String-Based Checks


bash

strings -n 6 unpacked_app.exe | grep -iE "trial|expired|license|demo|registered|unregistered|invalid|valid|key|serial|activate|registration"

# Look for comparison results and jump patterns
strings unpacked_app.exe | grep -iE "success|failure|error|welcome|thank|purchase|buy now"

Import Analysis


bash

objdump -p unpacked_app.exe | grep -E "GetTickCount|time|date|registry|CreateFile|RegQueryValue"

Suspicious imports for license checks:


Import

Purpose

GetTickCount

Time-based trial limit

time

Date checking

RegOpenKeyEx

Registry license storage

CreateFile

License file reading

MessageBox

"Invalid key" dialog


Ghidra/IDA Workflow


bash

# 1. Load unpacked binary
# 2. Search strings → find license-related strings
# 3. Follow cross-references to check routines
# 4. Look for strcmp/memcmp calls near those strings
# 5. Identify conditional jump that decides "registered" vs "trial"

  1. Patching: Classic Byte-Level Cracking


NOP-Out Jump Instructions


bash

# Scenario: "Invalid license" → JNZ (jump if not zero) at 0x4012A0
# Change: 75 XX (JNZ) → 90 90 (NOP)

# Using radare2:
r2 -w unpacked_app.exe
[0x004012a0]> s 0x004012a0
[0x004012a0]> wa nop          # Write NOP (0x90)
[0x004012a0]> q

# Or using dd:
echo -ne '\x90\x90' | dd of=unpacked_app.exe bs=1 seek=$((0x4012A0)) conv=notrunc

Force Jump Pattern


bash

# Change JZ (jump if zero) to JMP (unconditional jump)
# JZ = 74 XX, JMP = EB XX

# Using xxd:
printf '\xEB' | dd of=app.exe bs=1 seek=$((0x4012A0)) conv=notrunc

# Common patches:
# JNZ → NOP     : disable failed check
# JZ → NOP      : disable success check
# JZ → JMP      : always jump to success
# CMP → XOR     : force equal comparison

Common Patch Table


Original

Patched

Effect

75 XX (JNZ)

90 90 (NOP NOP)

Skip failure path

74 XX (JZ)

EB XX (JMP)

Always jump to success

0F 85 XX XX

0F 84 XX XX

Invert JNE→JE

3B C8 (CMP)

33 C0 (XOR EAX,EAX)

Force zero compare


  1. Dynamic Analysis: Runtime Patch


x64dbg Workflow (Windows)


bash

# 1. Open app.exe in x64dbg
# 2. Set breakpoint on:
#    - GetTickCount (trial timer)
#    - strcmp/strncmp (key compare)
#    - CreateFile (license file check)
#    - MessageBoxA (error dialogs)

# 3. Run app → enters license/validation
# 4. Check stack/registers at breakpoints
# 5. Modify EAX/EFLAGS to pass checks
# 6. Right-click → "Fill with NOPs" on jump
# 7. Right-click → "Patch → Apply patches to file"

GDB Workflow (Linux)


bash

gdb ./target_binary

# Set breakpoints on strcmp (common license check)
(gdb) break strcmp

# Run
(gdb) run

# When breakpoint hits, examine arguments
(gdb) print (char*)$rdi     # First string
(gdb) print (char*)$rsi     # Second string (your input)

# Override comparison result (force equal)
(gdb) set $eax=0
(gdb) continue

# Patch binary in memory (writes to file)
(gdb) set write on   # Enable writing
(gdb) set {int}0x4012A0=0x90909090

API Monitor (Quick Win)


bash

# API Monitor captures all API calls
# Search for "RegQueryValueExA" → see what registry key it reads
# Search for "CreateFile" → see what license file it opens
# Search for "GetTickCount" → see when timer was set

# Then create fake registry key/license file to bypass

  1. Time-Based Trial Bypass


Registry Manipulation


bash

# Monitor registry reads with Process Monitor or API Monitor
# Find trial start date → modify it

# Typical registry locations:
HKCU\Software\{Company}\{App}\TrialStart
HKCU\Software\{Company}\{App}\FirstRun
HKLM\SOFTWARE\{Company}\{App}\InstallDate

# Set date back:
# PowerShell: Set-ItemProperty -Path "HKCU:\Software\App" -Name "TrialStart" -Value "0"

File Date Manipulation


bash

# If app checks file creation date
# Change date of app executable to trick timer:

# Linux:
touch -t 202401010000 app.exe

# Windows PowerShell:
(Get-Item app.exe).CreationTime = Get-Date "2024-01-01"

Time-Jump (Debugger)


bash

# In x64dbg, break on GetTickCount
# Modify return value in EAX to trick trial logic
# Or: NOP out the timer check entirely

  1. Keygen-Like Analysis


Recover Algorithm from strcmp


bash

# 1. Break on strcmp with valid license key
# 2. Examine second argument (expected key)
# 3. Follow back to understand generation

# If key is hashed/derived from name:
# Find hash algorithm (MD5? SHA1? Custom XOR?)
# Write Python script to generate valid keys

Example: Simple XOR Keygen


python

#!/usr/bin/env python3
# Extracted from binary analysis (pseudocode)
# key[i] = username[i] XOR 0x42

def generate_key(username):
    key = ""
    for c in username:
        key += chr(ord(c) ^ 0x42)
    return key

name = "Admin"
license_key = generate_key(name)
print(f"Generated key for {name}: {license_key}")

  1. Automated Cracking Tools (Quick Assessment)


OllyDbg + OllyScript


bash

# Auto-patcher scripts
# Push "OllyScript" → run script that:
# - Skips trial checks
# - Patches JNZ to JMP
# - NOPs timer calls

Universal Patcher Script


bash

#!/bin/bash
# Patch common trial patterns

FILE=$1
if [ -z "$FILE" ]; then
    echo "Usage: $0 target.exe"
    exit 1
fi

# Common NOP patterns
echo "Patching trial checks..."
# Pattern: 75 XX (JNZ after license check)
xxd -p "$FILE" | tr -d '\n' | sed 's/75\([0-9a-f]\{2\}\)/9090/g' | xxd -r -p > "$FILE.patched"
# Pattern: 0F 85 XX XX XX XX (JNE near) → NOP
xxd -p "$FILE.patched" | tr -d '\n' | sed 's/0f85\([0-9a-f]\{8\}\)/909090909090/g' | xxd -r -p > "$FILE.patched2"

echo "Patched file: $FILE.patched2"

Complete Pentest Workflow


bash

Phase 1: Recon
├── file target_app.exe
├── strings target_app.exe | grep -iE "trial|license|error|success"
├── objdump -p target_app.exe | grep -iE "section|packer"
├── exiftool target_app.exe | grep -i packer

Phase 2: Unpack (if needed)
├── upx -d target_app.exe -o unpacked.exe
├── OR: x64dbg memory dump + Scylla import rebuild

Phase 3: Static Analysis
├── r2 -qc "aaa; izz~license; izz~trial; izz~key" unpacked.exe
├── Ghidra: decompile → find check functions → locate jumps
├── Identify patch candidates

Phase 4: Dynamic Analysis (Sandbox)
├── x64dbg: break on strcmp → observe license compare
├── API Monitor: capture registry/file reads
├── Trial reset: modify registry/timestamps

Phase 5: Patch
├── NOP jump instructions
├── OR force JMP to success path
├── Save patched binary as evidence

Phase 6: Report
├── Vulnerability: License check bypass via byte patch
├── Method: JNZ → NOP at offset 0x4012A0
├── Severity: CVSS 6.5 (Medium) - Authentication bypass
├── Fix: Implement server-side license validation + obfuscation

Anti-Cracking Protections & Evasion


Protection

Bypass Technique

Debugger detection (IsDebuggerPresent)

Patch check → NOP or return FALSE

Integrity checks (CRC of code)

Run CRC check → patch CRC or recalculate

Anti-dump (erase PE header in memory)

Use Scylla or advanced dumpers

Virtual machine detection

Patch hardware check → force return "physical"

API hooking detection

Use kernel debugger (WinDbg) instead


Anti-Debug Bypass:


bash

# In x64dbg, use ScyllaHide plugin
# Or patch IsDebuggerPresent:
# In Ghidra, find call to kernel32.IsDebuggerPresent
# Change: call → XOR EAX,EAX (force return 0)

Reporting Template


FINDING: License/Registration Bypass
=====================================
Application: ExampleApp v3.2.1
Protection: Standard trial (no packer)
Vulnerability: Client-side license validation

ANALYSIS:
- Binary: unpacked (no packer detected)
- License check: strcmp at 0x004012A0
- Bypass: JNZ (0x75 0x0C) → NOP (0x90 0x90)
- Result: Full functionality without valid license

EVIDENCE:
- Original bytes at 0x004012A0: 75 0C
- Patched bytes: 90 90
- Screenshot: Application shown as "Registered" after patch

SEVERITY: CVSS 6.5 (Medium)
- Vector: AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
- Impact: Full feature access without payment

RECOMMENDATION:
- Move critical validation to server-side
- Add code integrity checks
- Obfuscate comparison routines
- Implement hardware-bound licensing

Quick Reference Card


Task

Tool

Command/Action

Check packer

exiftool

`exiftool app.exe

Unpack UPX

upx

upx -d app.exe -o unpacked.exe

Find strings

strings

`strings app.exe

Patch JNZ→NOP

radare2

s 0x4012A0; wa nop

Dynamic analysis

x64dbg

Break on strcmp, CreateFile

Unpack .NET

de4dot

de4dot -f app.exe -o cleaned.exe

Memory dump

Process Dumper

Dump at OEP → Scylla fix imports


Enroll In Online Cybersecurity & Hacking Classes/Courses | Black Hat HQ

Comments


bottom of page