Skip to content

Instantly share code, notes, and snippets.

@ikonst
Last active January 27, 2024 22:18
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ikonst/364af37c44e5f549b722 to your computer and use it in GitHub Desktop.
Save ikonst/364af37c44e5f549b722 to your computer and use it in GitHub Desktop.
LLDB extension for saving CFData to local file; useful for remote iOS debugging
'''
INSTALLING
curl --create-dirs -o ~/.lldb/cfdata.py https://gist.githubusercontent.com/ikonst/364af37c44e5f549b722/raw/cfdata.py \
&& echo 'command script import ~/.lldb/cfdata.py' >> ~/.lldbinit
USING
(lldb) cfdata_save some_cfdata /Users/john/foo
(lldb) cfdata_save some_nsdata /Users/john/bar
'''
import lldb
import tempfile
import subprocess
def command_cfdata_save(debugger, command, result, dict):
error = lldb.SBError()
process = debugger.GetSelectedTarget().GetProcess()
frame = process.GetSelectedThread().GetSelectedFrame()
if not frame.IsValid():
result.SetError('no frame here')
return
args = command.split()
if len(args) != 2:
result.SetError('Syntax: cfdata_save [expr] [filename]')
return
frame.EvaluateExpression("@import Foundation")
expr = args[0]
cfdata_ptr_value = frame.EvaluateExpression(expr)
if not cfdata_ptr_value.IsValid():
result.SetError(cfdata_ptr_value.GetError())
return
cfdata_ptr = cfdata_ptr_value.GetValue()
cfdata_length_value = frame.EvaluateExpression(
'CFDataGetLength((CFDataRef){})'
.format(cfdata_ptr))
if not cfdata_length_value.IsValid():
result.SetError(cfdata_length_value.GetError())
return
cfdata_length = cfdata_length_value.GetValueAsUnsigned()
data_ptr_value = frame.EvaluateExpression(
'CFDataGetBytePtr((CFDataRef){})'
.format(cfdata_ptr))
if not cfdata_ptr_value.IsValid():
result.SetError(cfdata_ptr_value.GetError())
return
data_ptr = data_ptr_value.GetValueAsUnsigned()
if cfdata_length == 0:
result.SetError('Zero length data')
return
print "Reading {} bytes".format(cfdata_length)
data = process.ReadMemory(data_ptr, cfdata_length, error)
if not error:
result.SetError(error)
return
f = open(args[1], 'w+b')
f.write(data)
f.close()
print "Wrote CFData contents to file {}\n".format(args[1])
def __lldb_init_module (debugger, dict):
for cmdname in ['cfdata_save']:
debugger.HandleCommand('command script add -f cfdata.command_{0} {0}'.format(cmdname))
@tals
Copy link

tals commented Dec 28, 2015

mkdir -p ~/.lldb/ && curl "https://gist.githubusercontent.com/ikonst/364af37c44e5f549b722/raw/cfdata.py" -o ~/.lldb/cfdata.py && echo 'command script import ~/.lldb/cfdata.py' >> ~/.lldbinit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment