forked from gdbinit/lldbinit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlldbinit.py
4274 lines (3690 loc) · 139 KB
/
lldbinit.py
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
'''
.____ .____ ________ __________.__ _______ ._____________
| | | | \______ \\______ \__|\ \ |__\__ ___/
| | | | | | \| | _/ |/ | \| | | |
| |___| |___ | ` \ | \ / | \ | | |
|_______ \_______ \/_______ /______ /__\____|__ /__| |____|
\/ \/ \/ \/ \/
LLDBINIT v2.0
A gdbinit clone for LLDB aka how to make LLDB a bit more useful and less crappy
(c) Deroko 2014, 2015, 2016
(c) fG! 2017-2020 - reverser@put.as - https://reverse.put.as
Available at https://github.com/gdbinit/lldbinit
No original license by Deroko so I guess this is do whatever you want with this
as long you keep original credits and sources references.
Original lldbinit code by Deroko @ https://github.com/deroko/lldbinit
gdbinit available @ https://github.com/gdbinit/Gdbinit
Huge thanks to Deroko for his original effort!
To list all implemented commands use 'lldbinitcmds' command.
How to install it:
------------------
$ cp lldbinit.py ~
$ echo "command script import ~/lldbinit.py" >>$HOME/.lldbinit
or
$ cp lldbinit.py /Library/Python/2.7/site-packages
$ echo "command script import lldbinit" >> $HOME/.lldbinit
or
just copy it somewhere and use "command script import path_to_script" when you want to load it.
TODO:
-----
- better ARM support and testing - this version is focused on x86/x64
- shortcut to dump memory to file
- check sbthread class: stepoveruntil for example
- help for aliases
- error checking on many return values for lldb objects (target, frame, thread, etc) - verify if frame value is valid on the beginning of each command?
- add source window?
- add threads window?
- remove that ugly stop information (deroko's trick doesn't seem to work anymore, lldb forces that over our captured input?)
- command to search for symbol and display image address (image lookup -s symbol -v) (address is the range)
- command to update breakpoints with new ASLR
- fix get_indirect_flow_target (we can get real load address of the modules - check the new disassembler code)
- solve addresses like lea rsi, [rip + 0x38cf] (lldb does solve some stuff that it has symbols for and adds the info as comment)
- some sort of colors theme support
BUGS:
-----
LLDB design:
------------
lldb -> debugger -> target -> process -> thread -> frame(s)
-> thread -> frame(s)
'''
if __name__ == "__main__":
print("Run only as script from LLDB... Not as standalone program!")
try:
import lldb
except:
pass
import sys
import re
import os
import time
import struct
import argparse
import subprocess
import tempfile
try:
from keystone import *
CONFIG_KEYSTONE_AVAILABLE = 1
except:
CONFIG_KEYSTONE_AVAILABLE = 0
pass
VERSION = "2.0"
BUILD = "204"
#
# User configurable options
#
CONFIG_ENABLE_COLOR = 1
# display the instruction bytes in disassembler output
CONFIG_DISPLAY_DISASSEMBLY_BYTES = 1
# the maximum number of lines to display in disassembler output
CONFIG_DISASSEMBLY_LINE_COUNT = 8
# x/i and disas output customization - doesn't affect context disassembler output
CONFIG_USE_CUSTOM_DISASSEMBLY_FORMAT = 1
# enable all the register command shortcuts
CONFIG_ENABLE_REGISTER_SHORTCUTS = 1
# display stack contents on context stop
CONFIG_DISPLAY_STACK_WINDOW = 0
CONFIG_DISPLAY_FLOW_WINDOW = 0
# display data contents on context stop - an address for the data must be set with "datawin" command
CONFIG_DISPLAY_DATA_WINDOW = 0
# setup the logging level, which is a bitmask of any of the following possible values (don't use spaces, doesn't seem to work)
#
# LOG_VERBOSE LOG_PROCESS LOG_THREAD LOG_EXCEPTIONS LOG_SHLIB LOG_MEMORY LOG_MEMORY_DATA_SHORT LOG_MEMORY_DATA_LONG LOG_MEMORY_PROTECTIONS LOG_BREAKPOINTS LOG_EVENTS LOG_WATCHPOINTS
# LOG_STEP LOG_TASK LOG_ALL LOG_DEFAULT LOG_NONE LOG_RNB_MINIMAL LOG_RNB_MEDIUM LOG_RNB_MAX LOG_RNB_COMM LOG_RNB_REMOTE LOG_RNB_EVENTS LOG_RNB_PROC LOG_RNB_PACKETS LOG_RNB_ALL LOG_RNB_DEFAULT
# LOG_DARWIN_LOG LOG_RNB_NONE
#
# to see log (at least in macOS)
# $ log stream --process debugserver --style compact
# (or whatever style you like)
CONFIG_LOG_LEVEL = "LOG_NONE"
# removes the offsets and modifies the module name position
# reference: https://lldb.llvm.org/formats.html
CUSTOM_DISASSEMBLY_FORMAT = "\"{${function.initial-function}{${function.name-without-args}} @ {${module.file.basename}}:\n}{${function.changed}\n{${function.name-without-args}} @ {${module.file.basename}}:\n}{${current-pc-arrow} }${addr-file-or-load}: \""
# default colors - modify as you wish
COLOR_REGVAL = "BLACK"
COLOR_REGNAME = "GREEN"
COLOR_CPUFLAGS = "RED"
COLOR_SEPARATOR = "BLUE"
COLOR_HIGHLIGHT_LINE = "RED"
COLOR_REGVAL_MODIFIED = "RED"
COLOR_SYMBOL_NAME = "BLUE"
COLOR_CURRENT_PC = "RED"
#
# Don't mess after here unless you know what you are doing!
#
COLORS = {
"BLACK": "\033[30m",
"RED": "\033[31m",
"GREEN": "\033[32m",
"YELLOW": "\033[33m",
"BLUE": "\033[34m",
"MAGENTA": "\033[35m",
"CYAN": "\033[36m",
"WHITE": "\033[37m",
"RESET": "\033[0m",
"BOLD": "\033[1m",
"UNDERLINE": "\033[4m"
}
DATA_WINDOW_ADDRESS = 0
old_x86 = { "eax": 0, "ecx": 0, "edx": 0, "ebx": 0, "esp": 0, "ebp": 0, "esi": 0, "edi": 0, "eip": 0,
"eflags": 0, "cs": 0, "ds": 0, "fs": 0, "gs": 0, "ss": 0, "es": 0 }
old_x64 = { "rax": 0, "rcx": 0, "rdx": 0, "rbx": 0, "rsp": 0, "rbp": 0, "rsi": 0, "rdi": 0, "rip": 0,
"r8": 0, "r9": 0, "r10": 0, "r11": 0, "r12": 0, "r13": 0, "r14": 0, "r15": 0,
"rflags": 0, "cs": 0, "fs": 0, "gs": 0 }
old_arm = { "r0": 0, "r1": 0, "r2": 0, "r3": 0, "r4": 0, "r5": 0, "r6": 0, "r7": 0, "r8": 0, "r9": 0, "r10": 0,
"r11": 0, "r12": 0, "sp": 0, "lr": 0, "pc": 0, "cpsr": 0 }
arm_type = "thumbv7-apple-ios"
GlobalListOutput = []
int3patches = {}
crack_cmds = []
crack_cmds_noret = []
modules_list = []
def __lldb_init_module(debugger, internal_dict):
''' we can execute commands using debugger.HandleCommand which makes all output to default
lldb console. With GetCommandinterpreter().HandleCommand() we can consume all output
with SBCommandReturnObject and parse data before we send it to output (eg. modify it);
'''
# don't load if we are in Xcode since it is not compatible and will block Xcode
if os.getenv('PATH').startswith('/Applications/Xcode'):
return
'''
If I'm running from $HOME where .lldbinit is located, seems like lldb will load
.lldbinit 2 times, thus this dirty hack is here to prevent doulbe loading...
if somebody knows better way, would be great to know :)
'''
var = debugger.GetInternalVariableValue("stop-disassembly-count", debugger.GetInstanceName())
if var.IsValid():
var = var.GetStringAtIndex(0)
if var == "0":
return
res = lldb.SBCommandReturnObject()
ci = debugger.GetCommandInterpreter()
# settings
ci.HandleCommand("settings set target.x86-disassembly-flavor intel", res)
ci.HandleCommand("settings set prompt \"(lldbinit) \"", res)
#lldb.debugger.GetCommandInterpreter().HandleCommand("settings set prompt \"\033[01;31m(lldb) \033[0m\"", res);
ci.HandleCommand("settings set stop-disassembly-count 0", res)
# set the log level - must be done on startup?
ci.HandleCommand("settings set target.process.extra-startup-command QSetLogging:bitmask=" + CONFIG_LOG_LEVEL + ";", res)
if CONFIG_USE_CUSTOM_DISASSEMBLY_FORMAT == 1:
ci.HandleCommand("settings set disassembly-format " + CUSTOM_DISASSEMBLY_FORMAT, res)
# the hook that makes everything possible :-)
ci.HandleCommand("command script add -f lldbinit.HandleHookStopOnTarget HandleHookStopOnTarget", res)
ci.HandleCommand("command script add -f lldbinit.HandleHookStopOnTarget ctx", res)
ci.HandleCommand("command script add -f lldbinit.HandleHookStopOnTarget context", res)
# commands
ci.HandleCommand("command script add -f lldbinit.cmd_lldbinitcmds lldbinitcmds", res)
ci.HandleCommand("command script add -f lldbinit.cmd_IphoneConnect iphone", res)
#
# dump memory commands
#
ci.HandleCommand("command script add -f lldbinit.cmd_db db", res)
ci.HandleCommand("command script add -f lldbinit.cmd_dw dw", res)
ci.HandleCommand("command script add -f lldbinit.cmd_dd dd", res)
ci.HandleCommand("command script add -f lldbinit.cmd_dq dq", res)
ci.HandleCommand("command script add -f lldbinit.cmd_DumpInstructions u", res)
ci.HandleCommand("command script add -f lldbinit.cmd_findmem findmem", res)
#
# Settings related commands
#
ci.HandleCommand("command script add -f lldbinit.cmd_enable enable", res)
ci.HandleCommand("command script add -f lldbinit.cmd_disable disable", res)
ci.HandleCommand("command script add -f lldbinit.cmd_contextcodesize contextcodesize", res)
# a few settings aliases
ci.HandleCommand("command alias enablesolib enable solib", res)
ci.HandleCommand("command alias disablesolib disable solib", res)
ci.HandleCommand("command alias enableaslr enable aslr", res)
ci.HandleCommand("command alias disableaslr disable aslr", res)
#
# Breakpoint related commands
#
ci.HandleCommand("command script add -f lldbinit.cmd_bhb bhb", res)
ci.HandleCommand("command script add -f lldbinit.cmd_bht bht", res)
ci.HandleCommand("command script add -f lldbinit.cmd_bpt bpt", res)
ci.HandleCommand("command script add -f lldbinit.cmd_bpn bpn", res)
# disable a breakpoint or all
ci.HandleCommand("command script add -f lldbinit.cmd_bpd bpd", res)
ci.HandleCommand("command script add -f lldbinit.cmd_bpda bpda", res)
# clear a breakpoint or all
ci.HandleCommand("command script add -f lldbinit.cmd_bpc bpc", res)
ci.HandleCommand("command alias bpca breakpoint delete", res)
# enable a breakpoint or all
ci.HandleCommand("command script add -f lldbinit.cmd_bpe bpe", res)
ci.HandleCommand("command script add -f lldbinit.cmd_bpea bpea", res)
# commands to set temporary int3 patches and restore original bytes
ci.HandleCommand("command script add -f lldbinit.cmd_int3 int3", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rint3 rint3", res)
ci.HandleCommand("command script add -f lldbinit.cmd_listint3 listint3", res)
ci.HandleCommand("command script add -f lldbinit.cmd_nop nop", res)
ci.HandleCommand("command script add -f lldbinit.cmd_null null", res)
# change eflags commands
ci.HandleCommand("command script add -f lldbinit.cmd_cfa cfa", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfc cfc", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfd cfd", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfi cfi", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfo cfo", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfp cfp", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfs cfs", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cft cft", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfz cfz", res)
# skip/step current instruction commands
ci.HandleCommand("command script add -f lldbinit.cmd_skip skip", res)
ci.HandleCommand("command script add -f lldbinit.cmd_stepo stepo", res)
ci.HandleCommand("command script add -f lldbinit.cmd_si si", res)
# load breakpoints from file
ci.HandleCommand("command script add -f lldbinit.cmd_LoadBreakPoints lb", res)
ci.HandleCommand("command script add -f lldbinit.cmd_LoadBreakPointsRva lbrva", res)
# cracking friends
ci.HandleCommand("command script add -f lldbinit.cmd_crack crack", res)
ci.HandleCommand("command script add -f lldbinit.cmd_crackcmd crackcmd", res)
ci.HandleCommand("command script add -f lldbinit.cmd_crackcmd_noret crackcmd_noret", res)
# alias for existing breakpoint commands
# list all breakpoints
ci.HandleCommand("command alias bpl breakpoint list", res)
# alias "bp" command that exists in gdbinit - lldb also has alias for "b"
ci.HandleCommand("command alias bp _regexp-break", res)
# to set breakpoint commands - I hate typing too much
ci.HandleCommand("command alias bcmd breakpoint command add", res)
# launch process and stop at entrypoint (not exactly as gdb command that just inserts breakpoint)
# usually it will be inside dyld and not the target main()
ci.HandleCommand("command alias break_entrypoint process launch --stop-at-entry", res)
ci.HandleCommand("command script add -f lldbinit.cmd_show_loadcmds show_loadcmds", res)
ci.HandleCommand("command script add -f lldbinit.cmd_show_header show_header", res)
ci.HandleCommand("command script add -f lldbinit.cmd_tester tester", res)
ci.HandleCommand("command script add -f lldbinit.cmd_datawin datawin", res)
# shortcut command to modify registers content
if CONFIG_ENABLE_REGISTER_SHORTCUTS == 1:
# x64
ci.HandleCommand("command script add -f lldbinit.cmd_rip rip", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rax rax", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rbx rbx", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rbp rbp", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rsp rsp", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rdi rdi", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rsi rsi", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rdx rdx", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rcx rcx", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r8 r8", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r9 r9", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r10 r10", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r11 r11", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r12 r12", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r13 r13", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r14 r14", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r15 r15", res)
# x86
ci.HandleCommand("command script add -f lldbinit.cmd_eip eip", res)
ci.HandleCommand("command script add -f lldbinit.cmd_eax eax", res)
ci.HandleCommand("command script add -f lldbinit.cmd_ebx ebx", res)
ci.HandleCommand("command script add -f lldbinit.cmd_ebp ebp", res)
ci.HandleCommand("command script add -f lldbinit.cmd_esp esp", res)
ci.HandleCommand("command script add -f lldbinit.cmd_edi edi", res)
ci.HandleCommand("command script add -f lldbinit.cmd_esi esi", res)
ci.HandleCommand("command script add -f lldbinit.cmd_edx edx", res)
ci.HandleCommand("command script add -f lldbinit.cmd_ecx ecx", res)
if CONFIG_KEYSTONE_AVAILABLE == 1:
ci.HandleCommand("command script add -f lldbinit.cmd_asm32 asm32", res)
ci.HandleCommand("command script add -f lldbinit.cmd_asm64 asm64", res)
ci.HandleCommand("command script add -f lldbinit.cmd_arm32 arm32", res)
ci.HandleCommand("command script add -f lldbinit.cmd_arm64 arm64", res)
ci.HandleCommand("command script add -f lldbinit.cmd_armthumb armthumb", res)
# add the hook - we don't need to wait for a target to be loaded
ci.HandleCommand("target stop-hook add -o \"HandleHookStopOnTarget\"", res)
ci.HandleCommand("command script add --function lldbinit.cmd_banner banner", res)
debugger.HandleCommand("banner")
return
def cmd_banner(debugger,command,result,dict):
print(COLORS["RED"] + "[+] Loaded lldbinit version: " + VERSION + "." + BUILD + COLORS["RESET"])
def cmd_lldbinitcmds(debugger, command, result, dict):
'''Display all available lldbinit commands.'''
help_table = [
[ "lldbinitcmds", "this command" ],
[ "enable", "configure lldb and lldbinit options" ],
[ "disable", "configure lldb and lldbinit options" ],
[ "contextcodesize", "set number of instruction lines in code window" ],
[ "b", "breakpoint address" ],
[ "bpt", "set a temporary software breakpoint" ],
[ "bhb", "set an hardware breakpoint" ],
[ "bpc", "clear breakpoint" ],
[ "bpca", "clear all breakpoints" ],
[ "bpd", "disable breakpoint" ],
[ "bpda", "disable all breakpoints" ],
[ "bpe", "enable a breakpoint" ],
[ "bpea", "enable all breakpoints" ],
[ "bcmd", "alias to breakpoint command add"],
[ "bpl", "list all breakpoints"],
[ "bpn", "temporarly breakpoint next instruction" ],
[ "break_entrypoint", "launch target and stop at entrypoint" ],
[ "skip", "skip current instruction" ],
[ "int3", "patch memory address with INT3" ],
[ "rint3", "restore original byte at address patched with INT3" ],
[ "listint3", "list all INT3 patched addresses" ],
[ "nop", "patch memory address with NOP" ],
[ "null", "patch memory address with NULL" ],
[ "stepo", "step over calls and loop instructions" ],
[ "lb", "load breakpoints from file and apply them (currently only func names are applied)" ],
[ "lbrva", "load breakpoints from file and apply to main executable, only RVA in this case" ],
[ "db/dw/dd/dq", "memory hex dump in different formats" ],
[ "findmem", "search memory" ],
[ "cfa/cfc/cfd/cfi/cfo/cfp/cfs/cft/cfz", "change CPU flags" ],
[ "u", "dump instructions" ],
[ "iphone", "connect to debugserver running on iPhone" ],
[ "ctx/context", "show current instruction pointer CPU context" ],
[ "show_loadcmds", "show otool output of Mach-O load commands" ],
[ "show_header", "show otool output of Mach-O header" ],
[ "enablesolib/disablesolib", "enable/disable the stop on library load events" ],
[ "enableaslr/disableaslr", "enable/disable process ASLR" ],
[ "crack", "return from current function" ],
[ "crackcmd", "set a breakpoint and return from that function" ],
[ "crackcmd_noret", "set a breakpoint and set a register value. doesn't return from function" ],
[ "datawin", "set start address to display on data window" ],
[ "rip/rax/rbx/etc", "shortcuts to modify x64 registers" ],
[ "eip/eax/ebx/etc", "shortcuts to modify x86 register" ],
[ "asm32/asm64", "x86/x64 assembler using keystone" ],
[ "arm32/arm64/armthumb", "ARM assembler using keystone" ]
]
print("lldbinit available commands:")
for row in help_table:
print(" {: <20} - {: <30}".format(*row))
print("\nUse \'cmdname help\' for extended command help.")
# placeholder to make tests
def cmd_tester(debugger, command, result, dict):
print("test")
#frame = get_frame()
# the SBValue to ReturnFromFrame must be eValueTypeRegister type
# if we do a lldb.SBValue() we can't set to that type
# so we need to make a copy
# can we use FindRegister() from frame?
#return_value = frame.reg["rax"]
#return_value.value = "1"
#thread.ReturnFromFrame(frame, return_value)
# -------------------------
# Settings related commands
# -------------------------
def cmd_enable(debugger, command, result, dict):
'''Enable certain lldb and lldbinit options. Use \'enable help\' for more information.'''
help = """
Enable certain lldb and lldbinit configuration options.
Syntax: enable <setting>
Available settings:
color: enable color mode.
solib: enable stop on library events trick.
aslr: enable process aslr.
stackwin: enable stack window in context display.
datawin: enable data window in context display, configure address with datawin.
flow: call targets and objective-c class/methods.
"""
global CONFIG_ENABLE_COLOR
global CONFIG_DISPLAY_STACK_WINDOW
global CONFIG_DISPLAY_FLOW_WINDOW
global CONFIG_DISPLAY_DATA_WINDOW
cmd = command.split()
if len(cmd) == 0:
print("[-] error: command requires arguments.")
print("")
print(help)
return
if cmd[0] == "color":
CONFIG_ENABLE_COLOR = 1
print("[+] Enabled color mode.")
elif cmd[0] == "solib":
debugger.HandleCommand("settings set target.process.stop-on-sharedlibrary-events true")
print("[+] Enabled stop on library events trick.")
elif cmd[0] == "aslr":
debugger.HandleCommand("settings set target.disable-aslr false")
print("[+] Enabled ASLR.")
elif cmd[0] == "stackwin":
CONFIG_DISPLAY_STACK_WINDOW = 1
print("[+] Enabled stack window in context display.")
elif cmd[0] == "flow":
CONFIG_DISPLAY_FLOW_WINDOW = 1
print("[+] Enabled indirect control flow window in context display.")
elif cmd[0] == "datawin":
CONFIG_DISPLAY_DATA_WINDOW = 1
print("[+] Enabled data window in context display. Configure address with \'datawin\' cmd.")
elif cmd[0] == "help":
print(help)
else:
print("[-] error: unrecognized command.")
print(help)
return
def cmd_disable(debugger, command, result, dict):
'''Disable certain lldb and lldbinit options. Use \'disable help\' for more information.'''
help = """
Disable certain lldb and lldbinit configuration options.
Syntax: disable <setting>
Available settings:
color: disable color mode.
solib: disable stop on library events trick.
aslr: disable process aslr.
stackwin: disable stack window in context display.
datawin: enable data window in context display.
flow: call targets and objective-c class/methods.
"""
global CONFIG_ENABLE_COLOR
global CONFIG_DISPLAY_STACK_WINDOW
global CONFIG_DISPLAY_FLOW_WINDOW
global CONFIG_DISPLAY_DATA_WINDOW
cmd = command.split()
if len(cmd) == 0:
print("[-] error: command requires arguments.")
print("")
print(help)
return
if cmd[0] == "color":
CONFIG_ENABLE_COLOR = 0
print("[+] Disabled color mode.")
elif cmd[0] == "solib":
debugger.HandleCommand("settings set target.process.stop-on-sharedlibrary-events false")
print("[+] Disabled stop on library events trick.")
elif cmd[0] == "aslr":
debugger.HandleCommand("settings set target.disable-aslr true")
print("[+] Disabled ASLR.")
elif cmd[0] == "stackwin":
CONFIG_DISPLAY_STACK_WINDOW = 0
print("[+] Disabled stack window in context display.")
elif cmd[0] == "flow":
CONFIG_DISPLAY_FLOW_WINDOW = 0
print("[+] Disabled indirect control flow window in context display.")
elif cmd[0] == "datawin":
CONFIG_DISPLAY_DATA_WINDOW = 0
print("[+] Disabled data window in context display.")
elif cmd[0] == "help":
print(help)
else:
print("[-] error: unrecognized command.")
print(help)
return
def cmd_contextcodesize(debugger, command, result, dict):
'''Set the number of disassembly lines in code window. Use \'contextcodesize help\' for more information.'''
help = """
Configures the number of disassembly lines displayed in code window.
Syntax: contextcodesize <line_count>
Note: expressions supported, do not use spaces between operators.
"""
global CONFIG_DISASSEMBLY_LINE_COUNT
cmd = command.split()
if len(cmd) != 1:
print("[-] error: please insert the number of disassembly lines to display.")
print("")
print(help)
return
if cmd[0] == "help":
print(help)
print("\nCurrent configuration value is: {:d}".format(CONFIG_DISASSEMBLY_LINE_COUNT))
return
value = evaluate(cmd[0])
if value is None:
print("[-] error: invalid input value.")
print("")
print(help)
return
CONFIG_DISASSEMBLY_LINE_COUNT = value
return
# ---------------------------------
# Color and output related commands
# ---------------------------------
def color(x):
out_col = ""
if CONFIG_ENABLE_COLOR == 0:
output(out_col)
return
output(COLORS[x])
# append data to the output that we display at the end of the hook-stop
def output(x):
global GlobalListOutput
GlobalListOutput.append(x)
# ---------------------------
# Breakpoint related commands
# ---------------------------
# temporary software breakpoint
def cmd_bpt(debugger, command, result, dict):
'''Set a temporary software breakpoint. Use \'bpt help\' for more information.'''
help = """
Set a temporary software breakpoint.
Syntax: bpt <address>
Note: expressions supported, do not use spaces between operators.
"""
cmd = command.split()
if len(cmd) != 1:
print("[-] error: please insert a breakpoint address.")
print("")
print(help)
return
if cmd[0] == "help":
print(help)
return
value = evaluate(cmd[0])
if value is None:
print("[-] error: invalid input value.")
print("")
print(help)
return
target = get_target()
breakpoint = target.BreakpointCreateByAddress(value)
breakpoint.SetOneShot(True)
breakpoint.SetThreadID(get_frame().GetThread().GetThreadID())
print("[+] Set temporary breakpoint at 0x{:x}".format(value))
# hardware breakpoint
def cmd_bhb(debugger, command, result, dict):
'''Set an hardware breakpoint'''
help = """
Set an hardware breakpoint.
Syntax: bhb <address>
Note: expressions supported, do not use spaces between operators.
"""
cmd = command.split()
if len(cmd) != 1:
print("[-] error: please insert a breakpoint address.")
print("")
print(help)
return
if cmd[0] == "help":
print(help)
return
value = evaluate(cmd[0])
if value is None:
print("[-] error: invalid input value.")
print("")
print(help)
return
# the python API doesn't seem to support hardware breakpoints
# so we set it via command line interpreter
res = lldb.SBCommandReturnObject()
lldb.debugger.GetCommandInterpreter().HandleCommand("breakpoint set -H -a " + hex(value), res)
print("[+] Set hardware breakpoint at 0x{:x}".format(value))
return
# temporary hardware breakpoint
def cmd_bht(debugger, command, result, dict):
'''Set a temporary hardware breakpoint'''
print("[-] error: lldb has no x86/x64 temporary hardware breakpoints implementation.")
return
# clear breakpoint number
def cmd_bpc(debugger, command, result, dict):
'''Clear a breakpoint. Use \'bpc help\' for more information.'''
help = """
Clear a breakpoint.
Syntax: bpc <breakpoint_number>
Note: only breakpoint numbers are valid, not addresses. Use \'bpl\' to list breakpoints.
Note: expressions supported, do not use spaces between operators.
"""
cmd = command.split()
if len(cmd) != 1:
print("[-] error: please insert a breakpoint number.")
print("")
print(help)
return
if cmd[0] == "help":
print(help)
return
# breakpoint disable only accepts breakpoint numbers not addresses
value = evaluate(cmd[0])
if value is None:
print("[-] error: invalid input value - only a breakpoint number is valid.")
print("")
print(help)
return
target = get_target()
for bpt in target.breakpoint_iter():
if bpt.id == value:
if target.BreakpointDelete(bpt.id) == False:
print("[-] error: failed to delete breakpoint #{:d}".format(value))
return
print("[+] Deleted breakpoint #{:d}".format(value))
return
print("[-] error: breakpoint #{:d} not found".format(value))
return
# disable breakpoint number
# XXX: we could support addresses, not sure it's worth the trouble
def cmd_bpd(debugger, command, result, dict):
'''Disable a breakpoint. Use \'bpd help\' for more information.'''
help = """
Disable a breakpoint.
Syntax: bpd <breakpoint_number>
Note: only breakpoint numbers are valid, not addresses. Use \'bpl\' to list breakpoints.
Note: expressions supported, do not use spaces between operators.
"""
cmd = command.split()
if len(cmd) != 1:
print("[-] error: please insert a breakpoint number.")
print("")
print(help)
return
if cmd[0] == "help":
print(help)
return
# breakpoint disable only accepts breakpoint numbers not addresses
value = evaluate(cmd[0])
if value is None:
print("[-] error: invalid input value - only a breakpoint number is valid.")
print("")
print(help)
return
target = get_target()
for bpt in target.breakpoint_iter():
if bpt.id == value and bpt.IsEnabled() == True:
bpt.SetEnabled(False)
print("[+] Disabled breakpoint #{:d}".format(value))
# disable all breakpoints
def cmd_bpda(debugger, command, result, dict):
'''Disable all breakpoints. Use \'bpda help\' for more information.'''
help = """
Disable all breakpoints.
Syntax: bpda
"""
cmd = command.split()
if len(cmd) != 0:
if cmd[0] == "help":
print(help)
return
print("[-] error: command doesn't take any arguments.")
print("")
print(help)
return
target = get_target()
if target.DisableAllBreakpoints() == False:
print("[-] error: failed to disable all breakpoints.")
print("[+] Disabled all breakpoints.")
# enable breakpoint number
def cmd_bpe(debugger, command, result, dict):
'''Enable a breakpoint. Use \'bpe help\' for more information.'''
help = """
Enable a breakpoint.
Syntax: bpe <breakpoint_number>
Note: only breakpoint numbers are valid, not addresses. Use \'bpl\' to list breakpoints.
Note: expressions supported, do not use spaces between operators.
"""
cmd = command.split()
if len(cmd) != 1:
print("[-] error: please insert a breakpoint number.")
print("")
print(help)
return
if cmd[0] == "help":
print(help)
return
# breakpoint enable only accepts breakpoint numbers not addresses
value = evaluate(cmd[0])
if value is None:
print("[-] error: invalid input value - only a breakpoint number is valid.")
print("")
print(help)
return
target = get_target()
for bpt in target.breakpoint_iter():
if bpt.id == value and bpt.IsEnabled() == False:
bpt.SetEnabled(True)
print("[+] Enabled breakpoint #{:d}".format(value))
# enable all breakpoints
def cmd_bpea(debugger, command, result, dict):
'''Enable all breakpoints. Use \'bpea help\' for more information.'''
help = """
Enable all breakpoints.
Syntax: bpea
"""
cmd = command.split()
if len(cmd) != 0:
if cmd[0] == "help":
print(help)
return
print("[-] error: command doesn't take any arguments.")
print("")
print(help)
return
target = get_target()
if target.EnableAllBreakpoints() == False:
print("[-] error: failed to enable all breakpoints.")
print("[+] Enabled all breakpoints.")
# skip current instruction - just advances PC to next instruction but doesn't execute it
def cmd_skip(debugger, command, result, dict):
'''Advance PC to instruction at next address. Use \'skip help\' for more information.'''
help = """
Advance current instruction pointer to next instruction.
Syntax: skip
Note: control flow is not respected, it advances to next instruction in memory.
"""
cmd = command.split()
if len(cmd) != 0:
if cmd[0] == "help":
print(help)
return
print("[-] error: command doesn't take any arguments.")
print("")
print(help)
return
start_addr = get_current_pc()
next_addr = start_addr + get_inst_size(start_addr)
if is_x64():
get_frame().reg["rip"].value = format(next_addr, '#x')
elif is_i386():
get_frame().reg["eip"].value = format(next_addr, '#x')
# show the updated context
lldb.debugger.HandleCommand("context")
# XXX: ARM breakpoint
def cmd_int3(debugger, command, result, dict):
'''Patch byte at address to an INT3 (0xCC) instruction. Use \'int3 help\' for more information.'''
help = """
Patch process memory with an INT3 byte at given address.
Syntax: int3 [<address>]
Note: useful in cases where the debugger breakpoints aren't respected but an INT3 will always trigger the debugger.
Note: ARM not yet supported.
Note: expressions supported, do not use spaces between operators.
"""
global int3patches
error = lldb.SBError()
target = get_target()
cmd = command.split()
# if empty insert a int3 at current PC
if len(cmd) == 0:
int3_addr = get_current_pc()
if int3_addr == 0:
print("[-] error: invalid current address.")
return
elif len(cmd) == 1:
if cmd[0] == "help":
print(help)
return
int3_addr = evaluate(cmd[0])
if int3_addr is None:
print("[-] error: invalid input address value.")
print("")
print(help)
return
else:
print("[-] error: please insert a breakpoint address.")
print("")
print(help)
return
bytes_string = target.GetProcess().ReadMemory(int3_addr, 1, error)
if error.Success() == False:
print("[-] error: Failed to read memory at 0x{:x}.".format(int3_addr))
return
bytes_read = bytearray(bytes_string)
patch_bytes = str('\xCC')
result = target.GetProcess().WriteMemory(int3_addr, patch_bytes, error)
if error.Success() == False:
print("[-] error: Failed to write memory at 0x{:x}.".format(int3_addr))
return
# save original bytes for later restore
int3patches[str(int3_addr)] = bytes_read[0]
print("[+] Patched INT3 at 0x{:x}".format(int3_addr))
return
def cmd_rint3(debugger, command, result, dict):
'''Restore byte at address from a previously patched INT3 (0xCC) instruction. Use \'rint3 help\' for more information.'''
help = """
Restore the original byte at a previously patched address using \'int3\' command.
Syntax: rint3 [<address>]
Note: expressions supported, do not use spaces between operators.
"""
global int3patches
error = lldb.SBError()
target = get_target()
cmd = command.split()
# if empty insert a int3 at current PC
if len(cmd) == 0:
int3_addr = get_current_pc()
if int3_addr == 0:
print("[-] error: invalid current address.")
return
elif len(cmd) == 1:
if cmd[0] == "help":
print(help)
return
int3_addr = evaluate(cmd[0])
if int3_addr is None:
print("[-] error: invalid input address value.")
print("")
print(help)
return
else:
print("[-] error: please insert a INT3 patched address.")
print("")
print(help)
return
if len(int3patches) == 0:
print("[-] error: No INT3 patched addresses to restore available.")
return
bytes_string = target.GetProcess().ReadMemory(int3_addr, 1, error)
if error.Success() == False:
print("[-] error: Failed to read memory at 0x{:x}.".format(int3_addr))
return
bytes_read = bytearray(bytes_string)
if bytes_read[0] == 0xCC:
#print("Found byte patched byte at 0x{:x}".format(int3_addr))
try:
original_byte = int3patches[str(int3_addr)]
except:
print("[-] error: Original byte for address 0x{:x} not found.".format(int3_addr))
return
patch_bytes = chr(original_byte)
result = target.GetProcess().WriteMemory(int3_addr, patch_bytes, error)
if error.Success() == False:
print("[-] error: Failed to write memory at 0x{:x}.".format(int3_addr))
return
# remove element from original bytes list
del int3patches[str(int3_addr)]
else:
print("[-] error: No INT3 patch found at 0x{:x}.".format(int3_addr))
return
def cmd_listint3(debugger, command, result, dict):
'''List all patched INT3 (0xCC) instructions. Use \'listint3 help\' for more information.'''
help = """
List all addresses patched with \'int3\' command.
Syntax: listint3
"""
cmd = command.split()
if len(cmd) != 0:
if cmd[0] == "help":
print(help)
return
print("[-] error: command doesn't take any arguments.")
print("")
print(help)
return