@ecopoesis/homebridge-dmx 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +176 -0
- package/README.md +146 -0
- package/config.schema.json +143 -0
- package/dist/cli/stick.d.ts +3 -0
- package/dist/cli/stick.d.ts.map +1 -0
- package/dist/cli/stick.js +176 -0
- package/dist/cli/stick.js.map +1 -0
- package/dist/color/cct.d.ts +3 -0
- package/dist/color/cct.d.ts.map +1 -0
- package/dist/color/cct.js +33 -0
- package/dist/color/cct.js.map +1 -0
- package/dist/color/dimmer.d.ts +3 -0
- package/dist/color/dimmer.d.ts.map +1 -0
- package/dist/color/dimmer.js +16 -0
- package/dist/color/dimmer.js.map +1 -0
- package/dist/color/hsvcct.d.ts +3 -0
- package/dist/color/hsvcct.d.ts.map +1 -0
- package/dist/color/hsvcct.js +52 -0
- package/dist/color/hsvcct.js.map +1 -0
- package/dist/color/index.d.ts +7 -0
- package/dist/color/index.d.ts.map +1 -0
- package/dist/color/index.js +28 -0
- package/dist/color/index.js.map +1 -0
- package/dist/color/parsers.d.ts +20 -0
- package/dist/color/parsers.d.ts.map +1 -0
- package/dist/color/parsers.js +232 -0
- package/dist/color/parsers.js.map +1 -0
- package/dist/color/rgb.d.ts +3 -0
- package/dist/color/rgb.d.ts.map +1 -0
- package/dist/color/rgb.js +32 -0
- package/dist/color/rgb.js.map +1 -0
- package/dist/color/rgbaw.d.ts +3 -0
- package/dist/color/rgbaw.d.ts.map +1 -0
- package/dist/color/rgbaw.js +48 -0
- package/dist/color/rgbaw.js.map +1 -0
- package/dist/color/rgbw.d.ts +3 -0
- package/dist/color/rgbw.d.ts.map +1 -0
- package/dist/color/rgbw.js +37 -0
- package/dist/color/rgbw.js.map +1 -0
- package/dist/color/rgbww.d.ts +3 -0
- package/dist/color/rgbww.d.ts.map +1 -0
- package/dist/color/rgbww.js +54 -0
- package/dist/color/rgbww.js.map +1 -0
- package/dist/color/types.d.ts +64 -0
- package/dist/color/types.d.ts.map +1 -0
- package/dist/color/types.js +91 -0
- package/dist/color/types.js.map +1 -0
- package/dist/config.d.ts +60 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +191 -0
- package/dist/config.js.map +1 -0
- package/dist/controller.d.ts +32 -0
- package/dist/controller.d.ts.map +1 -0
- package/dist/controller.js +128 -0
- package/dist/controller.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/platform.d.ts +17 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +96 -0
- package/dist/platform.js.map +1 -0
- package/dist/platformAccessory.d.ts +18 -0
- package/dist/platformAccessory.d.ts.map +1 -0
- package/dist/platformAccessory.js +81 -0
- package/dist/platformAccessory.js.map +1 -0
- package/dist/settings.d.ts +14 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +15 -0
- package/dist/settings.js.map +1 -0
- package/dist/stick/frame.d.ts +16 -0
- package/dist/stick/frame.d.ts.map +1 -0
- package/dist/stick/frame.js +51 -0
- package/dist/stick/frame.js.map +1 -0
- package/dist/stick/kdf.d.ts +23 -0
- package/dist/stick/kdf.d.ts.map +1 -0
- package/dist/stick/kdf.js +90 -0
- package/dist/stick/kdf.js.map +1 -0
- package/dist/stick/protocol.d.ts +28 -0
- package/dist/stick/protocol.d.ts.map +1 -0
- package/dist/stick/protocol.js +78 -0
- package/dist/stick/protocol.js.map +1 -0
- package/dist/stick/session.d.ts +50 -0
- package/dist/stick/session.d.ts.map +1 -0
- package/dist/stick/session.js +301 -0
- package/dist/stick/session.js.map +1 -0
- package/examples/dmx.yaml +65 -0
- package/package.json +51 -0
- package/src/cli/stick.ts +198 -0
- package/src/color/cct.ts +40 -0
- package/src/color/dimmer.ts +24 -0
- package/src/color/hsvcct.ts +59 -0
- package/src/color/index.ts +34 -0
- package/src/color/parsers.ts +232 -0
- package/src/color/rgb.ts +33 -0
- package/src/color/rgbaw.ts +46 -0
- package/src/color/rgbw.ts +36 -0
- package/src/color/rgbww.ts +56 -0
- package/src/color/types.ts +150 -0
- package/src/config.ts +248 -0
- package/src/controller.ts +136 -0
- package/src/index.ts +9 -0
- package/src/platform.ts +118 -0
- package/src/platformAccessory.ts +102 -0
- package/src/settings.ts +18 -0
- package/src/stick/frame.ts +70 -0
- package/src/stick/kdf.ts +99 -0
- package/src/stick/protocol.ts +90 -0
- package/src/stick/session.ts +348 -0
- package/stick-de3.json +6 -0
- package/tools/aes-hook.c +1404 -0
- package/tools/analyze-pcap.mjs +143 -0
- package/tools/capture-aes-key.lldb +25 -0
- package/tools/capture-and-verify.sh +46 -0
- package/tools/capture-handshake.sh +59 -0
- package/tools/capture-send.sh +39 -0
- package/tools/crack-kdf.mjs +121 -0
- package/tools/crack-key.mjs +170 -0
- package/tools/decode-frame.mjs +110 -0
- package/tools/decrypt-011c.mjs +123 -0
- package/tools/decrypt-dmx.mjs +130 -0
- package/tools/decrypt-ssl2.ts +154 -0
- package/tools/derive-dmx-key.mjs +189 -0
- package/tools/diff-011c.mjs +127 -0
- package/tools/dump-pcap-summary.mjs +54 -0
- package/tools/dump-tcp-stream.mjs +123 -0
- package/tools/extract-011c.mjs +117 -0
- package/tools/extract-frame.mjs +78 -0
- package/tools/find-011c-key.mjs +140 -0
- package/tools/find-iv.mjs +153 -0
- package/tools/ghidra/README.md +136 -0
- package/tools/ghidra/__pycache__/dump-011c-callers.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-011c-handler.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-aes-candidates.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-anchors.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-auth2.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-authenticate.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-block-cipher.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-cipher.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-ctor-chain.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-curve.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-encompassing.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-handshake.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-kdf-chain.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-kdf-context.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-profile.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-real-encrypt.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-secret.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-setsoftware.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-stick3-vtable.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-swxref.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/dump-vt-key-getter.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/find-cipher.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/find-ctor.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/find-md5.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/find-secret-users.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/find-stick3-crypto.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/find-stick3-device.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/find-stick3a-ctor.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/find-stick3anet-ctor.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/find-vtables.cpython-313.pyc +0 -0
- package/tools/ghidra/__pycache__/string-walk.cpython-313.pyc +0 -0
- package/tools/ghidra/dump-011c-callers.py +140 -0
- package/tools/ghidra/dump-011c-handler.py +158 -0
- package/tools/ghidra/dump-aes-candidates.py +99 -0
- package/tools/ghidra/dump-anchors.py +192 -0
- package/tools/ghidra/dump-auth2.py +50 -0
- package/tools/ghidra/dump-authenticate.py +71 -0
- package/tools/ghidra/dump-block-cipher.py +88 -0
- package/tools/ghidra/dump-cipher.py +106 -0
- package/tools/ghidra/dump-ctor-chain.py +107 -0
- package/tools/ghidra/dump-curve.py +112 -0
- package/tools/ghidra/dump-encompassing.py +146 -0
- package/tools/ghidra/dump-handshake.py +76 -0
- package/tools/ghidra/dump-kdf-chain.py +105 -0
- package/tools/ghidra/dump-kdf-context.py +72 -0
- package/tools/ghidra/dump-profile.py +59 -0
- package/tools/ghidra/dump-real-encrypt.py +90 -0
- package/tools/ghidra/dump-secret.py +84 -0
- package/tools/ghidra/dump-setsoftware.py +63 -0
- package/tools/ghidra/dump-stick3-vtable.py +182 -0
- package/tools/ghidra/dump-swxref.py +27 -0
- package/tools/ghidra/dump-vt-key-getter.py +170 -0
- package/tools/ghidra/find-cipher.py +210 -0
- package/tools/ghidra/find-ctor.py +109 -0
- package/tools/ghidra/find-md5.py +97 -0
- package/tools/ghidra/find-secret-users.py +98 -0
- package/tools/ghidra/find-stick3-crypto.py +190 -0
- package/tools/ghidra/find-stick3-device.py +111 -0
- package/tools/ghidra/find-stick3a-ctor.py +87 -0
- package/tools/ghidra/find-stick3anet-ctor.py +76 -0
- package/tools/ghidra/find-vtables.py +165 -0
- package/tools/ghidra/out-011c-callers-run.log +51 -0
- package/tools/ghidra/out-011c-run.log +50 -0
- package/tools/ghidra/out-vt-key-run.log +55 -0
- package/tools/ghidra/string-walk.py +180 -0
- package/tools/hmac-key.sh +51 -0
- package/tools/hwm-entitlements.plist +18 -0
- package/tools/inspect-plaintext.mjs +87 -0
- package/tools/lldb-capture-aes.py +137 -0
- package/tools/lldb_hmac_key.py +93 -0
- package/tools/lldb_pathA_scan.py +341 -0
- package/tools/lldb_pathC_keytrace.py +300 -0
- package/tools/lldb_pathD_kdf_watch.py +281 -0
- package/tools/pathA-launch-hwm.sh +86 -0
- package/tools/pathA-scan.sh +52 -0
- package/tools/pathC-keytrace.sh +49 -0
- package/tools/pathC-run.sh +71 -0
- package/tools/pathD-kdf-watch.sh +51 -0
- package/tools/quick-trigger.mjs +86 -0
- package/tools/run-hooked-hwmanager.sh +51 -0
- package/tools/scan-aes-schedule.mjs +135 -0
- package/tools/send_dmx.mjs +480 -0
- package/tools/stick-status.mjs +57 -0
- package/tools/test-aes-detector.mjs +100 -0
- package/tools/test-tcp-write.ts +274 -0
- package/tools/test-udp-dmx.ts +324 -0
- package/tools/test-x25519.mjs +87 -0
- package/tools/try-decrypt.ts +144 -0
- package/tools/try-hardcoded-key.mjs +86 -0
- package/tools/try-hardcoded-key.ts +103 -0
- package/tools/try-key.mjs +103 -0
- package/tools/verify-011c-key.mjs +121 -0
- package/tools/verify-kdf.mjs +142 -0
- package/tsconfig.json +19 -0
package/tools/aes-hook.c
ADDED
|
@@ -0,0 +1,1404 @@
|
|
|
1
|
+
// DYLD_INSERT_LIBRARIES hook for HardwareManager
|
|
2
|
+
// Intercepts ALL mbedtls cipher functions + socket I/O
|
|
3
|
+
// to identify which cipher encrypts DMX frames.
|
|
4
|
+
|
|
5
|
+
#include <stdio.h>
|
|
6
|
+
#include <stdlib.h>
|
|
7
|
+
#include <string.h>
|
|
8
|
+
#include <stdint.h>
|
|
9
|
+
#include <dlfcn.h>
|
|
10
|
+
#include <time.h>
|
|
11
|
+
#include <unistd.h>
|
|
12
|
+
#include <sys/socket.h>
|
|
13
|
+
#include <arpa/inet.h>
|
|
14
|
+
#include <sys/uio.h>
|
|
15
|
+
#include <mach/mach.h>
|
|
16
|
+
#include <mach/mach_vm.h>
|
|
17
|
+
#include <mach-o/dyld.h>
|
|
18
|
+
#include <sys/mman.h>
|
|
19
|
+
#include <libkern/OSCacheControl.h>
|
|
20
|
+
#include <pthread.h>
|
|
21
|
+
#include <mach/exception_types.h>
|
|
22
|
+
#include <mach/task.h>
|
|
23
|
+
#include <mach/thread_act.h>
|
|
24
|
+
#include <mach/mach_init.h>
|
|
25
|
+
#include <mach/i386/thread_status.h>
|
|
26
|
+
|
|
27
|
+
#define DYLD_INTERPOSE(_replacement, _replacee) \
|
|
28
|
+
__attribute__((used)) static struct { \
|
|
29
|
+
const void* replacement; \
|
|
30
|
+
const void* replacee; \
|
|
31
|
+
} _interpose_##_replacee \
|
|
32
|
+
__attribute__((section("__DATA,__interpose"))) = { \
|
|
33
|
+
(const void*)(unsigned long)&_replacement, \
|
|
34
|
+
(const void*)(unsigned long)&_replacee \
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
static FILE *logf = NULL;
|
|
38
|
+
static int msg_count = 0;
|
|
39
|
+
|
|
40
|
+
static void hex_dump(FILE *f, const unsigned char *data, size_t len) {
|
|
41
|
+
for (size_t i = 0; i < len; i += 16) {
|
|
42
|
+
fprintf(f, " %04zx ", i);
|
|
43
|
+
for (size_t j = 0; j < 16; j++) {
|
|
44
|
+
if (i + j < len) fprintf(f, "%02x ", data[i + j]);
|
|
45
|
+
else fprintf(f, " ");
|
|
46
|
+
}
|
|
47
|
+
fprintf(f, " ");
|
|
48
|
+
for (size_t j = 0; j < 16 && i + j < len; j++) {
|
|
49
|
+
unsigned char c = data[i + j];
|
|
50
|
+
fprintf(f, "%c", (c >= 32 && c < 127) ? c : '.');
|
|
51
|
+
}
|
|
52
|
+
fprintf(f, "\n");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// =====================================================================
|
|
57
|
+
// Inline hook of the AES-128 key+IV setup function (Pro2 0x10040b3c0)
|
|
58
|
+
// At entry: rsi = ptr to raw 16-byte AES-128 key, rdx = ptr to 16-byte IV,
|
|
59
|
+
// rdi = crypto context. We dump key+IV, then one-shot unpatch
|
|
60
|
+
// and re-enter the function cleanly.
|
|
61
|
+
// =====================================================================
|
|
62
|
+
|
|
63
|
+
#define SETUP_FN_FILEVMADDR 0x10040b3c0ULL
|
|
64
|
+
|
|
65
|
+
// Expected first 14 bytes of the function prologue (verified before patching
|
|
66
|
+
// so we never corrupt an unrelated process e.g. the Qt-less CEF helper):
|
|
67
|
+
// 55 push %rbp
|
|
68
|
+
// 48 89 e5 mov %rsp,%rbp
|
|
69
|
+
// 41 56 push %r14
|
|
70
|
+
// 53 push %rbx
|
|
71
|
+
// 49 89 d6 mov %rdx,%r14
|
|
72
|
+
// 48 89 fb mov %rdi,%rbx
|
|
73
|
+
// e8 .. call 0x10040b2c0
|
|
74
|
+
static const unsigned char SETUP_FN_EXPECT[14] = {
|
|
75
|
+
0x55,0x48,0x89,0xe5,0x41,0x56,0x53,0x49,0x89,0xd6,0x48,0x89,0xfb,0xe8
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
void *g_target = NULL; // runtime addr of setup fn (used by asm)
|
|
79
|
+
static unsigned char g_orig[16]; // saved original prologue bytes
|
|
80
|
+
static int g_fired = 0;
|
|
81
|
+
|
|
82
|
+
extern void hook_stub(void); // asm trampoline (below)
|
|
83
|
+
|
|
84
|
+
// Naked trampoline: entered via JMP from the patched prologue, so the
|
|
85
|
+
// register state is exactly the function's entry state. Save everything,
|
|
86
|
+
// call the C capture+unpatch routine, restore, then jump to the (now
|
|
87
|
+
// un-patched) original entry so the function runs normally.
|
|
88
|
+
__asm__(
|
|
89
|
+
".text\n"
|
|
90
|
+
".globl _hook_stub\n"
|
|
91
|
+
"_hook_stub:\n"
|
|
92
|
+
" pushq %rax\n pushq %rcx\n pushq %rdx\n pushq %rbx\n pushq %rbp\n"
|
|
93
|
+
" pushq %rsi\n pushq %rdi\n pushq %r8\n pushq %r9\n pushq %r10\n"
|
|
94
|
+
" pushq %r11\n pushq %r12\n pushq %r13\n pushq %r14\n pushq %r15\n"
|
|
95
|
+
" movq %rsi, %rdi\n" /* arg1 = original rsi = key ptr */
|
|
96
|
+
" movq %rdx, %rsi\n" /* arg2 = original rdx = iv ptr */
|
|
97
|
+
" call _capture_and_unpatch\n"
|
|
98
|
+
" popq %r15\n popq %r14\n popq %r13\n popq %r12\n popq %r11\n"
|
|
99
|
+
" popq %r10\n popq %r9\n popq %r8\n popq %rdi\n popq %rsi\n"
|
|
100
|
+
" popq %rbp\n popq %rbx\n popq %rdx\n popq %rcx\n popq %rax\n"
|
|
101
|
+
" jmpq *_g_target(%rip)\n"
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// Make a code page writable on macOS. Plain mprotect() is denied on __TEXT
|
|
105
|
+
// (especially under Rosetta), so use mach_vm_protect with VM_PROT_COPY which
|
|
106
|
+
// forces a private copy-on-write page we are allowed to modify.
|
|
107
|
+
// Try plain RW first (no VM_PROT_COPY): we MUST modify the original
|
|
108
|
+
// file-backed page, because Rosetta's x86->arm64 translator reads that
|
|
109
|
+
// mapping. VM_PROT_COPY makes a private page Rosetta never sees, so the
|
|
110
|
+
// patch would silently have no effect. COPY is only a last resort.
|
|
111
|
+
static int make_writable(uint64_t addr, size_t len) {
|
|
112
|
+
uintptr_t pg = addr & ~0xFFFULL;
|
|
113
|
+
mach_vm_size_t span = ((addr + len) - pg + 0xFFF) & ~0xFFFULL;
|
|
114
|
+
kern_return_t kr = mach_vm_protect(mach_task_self(), pg, span, FALSE,
|
|
115
|
+
VM_PROT_READ | VM_PROT_WRITE);
|
|
116
|
+
if (kr == KERN_SUCCESS) {
|
|
117
|
+
fprintf(stderr, "[HOOK] make_writable: RW (no-copy) OK\n");
|
|
118
|
+
return 0;
|
|
119
|
+
}
|
|
120
|
+
fprintf(stderr, "[HOOK] make_writable: RW failed kr=%d, trying COPY "
|
|
121
|
+
"(note: COPY won't be seen by Rosetta translator)\n", kr);
|
|
122
|
+
kr = mach_vm_protect(mach_task_self(), pg, span, FALSE,
|
|
123
|
+
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY);
|
|
124
|
+
return kr == KERN_SUCCESS ? 0 : (int)kr;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static int make_exec(uint64_t addr, size_t len) {
|
|
128
|
+
uintptr_t pg = addr & ~0xFFFULL;
|
|
129
|
+
mach_vm_size_t span = ((addr + len) - pg + 0xFFF) & ~0xFFFULL;
|
|
130
|
+
kern_return_t kr = mach_vm_protect(mach_task_self(), pg, span, FALSE,
|
|
131
|
+
VM_PROT_READ | VM_PROT_EXECUTE);
|
|
132
|
+
return kr == KERN_SUCCESS ? 0 : (int)kr;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
void capture_and_unpatch(const unsigned char *key, const unsigned char *iv) {
|
|
136
|
+
if (g_fired) return;
|
|
137
|
+
g_fired = 1;
|
|
138
|
+
|
|
139
|
+
fprintf(stderr, "\n[HOOK] ====================================\n");
|
|
140
|
+
fprintf(stderr, "[HOOK] *** AES-128 KEY+IV CAPTURED (setup fn) ***\n");
|
|
141
|
+
fprintf(stderr, "[HOOK] KEY (16 bytes):\n");
|
|
142
|
+
hex_dump(stderr, key, 16);
|
|
143
|
+
fprintf(stderr, "[HOOK] IV (16 bytes):\n");
|
|
144
|
+
hex_dump(stderr, iv, 16);
|
|
145
|
+
fprintf(stderr, "[HOOK] ====================================\n");
|
|
146
|
+
if (logf) {
|
|
147
|
+
fprintf(logf, "\n[KEY] *** AES-128 KEY+IV CAPTURED via inline hook ***\n");
|
|
148
|
+
fprintf(logf, "[KEY] KEY(16):\n");
|
|
149
|
+
hex_dump(logf, key, 16);
|
|
150
|
+
fprintf(logf, "[KEY] IV(16):\n");
|
|
151
|
+
hex_dump(logf, iv, 16);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// One-shot: restore original bytes so the function runs normally forever.
|
|
155
|
+
uint64_t t = (uint64_t)g_target;
|
|
156
|
+
make_writable(t, 16);
|
|
157
|
+
memcpy((void *)t, g_orig, 16);
|
|
158
|
+
sys_icache_invalidate((void *)t, 16);
|
|
159
|
+
make_exec(t, 16);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
static void install_setup_hook(void) {
|
|
163
|
+
intptr_t slide = _dyld_get_image_vmaddr_slide(0);
|
|
164
|
+
uint64_t t = SETUP_FN_FILEVMADDR + (uint64_t)slide;
|
|
165
|
+
unsigned char *p = (unsigned char *)t;
|
|
166
|
+
|
|
167
|
+
// Verify the target is mapped and matches the expected prologue.
|
|
168
|
+
// mach_vm_read_overwrite avoids crashing if the page is unmapped
|
|
169
|
+
// (e.g. in the CEF helper process which lacks this code).
|
|
170
|
+
unsigned char probe[16];
|
|
171
|
+
mach_vm_size_t got = 16;
|
|
172
|
+
if (mach_vm_read_overwrite(mach_task_self(), t, 16,
|
|
173
|
+
(mach_vm_address_t)probe, &got) != KERN_SUCCESS
|
|
174
|
+
|| got < 14) {
|
|
175
|
+
fprintf(stderr, "[HOOK] setup-hook: target 0x%llx not readable, skip\n",
|
|
176
|
+
(unsigned long long)t);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (memcmp(probe, SETUP_FN_EXPECT, 14) != 0) {
|
|
180
|
+
fprintf(stderr, "[HOOK] setup-hook: prologue mismatch at 0x%llx, skip "
|
|
181
|
+
"(got %02x %02x %02x %02x ...)\n", (unsigned long long)t,
|
|
182
|
+
probe[0], probe[1], probe[2], probe[3]);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
g_target = (void *)t;
|
|
187
|
+
memcpy(g_orig, p, 16);
|
|
188
|
+
|
|
189
|
+
// 14-byte absolute jump: FF 25 00 00 00 00 | <8-byte abs addr of stub>
|
|
190
|
+
unsigned char patch[14];
|
|
191
|
+
patch[0] = 0xFF; patch[1] = 0x25;
|
|
192
|
+
patch[2] = patch[3] = patch[4] = patch[5] = 0x00;
|
|
193
|
+
uint64_t h = (uint64_t)&hook_stub;
|
|
194
|
+
memcpy(patch + 6, &h, 8);
|
|
195
|
+
|
|
196
|
+
int wr = make_writable(t, 16);
|
|
197
|
+
if (wr != 0) {
|
|
198
|
+
fprintf(stderr, "[HOOK] setup-hook: make_writable failed kr=%d, skip\n", wr);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
memcpy(p, patch, 14);
|
|
202
|
+
sys_icache_invalidate(p, 14);
|
|
203
|
+
make_exec(t, 16);
|
|
204
|
+
|
|
205
|
+
// Read back to confirm the patch actually landed in the mapping.
|
|
206
|
+
fprintf(stderr, "[HOOK] readback after patch: "
|
|
207
|
+
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
208
|
+
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
|
|
209
|
+
|
|
210
|
+
fprintf(stderr, "[HOOK] *** SETUP HOOK INSTALLED at 0x%llx "
|
|
211
|
+
"(stub=%p, slide=0x%lx) ***\n",
|
|
212
|
+
(unsigned long long)t, (void *)&hook_stub, (long)slide);
|
|
213
|
+
if (logf)
|
|
214
|
+
fprintf(logf, "[HOOK] setup hook installed at 0x%llx\n",
|
|
215
|
+
(unsigned long long)t);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// =====================================================================
|
|
219
|
+
// Mach exception-port + hardware breakpoint on the AES-128 setup fn.
|
|
220
|
+
// No __TEXT write (Rosetta/ad-hoc-sign safe). On the breakpoint we read
|
|
221
|
+
// the x86 thread state: rsi=raw key ptr, rdx=IV ptr, rdi=ctx.
|
|
222
|
+
// =====================================================================
|
|
223
|
+
|
|
224
|
+
static uint64_t g_bp_addr = 0; // runtime addr of 0x10040b3c0
|
|
225
|
+
static mach_port_t g_exc_port = MACH_PORT_NULL;
|
|
226
|
+
static volatile int g_bp_fired = 0;
|
|
227
|
+
|
|
228
|
+
// EXCEPTION_DEFAULT + MACH_EXCEPTION_CODES message structs (hand-rolled,
|
|
229
|
+
// avoids needing MIG-generated mach_exc_server).
|
|
230
|
+
#pragma pack(4)
|
|
231
|
+
typedef struct {
|
|
232
|
+
mach_msg_header_t Head;
|
|
233
|
+
mach_msg_body_t msgh_body;
|
|
234
|
+
mach_msg_port_descriptor_t thread;
|
|
235
|
+
mach_msg_port_descriptor_t task;
|
|
236
|
+
NDR_record_t NDR;
|
|
237
|
+
exception_type_t exception;
|
|
238
|
+
mach_msg_type_number_t codeCnt;
|
|
239
|
+
int64_t code[2];
|
|
240
|
+
char trailer[64];
|
|
241
|
+
} exc_request_t;
|
|
242
|
+
typedef struct {
|
|
243
|
+
mach_msg_header_t Head;
|
|
244
|
+
NDR_record_t NDR;
|
|
245
|
+
kern_return_t RetCode;
|
|
246
|
+
} exc_reply_t;
|
|
247
|
+
#pragma pack()
|
|
248
|
+
|
|
249
|
+
static void set_dr_all_threads(uint64_t bp) {
|
|
250
|
+
thread_act_array_t threads;
|
|
251
|
+
mach_msg_type_number_t count = 0;
|
|
252
|
+
if (task_threads(mach_task_self(), &threads, &count) != KERN_SUCCESS)
|
|
253
|
+
return;
|
|
254
|
+
mach_port_t me = mach_thread_self();
|
|
255
|
+
for (unsigned i = 0; i < count; i++) {
|
|
256
|
+
if (threads[i] == me) continue;
|
|
257
|
+
x86_debug_state64_t ds;
|
|
258
|
+
mach_msg_type_number_t dc = x86_DEBUG_STATE64_COUNT;
|
|
259
|
+
if (thread_get_state(threads[i], x86_DEBUG_STATE64,
|
|
260
|
+
(thread_state_t)&ds, &dc) != KERN_SUCCESS)
|
|
261
|
+
continue;
|
|
262
|
+
ds.__dr0 = bp;
|
|
263
|
+
// DR7: L0=1 (bit0). R/W0=00 (exec), LEN0=00 -> low byte 0x01.
|
|
264
|
+
ds.__dr7 = (ds.__dr7 & ~0xFULL) | 0x1ULL;
|
|
265
|
+
thread_set_state(threads[i], x86_DEBUG_STATE64,
|
|
266
|
+
(thread_state_t)&ds, x86_DEBUG_STATE64_COUNT);
|
|
267
|
+
}
|
|
268
|
+
mach_port_deallocate(mach_task_self(), me);
|
|
269
|
+
vm_deallocate(mach_task_self(), (vm_address_t)threads,
|
|
270
|
+
count * sizeof(thread_act_t));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
static void clear_dr_thread(mach_port_t th) {
|
|
274
|
+
x86_debug_state64_t ds;
|
|
275
|
+
mach_msg_type_number_t dc = x86_DEBUG_STATE64_COUNT;
|
|
276
|
+
if (thread_get_state(th, x86_DEBUG_STATE64,
|
|
277
|
+
(thread_state_t)&ds, &dc) != KERN_SUCCESS)
|
|
278
|
+
return;
|
|
279
|
+
ds.__dr0 = 0;
|
|
280
|
+
ds.__dr7 &= ~0xFULL;
|
|
281
|
+
thread_set_state(th, x86_DEBUG_STATE64,
|
|
282
|
+
(thread_state_t)&ds, x86_DEBUG_STATE64_COUNT);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
static void capture_from_thread(mach_port_t th) {
|
|
286
|
+
if (g_bp_fired) return;
|
|
287
|
+
|
|
288
|
+
x86_thread_state64_t ts;
|
|
289
|
+
mach_msg_type_number_t tc = x86_THREAD_STATE64_COUNT;
|
|
290
|
+
if (thread_get_state(th, x86_THREAD_STATE64,
|
|
291
|
+
(thread_state_t)&ts, &tc) != KERN_SUCCESS) {
|
|
292
|
+
fprintf(stderr, "[HOOK] bp: thread_get_state failed\n");
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
uint64_t rip = ts.__rip, rsi = ts.__rsi, rdx = ts.__rdx, rdi = ts.__rdi;
|
|
297
|
+
fprintf(stderr, "\n[HOOK] *** BREAKPOINT HIT rip=0x%llx ***\n",
|
|
298
|
+
(unsigned long long)rip);
|
|
299
|
+
fprintf(stderr, "[HOOK] rsi(key)=0x%llx rdx(iv)=0x%llx rdi(ctx)=0x%llx\n",
|
|
300
|
+
(unsigned long long)rsi, (unsigned long long)rdx,
|
|
301
|
+
(unsigned long long)rdi);
|
|
302
|
+
|
|
303
|
+
unsigned char key[16], iv[16];
|
|
304
|
+
mach_vm_size_t n = 16;
|
|
305
|
+
int ok_k = (rsi && mach_vm_read_overwrite(mach_task_self(), rsi, 16,
|
|
306
|
+
(mach_vm_address_t)key, &n) == KERN_SUCCESS);
|
|
307
|
+
n = 16;
|
|
308
|
+
int ok_i = (rdx && mach_vm_read_overwrite(mach_task_self(), rdx, 16,
|
|
309
|
+
(mach_vm_address_t)iv, &n) == KERN_SUCCESS);
|
|
310
|
+
|
|
311
|
+
if (ok_k) {
|
|
312
|
+
fprintf(stderr, "[HOOK] *** AES-128 KEY (16) ***\n");
|
|
313
|
+
hex_dump(stderr, key, 16);
|
|
314
|
+
}
|
|
315
|
+
if (ok_i) {
|
|
316
|
+
fprintf(stderr, "[HOOK] *** IV (16) ***\n");
|
|
317
|
+
hex_dump(stderr, iv, 16);
|
|
318
|
+
}
|
|
319
|
+
if (logf) {
|
|
320
|
+
fprintf(logf, "\n[KEY] *** CAPTURED via HW breakpoint rip=0x%llx ***\n",
|
|
321
|
+
(unsigned long long)rip);
|
|
322
|
+
if (ok_k) { fprintf(logf, "[KEY] KEY(16):\n"); hex_dump(logf, key, 16); }
|
|
323
|
+
if (ok_i) { fprintf(logf, "[KEY] IV(16):\n"); hex_dump(logf, iv, 16); }
|
|
324
|
+
// Also dump the crypto context (rdi) for offset analysis.
|
|
325
|
+
if (rdi) {
|
|
326
|
+
unsigned char ctx[256]; n = 256;
|
|
327
|
+
if (mach_vm_read_overwrite(mach_task_self(), rdi, 256,
|
|
328
|
+
(mach_vm_address_t)ctx, &n) == KERN_SUCCESS) {
|
|
329
|
+
fprintf(logf, "[KEY] ctx(rdi) first 256:\n");
|
|
330
|
+
hex_dump(logf, ctx, 256);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
g_bp_fired = 1;
|
|
336
|
+
clear_dr_thread(th); // one-shot: don't re-trap this thread
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
static void *exc_server_thread(void *arg) {
|
|
340
|
+
(void)arg;
|
|
341
|
+
for (;;) {
|
|
342
|
+
exc_request_t req;
|
|
343
|
+
memset(&req, 0, sizeof(req));
|
|
344
|
+
kern_return_t kr = mach_msg(&req.Head, MACH_RCV_MSG, 0, sizeof(req),
|
|
345
|
+
g_exc_port, MACH_MSG_TIMEOUT_NONE,
|
|
346
|
+
MACH_PORT_NULL);
|
|
347
|
+
if (kr != KERN_SUCCESS) continue;
|
|
348
|
+
|
|
349
|
+
mach_port_t th = req.thread.name; // faulting thread send right
|
|
350
|
+
capture_from_thread(th);
|
|
351
|
+
|
|
352
|
+
exc_reply_t rep;
|
|
353
|
+
memset(&rep, 0, sizeof(rep));
|
|
354
|
+
rep.Head.msgh_bits =
|
|
355
|
+
MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(req.Head.msgh_bits), 0);
|
|
356
|
+
rep.Head.msgh_size = sizeof(rep);
|
|
357
|
+
rep.Head.msgh_remote_port = req.Head.msgh_remote_port;
|
|
358
|
+
rep.Head.msgh_local_port = MACH_PORT_NULL;
|
|
359
|
+
rep.Head.msgh_id = req.Head.msgh_id + 100;
|
|
360
|
+
rep.NDR = req.NDR;
|
|
361
|
+
rep.RetCode = KERN_SUCCESS; // resume thread; DR cleared so no re-trap
|
|
362
|
+
mach_msg(&rep.Head, MACH_SEND_MSG, sizeof(rep), 0,
|
|
363
|
+
MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
|
364
|
+
|
|
365
|
+
if (req.thread.name)
|
|
366
|
+
mach_port_deallocate(mach_task_self(), req.thread.name);
|
|
367
|
+
if (req.task.name)
|
|
368
|
+
mach_port_deallocate(mach_task_self(), req.task.name);
|
|
369
|
+
}
|
|
370
|
+
return NULL;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
static void *rearm_thread(void *arg) {
|
|
374
|
+
(void)arg;
|
|
375
|
+
// Crypto runs on a thread spawned after we load; re-apply DR to all
|
|
376
|
+
// threads until the breakpoint fires once.
|
|
377
|
+
for (int i = 0; i < 4000 && !g_bp_fired; i++) {
|
|
378
|
+
set_dr_all_threads(g_bp_addr);
|
|
379
|
+
usleep(200000); // 200ms
|
|
380
|
+
}
|
|
381
|
+
fprintf(stderr, "[HOOK] rearm thread exiting (fired=%d)\n", g_bp_fired);
|
|
382
|
+
return NULL;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
static void install_exc_breakpoint(void) {
|
|
386
|
+
intptr_t slide = _dyld_get_image_vmaddr_slide(0);
|
|
387
|
+
uint64_t t = SETUP_FN_FILEVMADDR + (uint64_t)slide;
|
|
388
|
+
|
|
389
|
+
// Verify target is mapped & matches expected prologue (so we don't
|
|
390
|
+
// arm garbage in the Qt-less CEF helper process).
|
|
391
|
+
unsigned char probe[16];
|
|
392
|
+
mach_vm_size_t got = 16;
|
|
393
|
+
if (mach_vm_read_overwrite(mach_task_self(), t, 16,
|
|
394
|
+
(mach_vm_address_t)probe, &got) != KERN_SUCCESS
|
|
395
|
+
|| got < 14 || memcmp(probe, SETUP_FN_EXPECT, 14) != 0) {
|
|
396
|
+
fprintf(stderr, "[HOOK] exc-bp: target 0x%llx not the expected fn, skip\n",
|
|
397
|
+
(unsigned long long)t);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
g_bp_addr = t;
|
|
401
|
+
|
|
402
|
+
if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
|
|
403
|
+
&g_exc_port) != KERN_SUCCESS) {
|
|
404
|
+
fprintf(stderr, "[HOOK] exc-bp: port alloc failed\n");
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
mach_port_insert_right(mach_task_self(), g_exc_port, g_exc_port,
|
|
408
|
+
MACH_MSG_TYPE_MAKE_SEND);
|
|
409
|
+
|
|
410
|
+
kern_return_t kr = task_set_exception_ports(
|
|
411
|
+
mach_task_self(), EXC_MASK_BREAKPOINT, g_exc_port,
|
|
412
|
+
EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, x86_THREAD_STATE64);
|
|
413
|
+
if (kr != KERN_SUCCESS) {
|
|
414
|
+
fprintf(stderr, "[HOOK] exc-bp: task_set_exception_ports kr=%d\n", kr);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
pthread_t s, r;
|
|
419
|
+
pthread_create(&s, NULL, exc_server_thread, NULL);
|
|
420
|
+
pthread_detach(s);
|
|
421
|
+
pthread_create(&r, NULL, rearm_thread, NULL);
|
|
422
|
+
pthread_detach(r);
|
|
423
|
+
|
|
424
|
+
fprintf(stderr, "[HOOK] *** EXC BREAKPOINT ARMED at 0x%llx "
|
|
425
|
+
"(slide=0x%lx) ***\n", (unsigned long long)t, (long)slide);
|
|
426
|
+
if (logf)
|
|
427
|
+
fprintf(logf, "[HOOK] exc breakpoint armed at 0x%llx\n",
|
|
428
|
+
(unsigned long long)t);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// =====================================================================
|
|
432
|
+
// Verification: check if mbedtls symbols resolve at load time
|
|
433
|
+
// =====================================================================
|
|
434
|
+
__attribute__((constructor))
|
|
435
|
+
static void hook_init(void) {
|
|
436
|
+
logf = fopen("/tmp/stick-tls-plaintext.log", "w");
|
|
437
|
+
if (logf) {
|
|
438
|
+
setvbuf(logf, NULL, _IONBF, 0);
|
|
439
|
+
time_t now = time(NULL);
|
|
440
|
+
fprintf(logf, "=== Hook loaded PID %d at %s", getpid(), ctime(&now));
|
|
441
|
+
}
|
|
442
|
+
fprintf(stderr, "\n\n========================================\n");
|
|
443
|
+
fprintf(stderr, "[HOOK] LOADED PID %d\n", getpid());
|
|
444
|
+
fprintf(stderr, "========================================\n");
|
|
445
|
+
|
|
446
|
+
// Verify we can find mbedtls symbols (proves dynamic linking works)
|
|
447
|
+
const char *syms[] = {
|
|
448
|
+
"mbedtls_aes_setkey_enc", "mbedtls_aes_setkey_dec",
|
|
449
|
+
"mbedtls_aes_crypt_ecb", "mbedtls_aes_crypt_cbc",
|
|
450
|
+
"mbedtls_aes_crypt_ctr", "mbedtls_aes_crypt_cfb128",
|
|
451
|
+
"mbedtls_aes_crypt_ofb", "mbedtls_aes_crypt_xts",
|
|
452
|
+
"mbedtls_gcm_crypt_and_tag", "mbedtls_gcm_update",
|
|
453
|
+
"mbedtls_ccm_encrypt_and_tag", "mbedtls_ccm_update",
|
|
454
|
+
"mbedtls_chacha20_crypt", "mbedtls_chacha20_update",
|
|
455
|
+
"mbedtls_cipher_crypt", "mbedtls_cipher_setkey",
|
|
456
|
+
"mbedtls_cipher_auth_encrypt_ext",
|
|
457
|
+
NULL
|
|
458
|
+
};
|
|
459
|
+
for (int i = 0; syms[i]; i++) {
|
|
460
|
+
void *p = dlsym(RTLD_DEFAULT, syms[i]);
|
|
461
|
+
fprintf(stderr, "[HOOK] %s -> %s\n", syms[i], p ? "FOUND" : "NOT FOUND");
|
|
462
|
+
if (logf) fprintf(logf, "[HOOK] %s -> %s\n", syms[i], p ? "FOUND" : "NOT FOUND");
|
|
463
|
+
}
|
|
464
|
+
fprintf(stderr, "========================================\n\n");
|
|
465
|
+
|
|
466
|
+
install_exc_breakpoint();
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// =====================================================================
|
|
470
|
+
// Socket hooks (send, sendto, sendmsg, recv, connect, write, read, writev)
|
|
471
|
+
// =====================================================================
|
|
472
|
+
|
|
473
|
+
static int stick_fds[8] = {0};
|
|
474
|
+
static int stick_fd_count = 0;
|
|
475
|
+
static int is_stick_fd(int fd) {
|
|
476
|
+
for (int i = 0; i < stick_fd_count; i++)
|
|
477
|
+
if (stick_fds[i] == fd) return 1;
|
|
478
|
+
return 0;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
ssize_t hooked_send(int sockfd, const void *buf, size_t len, int flags) {
|
|
482
|
+
if (logf && len > 0) {
|
|
483
|
+
msg_count++;
|
|
484
|
+
fprintf(logf, "\n[%d] SEND fd=%d len=%zu flags=%d\n", msg_count, sockfd, len, flags);
|
|
485
|
+
hex_dump(logf, (const unsigned char *)buf, len > 512 ? 512 : len);
|
|
486
|
+
}
|
|
487
|
+
return send(sockfd, buf, len, flags);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// =====================================================================
|
|
491
|
+
// AES key scanner — searches heap for AES-256 key schedule
|
|
492
|
+
// =====================================================================
|
|
493
|
+
static int key_dumped = 0;
|
|
494
|
+
|
|
495
|
+
static const unsigned char aes_sbox[256] = {
|
|
496
|
+
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
|
|
497
|
+
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
|
|
498
|
+
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
|
|
499
|
+
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
|
|
500
|
+
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
|
|
501
|
+
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
|
|
502
|
+
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
|
|
503
|
+
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
|
|
504
|
+
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
|
|
505
|
+
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
|
|
506
|
+
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
|
|
507
|
+
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
|
|
508
|
+
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
|
|
509
|
+
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
|
|
510
|
+
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
|
|
511
|
+
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
static uint32_t sub_word(uint32_t w) {
|
|
515
|
+
return ((uint32_t)aes_sbox[w & 0xff]) |
|
|
516
|
+
((uint32_t)aes_sbox[(w >> 8) & 0xff] << 8) |
|
|
517
|
+
((uint32_t)aes_sbox[(w >> 16) & 0xff] << 16) |
|
|
518
|
+
((uint32_t)aes_sbox[(w >> 24) & 0xff] << 24);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
static int is_aes256_key_schedule(const unsigned char *data) {
|
|
522
|
+
uint32_t W[60];
|
|
523
|
+
memcpy(W, data, 240);
|
|
524
|
+
|
|
525
|
+
// Reject trivial (all-zero key)
|
|
526
|
+
int nonzero = 0;
|
|
527
|
+
for (int i = 0; i < 8; i++) if (W[i]) nonzero = 1;
|
|
528
|
+
if (!nonzero) return 0;
|
|
529
|
+
|
|
530
|
+
static const uint32_t rcon[8] = {
|
|
531
|
+
0, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
for (int i = 8; i < 60; i++) {
|
|
535
|
+
uint32_t temp = W[i - 1];
|
|
536
|
+
if (i % 8 == 0) {
|
|
537
|
+
temp = (temp >> 8) | (temp << 24); // RotWord
|
|
538
|
+
temp = sub_word(temp);
|
|
539
|
+
temp ^= rcon[i / 8];
|
|
540
|
+
} else if (i % 8 == 4) {
|
|
541
|
+
temp = sub_word(temp);
|
|
542
|
+
}
|
|
543
|
+
if (W[i] != (W[i - 8] ^ temp)) return 0;
|
|
544
|
+
}
|
|
545
|
+
return 1;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// AES-128: 44 words / 176 bytes. Nk=4, Nr=10.
|
|
549
|
+
// W[i]=W[i-4]^temp; if i%4==0 temp=SubWord(RotWord(W[i-1]))^Rcon[i/4]
|
|
550
|
+
static int is_aes128_key_schedule(const unsigned char *data) {
|
|
551
|
+
uint32_t W[44];
|
|
552
|
+
memcpy(W, data, 176);
|
|
553
|
+
|
|
554
|
+
int nonzero = 0;
|
|
555
|
+
for (int i = 0; i < 4; i++) if (W[i]) nonzero = 1;
|
|
556
|
+
if (!nonzero) return 0;
|
|
557
|
+
|
|
558
|
+
static const uint32_t rcon[11] = {
|
|
559
|
+
0, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
for (int i = 4; i < 44; i++) {
|
|
563
|
+
uint32_t temp = W[i - 1];
|
|
564
|
+
if (i % 4 == 0) {
|
|
565
|
+
temp = (temp >> 8) | (temp << 24); // RotWord
|
|
566
|
+
temp = sub_word(temp);
|
|
567
|
+
temp ^= rcon[i / 4];
|
|
568
|
+
}
|
|
569
|
+
if (W[i] != (W[i - 4] ^ temp)) return 0;
|
|
570
|
+
}
|
|
571
|
+
return 1;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Same as is_aes128_key_schedule but treats each stored 4-byte word as
|
|
575
|
+
// byte-swapped (the custom expander at 0x10040b2c0 may store words in the
|
|
576
|
+
// opposite endianness, which would make a valid schedule fail the normal
|
|
577
|
+
// check).
|
|
578
|
+
static int is_aes128_key_schedule_bswap(const unsigned char *data) {
|
|
579
|
+
unsigned char tmp[176];
|
|
580
|
+
for (int i = 0; i < 176; i += 4) {
|
|
581
|
+
tmp[i+0] = data[i+3];
|
|
582
|
+
tmp[i+1] = data[i+2];
|
|
583
|
+
tmp[i+2] = data[i+1];
|
|
584
|
+
tmp[i+3] = data[i+0];
|
|
585
|
+
}
|
|
586
|
+
return is_aes128_key_schedule(tmp);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
static void scan_for_key_schedule(void) {
|
|
590
|
+
mach_port_t task = mach_task_self();
|
|
591
|
+
size_t chunk = 0x10000; // 64K
|
|
592
|
+
unsigned char *buf = (unsigned char *)malloc(chunk + 240);
|
|
593
|
+
if (!buf) return;
|
|
594
|
+
|
|
595
|
+
fprintf(stderr, "[HOOK] Scanning ALL memory for AES-256 key schedule...\n");
|
|
596
|
+
|
|
597
|
+
int regions_scanned = 0;
|
|
598
|
+
int found_count = 0;
|
|
599
|
+
mach_vm_address_t addr = 0;
|
|
600
|
+
|
|
601
|
+
while (1) {
|
|
602
|
+
mach_vm_size_t region_size = 0;
|
|
603
|
+
vm_region_basic_info_data_64_t info;
|
|
604
|
+
mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
|
|
605
|
+
mach_port_t obj_name;
|
|
606
|
+
|
|
607
|
+
kern_return_t kr = mach_vm_region(task, &addr, ®ion_size,
|
|
608
|
+
VM_REGION_BASIC_INFO_64,
|
|
609
|
+
(vm_region_info_t)&info, &info_count,
|
|
610
|
+
&obj_name);
|
|
611
|
+
if (kr != KERN_SUCCESS) break;
|
|
612
|
+
|
|
613
|
+
if ((info.protection & VM_PROT_READ) && (info.protection & VM_PROT_WRITE)) {
|
|
614
|
+
regions_scanned++;
|
|
615
|
+
for (uint64_t offset = 0; offset < region_size; offset += chunk) {
|
|
616
|
+
mach_vm_size_t read_size = chunk + 240;
|
|
617
|
+
if (offset + read_size > region_size)
|
|
618
|
+
read_size = region_size - offset;
|
|
619
|
+
if (read_size < 240) { continue; }
|
|
620
|
+
|
|
621
|
+
mach_vm_size_t actual = read_size;
|
|
622
|
+
kr = mach_vm_read_overwrite(task, addr + offset, read_size,
|
|
623
|
+
(mach_vm_address_t)buf, &actual);
|
|
624
|
+
if (kr != KERN_SUCCESS) continue;
|
|
625
|
+
|
|
626
|
+
for (size_t i = 0; i + 240 <= (size_t)actual; i += 4) {
|
|
627
|
+
if (is_aes256_key_schedule(buf + i)) {
|
|
628
|
+
uint64_t key_addr = addr + offset + i;
|
|
629
|
+
found_count++;
|
|
630
|
+
fprintf(stderr, "\n[HOOK] *** FOUND AES-256 KEY SCHEDULE at 0x%llx ***\n",
|
|
631
|
+
(unsigned long long)key_addr);
|
|
632
|
+
fprintf(stderr, "[HOOK] Original key (first 32 bytes):\n");
|
|
633
|
+
hex_dump(stderr, buf + i, 32);
|
|
634
|
+
if (logf) {
|
|
635
|
+
fprintf(logf, "\n[KEY] AES-256 KEY SCHEDULE at 0x%llx\n",
|
|
636
|
+
(unsigned long long)key_addr);
|
|
637
|
+
hex_dump(logf, buf + i, 240);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
if (is_aes128_key_schedule_bswap(buf + i)) {
|
|
641
|
+
uint64_t key_addr = addr + offset + i;
|
|
642
|
+
found_count++;
|
|
643
|
+
fprintf(stderr, "\n[HOOK] *** FOUND AES-128 (BSWAP) SCHEDULE at 0x%llx ***\n",
|
|
644
|
+
(unsigned long long)key_addr);
|
|
645
|
+
fprintf(stderr, "[HOOK] raw 16 bytes:\n");
|
|
646
|
+
hex_dump(stderr, buf + i, 16);
|
|
647
|
+
if (logf) {
|
|
648
|
+
fprintf(logf, "\n[KEY] *** AES-128 BSWAP SCHEDULE at 0x%llx ***\n",
|
|
649
|
+
(unsigned long long)key_addr);
|
|
650
|
+
fprintf(logf, "[KEY] raw KEY(16):\n");
|
|
651
|
+
hex_dump(logf, buf + i, 16);
|
|
652
|
+
fprintf(logf, "[KEY] full raw schedule(176):\n");
|
|
653
|
+
hex_dump(logf, buf + i, 176);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (is_aes128_key_schedule(buf + i)) {
|
|
657
|
+
uint64_t key_addr = addr + offset + i;
|
|
658
|
+
found_count++;
|
|
659
|
+
fprintf(stderr, "\n[HOOK] *** FOUND AES-128 KEY SCHEDULE at 0x%llx ***\n",
|
|
660
|
+
(unsigned long long)key_addr);
|
|
661
|
+
fprintf(stderr, "[HOOK] Original key (first 16 bytes):\n");
|
|
662
|
+
hex_dump(stderr, buf + i, 16);
|
|
663
|
+
fprintf(stderr, "[HOOK] Full schedule (176 bytes):\n");
|
|
664
|
+
hex_dump(stderr, buf + i, 176);
|
|
665
|
+
// IV typically follows at +0xb0 (176) within the crypto context
|
|
666
|
+
fprintf(stderr, "[HOOK] Bytes at +0xb0 (possible IV, 16 bytes):\n");
|
|
667
|
+
hex_dump(stderr, buf + i + 176, 16);
|
|
668
|
+
if (logf) {
|
|
669
|
+
fprintf(logf, "\n[KEY] *** AES-128 KEY SCHEDULE at 0x%llx ***\n",
|
|
670
|
+
(unsigned long long)key_addr);
|
|
671
|
+
fprintf(logf, "[KEY] KEY (16 bytes):\n");
|
|
672
|
+
hex_dump(logf, buf + i, 16);
|
|
673
|
+
fprintf(logf, "[KEY] Full schedule (176 bytes):\n");
|
|
674
|
+
hex_dump(logf, buf + i, 176);
|
|
675
|
+
fprintf(logf, "[KEY] IV candidate at +0xb0 (16 bytes):\n");
|
|
676
|
+
hex_dump(logf, buf + i + 176, 16);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
addr += region_size;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
free(buf);
|
|
687
|
+
fprintf(stderr, "[HOOK] Key schedule scan: %d regions, %d schedules found.\n",
|
|
688
|
+
regions_scanned, found_count);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
static void dump_ptr_at(mach_port_t task, uint64_t addr, int depth, const char *path) {
|
|
692
|
+
if (depth > 2) return;
|
|
693
|
+
kern_return_t kr;
|
|
694
|
+
unsigned char obj[1024];
|
|
695
|
+
mach_vm_size_t osz = 1024;
|
|
696
|
+
kr = mach_vm_read_overwrite(task, addr, 1024, (mach_vm_address_t)obj, &osz);
|
|
697
|
+
if (kr != KERN_SUCCESS) return;
|
|
698
|
+
|
|
699
|
+
fprintf(stderr, "\n[HOOK] === %s at 0x%llx (depth=%d) ===\n",
|
|
700
|
+
path, (unsigned long long)addr, depth);
|
|
701
|
+
|
|
702
|
+
// Check for key schedule at various offsets
|
|
703
|
+
for (size_t off = 0; off + 192 <= (size_t)osz; off += 4) {
|
|
704
|
+
if (off + 240 <= (size_t)osz && is_aes256_key_schedule(obj + off)) {
|
|
705
|
+
fprintf(stderr, "[HOOK] *** AES-256 SCHEDULE at %s+0x%zx ***\n", path, off);
|
|
706
|
+
hex_dump(stderr, obj + off, 32);
|
|
707
|
+
if (logf) {
|
|
708
|
+
fprintf(logf, "\n[KEY] AES256 at %s+0x%zx addr=0x%llx\n",
|
|
709
|
+
path, off, (unsigned long long)(addr + off));
|
|
710
|
+
hex_dump(logf, obj + off, 32);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
if (is_aes128_key_schedule_bswap(obj + off)) {
|
|
714
|
+
unsigned char k[16];
|
|
715
|
+
for (int b = 0; b < 16; b += 4) {
|
|
716
|
+
k[b+0]=obj[off+b+3]; k[b+1]=obj[off+b+2];
|
|
717
|
+
k[b+2]=obj[off+b+1]; k[b+3]=obj[off+b+0];
|
|
718
|
+
}
|
|
719
|
+
fprintf(stderr, "[HOOK] *** AES-128 BSWAP SCHEDULE at %s+0x%zx ***\n", path, off);
|
|
720
|
+
fprintf(stderr, "[HOOK] KEY (bswapped 16):\n");
|
|
721
|
+
hex_dump(stderr, k, 16);
|
|
722
|
+
fprintf(stderr, "[HOOK] raw 16 / IV cand +0xb0:\n");
|
|
723
|
+
hex_dump(stderr, obj + off, 16);
|
|
724
|
+
hex_dump(stderr, obj + off + 176, 16);
|
|
725
|
+
if (logf) {
|
|
726
|
+
fprintf(logf, "\n[KEY] *** AES128-BSWAP at %s+0x%zx addr=0x%llx ***\n",
|
|
727
|
+
path, off, (unsigned long long)(addr + off));
|
|
728
|
+
fprintf(logf, "[KEY] KEY bswapped(16):\n");
|
|
729
|
+
hex_dump(logf, k, 16);
|
|
730
|
+
fprintf(logf, "[KEY] raw(16):\n");
|
|
731
|
+
hex_dump(logf, obj + off, 16);
|
|
732
|
+
fprintf(logf, "[KEY] IV cand(+0xb0):\n");
|
|
733
|
+
hex_dump(logf, obj + off + 176, 16);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
if (is_aes128_key_schedule(obj + off)) {
|
|
737
|
+
fprintf(stderr, "[HOOK] *** AES-128 SCHEDULE at %s+0x%zx ***\n", path, off);
|
|
738
|
+
hex_dump(stderr, obj + off, 16);
|
|
739
|
+
fprintf(stderr, "[HOOK] IV cand +0xb0:\n");
|
|
740
|
+
hex_dump(stderr, obj + off + 176, 16);
|
|
741
|
+
if (logf) {
|
|
742
|
+
fprintf(logf, "\n[KEY] *** AES128 at %s+0x%zx addr=0x%llx ***\n",
|
|
743
|
+
path, off, (unsigned long long)(addr + off));
|
|
744
|
+
fprintf(logf, "[KEY] KEY(16):\n");
|
|
745
|
+
hex_dump(logf, obj + off, 16);
|
|
746
|
+
fprintf(logf, "[KEY] IV cand(+0xb0):\n");
|
|
747
|
+
hex_dump(logf, obj + off + 176, 16);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// Dump first 512 bytes
|
|
753
|
+
hex_dump(stderr, obj, osz < 512 ? (size_t)osz : 512);
|
|
754
|
+
if (logf) {
|
|
755
|
+
fprintf(logf, "\n[OBJ] %s at 0x%llx:\n", path, (unsigned long long)addr);
|
|
756
|
+
hex_dump(logf, obj, osz < 512 ? (size_t)osz : 512);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// Follow pointers (only in first 256 bytes, heap range 0x1-0x7fff)
|
|
760
|
+
if (depth < 2) {
|
|
761
|
+
for (size_t off = 0; off + 8 <= 256 && off + 8 <= (size_t)osz; off += 8) {
|
|
762
|
+
uint64_t val;
|
|
763
|
+
memcpy(&val, obj + off, 8);
|
|
764
|
+
// Skip null, small values, and the vtable pointer we already know
|
|
765
|
+
if (val < 0x10000 || val > 0x7fffffffffffULL) continue;
|
|
766
|
+
// Skip code pointers (in __TEXT segment ~0x100000000-0x110000000)
|
|
767
|
+
if (val >= 0x100000000ULL && val < 0x110000000ULL) continue;
|
|
768
|
+
char subpath[256];
|
|
769
|
+
snprintf(subpath, sizeof(subpath), "%s+0x%zx->", path, off);
|
|
770
|
+
dump_ptr_at(task, val, depth + 1, subpath);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
static void scan_for_key(uint64_t vtable_target) {
|
|
776
|
+
mach_port_t task = mach_task_self();
|
|
777
|
+
size_t chunk = 0x10000; // 64K
|
|
778
|
+
unsigned char *buf = (unsigned char *)malloc(chunk);
|
|
779
|
+
if (!buf) return;
|
|
780
|
+
|
|
781
|
+
unsigned char vtable_bytes[8];
|
|
782
|
+
memcpy(vtable_bytes, &vtable_target, 8);
|
|
783
|
+
|
|
784
|
+
fprintf(stderr, "[HOOK] Scanning ALL memory regions for vtable 0x%llx...\n",
|
|
785
|
+
(unsigned long long)vtable_target);
|
|
786
|
+
|
|
787
|
+
int regions_scanned = 0;
|
|
788
|
+
int found_count = 0;
|
|
789
|
+
mach_vm_address_t addr = 0;
|
|
790
|
+
|
|
791
|
+
while (1) {
|
|
792
|
+
mach_vm_size_t region_size = 0;
|
|
793
|
+
vm_region_basic_info_data_64_t info;
|
|
794
|
+
mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
|
|
795
|
+
mach_port_t obj_name;
|
|
796
|
+
|
|
797
|
+
kern_return_t kr = mach_vm_region(task, &addr, ®ion_size,
|
|
798
|
+
VM_REGION_BASIC_INFO_64,
|
|
799
|
+
(vm_region_info_t)&info, &info_count,
|
|
800
|
+
&obj_name);
|
|
801
|
+
if (kr != KERN_SUCCESS) break;
|
|
802
|
+
|
|
803
|
+
// Only scan readable, writable regions (heap)
|
|
804
|
+
if ((info.protection & VM_PROT_READ) && (info.protection & VM_PROT_WRITE)) {
|
|
805
|
+
regions_scanned++;
|
|
806
|
+
for (uint64_t offset = 0; offset < region_size; offset += chunk) {
|
|
807
|
+
mach_vm_size_t read_size = chunk;
|
|
808
|
+
if (offset + read_size > region_size)
|
|
809
|
+
read_size = region_size - offset;
|
|
810
|
+
|
|
811
|
+
mach_vm_size_t actual = read_size;
|
|
812
|
+
kr = mach_vm_read_overwrite(task, addr + offset, read_size,
|
|
813
|
+
(mach_vm_address_t)buf, &actual);
|
|
814
|
+
if (kr != KERN_SUCCESS) continue;
|
|
815
|
+
|
|
816
|
+
for (size_t i = 0; i + 8 <= (size_t)actual; i += 8) {
|
|
817
|
+
if (memcmp(buf + i, vtable_bytes, 8) == 0) {
|
|
818
|
+
uint64_t obj_addr = addr + offset + i;
|
|
819
|
+
found_count++;
|
|
820
|
+
fprintf(stderr, "\n[HOOK] *** FOUND vtable match at 0x%llx ***\n",
|
|
821
|
+
(unsigned long long)obj_addr);
|
|
822
|
+
|
|
823
|
+
char rootpath[64];
|
|
824
|
+
snprintf(rootpath, sizeof(rootpath), "vtable_0x%llx",
|
|
825
|
+
(unsigned long long)vtable_target);
|
|
826
|
+
dump_ptr_at(task, obj_addr, 0, rootpath);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
addr += region_size;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
free(buf);
|
|
836
|
+
fprintf(stderr, "[HOOK] Scan complete: %d regions scanned, %d matches found.\n",
|
|
837
|
+
regions_scanned, found_count);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
static void try_dump_key(void) {
|
|
841
|
+
if (key_dumped) return;
|
|
842
|
+
key_dumped = 1;
|
|
843
|
+
|
|
844
|
+
intptr_t slide = _dyld_get_image_vmaddr_slide(0);
|
|
845
|
+
// Stick3CryptDmxUniverse vtable[0] file vmaddr
|
|
846
|
+
uint64_t vtable_stick3 = (uint64_t)(0x100964F20 + slide);
|
|
847
|
+
// DasNetCryptDmxUniverse vtable[0] file vmaddr
|
|
848
|
+
uint64_t vtable_base = (uint64_t)(0x100985F18 + slide);
|
|
849
|
+
|
|
850
|
+
fprintf(stderr, "\n[HOOK] === KEY SCAN ===\n");
|
|
851
|
+
fprintf(stderr, "[HOOK] slide=0x%lx\n", (long)slide);
|
|
852
|
+
fprintf(stderr, "[HOOK] Stick3 vtable=0x%llx\n", (unsigned long long)vtable_stick3);
|
|
853
|
+
fprintf(stderr, "[HOOK] DasNet vtable=0x%llx\n", (unsigned long long)vtable_base);
|
|
854
|
+
|
|
855
|
+
scan_for_key(vtable_stick3);
|
|
856
|
+
scan_for_key(vtable_base);
|
|
857
|
+
|
|
858
|
+
// Global scan disabled: the triple validation across all memory is
|
|
859
|
+
// pathologically slow and freezes the app. The fast pointer-following
|
|
860
|
+
// path above (dump_ptr_at) now checks AES-128 + AES-128-bswap on the
|
|
861
|
+
// ~686 crypto sub-objects, which is where the key context actually is.
|
|
862
|
+
// scan_for_key_schedule();
|
|
863
|
+
fprintf(stderr, "[HOOK] (global key-schedule scan skipped; "
|
|
864
|
+
"see AES-128 BSWAP hits in pointer-following output above)\n");
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
ssize_t hooked_sendto(int sockfd, const void *buf, size_t len, int flags,
|
|
868
|
+
const struct sockaddr *dest, socklen_t addrlen) {
|
|
869
|
+
// Trigger key dump on first 576-byte DMX frame
|
|
870
|
+
if (len == 576 && !key_dumped) {
|
|
871
|
+
try_dump_key();
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
if (logf && len > 0) {
|
|
875
|
+
msg_count++;
|
|
876
|
+
if (dest && dest->sa_family == AF_INET) {
|
|
877
|
+
struct sockaddr_in *sin = (struct sockaddr_in *)dest;
|
|
878
|
+
char ip[INET_ADDRSTRLEN];
|
|
879
|
+
inet_ntop(AF_INET, &sin->sin_addr, ip, sizeof(ip));
|
|
880
|
+
fprintf(logf, "\n[%d] SENDTO fd=%d len=%zu -> %s:%d\n", msg_count, sockfd, len, ip, ntohs(sin->sin_port));
|
|
881
|
+
} else {
|
|
882
|
+
fprintf(logf, "\n[%d] SENDTO fd=%d len=%zu\n", msg_count, sockfd, len);
|
|
883
|
+
}
|
|
884
|
+
hex_dump(logf, (const unsigned char *)buf, len > 576 ? 576 : len);
|
|
885
|
+
}
|
|
886
|
+
return sendto(sockfd, buf, len, flags, dest, addrlen);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
ssize_t hooked_sendmsg(int sockfd, const struct msghdr *msg, int flags) {
|
|
890
|
+
ssize_t ret = sendmsg(sockfd, msg, flags);
|
|
891
|
+
if (logf && ret > 0) {
|
|
892
|
+
msg_count++;
|
|
893
|
+
fprintf(logf, "\n[%d] SENDMSG fd=%d ret=%zd iovlen=%d\n", msg_count, sockfd, ret, (int)msg->msg_iovlen);
|
|
894
|
+
for (int i = 0; i < (int)msg->msg_iovlen && i < 4; i++) {
|
|
895
|
+
size_t dump_len = msg->msg_iov[i].iov_len;
|
|
896
|
+
if (dump_len > 256) dump_len = 256;
|
|
897
|
+
fprintf(logf, " iov[%d] len=%zu:\n", i, msg->msg_iov[i].iov_len);
|
|
898
|
+
hex_dump(logf, (const unsigned char *)msg->msg_iov[i].iov_base, dump_len);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
return ret;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
ssize_t hooked_writev(int fd, const struct iovec *iov, int iovcnt) {
|
|
905
|
+
ssize_t ret = writev(fd, iov, iovcnt);
|
|
906
|
+
if (logf && ret > 0) {
|
|
907
|
+
msg_count++;
|
|
908
|
+
fprintf(logf, "\n[%d] WRITEV fd=%d ret=%zd iovcnt=%d\n", msg_count, fd, ret, iovcnt);
|
|
909
|
+
for (int i = 0; i < iovcnt && i < 4; i++) {
|
|
910
|
+
size_t dump_len = iov[i].iov_len;
|
|
911
|
+
if (dump_len > 256) dump_len = 256;
|
|
912
|
+
fprintf(logf, " iov[%d] len=%zu:\n", i, iov[i].iov_len);
|
|
913
|
+
hex_dump(logf, (const unsigned char *)iov[i].iov_base, dump_len);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
return ret;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
ssize_t hooked_recv(int sockfd, void *buf, size_t len, int flags) {
|
|
920
|
+
ssize_t ret = recv(sockfd, buf, len, flags);
|
|
921
|
+
if (logf && ret > 0) {
|
|
922
|
+
msg_count++;
|
|
923
|
+
fprintf(logf, "\n[%d] RECV fd=%d len=%zd\n", msg_count, sockfd, ret);
|
|
924
|
+
hex_dump(logf, (const unsigned char *)buf, (size_t)ret > 512 ? 512 : (size_t)ret);
|
|
925
|
+
}
|
|
926
|
+
return ret;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
int hooked_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
|
930
|
+
int ret = connect(sockfd, addr, addrlen);
|
|
931
|
+
if (addr->sa_family == AF_INET) {
|
|
932
|
+
struct sockaddr_in *sin = (struct sockaddr_in *)addr;
|
|
933
|
+
char ip[INET_ADDRSTRLEN];
|
|
934
|
+
inet_ntop(AF_INET, &sin->sin_addr, ip, sizeof(ip));
|
|
935
|
+
int port = ntohs(sin->sin_port);
|
|
936
|
+
if (logf) fprintf(logf, "\n[CONNECT] fd=%d -> %s:%d ret=%d\n", sockfd, ip, port, ret);
|
|
937
|
+
fprintf(stderr, "[HOOK] CONNECT fd=%d -> %s:%d ret=%d\n", sockfd, ip, port, ret);
|
|
938
|
+
if (port == 2431 && stick_fd_count < 8) {
|
|
939
|
+
stick_fds[stick_fd_count++] = sockfd;
|
|
940
|
+
if (logf) fprintf(logf, "[CONNECT] Tracking Stick fd=%d\n", sockfd);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
return ret;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
ssize_t hooked_write(int fd, const void *buf, size_t len) {
|
|
947
|
+
ssize_t ret = write(fd, buf, len);
|
|
948
|
+
if (logf && ret > 0 && is_stick_fd(fd)) {
|
|
949
|
+
msg_count++;
|
|
950
|
+
fprintf(logf, "\n[%d] WRITE fd=%d len=%zu\n", msg_count, fd, len);
|
|
951
|
+
hex_dump(logf, (const unsigned char *)buf, len > 512 ? 512 : len);
|
|
952
|
+
}
|
|
953
|
+
return ret;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
ssize_t hooked_read(int fd, void *buf, size_t len) {
|
|
957
|
+
ssize_t ret = read(fd, buf, len);
|
|
958
|
+
if (logf && ret > 0 && is_stick_fd(fd)) {
|
|
959
|
+
msg_count++;
|
|
960
|
+
fprintf(logf, "\n[%d] READ fd=%d len=%zd\n", msg_count, fd, ret);
|
|
961
|
+
hex_dump(logf, (const unsigned char *)buf, (size_t)ret > 512 ? 512 : (size_t)ret);
|
|
962
|
+
}
|
|
963
|
+
return ret;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// =====================================================================
|
|
967
|
+
// mbedtls AES — ALL MODES
|
|
968
|
+
// =====================================================================
|
|
969
|
+
typedef struct mbedtls_aes_context mbedtls_aes_context;
|
|
970
|
+
typedef struct mbedtls_aes_xts_context mbedtls_aes_xts_context;
|
|
971
|
+
|
|
972
|
+
extern int mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key, unsigned int keybits);
|
|
973
|
+
extern int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key, unsigned int keybits);
|
|
974
|
+
extern int mbedtls_aes_crypt_ecb(mbedtls_aes_context *ctx, int mode, const unsigned char input[16], unsigned char output[16]);
|
|
975
|
+
extern int mbedtls_aes_crypt_cbc(mbedtls_aes_context *ctx, int mode, size_t length, unsigned char iv[16], const unsigned char *input, unsigned char *output);
|
|
976
|
+
extern int mbedtls_aes_crypt_cfb128(mbedtls_aes_context *ctx, int mode, size_t length, size_t *iv_off, unsigned char iv[16], const unsigned char *input, unsigned char *output);
|
|
977
|
+
extern int mbedtls_aes_crypt_ofb(mbedtls_aes_context *ctx, size_t length, size_t *iv_off, unsigned char iv[16], const unsigned char *input, unsigned char *output);
|
|
978
|
+
extern int mbedtls_aes_crypt_ctr(mbedtls_aes_context *ctx, size_t length, size_t *nc_off, unsigned char nonce_counter[16], unsigned char stream_block[16], const unsigned char *input, unsigned char *output);
|
|
979
|
+
extern int mbedtls_aes_crypt_xts(mbedtls_aes_xts_context *ctx, int mode, size_t length, const unsigned char data_unit[16], const unsigned char *input, unsigned char *output);
|
|
980
|
+
|
|
981
|
+
int hooked_mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key, unsigned int keybits) {
|
|
982
|
+
fprintf(stderr, "[HOOK] >>> AES_SETKEY_ENC keybits=%u <<<\n", keybits);
|
|
983
|
+
if (logf) {
|
|
984
|
+
fprintf(logf, "\n=== AES_SETKEY_ENC keybits=%u ===\n", keybits);
|
|
985
|
+
hex_dump(logf, key, keybits / 8);
|
|
986
|
+
}
|
|
987
|
+
return mbedtls_aes_setkey_enc(ctx, key, keybits);
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
int hooked_mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key, unsigned int keybits) {
|
|
991
|
+
fprintf(stderr, "[HOOK] >>> AES_SETKEY_DEC keybits=%u <<<\n", keybits);
|
|
992
|
+
if (logf) {
|
|
993
|
+
fprintf(logf, "\n=== AES_SETKEY_DEC keybits=%u ===\n", keybits);
|
|
994
|
+
hex_dump(logf, key, keybits / 8);
|
|
995
|
+
}
|
|
996
|
+
return mbedtls_aes_setkey_dec(ctx, key, keybits);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
int hooked_mbedtls_aes_crypt_ecb(mbedtls_aes_context *ctx, int mode, const unsigned char input[16], unsigned char output[16]) {
|
|
1000
|
+
fprintf(stderr, "[HOOK] >>> AES_ECB mode=%d <<<\n", mode);
|
|
1001
|
+
if (logf) {
|
|
1002
|
+
fprintf(logf, "\n=== AES_ECB mode=%s ===\n", mode ? "DECRYPT" : "ENCRYPT");
|
|
1003
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, 16);
|
|
1004
|
+
}
|
|
1005
|
+
int ret = mbedtls_aes_crypt_ecb(ctx, mode, input, output);
|
|
1006
|
+
if (logf) { fprintf(logf, " output:\n"); hex_dump(logf, output, 16); }
|
|
1007
|
+
return ret;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
int hooked_mbedtls_aes_crypt_cbc(mbedtls_aes_context *ctx, int mode, size_t length, unsigned char iv[16], const unsigned char *input, unsigned char *output) {
|
|
1011
|
+
fprintf(stderr, "[HOOK] >>> AES_CBC mode=%d len=%zu <<<\n", mode, length);
|
|
1012
|
+
if (logf) {
|
|
1013
|
+
fprintf(logf, "\n=== AES_CBC mode=%s len=%zu ===\n", mode ? "DECRYPT" : "ENCRYPT", length);
|
|
1014
|
+
fprintf(logf, " iv:\n"); hex_dump(logf, iv, 16);
|
|
1015
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, length > 256 ? 256 : length);
|
|
1016
|
+
}
|
|
1017
|
+
int ret = mbedtls_aes_crypt_cbc(ctx, mode, length, iv, input, output);
|
|
1018
|
+
if (logf) { fprintf(logf, " output:\n"); hex_dump(logf, output, length > 256 ? 256 : length); }
|
|
1019
|
+
return ret;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
int hooked_mbedtls_aes_crypt_cfb128(mbedtls_aes_context *ctx, int mode, size_t length, size_t *iv_off, unsigned char iv[16], const unsigned char *input, unsigned char *output) {
|
|
1023
|
+
fprintf(stderr, "[HOOK] >>> AES_CFB128 mode=%d len=%zu <<<\n", mode, length);
|
|
1024
|
+
if (logf) {
|
|
1025
|
+
fprintf(logf, "\n=== AES_CFB128 mode=%s len=%zu iv_off=%zu ===\n", mode ? "DECRYPT" : "ENCRYPT", length, *iv_off);
|
|
1026
|
+
fprintf(logf, " iv:\n"); hex_dump(logf, iv, 16);
|
|
1027
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, length > 256 ? 256 : length);
|
|
1028
|
+
}
|
|
1029
|
+
int ret = mbedtls_aes_crypt_cfb128(ctx, mode, length, iv_off, iv, input, output);
|
|
1030
|
+
if (logf) { fprintf(logf, " output:\n"); hex_dump(logf, output, length > 256 ? 256 : length); }
|
|
1031
|
+
return ret;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
int hooked_mbedtls_aes_crypt_ofb(mbedtls_aes_context *ctx, size_t length, size_t *iv_off, unsigned char iv[16], const unsigned char *input, unsigned char *output) {
|
|
1035
|
+
fprintf(stderr, "[HOOK] >>> AES_OFB len=%zu <<<\n", length);
|
|
1036
|
+
if (logf) {
|
|
1037
|
+
fprintf(logf, "\n=== AES_OFB len=%zu iv_off=%zu ===\n", length, *iv_off);
|
|
1038
|
+
fprintf(logf, " iv:\n"); hex_dump(logf, iv, 16);
|
|
1039
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, length > 256 ? 256 : length);
|
|
1040
|
+
}
|
|
1041
|
+
int ret = mbedtls_aes_crypt_ofb(ctx, length, iv_off, iv, input, output);
|
|
1042
|
+
if (logf) { fprintf(logf, " output:\n"); hex_dump(logf, output, length > 256 ? 256 : length); }
|
|
1043
|
+
return ret;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
int hooked_mbedtls_aes_crypt_ctr(mbedtls_aes_context *ctx, size_t length, size_t *nc_off, unsigned char nonce_counter[16], unsigned char stream_block[16], const unsigned char *input, unsigned char *output) {
|
|
1047
|
+
fprintf(stderr, "[HOOK] >>> AES_CTR len=%zu <<<\n", length);
|
|
1048
|
+
if (logf) {
|
|
1049
|
+
fprintf(logf, "\n=== AES_CTR len=%zu nc_off=%zu ===\n", length, *nc_off);
|
|
1050
|
+
fprintf(logf, " nonce_counter:\n"); hex_dump(logf, nonce_counter, 16);
|
|
1051
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, length > 256 ? 256 : length);
|
|
1052
|
+
}
|
|
1053
|
+
int ret = mbedtls_aes_crypt_ctr(ctx, length, nc_off, nonce_counter, stream_block, input, output);
|
|
1054
|
+
if (logf) { fprintf(logf, " output:\n"); hex_dump(logf, output, length > 256 ? 256 : length); }
|
|
1055
|
+
return ret;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
int hooked_mbedtls_aes_crypt_xts(mbedtls_aes_xts_context *ctx, int mode, size_t length, const unsigned char data_unit[16], const unsigned char *input, unsigned char *output) {
|
|
1059
|
+
fprintf(stderr, "[HOOK] >>> AES_XTS mode=%d len=%zu <<<\n", mode, length);
|
|
1060
|
+
if (logf) {
|
|
1061
|
+
fprintf(logf, "\n=== AES_XTS mode=%s len=%zu ===\n", mode ? "DECRYPT" : "ENCRYPT", length);
|
|
1062
|
+
fprintf(logf, " data_unit:\n"); hex_dump(logf, data_unit, 16);
|
|
1063
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, length > 256 ? 256 : length);
|
|
1064
|
+
}
|
|
1065
|
+
int ret = mbedtls_aes_crypt_xts(ctx, mode, length, data_unit, input, output);
|
|
1066
|
+
if (logf) { fprintf(logf, " output:\n"); hex_dump(logf, output, length > 256 ? 256 : length); }
|
|
1067
|
+
return ret;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// =====================================================================
|
|
1071
|
+
// mbedtls GCM
|
|
1072
|
+
// =====================================================================
|
|
1073
|
+
typedef struct mbedtls_gcm_context mbedtls_gcm_context;
|
|
1074
|
+
|
|
1075
|
+
extern int mbedtls_gcm_setkey(mbedtls_gcm_context *ctx, int cipher, const unsigned char *key, unsigned int keybits);
|
|
1076
|
+
extern int mbedtls_gcm_crypt_and_tag(mbedtls_gcm_context *ctx, int mode, size_t length,
|
|
1077
|
+
const unsigned char *iv, size_t iv_len, const unsigned char *add, size_t add_len,
|
|
1078
|
+
const unsigned char *input, unsigned char *output, size_t tag_len, unsigned char *tag);
|
|
1079
|
+
extern int mbedtls_gcm_starts(mbedtls_gcm_context *ctx, int mode, const unsigned char *iv, size_t iv_len);
|
|
1080
|
+
extern int mbedtls_gcm_update(mbedtls_gcm_context *ctx, const unsigned char *input, size_t input_length, unsigned char *output, size_t output_size, size_t *output_length);
|
|
1081
|
+
|
|
1082
|
+
int hooked_mbedtls_gcm_setkey(mbedtls_gcm_context *ctx, int cipher, const unsigned char *key, unsigned int keybits) {
|
|
1083
|
+
fprintf(stderr, "[HOOK] >>> GCM_SETKEY cipher=%d keybits=%u <<<\n", cipher, keybits);
|
|
1084
|
+
if (logf) {
|
|
1085
|
+
fprintf(logf, "\n=== GCM_SETKEY cipher=%d keybits=%u ===\n", cipher, keybits);
|
|
1086
|
+
hex_dump(logf, key, keybits / 8);
|
|
1087
|
+
}
|
|
1088
|
+
return mbedtls_gcm_setkey(ctx, cipher, key, keybits);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
int hooked_mbedtls_gcm_crypt_and_tag(mbedtls_gcm_context *ctx, int mode, size_t length,
|
|
1092
|
+
const unsigned char *iv, size_t iv_len, const unsigned char *add, size_t add_len,
|
|
1093
|
+
const unsigned char *input, unsigned char *output, size_t tag_len, unsigned char *tag) {
|
|
1094
|
+
fprintf(stderr, "[HOOK] >>> GCM_CRYPT_AND_TAG mode=%d len=%zu <<<\n", mode, length);
|
|
1095
|
+
if (logf) {
|
|
1096
|
+
fprintf(logf, "\n=== GCM_CRYPT_AND_TAG mode=%s len=%zu iv_len=%zu add_len=%zu tag_len=%zu ===\n",
|
|
1097
|
+
mode ? "DECRYPT" : "ENCRYPT", length, iv_len, add_len, tag_len);
|
|
1098
|
+
fprintf(logf, " iv:\n"); hex_dump(logf, iv, iv_len);
|
|
1099
|
+
if (add_len > 0) { fprintf(logf, " aad:\n"); hex_dump(logf, add, add_len > 64 ? 64 : add_len); }
|
|
1100
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, length > 256 ? 256 : length);
|
|
1101
|
+
}
|
|
1102
|
+
int ret = mbedtls_gcm_crypt_and_tag(ctx, mode, length, iv, iv_len, add, add_len, input, output, tag_len, tag);
|
|
1103
|
+
if (logf) {
|
|
1104
|
+
fprintf(logf, " output:\n"); hex_dump(logf, output, length > 256 ? 256 : length);
|
|
1105
|
+
fprintf(logf, " tag:\n"); hex_dump(logf, tag, tag_len);
|
|
1106
|
+
}
|
|
1107
|
+
return ret;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
int hooked_mbedtls_gcm_starts(mbedtls_gcm_context *ctx, int mode, const unsigned char *iv, size_t iv_len) {
|
|
1111
|
+
fprintf(stderr, "[HOOK] >>> GCM_STARTS mode=%d iv_len=%zu <<<\n", mode, iv_len);
|
|
1112
|
+
if (logf) {
|
|
1113
|
+
fprintf(logf, "\n=== GCM_STARTS mode=%s iv_len=%zu ===\n", mode ? "DECRYPT" : "ENCRYPT", iv_len);
|
|
1114
|
+
fprintf(logf, " iv:\n"); hex_dump(logf, iv, iv_len);
|
|
1115
|
+
}
|
|
1116
|
+
return mbedtls_gcm_starts(ctx, mode, iv, iv_len);
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
int hooked_mbedtls_gcm_update(mbedtls_gcm_context *ctx, const unsigned char *input, size_t input_length, unsigned char *output, size_t output_size, size_t *output_length) {
|
|
1120
|
+
fprintf(stderr, "[HOOK] >>> GCM_UPDATE input_len=%zu <<<\n", input_length);
|
|
1121
|
+
if (logf) {
|
|
1122
|
+
fprintf(logf, "\n=== GCM_UPDATE input_len=%zu output_size=%zu ===\n", input_length, output_size);
|
|
1123
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, input_length > 256 ? 256 : input_length);
|
|
1124
|
+
}
|
|
1125
|
+
int ret = mbedtls_gcm_update(ctx, input, input_length, output, output_size, output_length);
|
|
1126
|
+
if (logf && output_length) {
|
|
1127
|
+
fprintf(logf, " output (len=%zu):\n", *output_length);
|
|
1128
|
+
hex_dump(logf, output, *output_length > 256 ? 256 : *output_length);
|
|
1129
|
+
}
|
|
1130
|
+
return ret;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
// =====================================================================
|
|
1134
|
+
// mbedtls CCM
|
|
1135
|
+
// =====================================================================
|
|
1136
|
+
typedef struct mbedtls_ccm_context mbedtls_ccm_context;
|
|
1137
|
+
|
|
1138
|
+
extern int mbedtls_ccm_setkey(mbedtls_ccm_context *ctx, int cipher, const unsigned char *key, unsigned int keybits);
|
|
1139
|
+
extern int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
|
|
1140
|
+
const unsigned char *iv, size_t iv_len, const unsigned char *ad, size_t ad_len,
|
|
1141
|
+
const unsigned char *input, unsigned char *output, unsigned char *tag, size_t tag_len);
|
|
1142
|
+
extern int mbedtls_ccm_update(mbedtls_ccm_context *ctx, const unsigned char *input, size_t input_length, unsigned char *output, size_t output_size, size_t *output_length);
|
|
1143
|
+
|
|
1144
|
+
int hooked_mbedtls_ccm_setkey(mbedtls_ccm_context *ctx, int cipher, const unsigned char *key, unsigned int keybits) {
|
|
1145
|
+
fprintf(stderr, "[HOOK] >>> CCM_SETKEY cipher=%d keybits=%u <<<\n", cipher, keybits);
|
|
1146
|
+
if (logf) {
|
|
1147
|
+
fprintf(logf, "\n=== CCM_SETKEY cipher=%d keybits=%u ===\n", cipher, keybits);
|
|
1148
|
+
hex_dump(logf, key, keybits / 8);
|
|
1149
|
+
}
|
|
1150
|
+
return mbedtls_ccm_setkey(ctx, cipher, key, keybits);
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
int hooked_mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
|
|
1154
|
+
const unsigned char *iv, size_t iv_len, const unsigned char *ad, size_t ad_len,
|
|
1155
|
+
const unsigned char *input, unsigned char *output, unsigned char *tag, size_t tag_len) {
|
|
1156
|
+
fprintf(stderr, "[HOOK] >>> CCM_ENCRYPT_AND_TAG len=%zu <<<\n", length);
|
|
1157
|
+
if (logf) {
|
|
1158
|
+
fprintf(logf, "\n=== CCM_ENCRYPT_AND_TAG len=%zu iv_len=%zu ad_len=%zu tag_len=%zu ===\n",
|
|
1159
|
+
length, iv_len, ad_len, tag_len);
|
|
1160
|
+
fprintf(logf, " iv:\n"); hex_dump(logf, iv, iv_len);
|
|
1161
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, length > 256 ? 256 : length);
|
|
1162
|
+
}
|
|
1163
|
+
int ret = mbedtls_ccm_encrypt_and_tag(ctx, length, iv, iv_len, ad, ad_len, input, output, tag, tag_len);
|
|
1164
|
+
if (logf) {
|
|
1165
|
+
fprintf(logf, " output:\n"); hex_dump(logf, output, length > 256 ? 256 : length);
|
|
1166
|
+
fprintf(logf, " tag:\n"); hex_dump(logf, tag, tag_len);
|
|
1167
|
+
}
|
|
1168
|
+
return ret;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
int hooked_mbedtls_ccm_update(mbedtls_ccm_context *ctx, const unsigned char *input, size_t input_length, unsigned char *output, size_t output_size, size_t *output_length) {
|
|
1172
|
+
fprintf(stderr, "[HOOK] >>> CCM_UPDATE input_len=%zu <<<\n", input_length);
|
|
1173
|
+
if (logf) {
|
|
1174
|
+
fprintf(logf, "\n=== CCM_UPDATE input_len=%zu ===\n", input_length);
|
|
1175
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, input_length > 256 ? 256 : input_length);
|
|
1176
|
+
}
|
|
1177
|
+
int ret = mbedtls_ccm_update(ctx, input, input_length, output, output_size, output_length);
|
|
1178
|
+
if (logf && output_length) {
|
|
1179
|
+
fprintf(logf, " output (len=%zu):\n", *output_length);
|
|
1180
|
+
hex_dump(logf, output, *output_length > 256 ? 256 : *output_length);
|
|
1181
|
+
}
|
|
1182
|
+
return ret;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// =====================================================================
|
|
1186
|
+
// mbedtls ChaCha20 / ChaChaPoly
|
|
1187
|
+
// =====================================================================
|
|
1188
|
+
typedef struct mbedtls_chacha20_context mbedtls_chacha20_context;
|
|
1189
|
+
typedef struct mbedtls_chachapoly_context mbedtls_chachapoly_context;
|
|
1190
|
+
|
|
1191
|
+
extern int mbedtls_chacha20_crypt(const unsigned char key[32], const unsigned char nonce[12], uint32_t counter, size_t size, const unsigned char *input, unsigned char *output);
|
|
1192
|
+
extern int mbedtls_chacha20_update(mbedtls_chacha20_context *ctx, size_t size, const unsigned char *input, unsigned char *output);
|
|
1193
|
+
extern int mbedtls_chachapoly_encrypt_and_tag(mbedtls_chachapoly_context *ctx, size_t length, const unsigned char nonce[12], const unsigned char *aad, size_t aad_len, const unsigned char *input, unsigned char *output, unsigned char tag[16]);
|
|
1194
|
+
extern int mbedtls_chachapoly_update(mbedtls_chachapoly_context *ctx, size_t len, const unsigned char *input, unsigned char *output);
|
|
1195
|
+
|
|
1196
|
+
int hooked_mbedtls_chacha20_crypt(const unsigned char key[32], const unsigned char nonce[12], uint32_t counter, size_t size, const unsigned char *input, unsigned char *output) {
|
|
1197
|
+
fprintf(stderr, "[HOOK] >>> CHACHA20_CRYPT size=%zu <<<\n", size);
|
|
1198
|
+
if (logf) {
|
|
1199
|
+
fprintf(logf, "\n=== CHACHA20_CRYPT size=%zu counter=%u ===\n", size, counter);
|
|
1200
|
+
fprintf(logf, " key:\n"); hex_dump(logf, key, 32);
|
|
1201
|
+
fprintf(logf, " nonce:\n"); hex_dump(logf, nonce, 12);
|
|
1202
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, size > 256 ? 256 : size);
|
|
1203
|
+
}
|
|
1204
|
+
int ret = mbedtls_chacha20_crypt(key, nonce, counter, size, input, output);
|
|
1205
|
+
if (logf) { fprintf(logf, " output:\n"); hex_dump(logf, output, size > 256 ? 256 : size); }
|
|
1206
|
+
return ret;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
int hooked_mbedtls_chacha20_update(mbedtls_chacha20_context *ctx, size_t size, const unsigned char *input, unsigned char *output) {
|
|
1210
|
+
fprintf(stderr, "[HOOK] >>> CHACHA20_UPDATE size=%zu <<<\n", size);
|
|
1211
|
+
if (logf) {
|
|
1212
|
+
fprintf(logf, "\n=== CHACHA20_UPDATE size=%zu ===\n", size);
|
|
1213
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, size > 256 ? 256 : size);
|
|
1214
|
+
}
|
|
1215
|
+
int ret = mbedtls_chacha20_update(ctx, size, input, output);
|
|
1216
|
+
if (logf) { fprintf(logf, " output:\n"); hex_dump(logf, output, size > 256 ? 256 : size); }
|
|
1217
|
+
return ret;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
int hooked_mbedtls_chachapoly_encrypt_and_tag(mbedtls_chachapoly_context *ctx, size_t length, const unsigned char nonce[12], const unsigned char *aad, size_t aad_len, const unsigned char *input, unsigned char *output, unsigned char tag[16]) {
|
|
1221
|
+
fprintf(stderr, "[HOOK] >>> CHACHAPOLY_ENCRYPT len=%zu <<<\n", length);
|
|
1222
|
+
if (logf) {
|
|
1223
|
+
fprintf(logf, "\n=== CHACHAPOLY_ENCRYPT_AND_TAG len=%zu aad_len=%zu ===\n", length, aad_len);
|
|
1224
|
+
fprintf(logf, " nonce:\n"); hex_dump(logf, nonce, 12);
|
|
1225
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, length > 256 ? 256 : length);
|
|
1226
|
+
}
|
|
1227
|
+
int ret = mbedtls_chachapoly_encrypt_and_tag(ctx, length, nonce, aad, aad_len, input, output, tag);
|
|
1228
|
+
if (logf) {
|
|
1229
|
+
fprintf(logf, " output:\n"); hex_dump(logf, output, length > 256 ? 256 : length);
|
|
1230
|
+
fprintf(logf, " tag:\n"); hex_dump(logf, tag, 16);
|
|
1231
|
+
}
|
|
1232
|
+
return ret;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
int hooked_mbedtls_chachapoly_update(mbedtls_chachapoly_context *ctx, size_t len, const unsigned char *input, unsigned char *output) {
|
|
1236
|
+
fprintf(stderr, "[HOOK] >>> CHACHAPOLY_UPDATE len=%zu <<<\n", len);
|
|
1237
|
+
if (logf) {
|
|
1238
|
+
fprintf(logf, "\n=== CHACHAPOLY_UPDATE len=%zu ===\n", len);
|
|
1239
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, len > 256 ? 256 : len);
|
|
1240
|
+
}
|
|
1241
|
+
int ret = mbedtls_chachapoly_update(ctx, len, input, output);
|
|
1242
|
+
if (logf) { fprintf(logf, " output:\n"); hex_dump(logf, output, len > 256 ? 256 : len); }
|
|
1243
|
+
return ret;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// =====================================================================
|
|
1247
|
+
// mbedtls generic cipher API
|
|
1248
|
+
// =====================================================================
|
|
1249
|
+
typedef struct mbedtls_cipher_context_t mbedtls_cipher_context_t;
|
|
1250
|
+
typedef void mbedtls_cipher_info_t;
|
|
1251
|
+
|
|
1252
|
+
extern int mbedtls_cipher_setkey(mbedtls_cipher_context_t *ctx, const unsigned char *key, int key_bitlen, int operation);
|
|
1253
|
+
extern int mbedtls_cipher_crypt(mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen);
|
|
1254
|
+
extern int mbedtls_cipher_auth_encrypt_ext(mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len, const unsigned char *ad, size_t ad_len, const unsigned char *input, size_t ilen, unsigned char *output, size_t output_len, size_t *olen, size_t tag_len);
|
|
1255
|
+
|
|
1256
|
+
int hooked_mbedtls_cipher_setkey(mbedtls_cipher_context_t *ctx, const unsigned char *key, int key_bitlen, int operation) {
|
|
1257
|
+
fprintf(stderr, "[HOOK] >>> CIPHER_SETKEY keybits=%d op=%s <<<\n", key_bitlen, operation ? "DECRYPT" : "ENCRYPT");
|
|
1258
|
+
if (logf) {
|
|
1259
|
+
fprintf(logf, "\n=== CIPHER_SETKEY keybits=%d op=%s ===\n", key_bitlen, operation ? "DECRYPT" : "ENCRYPT");
|
|
1260
|
+
hex_dump(logf, key, key_bitlen / 8);
|
|
1261
|
+
}
|
|
1262
|
+
return mbedtls_cipher_setkey(ctx, key, key_bitlen, operation);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
int hooked_mbedtls_cipher_crypt(mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen) {
|
|
1266
|
+
fprintf(stderr, "[HOOK] >>> CIPHER_CRYPT ilen=%zu iv_len=%zu <<<\n", ilen, iv_len);
|
|
1267
|
+
if (logf) {
|
|
1268
|
+
fprintf(logf, "\n=== CIPHER_CRYPT ilen=%zu iv_len=%zu ===\n", ilen, iv_len);
|
|
1269
|
+
if (iv_len > 0) { fprintf(logf, " iv:\n"); hex_dump(logf, iv, iv_len); }
|
|
1270
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, ilen > 256 ? 256 : ilen);
|
|
1271
|
+
}
|
|
1272
|
+
int ret = mbedtls_cipher_crypt(ctx, iv, iv_len, input, ilen, output, olen);
|
|
1273
|
+
if (logf && olen) {
|
|
1274
|
+
fprintf(logf, " output (len=%zu):\n", *olen);
|
|
1275
|
+
hex_dump(logf, output, *olen > 256 ? 256 : *olen);
|
|
1276
|
+
}
|
|
1277
|
+
return ret;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
int hooked_mbedtls_cipher_auth_encrypt_ext(mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len, const unsigned char *ad, size_t ad_len, const unsigned char *input, size_t ilen, unsigned char *output, size_t output_len, size_t *olen, size_t tag_len) {
|
|
1281
|
+
fprintf(stderr, "[HOOK] >>> CIPHER_AUTH_ENCRYPT_EXT ilen=%zu tag_len=%zu <<<\n", ilen, tag_len);
|
|
1282
|
+
if (logf) {
|
|
1283
|
+
fprintf(logf, "\n=== CIPHER_AUTH_ENCRYPT_EXT ilen=%zu iv_len=%zu ad_len=%zu tag_len=%zu ===\n",
|
|
1284
|
+
ilen, iv_len, ad_len, tag_len);
|
|
1285
|
+
if (iv_len > 0) { fprintf(logf, " iv:\n"); hex_dump(logf, iv, iv_len); }
|
|
1286
|
+
fprintf(logf, " input:\n"); hex_dump(logf, input, ilen > 256 ? 256 : ilen);
|
|
1287
|
+
}
|
|
1288
|
+
int ret = mbedtls_cipher_auth_encrypt_ext(ctx, iv, iv_len, ad, ad_len, input, ilen, output, output_len, olen, tag_len);
|
|
1289
|
+
if (logf && olen) {
|
|
1290
|
+
fprintf(logf, " output (len=%zu):\n", *olen);
|
|
1291
|
+
hex_dump(logf, output, *olen > 256 ? 256 : *olen);
|
|
1292
|
+
}
|
|
1293
|
+
return ret;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
// =====================================================================
|
|
1297
|
+
// QCryptographicHash::hash hook — capture key derivation
|
|
1298
|
+
// =====================================================================
|
|
1299
|
+
|
|
1300
|
+
// Qt's QByteArray internal: pointer to QArrayData
|
|
1301
|
+
// QArrayData: ref(4), size(4), alloc(4), [pad 4], offset(8)
|
|
1302
|
+
// Data at: (char*)d + d->offset
|
|
1303
|
+
|
|
1304
|
+
extern void* _ZN18QCryptographicHash4hashERK10QByteArrayNS_9AlgorithmE(
|
|
1305
|
+
void *retval, const void *data, int method);
|
|
1306
|
+
|
|
1307
|
+
void* hooked_QCryptographicHash_hash(void *retval, const void *data, int method) {
|
|
1308
|
+
static const char *algo_names[] = {
|
|
1309
|
+
"MD4", "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512",
|
|
1310
|
+
"SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512", "KECCAK_224",
|
|
1311
|
+
"KECCAK_256", "KECCAK_384", "KECCAK_512", "BLAKE2b_512", "BLAKE2s_256"
|
|
1312
|
+
};
|
|
1313
|
+
const char *algo = (method >= 0 && method < 17) ? algo_names[method] : "UNKNOWN";
|
|
1314
|
+
|
|
1315
|
+
msg_count++;
|
|
1316
|
+
fprintf(stderr, "\n[HOOK] >>> QCryptographicHash::hash algo=%d (%s) <<<\n", method, algo);
|
|
1317
|
+
|
|
1318
|
+
// Extract input from QByteArray
|
|
1319
|
+
void *d = *(void **)data;
|
|
1320
|
+
int in_size = 0;
|
|
1321
|
+
const unsigned char *in_bytes = NULL;
|
|
1322
|
+
if (d) {
|
|
1323
|
+
in_size = *((int *)((char *)d + 4));
|
|
1324
|
+
long off = *(long *)((char *)d + 16);
|
|
1325
|
+
in_bytes = (const unsigned char *)((char *)d + off);
|
|
1326
|
+
fprintf(stderr, "[HOOK] input (%d bytes):\n", in_size);
|
|
1327
|
+
hex_dump(stderr, in_bytes, in_size > 256 ? 256 : in_size);
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
if (logf) {
|
|
1331
|
+
fprintf(logf, "\n[%d] QCryptographicHash::hash algo=%d (%s)\n", msg_count, method, algo);
|
|
1332
|
+
if (in_bytes) {
|
|
1333
|
+
fprintf(logf, " input (%d bytes):\n", in_size);
|
|
1334
|
+
hex_dump(logf, in_bytes, in_size > 256 ? 256 : in_size);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
void *result = _ZN18QCryptographicHash4hashERK10QByteArrayNS_9AlgorithmE(retval, data, method);
|
|
1339
|
+
|
|
1340
|
+
// Extract output
|
|
1341
|
+
void *rd = *(void **)retval;
|
|
1342
|
+
if (rd) {
|
|
1343
|
+
int out_size = *((int *)((char *)rd + 4));
|
|
1344
|
+
long roff = *(long *)((char *)rd + 16);
|
|
1345
|
+
const unsigned char *out_bytes = (const unsigned char *)((char *)rd + roff);
|
|
1346
|
+
fprintf(stderr, "[HOOK] output (%d bytes):\n", out_size);
|
|
1347
|
+
hex_dump(stderr, out_bytes, out_size > 64 ? 64 : out_size);
|
|
1348
|
+
if (logf) {
|
|
1349
|
+
fprintf(logf, " output (%d bytes):\n", out_size);
|
|
1350
|
+
hex_dump(logf, out_bytes, out_size > 64 ? 64 : out_size);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
return result;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
// =====================================================================
|
|
1358
|
+
// DYLD_INTERPOSE declarations
|
|
1359
|
+
// =====================================================================
|
|
1360
|
+
|
|
1361
|
+
// Socket hooks
|
|
1362
|
+
DYLD_INTERPOSE(hooked_send, send)
|
|
1363
|
+
DYLD_INTERPOSE(hooked_recv, recv)
|
|
1364
|
+
DYLD_INTERPOSE(hooked_write, write)
|
|
1365
|
+
DYLD_INTERPOSE(hooked_read, read)
|
|
1366
|
+
DYLD_INTERPOSE(hooked_connect, connect)
|
|
1367
|
+
DYLD_INTERPOSE(hooked_sendto, sendto)
|
|
1368
|
+
DYLD_INTERPOSE(hooked_sendmsg, sendmsg)
|
|
1369
|
+
DYLD_INTERPOSE(hooked_writev, writev)
|
|
1370
|
+
|
|
1371
|
+
// AES — all modes
|
|
1372
|
+
DYLD_INTERPOSE(hooked_mbedtls_aes_setkey_enc, mbedtls_aes_setkey_enc)
|
|
1373
|
+
DYLD_INTERPOSE(hooked_mbedtls_aes_setkey_dec, mbedtls_aes_setkey_dec)
|
|
1374
|
+
DYLD_INTERPOSE(hooked_mbedtls_aes_crypt_ecb, mbedtls_aes_crypt_ecb)
|
|
1375
|
+
DYLD_INTERPOSE(hooked_mbedtls_aes_crypt_cbc, mbedtls_aes_crypt_cbc)
|
|
1376
|
+
DYLD_INTERPOSE(hooked_mbedtls_aes_crypt_cfb128, mbedtls_aes_crypt_cfb128)
|
|
1377
|
+
DYLD_INTERPOSE(hooked_mbedtls_aes_crypt_ofb, mbedtls_aes_crypt_ofb)
|
|
1378
|
+
DYLD_INTERPOSE(hooked_mbedtls_aes_crypt_ctr, mbedtls_aes_crypt_ctr)
|
|
1379
|
+
DYLD_INTERPOSE(hooked_mbedtls_aes_crypt_xts, mbedtls_aes_crypt_xts)
|
|
1380
|
+
|
|
1381
|
+
// GCM
|
|
1382
|
+
DYLD_INTERPOSE(hooked_mbedtls_gcm_setkey, mbedtls_gcm_setkey)
|
|
1383
|
+
DYLD_INTERPOSE(hooked_mbedtls_gcm_crypt_and_tag, mbedtls_gcm_crypt_and_tag)
|
|
1384
|
+
DYLD_INTERPOSE(hooked_mbedtls_gcm_starts, mbedtls_gcm_starts)
|
|
1385
|
+
DYLD_INTERPOSE(hooked_mbedtls_gcm_update, mbedtls_gcm_update)
|
|
1386
|
+
|
|
1387
|
+
// CCM
|
|
1388
|
+
DYLD_INTERPOSE(hooked_mbedtls_ccm_setkey, mbedtls_ccm_setkey)
|
|
1389
|
+
DYLD_INTERPOSE(hooked_mbedtls_ccm_encrypt_and_tag, mbedtls_ccm_encrypt_and_tag)
|
|
1390
|
+
DYLD_INTERPOSE(hooked_mbedtls_ccm_update, mbedtls_ccm_update)
|
|
1391
|
+
|
|
1392
|
+
// ChaCha20 / ChaChaPoly
|
|
1393
|
+
DYLD_INTERPOSE(hooked_mbedtls_chacha20_crypt, mbedtls_chacha20_crypt)
|
|
1394
|
+
DYLD_INTERPOSE(hooked_mbedtls_chacha20_update, mbedtls_chacha20_update)
|
|
1395
|
+
DYLD_INTERPOSE(hooked_mbedtls_chachapoly_encrypt_and_tag, mbedtls_chachapoly_encrypt_and_tag)
|
|
1396
|
+
DYLD_INTERPOSE(hooked_mbedtls_chachapoly_update, mbedtls_chachapoly_update)
|
|
1397
|
+
|
|
1398
|
+
// Generic cipher API
|
|
1399
|
+
DYLD_INTERPOSE(hooked_mbedtls_cipher_setkey, mbedtls_cipher_setkey)
|
|
1400
|
+
DYLD_INTERPOSE(hooked_mbedtls_cipher_crypt, mbedtls_cipher_crypt)
|
|
1401
|
+
DYLD_INTERPOSE(hooked_mbedtls_cipher_auth_encrypt_ext, mbedtls_cipher_auth_encrypt_ext)
|
|
1402
|
+
|
|
1403
|
+
// Qt crypto
|
|
1404
|
+
DYLD_INTERPOSE(hooked_QCryptographicHash_hash, _ZN18QCryptographicHash4hashERK10QByteArrayNS_9AlgorithmE)
|