aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/kd/kd.go
blob: e700d9762e4e494c79160d0f64b56121bc70e912 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// Minimal KD protocol decoder.
// KD protocol is used by windows to talk to debuggers. Here are some links:
// https://github.com/radare/radare2/issues/1246#issuecomment-135565901
// http://articles.sysprogs.org/kdvmware/kdcom/
// https://doxygen.reactos.org/df/de3/windbgkd_8h_source.html
package kd

import (
	"bytes"
	"fmt"
	"unsafe"
)

var (
	dataHeader = []byte{0x30, 0x30, 0x30, 0x30}
)

const (
	typStateChange64 = 7
)

type packet struct {
	header uint32
	typ    uint16
	size   uint16
	id     uint32
	csum   uint32
}

func Decode(data []byte) (start, size int, decoded []byte) {
	if len(data) < len(dataHeader) {
		return
	}
	start = bytes.Index(data, dataHeader)
	if start == -1 {
		start = len(data) - len(dataHeader) - 1
		return
	}
	packetSize := int(unsafe.Sizeof(packet{}))
	if len(data)-start < packetSize {
		return // incomplete header
	}
	// Note: assuming little-endian machine.
	pkt := (*packet)(unsafe.Pointer(&data[start]))
	if len(data)-start < packetSize+int(pkt.size) {
		return // incomplete data
	}
	size = packetSize + int(pkt.size) // skip whole packet
	if pkt.typ == typStateChange64 {
		if int(pkt.size) < int(unsafe.Sizeof(stateChange64{})) {
			return
		}
		payload := (*stateChange64)(unsafe.Pointer(&data[start+packetSize]))
		chance := "second"
		if payload.exception.firstChance != 0 {
			chance = "first"
		}
		decoded = []byte(fmt.Sprintf("\n\nBUG: %v chance exception 0x%x\n\n%#v\n\n",
			chance, payload.exception.code, payload))
	}
	return
}

type stateChange64 struct {
	state          uint32
	processorLevel uint16
	processor      uint16
	numProcessors  uint32
	thread         uint64
	pc             uint64
	exception      exception64
	report         controlReport
}

type exception64 struct {
	code        uint32
	flags       uint32
	record      uint64
	address     uint64
	numParams   uint32
	unused      uint32
	params      [15]uint64
	firstChance uint32
}

type controlReport struct {
	dr6         uint64
	dr7         uint64
	eflags      uint32
	numInstr    uint16
	reportFlags uint16
	instr       [16]byte
	cs          uint16
	ds          uint16
	es          uint16
	fs          uint16
}