-
Notifications
You must be signed in to change notification settings - Fork 9
/
beginners-tut-II.txt
1278 lines (1084 loc) · 61.7 KB
/
beginners-tut-II.txt
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
Universe's best and legal Mac OS X reversing tutorial for newbies (or maybe not!)
------------------------------------------------------------------------------
(c) 2011 Fractal Guru (reverse AT put.as , http://reverse.put.as)
Target: Macserialjunkie.com Cracking Challenge 09 #1
Tools used: OTX, GDB, 0xED, gcc
Platform: Mac OS X Leopard 10.6.5 @ Intel x86
Document version: 0.1 (12/02/2011)
Index:
0 - Introduction
1 - Building our toolkit
2 - How to use our tools
2.1 - OTX
2.2 - GDB
2.3 - Putting otx and gdb together
3 - Reversing and cracking Challenge #1
3.0 - Introduction and workflow
3.1 - Patching the binary
3.2 - Fishing a valid serial number
3.3 - Keygen
4 - Conclusion
0 - Introduction
----------------
Update from the original version:
Reversing and breaking protections is a great hobby and fantastic knowledge to possess.
The problem is that many abuse this and want to profit from it. I really don't like not sharing
knowledge because sharing also allows me to progress, seeking new challenges and learning new things.
I really hope that you make good use of this information and do not share your cracks with the world,
especially in MSJ that is full of idiots just wanting to rip off others work. Don't do that please.
Don't make me regret once again releasing knowledge that may ease piracy!
Enjoy the process, learn, get frustrated, and buy the apps if you really use them in your day to day.
This tutorial is still based on 32bit binaries.
Have fun,
fG!
----
One of the most difficult tasks is to write a tutorial for beginners. It's not an easy task
so here's an attempt to create one that can launch people with some basic knowledge into the
world of reverse engineering (I consider cracking a subset of reverse engineering, and a very
useful one as a learning platform).
It's assumed you have basic x86 assembly knowledge (already too many good tutorials about this!).
Some URLs:
http://www.woodmann.com/crackz/Getstart.htm
http://www.uc-forum.com/forum/programming-beginners/63947-reverse-engineering-beginners-guide-x86-assembly-and-debugging-windows-apps.html
http://en.wikipedia.org/wiki/Assembly_language
The term "function" will be used alot. If you know Objective-C or C++, you know it's not entirely
correct to use it. Method would be more correct in this context. But some parts of this tutorial
can be used to reverse other languages where the term function is correct. It shouldn't be a big
deal for you to handle.
A word of caution: reversing/cracking is about exploring and thinking. You should get used to
think and explore problems and find solutions for them. These days, Google and other search
engines are your main friend and they can make your task much easier ! Get used to search, think
and explore ! That's the beauty of Reverse Engineering, diving into the unknown !
And now, let's start the fun !
fG!
1 - Building our toolkit
--------------------------
The first step is to build our reversing toolkit.
For me, two tools are essential, a disassembler and a debugger (especially this one!).
There are three available disassemblers and two debuggers. In disassemblers we have
IDA Pro, Otool and OTX. IDA is the most famous and powerful but it's paid (there is a demo
version available (HexRays released a native OS X demo version!), and a warez version is around of
course) and it's expensive. If you are serious to RE field and can buy it, do it !
If your company can buy it, ask them to buy it. It's worth the money!
An excellent book about IDA is "The IDA Pro Book: The Unofficial Guide to the World's Most Popular Disassembler"
by Chris Eagle. Buy it if you can (it's not that expensive and author deserves it!).
The other two options are technically just one, since OTX is a frontend for Otool.
OTX is available at: http://otx.osxninja.com/
Otool is part of XCode, available at: http://developer.apple.com/ (open an account, it's free!)
GDB is part of XCode, so you should download both.
The available debuggers are GDB and IDA (the debugger is integrated with the disassembler).
GDB is free and part of XCode. This tutorial will use GDB since it's faster to use (because IDA uses remote
debugging, meaning you will need two machines to debug) and it's capable to do everything we need
for this tutorial and any future uses you may have.
To make GDB even more easier to use, you should grab gdbinit. This is a script for GDB that will
enhance it's output and has macros to make our work easier and faster.
Grab my modified version here: http://reverse.put.as/wp-content/uploads/2010/04/gdbinit73
To install gdbinit, you will need to copy it into your home folder with the name ".gdbinit".
For example, if you have downloaded the file gdbinit73 into your download folders, you can install
it using Terminal.app with the following command:
cp ~/Downloads/gdbinit73 ~/.gdbinit
~ in Unix means your home folder.
There is a bug in Apple GDB version. You can read about it here: http://reverse.put.as/2008/11/28/apples-gdb-bug/
It's annoying and not a big obstacle to our work, and it's useful to fix it.
You might also want to give a look at http://reverse.put.as/2009/08/26/gdb-patches/ , which features other patches.
The next tool is an Hex Editor. I use 0xEd, available at http://www.suavetech.com/0xed/0xed.html.
Hex-Fiend is another good alternative (http://ridiculousfish.com/hexfiend/)
You should be able to install everything without any problem.
To resume, our basic reversing toolkit is composed of gdb, OTX/otool/IDA and 0xED/Hex-Fiend.
2 - How to use our tools
------------------------
2.0 - Updating OTX
------------------
The binary version of OTX doesn't support 64bit binaries, so you should download the version from the
SVN repository. The information is available here: http://otx.osxninja.com/subinfo.html
You will need XCode to compile the project.
2.1 - OTX
---------
Run OTX and you will get the program window. We need to open the binary file we want to disassemble.
Open a Terminal.app windows (yes I really love Terminal, some things are done faster and better thru the command line) and
go to the folder where you have the Cracking Challenge #1 application.
List all available files with "ls" command.
You should see a folder named Challenge #1.app. This is our target.
Mac OS X programs have a nice program structure, where everything (almost) is contained into a single folder.
Using Challenge #1.app as an example, we have the following structure inside it:
Challenge\ #1.app/Contents/
Then we have the following folders:
Info.plist MacOS PkgInfo Resources
You can find the main binary inside the MacOS folder. This is where we should start.
Frameworks folder (not present in this binary) might have interesting binaries to disassemble because
some protections can reside there instead in the main binary.
Listing the MacOS folder gives us:
$ ls MacOS/
Challenge #1
Challenge #1 is the binary we want to disassemble. The full path is:
Challenge\ #1.app/Contents/MacOS/Challenge #1
Some information from the binary can be extracted with the "file" command or otool.
To see if this is a fat binary (contains more than 1 architecture), you can use the following command:
$ file Challenge\ #1.app/Contents/MacOS/Challenge\ #1
Challenge #1.app/Contents/MacOS/Challenge #1: Mach-O universal binary with 2 architectures
Challenge #1.app/Contents/MacOS/Challenge #1 (for architecture i386): Mach-O executable i386
Challenge #1.app/Contents/MacOS/Challenge #1 (for architecture ppc): Mach-O executable ppc
The equivalent otool command is:
$ otool -h Challenge\ #1.app/Contents/MacOS/Challenge\ #1
Challenge #1.app/Contents/MacOS/Challenge #1 (architecture i386):
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedface 7 3 0x00 2 19 2356 0x00000085
Challenge #1.app/Contents/MacOS/Challenge #1 (architecture ppc):
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedface 18 0 0x00 2 17 2412 0x00000085
So this binary contains two architectures, x86 32 bits and PowerPC.
Let's try to disassemble the x86 version.
Select Open File in OTX and select that binary. You should select x86 as processor (it's the default).
You might change the output name or just leave the default. Click Save and select where to save (usually
Desktop or select one folder dedicated to your reversing project to have things organized).
If you can also use the otx command line version (I have installed mine at /usr/local/bin).
I usually use the following command "otx Challenge #1 >dump.txt".
And voila, you have disassembled your first binary. Very simple ! The output file is the disassembled listing of the
selected binary, and it will be our main guide into reversing the target.
2.2 - GDB
---------
Gdb is a very powerful debugger although not easy and not intuitive as Windows equivalents like OllyDbg
or Softice (well, Softice as also text only).
Nevertheless you can master it and do everything you should need for your RE projects.
Let's give it a shot and introduce you the world of GDB !
Just a little note on the commands to be used:
1) Commands issued inside gdb will always use the following prompt: gdb$
2) Commands issued in a Terminal.app shell will always use the following prompt: shell$
To learn gdb we are going to use a simpler target so we can understand the basic commands.
You will need to compile the following program example.c:
------------------- CUT HERE -----------------
#include <stdio.h>
main(int argc, char *argv[])
{
printf("Hello GDB!\n");
printf("Argument is: %s\n", argv[1]);
}
------------------- CUT HERE -----------------
Save this source code somewhere and compile it with (if you have called it example.c, else modify the name):
$ gcc -arch i386 -o example example.c
Note:
The -arch i386 option is required to compile the binary in 32bits instead of the default 64bits in Snow Leopard.
This small program will print 2 lines, where the second prints the argument from the command line.
Example:
$ ./example Test
Hello GDB!
Argument is: Test
GDB runs from the command line, so you will need to open a Terminal.App (at this moment you should already
have a Terminal.app shortcut into your Dock hehehe). To start gdb, just type "gdb" at the prompt and press enter.
You should get something like this (date should be different since this one was compiled by me on January):
GNU gdb 6.3.50-20050815 (Apple version gdb-768) (Fri Jan 23 17:22:29 UTC 2009)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-apple-darwin".
gdb$
To make sure gdbinit is installed correctly, type "help user". You should get a list of available commands,
the ones created by gdbinit script.
There are two different ways to debug a program, one is to attach to a version already running and the other one to
start the program from gdb.
To attach you will need the PID (process ID) for your target. You can find it by issuing a "ps aux" command
(or in Activity Monitor). The PID is the number in the second column. After you have the PID, you use the
"attach <PID>" gdb command.
To start the program from gdb, you can use the "exec-file <PATH_TO_EXECUTABLE_FILE>" (this is the best way to
overcome the gdb bug described earlier, if you don't have a patched version).
If you need to set parameters to the executable (usually not needed for our targets), you can use "set args" command
or set the arguments when you start the program with "run" command.
Practical example:
To start debugging our example code, open a command prompt and then type the following commands:
$gdb
(gdb is loaded)
gdb$ exec-file "PATH/example"
(substitute PATH for the full path where our example binary is)
or
$cd "PATH"
(substitute PATH for the full path where our example binary is)
$gdb
(gdb is loaded)
gdb$ exec-file ./example
In the first example we are using the full path to our binary, in the second example we change into the correct directory
and just point to the binary. It's a matter of personal taste (you can use TAB completation inside gdb!).
The basic commands we need are related to breakpoints, stepping, change flags or memory, dump/evaluate memory locations.
What is a breakpoint ?
From Wikipedia (http://en.wikipedia.org/wiki/Breakpoint):
"A breakpoint, in software development, is an intentional stopping or pausing place in a program, put in place for debugging purposes.
More generally, a breakpoint is a means of acquiring knowledge about a program during its execution. During the interruption, the
programmer inspects the test environment (logs, memory, files, etc.) to find out whether the program functions as expected.
In practice, a breakpoint consists of one or more conditions that determine when a program's execution should be interrupted."
The breakpoint related commands interesting to us are:
1) bp/b (set a breakpoint)
You can set a breakpoint on a memory location (most used) or in a symbol (if GDB knows about it).
For a memory breakpoint you just need to use the memory location where you want the program to stop.
Example:
gdb$ bp *0x1234
This will set a breakpoint on memory location 0x1234 (you need to use the * before the address). You should have guessed that 0x is the
format for hexadecimal number. If program execution reaches that memory location, program execution will be interrupted and you will
get back to gdb prompt!
Setting a breakpoint on a symbol is equivalent to use a name instead a memory location. Usually it's a function from a library or some
other symbol that GDB can solve.
An example is:
gdb$bp [NSControl stringValue]
This means whenever the program calls the stringValue function gdb will halt it's execution and return control to us. This function can
allow you to break on text input routines, so you can for example fish a valid serial.
2) bpl (list all breakpoints)
This command will list all breakpoints active or inactive.
Example:
gdb$ bpl
Num Type Disp Enb Address What
1 breakpoint keep y 0x00001f44 <start>
2 breakpoint keep n 0x00001f46 <start+2>
3) bpd/bpe (disable/enable a breakpoint)
This will enable or disable a breakpoint.
You should use the Num column from bpl output to select which one to enable or disable.
Example:
gdb$ bpd 1
gdb$ bpl
Num Type Disp Enb Address What
1 breakpoint keep n 0x00001f44 <start> <- we have disabled this one as you can see
2 breakpoint keep n 0x00001f46 <start+2>
4) bpc (clear breakpoint)
This will clear a breakpoint. Unlike bpe/bpd, you should use the memory location to remove from breakpoint list (same syntax as bp command).
Example:
gdb$ bpc *0x1f44
gdb$ bpl
Num Type Disp Enb Address What
2 breakpoint keep n 0x00001f46 <start+2>
You can also use the delete command to clear breakpoints by number (bpc is a gdbinit command, which uses clear instead delete [maybe to be modified in the future]).
Example:
gdb$ delete 2
gdb$ bpl
No breakpoints or watchpoints.
Breakpoints are done, let's go to the step commands.
Step commands will allow you to "browse" and run the assembly code for your target. All step commands
allow you to advance to the next address pointed by EIP (meaning, executing the code pointed by EIP).
But there is a distinction to be made. Some commands allow you to go into functions or subroutines, usually "calls".
Making it easier to understand, if you find a call to another function and want to see what happens
inside that function, you can step into that function and trace it, and then you get back to where
you were (in reality you get back to the address after the call you traced). Or you maybe want
to skip that call and just execute it without getting into it's details.
The functions I regularly use are nexti (or it's shortcut ni) and stepo (if I want to skip over calls or subroutines).
These should be enough for your reversing efforts.
Step commands interesting to us are (this is just a dump of help from gdb, should be enough):
1) next
gdb$ help next
Step program, proceeding through subroutine calls.
Like the "step" command as long as subroutine calls do not happen;
when they do, the call is treated as one instruction.
Argument N means do this N times (or till program stops for another reason).
2) nexti
gdb$ help nexti
Step one instruction, but proceed through subroutine calls.
Argument N means do this N times (or till program stops for another reason).
3) step
gdb$ help step
Step program until it reaches a different source line.
Argument N means do this N times (or till program stops for another reason).
4) stepi
gdb$ help stepi
Step one instruction exactly.
Argument N means do this N times (or till program stops for another reason).
5) stepo
gdb$ help stepo
Step over calls (interesting to bypass the ones to msgSend)
This function will set a temporary breakpoint on next instruction after the call so the call will be bypassed
You can safely use it instead nexti or n since it will single step code if it's not a call instruction
(unless you want to go into the call function)
Try to play with these step commands and see what are the differences between them. Like I said,
nexti and stepo should be enough!
The dump/evaluate commands will allow you to dump the contents of memory, cpu registers, variables,
pointers, etc.
Dump/evaluate commands are:
1) x
gdb$ help x
Examine memory: x/FMT ADDRESS.
ADDRESS is an expression for the memory address to examine.
FMT is a repeat count followed by a format letter and a size letter.
Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),
t(binary), f(float), a(address), i(instruction), c(char) and s(string),
T(OSType).
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).
The specified number of objects of the specified size are printed
according to the format.
Defaults for format and size letters are those previously used.
Default count is 1. Default address is following last thing printed
with this command or "print".
"x" will allow you to examine memory addresses and registers. It allows you to use formats for the output (something like printf).
Usually you will want to use the "x" format (hexadecimal) and "s" format (string).
For example, to dump EAX register contents in hexadecimal you would use gdb$ x/x $eax
Check this live example, using our example.c code:
gdb$
0x00001fb9 in main ()
--------------------------------------------------------------------------[regs]
EAX: 00001FE1 EBX: 00001FB2 ECX: BFFFF848 EDX: 00000000 o d I t S z a p c
ESI: 00000000 EDI: 00000000 EBP: BFFFF828 ESP: BFFFF810 EIP: 00001FB9
CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F
[001F:BFFFF810]----------------------------------------------------------[stack]
BFFFF860 : D2 F9 FF BF F1 F9 FF BF - 01 FA FF BF 3B FA FF BF ............;...
BFFFF850 : 33 F9 FF BF 6C F9 FF BF - 88 F9 FF BF C1 F9 FF BF 3...l...........
BFFFF840 : 00 00 00 00 01 00 00 00 - FC F8 FF BF 00 00 00 00 ................
BFFFF830 : 01 00 00 00 48 F8 FF BF - 50 F8 FF BF BC F8 FF BF ....H...P.......
BFFFF820 : 00 10 00 00 BC F8 FF BF - 40 F8 FF BF 7A 1F 00 00 [email protected]...
BFFFF810 : 00 00 00 00 00 00 00 00 - 3C F8 FF BF 37 10 E0 8F ........<...7...
[0017:00001FB9]-----------------------------------------------------------[code]
0x1fb9 <main+19>: mov DWORD PTR [esp],eax
0x1fbc <main+22>: call 0x300a <dyld_stub_puts>
0x1fc1 <main+27>: mov eax,DWORD PTR [ebp+0xc]
0x1fc4 <main+30>: add eax,0x4
0x1fc7 <main+33>: mov eax,DWORD PTR [eax]
0x1fc9 <main+35>: mov DWORD PTR [esp+0x4],eax
0x1fcd <main+39>: lea eax,[ebx+0x3a]
0x1fd3 <main+45>: mov DWORD PTR [esp],eax
--------------------------------------------------------------------------------
gdb$ x/s $eax
0x1fe1 <main+59>: "Hello GDB!"
We just printed the string that was pointed by EAX register.
Still using the same example, if you increase count to 2 (x/2s), the next string is printed too.
gdb$ x/2s $eax
0x1fe1 <main+59>: "Hello GDB!"
0x1fec <main+70>: "Argument is: %s\n"
2) print
This one is used more or less like "x". Usually used when you have the source, so you can print the program variables.
Check it's help on gdb.
3) po
gdb$ help po
Ask an Objective-C object to print itself.
This command will allow you to print Objective-C objects. This command is very handy when you are
debugging Objective-C and you want to print the object.
You can't simply see an object by using the "x" command.
Little example:
Breakpoint in 0x30001acf
+548 30001acf 890424 movl %eax,(%esp,1) <- NSBundle </Users/aaaaaaaa/You Control Desktops.app/> (loaded)
+551 30001ad2 e82eb50300 calll 0x3003d005 _objc_msgSend
In gdb:
gdb $ x/s $eax
0x30a9c0: "?c??"
gdb $ po $eax
NSBundle </Users/username/reverse/You Control Desktops-newcrack.app> (loaded)
You can see the object where eax is pointing too. Much better than the first x/s $eax
Change flags or memory commands are:
1) cfX, where X can be a,c,d,i,o,p,s,t,z,s
All the cfX commands are from gdbinit. These will allow you to change the cpu register flags (they will invert the current flag state).
For example, the JE (jump if equal) assembler instruction, will be followed (meaning the code will jump to the new location) only if the Zero flag
(ZF or Z) is equal to 1. If the next instruction to be executed is a JE and the Zero flag is equal to 0, there will be no jump. But if you want to
easily force the jump, then you just need to modify the Zero Flag and make it equal to one. You can simply do this by using the cfz command, like
gdb$ cfz
This would change the value for ZF from 0 to 1. Or maybe you don't want the jump to be followed (ZF=1) and so you issue cfz to reverse ZF to 0.
The different cfX commands are:
cfa -- Change Auxiliary Carry Flag
cfc -- Change Carry Flag
cfd -- Change Direction Flag
cfi -- Change Interrupt Flag
cfo -- Change Overflow Flag
cfp -- Change Parity Flag
cfs -- Change Sign Flag
cft -- Change Trap Flag
cfz -- Change Zero Flag
2) set
The set command has many available subcommands. We are interested in changing memory contents and/or registers contents.
To change memory location the syntax is:
gdb$ set *address = newvalue , where address is in the usual hexadecimal format.
The memory location can be program code (if you want for example to live patch the program) or any
other memory location (for example an address holding a variable).
If you want to change a register content, for example EAX, the syntax is:
gdb$ set $eax = newvalue
You can use complex expressions with set, for example type casting. For example if you want to write a single byte you could use:
gdb$ set $eax = (char) 0x12345
gdb$ print $eax
$3 = 0x45
gdb$ set $eax = (int) 0x12345
gdb$ print $eax
$4 = 0x12345
Do you understand what happened with this example ? Think about it (should be easy to understand!).
2.3 - Putting otx and gdb together
----------------------------------
Let's play a little bit with gdb so you can watch a debugging session.
Disassemble the example binary with otx. You should have an output more or like this (I have added line
numbers for easy reference here!):
md5: 27cc7b61ed3322057d52b6b014d589e6
(__TEXT,__text) section
(Uninteresting code here for our purposes, we are just interested in the main function)
_main:
1: +0 00001fa6 55 pushl %ebp
2: +1 00001fa7 89e5 movl %esp,%ebp
3: +3 00001fa9 53 pushl %ebx
4: +4 00001faa 83ec14 subl $0x14,%esp
5: +7 00001fad e800000000 calll 0x00001fb2
6: +12 00001fb2 5b popl %ebx
7: +13 00001fb3 8d832f000000 leal 0x0000002f(%ebx),%eax Hello GDB!
8: +19 00001fb9 890424 movl %eax,(%esp)
9: +22 00001fbc e849100000 calll 0x0000300a _puts
10: +27 00001fc1 8b450c movl 0x0c(%ebp),%eax
11: +30 00001fc4 83c004 addl $0x04,%eax
12: +33 00001fc7 8b00 movl (%eax),%eax
13: +35 00001fc9 89442404 movl %eax,0x04(%esp)
14: +39 00001fcd 8d833a000000 leal 0x0000003a(%ebx),%eax Argument is: %s\n
15: +45 00001fd3 890424 movl %eax,(%esp)
16: +48 00001fd6 e82a100000 calll 0x00003005 _printf
17: +53 00001fdb 83c414 addl $0x14,%esp
18: +56 00001fde 5b popl %ebx
19: +57 00001fdf c9 leave
20: +58 00001fe0 c3 ret
Remember that our source version looks like:
main(int argc, char *argv[])
{
printf("Hello GDB!\n");
printf("Argument is: %s\n", argv[1]);
}
You can easily see that the compiler used "puts" for our first printf and used printf for our second.
This was a compiler optimization. Compilers usually optimized your source code and use the best options
available to make your code shorter and faster.
Since our first printf doesn't have any format string being used, it can be replaced by a shorter and
faster function at compiler level, puts, and still do what we wanted in our source code, to print a
simple "Hello GDB!" message.
Let's start debugging our little program. Open gdb and start our example program.
shell$ gdb
GNU gdb 6.3.50-20050815 (Apple version gdb-962) (Sat Jul 26 08:14:40 UTC 2008)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-apple-darwin".
gdb$ exec-file ./example
Reading symbols for shared libraries ... done
gdb$
If you type the run command, our program will run and exit, since we haven't set any breakpoint yet.
Let's give it a try:
gdb$ run
Reading symbols for shared libraries .++. done
Hello GDB!
Argument is: (null)
Program exited with code 024.
--------------------------------------------------------------------------[regs]
EAX:Error while running hook_stop:
No registers.
gdb$
You can easily see our messages printed.
Let's try running our program with an argument:
gdb$ run TESTING
Hello GDB!
Argument is: TESTING
Program exited with code 025.
--------------------------------------------------------------------------[regs]
EAX:Error while running hook_stop:
No registers.
gdb$
Now let's set our first breakpoint. We want to breakpoint the program before the first message "Hello GDB!"
is printed. We already know that the function responsible to print that first message is "puts", and
you can find the call to this function at line 9. Let's explain this line contents:
9: +22 : local offset, meaning the offset inside this function (it's not interesting
to us and you can configure otx to remove this)
00001fbc : code address (hexadecimal format), this is the address we are going to use
for our breakpoint(s)
e849100000 : opcodes, these are the bytes your cpu will read and form your instructions
(and the ones we can modify to patch the code)
calll 0x0000300a : this is the assembly mnemonic correspondent to the previous opcode bytes
_puts : this is additional information that otx was able to identify, in this case
it identified we are going to call the "puts" function
Hopefully you have understood otx output. So if we want to break on line 9, we should use memory
address 0x1fbc. To be honest, since we have the source code, we could use source file line reference
to create the breakpoint but since we usually don't have source for our targets, this will not be explored.
Set the breakpoint:
gdb$ bp *0x1fbc
Breakpoint 1 at 0x1fbc
gdb$
And list:
gdb$ bpl
Num Type Disp Enb Address What
1 breakpoint keep y 0x00001fbc <main+22>
gdb$
Our first breakpoint is set, we can run again our program (you should already have noted that we can
run again and again the program after we have loaded it into gdb).
Let's go...
gdb$ run
Breakpoint 1, 0x00001fbc in main ()
--------------------------------------------------------------------------[regs]
EAX: 00001FE1 EBX: 00001FB2 ECX: BFFFF848 EDX: 00000000 o d I t S z a p c
ESI: 00000000 EDI: 00000000 EBP: BFFFF828 ESP: BFFFF810 EIP: 00001FBC
CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F
[001F:BFFFF810]----------------------------------------------------------[stack]
BFFFF860 : D2 F9 FF BF F1 F9 FF BF - 01 FA FF BF 3B FA FF BF ............;...
BFFFF850 : 33 F9 FF BF 6C F9 FF BF - 88 F9 FF BF C1 F9 FF BF 3...l...........
BFFFF840 : 00 00 00 00 01 00 00 00 - FC F8 FF BF 00 00 00 00 ................
BFFFF830 : 01 00 00 00 48 F8 FF BF - 50 F8 FF BF BC F8 FF BF ....H...P.......
BFFFF820 : 00 10 00 00 BC F8 FF BF - 40 F8 FF BF 7A 1F 00 00 [email protected]...
BFFFF810 : E1 1F 00 00 00 00 00 00 - 3C F8 FF BF 37 10 E0 8F ........<...7...
[0017:00001FBC]-----------------------------------------------------------[code]
0x1fbc <main+22>: call 0x300a <dyld_stub_puts>
0x1fc1 <main+27>: mov eax,DWORD PTR [ebp+0xc]
0x1fc4 <main+30>: add eax,0x4
0x1fc7 <main+33>: mov eax,DWORD PTR [eax]
0x1fc9 <main+35>: mov DWORD PTR [esp+0x4],eax
0x1fcd <main+39>: lea eax,[ebx+0x3a]
0x1fd3 <main+45>: mov DWORD PTR [esp],eax
0x1fd6 <main+48>: call 0x3005 <dyld_stub_printf>
--------------------------------------------------------------------------------
gdb$
This is the output you will get. GDB did it's job correctly and program stopped at address 0x1fbc as we wanted.
There are two areas of output interesting to us. The first one is [regs] and the seconde [code].
In [regs] you can find the current state of cpu registers and flags at breakpoint moment. You should
know the meaning of each register ;)
In [code] you have disassembly output for the current memory address. The first line is always the
next line code to be executed.
If you compare otx disassemble output and gdb output, you will see there are cosmetic differences.
These are due to otx using AT&T syntax and gdb is configured for Intel syntax. You can modify gdb to
use AT&T syntax if you aren't comfortable with different syntaxes. Refer to
http://www.redhat.com/docs/manuals/enterprise/RHEL-3-Manual/gnu-assembler/i386-syntax.html if you
are interested in understanding differences between the two.
At this moment, you can do various operations. For example, you can dump the contents of EAX register
or any other memory location. Or you can step the code to understand it, or simply let the program
continue running without any further interference.
If you use "c" or "continue" commands, program will continue running and eventually end. Let's try.
gdb$ c
Hello GDB!
Argument is: (null)
Program exited with code 024.
--------------------------------------------------------------------------[regs]
EAX:Error while running hook_stop:
No registers.
gdb$
Since our breakpoint is still set, we can run the program again and it will stop again at the same place. Try it...
Assuming you did tried, we are back to our breakpoint. We want to follow and understand the code, so
we are going to step each line of code.
Since the next instruction to be executed is a call, you know we can step over it (meaning we don't
want to analyse what "puts" function will do) or we can step into it (meaning we want to analyse
what "puts" is going to do).
For this example, we are not interested in understanding how "puts" work (since we already know it
will just print characters) and just want it to be executed.
We can use either "n", "ni", "nexti", "stepo" gdb commands. If you use "stepi" you will get inside
"puts" function. The safest bet is to use "stepo" if you want to skip over calls.
Let's try...
gdb$ stepo
Breakpoint 3 at 0x1fc1 <----------- you can ignore this, it's a temporary breakpoint used by stepo
Hello GDB! <----------- OUR MESSAGE WAS PRINTED
Breakpoint 3, 0x00001fc1 in main ()
--------------------------------------------------------------------------[regs]
EAX: 0000000A EBX: 00001FB2 ECX: 0000000B EDX: 00000000 o d I t S z a P c
ESI: 00000000 EDI: 00000000 EBP: BFFFF828 ESP: BFFFF810 EIP: 00001FC1
CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F
[001F:BFFFF810]----------------------------------------------------------[stack]
BFFFF860 : D2 F9 FF BF F1 F9 FF BF - 01 FA FF BF 3B FA FF BF ............;...
BFFFF850 : 33 F9 FF BF 6C F9 FF BF - 88 F9 FF BF C1 F9 FF BF 3...l...........
BFFFF840 : 00 00 00 00 01 00 00 00 - FC F8 FF BF 00 00 00 00 ................
BFFFF830 : 01 00 00 00 48 F8 FF BF - 50 F8 FF BF BC F8 FF BF ....H...P.......
BFFFF820 : 00 10 00 00 BC F8 FF BF - 40 F8 FF BF 7A 1F 00 00 [email protected]...
BFFFF810 : E1 1F 00 00 00 00 00 00 - 3C F8 FF BF 37 10 E0 8F ........<...7...
[0017:00001FC1]-----------------------------------------------------------[code]
0x1fc1 <main+27>: mov eax,DWORD PTR [ebp+0xc]
0x1fc4 <main+30>: add eax,0x4
0x1fc7 <main+33>: mov eax,DWORD PTR [eax]
0x1fc9 <main+35>: mov DWORD PTR [esp+0x4],eax
0x1fcd <main+39>: lea eax,[ebx+0x3a]
0x1fd3 <main+45>: mov DWORD PTR [esp],eax
0x1fd6 <main+48>: call 0x3005 <dyld_stub_printf>
0x1fdb <main+53>: add esp,0x14
--------------------------------------------------------------------------------
gdb$
What we have here ? Next code to be executed is line 10: and we can clearly see that "puts" function
was executed (Hello GDB! message is displayed!).
As before, you can do whatever operations you want now. You can continue stepping thru the code, set
more breakpoints, dump memory/registers, continue the program, etc...
As an exercise, now we want to stop at line 13. How many alternatives do you have to do that ? At
least 2 ! Breakpoint on address correspondent to line 13 or step thru the code until you reach line 13.
You should reach something like this:
gdb$
0x00001fc9 in main ()
--------------------------------------------------------------------------[regs]
EAX: 00000000 EBX: 00001FB2 ECX: 0000000B EDX: 00000000 o d I t S z a p c
ESI: 00000000 EDI: 00000000 EBP: BFFFF828 ESP: BFFFF810 EIP: 00001FC9
CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F
[001F:BFFFF810]----------------------------------------------------------[stack]
BFFFF860 : D2 F9 FF BF F1 F9 FF BF - 01 FA FF BF 3B FA FF BF ............;...
BFFFF850 : 33 F9 FF BF 6C F9 FF BF - 88 F9 FF BF C1 F9 FF BF 3...l...........
BFFFF840 : 00 00 00 00 01 00 00 00 - FC F8 FF BF 00 00 00 00 ................
BFFFF830 : 01 00 00 00 48 F8 FF BF - 50 F8 FF BF BC F8 FF BF ....H...P.......
BFFFF820 : 00 10 00 00 BC F8 FF BF - 40 F8 FF BF 7A 1F 00 00 [email protected]...
BFFFF810 : E1 1F 00 00 00 00 00 00 - 3C F8 FF BF 37 10 E0 8F ........<...7...
--------------------------------------------------------------------[ObjectiveC]
0x0: <Address 0x0 out of bounds>
[0017:00001FC9]-----------------------------------------------------------[code]
0x1fc9 <main+35>: mov DWORD PTR [esp+0x4],eax <---- first mov instruction
0x1fcd <main+39>: lea eax,[ebx+0x3a]
0x1fd3 <main+45>: mov DWORD PTR [esp],eax <---- 2nd mov instruction
0x1fd6 <main+48>: call 0x3005 <dyld_stub_printf>
0x1fdb <main+53>: add esp,0x14
0x1fde <main+56>: pop ebx
0x1fdf <main+57>: leave
0x1fe0 <main+58>: ret
--------------------------------------------------------------------------------
gdb$
For now you can ignore the ObjectiveC part. The code for our printf function is:
printf("Argument is: %s\n", argv[1]);
You can easily see that we have two arguments passed onto printf function, "Argument is: %s\n" and argv[1].
You should already know that arguments are passed into the stack (ESP) in reverse order, from last to first.
So this first mov instruction is moving the second argument into the stack and the second mov is moving
the first argument.
You should be able to identify that in this case the was no argument to "run" command since EAX is empty.
If you have used a parameter (or set args command) EAX would hold it's contents. Try it ! When you stop
there, use the "x" command to dump EAX contents, like this:
(I used run TESTING)
gdb$ x/s $eax
0xbffff923: "TESTING"
You can step to line 15 (0x1fd3 address) and dump again the contents of EAX. You should see the first
argument to printf function.
And that's it ! The basics are covered. You should now know how to set breakpoints, step code and
dump memory/register contents.
3 - Reversing and cracking Challenge #1
---------------------------------------
3.0 - Introduction and workflow
-------------------------------
The first thing to do is reconnaissance. We need to understand what are the program limits and what
messages (if any!) are being displayed about those limits.
If we have an error message like "Bad serial", "Trial is expired" or something like this, the next
step is to check if this message is present in the program binaries in plain text, which can give us
fast clues where we should start our work.
The best tool for this job is "grep". If you have Unix experience you should already know it, else
you are about to be introduced.
We want to grep all files belonging to our application. Best way is like this:
shell$ cd Challenge\ #1.app/Contents/
shell$ grep -r -i "message" *
(-r means recursive and -i case insensitive)
When you start Challen #1 for the first time you have a message telling you about the goals of this crackme.
Continue and insert a random name and a random serial. You get an error message:
"The name and serial number combination you entered is incorrect."
Try to search for that one...
There is one hit at "Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib".
shell$ grep -r -i "you entered is incorrect" *
Binary file Challenge #1.app/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib matches
This means that there are no direct references in the main binary to the string, so we need to
use other methods.
Another classic way is to open the disassembly listing and search for methods with interesting names.
If you browse the disassembly for this challenge, you will find an interesting string "isRegistered".
Unfortunately, many developers for OS X use names like this for their registration/protection code,
so it's very easy to track them.
The interesting place where you find this is here:
-(void)[Level1 applicationDidFinishLaunching:]
+0 0000251e 55 pushl %ebp
+1 0000251f 89e5 movl %esp,%ebp
+3 00002521 53 pushl %ebx
+4 00002522 83ec24 subl $0x24,%esp
+7 00002525 8b5d08 movl 0x08(%ebp),%ebx
+10 00002528 a110400000 movl 0x00004010,%eax isRegistered
+15 0000252d 891c24 movl %ebx,(%esp)
+18 00002530 89442404 movl %eax,0x04(%esp)
+22 00002534 e8252b0000 calll 0x0000505e -[(%esp,1) isRegistered]
+27 00002539 84c0 testb %al,%al
+29 0000253b 742b je 0x00002568
From Apple's documentation available at
http://developer.apple.com/library/mac/#documentation/cocoa/reference/NSApplicationDelegate_Protocol/Reference/Reference.html
you get the following about applicationDidFinishLaunching:
Delegates can implement this method to perform further initialization. This method is called after
the applicationÕs main run loop has been started but before it has processed any events. If the
application was launched by the user opening a file, the delegateÕs application:openFile: method is
called before this method. If you want to perform initialization before any files are opened, implement
the applicationWillFinishLaunching: method in your delegate, which is called before application:openFile:.)
This is a good place to start in Cocoa apps, because many developers start checking here if trials are ok,
if serial numbers are ok, etc.
This is more or less the behaviour we have experienced with the crackme, because we got that initial
message telling us about what we need to do (we can speculate that the message will not appear if the
crackme is registered successfully).
Getting back to that piece of code:
-(void)[Level1 applicationDidFinishLaunching:]
+0 0000251e 55 pushl %ebp
+1 0000251f 89e5 movl %esp,%ebp
+3 00002521 53 pushl %ebx
+4 00002522 83ec24 subl $0x24,%esp
+7 00002525 8b5d08 movl 0x08(%ebp),%ebx
+10 00002528 a110400000 movl 0x00004010,%eax isRegistered
+15 0000252d 891c24 movl %ebx,(%esp)
+18 00002530 89442404 movl %eax,0x04(%esp)
+22 00002534 e8252b0000 calll 0x0000505e -[(%esp,1) isRegistered] <- call the routine
+27 00002539 84c0 testb %al,%al
+29 0000253b 742b je 0x00002568 <- if it's not registered, then it will show the bad message
+31 0000253d a10c500000 movl 0x0000500c,%eax
+36 00002542 8b10 movl (%eax),%edx
+38 00002544 c744241800000000 movl $0x00000000,0x18(%esp)
+46 0000254c c744241400000000 movl $0x00000000,0x14(%esp)
+54 00002554 c744241000000000 movl $0x00000000,0x10(%esp)
+62 0000255c 8b430c movl 0x0c(%ebx),%eax (id)mainWindow
+65 0000255f 8944240c movl %eax,0x0c(%esp)
+69 00002563 8b4314 movl 0x14(%ebx),%eax (id)registeredSheet <- the good message
+72 00002566 eb29 jmp 0x00002591
What we got here is a classical (and very weak) test for available registration or not. If the function isRegistered
returns true, then the good message will be shown, else the bad one will be shown since the program isn't registered.
Since that je is conditional we have two possible solutions for a crack:
1) Nop the conditional jump: JE to NOP
2) Patch the isRegistered routine to return always true
The first alternative is very easy to test with gdb, even before patching anything.
Load the crackme into gdb and set a breakpoint at 0x0000253b (the address of the JE).
Sample session:
$ gdb Challenge\ #1
GNU gdb 6.3.50-20050815 (Apple version gdb-1344) (Mon Dec 28 15:21:35 UTC 2009)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries ......b .. done
gdb$ b *0x0000253b
Breakpoint 1 at 0x253b
gdb$ r
Reading symbols for shared libraries .+++++++.................................................................................. done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Breakpoint 1, 0x0000253b in -[Level1 applicationDidFinishLaunching:] ()
--------------------------------------------------------------------------[regs]
EAX: 0x00000000 EBX: 0x00415CC0 ECX: 0x00000001 EDX: 0x00000000 o d I t s Z a P c
ESI: 0xBFFFEA50 EDI: 0x00000002 EBP: 0xBFFFEA18 ESP: 0xBFFFE9F0 EIP: 0x0000253B
CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F Jump is taken (z=1)
--------------------------------------------------------------------------[code]
0x253b: 74 2b je 0x2568
0x253d: a1 0c 50 00 00 mov eax,ds:0x500c
0x2542: 8b 10 mov edx,DWORD PTR [eax]
0x2544: c7 44 24 18 00 00 00 00 mov DWORD PTR [esp+0x18],0x0
0x254c: c7 44 24 14 00 00 00 00 mov DWORD PTR [esp+0x14],0x0
0x2554: c7 44 24 10 00 00 00 00 mov DWORD PTR [esp+0x10],0x0
0x255c: 8b 43 0c mov eax,DWORD PTR [ebx+0xc]
0x255f: 89 44 24 0c mov DWORD PTR [esp+0xc],eax
--------------------------------------------------------------------------------
gdb$
Gdb stopped before executing the JE and we can observe that the jump will be taken, so the not
registered message will appear. To test our theory, you should use the "cfz" command.
This will change the zero flag, from 1 to 0 (you know it's the zero flag because you have that
information in the Jump is taken msg, z=1).
Change the flag and then issue the command "context". This will redraw gdb output without advancing
any instruction.
gdb$ cfz
gdb$ context
--------------------------------------------------------------------------[regs]
EAX: 0x00000000 EBX: 0x00416FC0 ECX: 0x00000001 EDX: 0x00000000 o d I t s z a P c
ESI: 0xBFFFEA50 EDI: 0x00000002 EBP: 0xBFFFEA18 ESP: 0xBFFFE9F0 EIP: 0x0000253B
CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F Jump is NOT taken (z!=1)
--------------------------------------------------------------------------[code]
0x253b: 74 2b je 0x2568
0x253d: a1 0c 50 00 00 mov eax,ds:0x500c
0x2542: 8b 10 mov edx,DWORD PTR [eax]
0x2544: c7 44 24 18 00 00 00 00 mov DWORD PTR [esp+0x18],0x0
0x254c: c7 44 24 14 00 00 00 00 mov DWORD PTR [esp+0x14],0x0
0x2554: c7 44 24 10 00 00 00 00 mov DWORD PTR [esp+0x10],0x0
0x255c: 8b 43 0c mov eax,DWORD PTR [ebx+0xc]
0x255f: 89 44 24 0c mov DWORD PTR [esp+0xc],eax
--------------------------------------------------------------------------------
You can observe that the message changed and the jump will not be executed.
Issue the continue command and check the program... Voila, you have just bypassed the protection!
So the first method is to change the JE into a NOP. A nop mean no-operation, a harmless instruction
will be executed. Since the instruction JE is two bytes (74 2b), and NOPs are a single byte (90),
you will need two use two nops to replace 74 2b. More on patching later...
The alternative, is to modify the isRegistered method.
The disassembly is:
-(BOOL)[Level1 isRegistered]
+0 00002a88 55 pushl %ebp
+1 00002a89 89e5 movl %esp,%ebp
+3 00002a8b 8b4508 movl 0x08(%ebp),%eax
+6 00002a8e 0fb64020 movzbl 0x20(%eax),%eax
+10 00002a92 c9 leave
+11 00002a93 c3 ret
You can modify this method to always return 1 (true).
The most common way to do this is to replace the beginning of this method with the following code:
xor eax, eax
inc eax
ret
Using the assemble command from gdb:
gdb$ assemble
Instructions will be written to stdout.
Type instructions, one per line. Do not forget to use NASM assembler syntax!
End with a line saying just "end".
>xor eax,eax
>inc eax
>ret
>end
00000000 31C0 xor eax,eax
00000002 40 inc eax
00000003 C3 ret
Those are the bytes you need to use and replace in the original method, 31 C0 40 c3.
You need to patch 4 bytes, starting at 0x00002a88. The two first instructions total 3 bytes, so you
will "eat" space in the third instruction, which is 3 bytes long. Since you will patch a single byte
in the third instruction, the rest of the code there will be most probably invalid. This isn't a
problem because we will not execute any code after the ret (return). To make this cleaner you could
NOP the two remaining bytes from the old third instruction.
A variation of patching isRegistered, is to patch the code before the method is called.
The original code is:
+7 00002525 8b5d08 movl 0x08(%ebp),%ebx
+10 00002528 a110400000 movl 0x00004010,%eax isRegistered
+15 0000252d 891c24 movl %ebx,(%esp)
+18 00002530 89442404 movl %eax,0x04(%esp)
+22 00002534 e8252b0000 calll 0x0000505e -[(%esp,1) isRegistered] <- call the routine
+27 00002539 84c0 testb %al,%al
+29 0000253b 742b je 0x00002568 <- if it's not registered, then it will show the bad message
For example, you could replace the code at address 0x00002534 by:
xor eax, eax
inc eax
and NOP the remaining bytes.
So there are different ways to do this, based on available space, conditions and your lazyness ;-)
As with the first alternative, you can try this in gdb before patching. Breakpoint the isRegistered method
at 0x00002a88 and run the crackme.
$ gdb Challenge\ #1
GNU gdb 6.3.50-20050815 (Apple version gdb-1344) (Mon Dec 28 15:21:35 UTC 2009)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries ........ done
gdb$ b *0x00002a88
Breakpoint 1 at 0x2a88
gdb$ r
Reading symbols for shared libraries .+++++++.................................................................................. done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
Breakpoint 1, 0x00002a88 in -[Level1 isRegistered] ()
--------------------------------------------------------------------------[regs]
EAX: 0x00002A88 EBX: 0x00418820 ECX: 0x00000001 EDX: 0x00000000 o d I t s Z a P c
ESI: 0xBFFFEA50 EDI: 0x00000002 EBP: 0xBFFFEA18 ESP: 0xBFFFE9EC EIP: 0x00002A88
CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F
--------------------------------------------------------------------------[code]
0x2a88: 55 push ebp
0x2a89: 89 e5 mov ebp,esp