Skip to content

Commit

Permalink
contrib: add extract-handshakes kprobe example
Browse files Browse the repository at this point in the history
  • Loading branch information
zx2c4 committed Mar 4, 2018
1 parent 37dc953 commit b6a5cc0
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ src/tests/qemu/distfiles/
*.nam
*.til
*.pro.user
.cache.mk
3 changes: 3 additions & 0 deletions contrib/examples/extract-handshakes/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
offset-finder.o
offset-finder
offsets.include
28 changes: 28 additions & 0 deletions contrib/examples/extract-handshakes/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
CFLAGS ?= -O3 -march=native
CFLAGS += -Wall -pedantic -std=gnu11

offsets.include: offset-finder
./$^ > $@

offset-finder: offset-finder.c offset-finder.o
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^

offset-finder.o: offset-finder.c
$(MAKE) -C $(KERNELDIR) M=$(PWD) $@
objcopy -j '.rodata*' $@ $@

clean:
rm -f offset-finder offsets.include
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean

.PHONY: clean
else
offset-finder-m := offset-finder.o
oldsrc := $(src)
src := $(src)/../../../src
include $(src)/compat/Kbuild.include
src := $(oldsrc)
endif
20 changes: 20 additions & 0 deletions contrib/examples/extract-handshakes/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Handshake Extractor
===================

This will extract private keys from outgoing handshake sessions, prior
to them being sent, via kprobes. It exports the bare minimum to be
able to then decrypt all packets in the handshake and in the subsequent
transport data session.

Build:

$ make

Run (as root):

# ./extract-handshakes.sh
New handshake session:
LOCAL_STATIC_PRIVATE_KEY = QChaGDXeH3eQsbFAhueUNWFdq9KfpF3yl+eITjZbXEk=
REMOTE_STATIC_PUBLIC_KEY = HzgTY6aWXtuSyW/PUquZtg8LB/DyMwEXGkPiEmdSsUU=
LOCAL_EPHEMERAL_PRIVATE_KEY = UNGdRHuKDeqbFvmiV5FD4wP7a8PqI6v3Xnnz6Jc6NXQ=
PRESHARED_KEY = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
80 changes: 80 additions & 0 deletions contrib/examples/extract-handshakes/extract-handshakes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2018 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
# Copyright (C) 2017-2018 Peter Wu <[email protected]>. All Rights Reserved.

set -e

ME_DIR="${BASH_SOURCE[0]}"
ME_DIR="${ME_DIR%/*}"
source "$ME_DIR/offsets.include" || { echo "Did you forget to run make?" >&2; exit 1; }

case "$(uname -m)" in
x86_64) ARGUMENT_REGISTER="%si" ;;
i386|i686) ARGUMENT_REGISTER="%dx" ;;
aarch64) ARGUMENT_REGISTER="%x1" ;;
arm) ARGUMENT_REGISTER="%r1" ;;
*) echo "ERROR: Unknown architecture" >&2; exit 1 ;;
esac

ARGS=( )
REGEX=".*: idxadd: .*"
for key in "${!OFFSETS[@]}"; do
values="${OFFSETS[$key]}"
values=( ${values//,/ } )
for i in {0..3}; do
value="$ARGUMENT_REGISTER"
for indirection in "${values[@]:1}"; do
value="+$indirection($value)"
done
value="+$((i * 8 + values[0]))($value)"
ARGS+=( "${key,,}$i=$value:x64" )
REGEX="$REGEX ${key,,}$i=0x([0-9a-f]+)"
done
done

turn_off() {
set +e
[[ -f /sys/kernel/debug/tracing/events/wireguard/idxadd/enable ]] || exit
echo 0 > /sys/kernel/debug/tracing/events/wireguard/idxadd/enable
echo "-:wireguard/idxadd" >> /sys/kernel/debug/tracing/kprobe_events
exit
}

trap turn_off INT TERM EXIT
echo "p:wireguard/idxadd index_hashtable_insert ${ARGS[*]}" >> /sys/kernel/debug/tracing/kprobe_events
echo 1 > /sys/kernel/debug/tracing/events/wireguard/idxadd/enable

unpack_u64() {
local i expanded="$1"
if [[ $ENDIAN == big ]]; then
printf -v expanded "%.*s$expanded" $((16 - ${#expanded})) 0000000000000000
for i in {0..7}; do
echo -n "\\x${expanded:(i * 2):2}"
done
elif [[ $ENDIAN == little ]]; then
(( ${#expanded} % 2 == 1 )) && expanded="0$expanded"
expanded="${expanded}0000000000000000"
for i in {0..7}; do
echo -n "\\x${expanded:((7 - i) * 2):2}"
done
else
echo "ERROR: Unable to determine endian" >&2
exit 1
fi
}

while read -r line; do
[[ $line =~ $REGEX ]] || continue
echo "New handshake session:"
j=1
for key in "${!OFFSETS[@]}"; do
bytes=""
for i in {0..3}; do
bytes="$bytes$(unpack_u64 "${BASH_REMATCH[j]}")"
((++j))
done
echo " $key = $(printf "$bytes" | base64)"
done
done < /sys/kernel/debug/tracing/trace_pipe
44 changes: 44 additions & 0 deletions contrib/examples/extract-handshakes/offset-finder.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2015-2018 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
*/

struct def {
const char *name;
unsigned long offset;
unsigned long indirection_offset;
};
extern const struct def defs[];

#ifdef __KERNEL__
#include "../../../src/noise.h"

const struct def defs[] = {
{ "LOCAL_STATIC_PRIVATE_KEY", offsetof(struct noise_static_identity, static_private), offsetof(struct noise_handshake, static_identity) },
{ "LOCAL_EPHEMERAL_PRIVATE_KEY", offsetof(struct noise_handshake, ephemeral_private), -1 },
{ "REMOTE_STATIC_PUBLIC_KEY", offsetof(struct noise_handshake, remote_static), -1 },
{ "PRESHARED_KEY", offsetof(struct noise_handshake, preshared_key), -1 },
{ NULL, 0 }
};
#else
#include <stdio.h>
int main(int argc, char *argv[])
{
puts("declare -A OFFSETS=(");
for (const struct def *def = defs; def->name; ++def) {
printf("\t[%s]=%ld", def->name, def->offset);
if (def->indirection_offset != -1)
printf(",%ld", def->indirection_offset);
putchar('\n');
}
puts(")");
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
puts("ENDIAN=big");
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
puts("ENDIAN=little");
#else
#error "Unsupported endianness"
#endif
return 0;
}
#endif

0 comments on commit b6a5cc0

Please sign in to comment.