From cd88cecc9a53f852bca98d95d937576a29fb3e91 Mon Sep 17 00:00:00 2001 From: Mitchell Grenier Date: Mon, 16 Oct 2017 13:07:24 -0700 Subject: [PATCH] Publisher and Table for Event Tap Capture (KeyDown) (#3829) --- osquery/events/darwin/event_taps.cpp | 89 +++++++++++++++++++++ osquery/events/darwin/event_taps.h | 68 ++++++++++++++++ osquery/tables/events/darwin/key_events.cpp | 42 ++++++++++ specs/darwin/key_events.table | 7 ++ 4 files changed, 206 insertions(+) create mode 100644 osquery/events/darwin/event_taps.cpp create mode 100644 osquery/events/darwin/event_taps.h create mode 100644 osquery/tables/events/darwin/key_events.cpp create mode 100644 specs/darwin/key_events.table diff --git a/osquery/events/darwin/event_taps.cpp b/osquery/events/darwin/event_taps.cpp new file mode 100644 index 00000000..872efca4 --- /dev/null +++ b/osquery/events/darwin/event_taps.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#include + +#include "osquery/events/darwin/event_taps.h" + +namespace osquery { + +/// Flag that turns the eventing system for event taps on or off +FLAG(bool, + enable_keyboard_events, + false, + "Enable listening for keyboard events"); + +REGISTER(EventTappingEventPublisher, "event_publisher", "event_tapping"); + +CGEventRef EventTappingEventPublisher::eventCallback(CGEventTapProxy proxy, + CGEventType type, + CGEventRef event, + void* refcon) { + auto ec = createEventContext(); + EventFactory::fire(ec); + return event; +} + +Status EventTappingEventPublisher::setUp() { + if (!FLAGS_enable_keyboard_events) { + return Status(1, "Publisher disabled via configuration"); + } + return Status(0); +} + +void EventTappingEventPublisher::tearDown() { + stop(); +} + +void EventTappingEventPublisher::stop() { + WriteLock lock(run_loop_mutex_); + + if (run_loop_source_ != nullptr) { + CFRunLoopRemoveSource(run_loop_, run_loop_source_, kCFRunLoopCommonModes); + CFRelease(run_loop_source_); + run_loop_source_ = nullptr; + } + if (run_loop_ != nullptr) { + CFRunLoopStop(run_loop_); + run_loop_ = nullptr; + } +} + +void EventTappingEventPublisher::restart() { + stop(); + WriteLock lock(run_loop_mutex_); + + run_loop_ = CFRunLoopGetCurrent(); + CGEventMask eventMask = (1 << kCGEventKeyDown); + CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, + kCGHeadInsertEventTap, + kCGEventTapOptionListenOnly, + eventMask, + eventCallback, + NULL); + run_loop_source_ = + CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0); + CFRunLoopAddSource(run_loop_, run_loop_source_, kCFRunLoopCommonModes); + CGEventTapEnable(eventTap, true); + CFRelease(eventTap); +} + +Status EventTappingEventPublisher::run() { + restart(); + CFRunLoopRun(); + return Status(0); +} + +bool EventTappingEventPublisher::shouldFire( + const EventTappingSubscriptionContextRef& mc, + const EventTappingEventContextRef& ec) const { + return true; +} +} diff --git a/osquery/events/darwin/event_taps.h b/osquery/events/darwin/event_taps.h new file mode 100644 index 00000000..30b99fc3 --- /dev/null +++ b/osquery/events/darwin/event_taps.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#pragma once + +#include + +#include + +namespace osquery { + +struct EventTappingSubscriptionContext : public SubscriptionContext {}; +struct EventTappingEventContext : public EventContext {}; + +using EventTappingEventContextRef = std::shared_ptr; +using EventTappingSubscriptionContextRef = + std::shared_ptr; + +/// This is a dispatched service that handles published EventTapping events. +class EventTappingConsumerRunner; + +class EventTappingEventPublisher + : public EventPublisher { + DECLARE_PUBLISHER("event_tapping"); + + public: + Status setUp() override; + + void tearDown() override; + + void stop() override; + + void restart(); + + Status run() override; + + EventTappingEventPublisher() : EventPublisher() {} + + virtual ~EventTappingEventPublisher() { + tearDown(); + } + + private: + /// Apply normal subscription to event matching logic. + bool shouldFire(const EventTappingSubscriptionContextRef& mc, + const EventTappingEventContextRef& ec) const override; + + static CGEventRef eventCallback(CGEventTapProxy proxy, + CGEventType type, + CGEventRef event, + void* refcon); + + /// This publisher thread's runloop. + CFRunLoopSourceRef run_loop_source_{nullptr}; + CFRunLoopRef run_loop_{nullptr}; + + /// Storage/container operations protection mutex. + mutable Mutex run_loop_mutex_; +}; +} // namespace osquery diff --git a/osquery/tables/events/darwin/key_events.cpp b/osquery/tables/events/darwin/key_events.cpp new file mode 100644 index 00000000..d84888d9 --- /dev/null +++ b/osquery/tables/events/darwin/key_events.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#include "osquery/events/darwin/event_taps.h" + +namespace osquery { + +class EventTapsKeySubscriber + : public EventSubscriber { + public: + Status init() override { + return Status(0); + } + + void configure() override; + + Status Callback(const EventTappingEventContextRef& ec, + const EventTappingSubscriptionContextRef& sc); +}; + +REGISTER(EventTapsKeySubscriber, "event_subscriber", "key_events"); + +void EventTapsKeySubscriber::configure() { + auto sc = createSubscriptionContext(); + subscribe(&EventTapsKeySubscriber::Callback, sc); +} + +Status EventTapsKeySubscriber::Callback( + const EventTappingEventContextRef& ec, + const EventTappingSubscriptionContextRef& sc) { + Row r; + add(r); + return Status(0); +} +} // namespace osquery diff --git a/specs/darwin/key_events.table b/specs/darwin/key_events.table new file mode 100644 index 00000000..48521c5b --- /dev/null +++ b/specs/darwin/key_events.table @@ -0,0 +1,7 @@ +table_name("key_events") +description("Track key events.") +schema([ + Column("time", BIGINT, "Time") +]) +attributes(event_subscriber=True) +implementation("events/darwin/key_events@key_events::genTable")