Advertisement
AS_x264

RCE on MAC for newbies II

Sep 15th, 2013
187
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 62.92 KB | None | 0 0
  1. Universe's best and legal Mac OS X reversing tutorial for newbies (or maybe not!)
  2. ------------------------------------------------------------------------------
  3. (c) 2011 Fractal Guru (reverse AT put.as , http://reverse.put.as)
  4.  
  5. Target: Macserialjunkie.com Cracking Challenge 09 #1
  6. Tools used: OTX, GDB, 0xED, gcc
  7. Platform: Mac OS X Leopard 10.6.5 @ Intel x86
  8. Document version: 0.1 (12/02/2011)
  9.  
  10. Index:
  11. 0 - Introduction
  12. 1 - Building our toolkit
  13. 2 - How to use our tools
  14. 2.1 - OTX
  15. 2.2 - GDB
  16. 2.3 - Putting otx and gdb together
  17. 3 - Reversing and cracking Challenge #1
  18. 3.0 - Introduction and workflow
  19. 3.1 - Patching the binary
  20. 3.2 - Fishing a valid serial number
  21. 3.3 - Keygen
  22. 4 - Conclusion
  23.  
  24. 0 - Introduction
  25. ----------------
  26. Update from the original version:
  27.  
  28. Reversing and breaking protections is a great hobby and fantastic knowledge to possess.
  29. The problem is that many abuse this and want to profit from it. I really don't like not sharing
  30. knowledge because sharing also allows me to progress, seeking new challenges and learning new things.
  31. I really hope that you make good use of this information and do not share your cracks with the world,
  32. especially in MSJ that is full of idiots just wanting to rip off others work. Don't do that please.
  33. Don't make me regret once again releasing knowledge that may ease piracy!
  34. Enjoy the process, learn, get frustrated, and buy the apps if you really use them in your day to day.
  35. This tutorial is still based on 32bit binaries.
  36.  
  37. Have fun,
  38. fG!
  39.  
  40. ----
  41.  
  42. One of the most difficult tasks is to write a tutorial for beginners. It's not an easy task
  43. so here's an attempt to create one that can launch people with some basic knowledge into the
  44. world of reverse engineering (I consider cracking a subset of reverse engineering, and a very
  45. useful one as a learning platform).
  46. It's assumed you have basic x86 assembly knowledge (already too many good tutorials about this!).
  47. Some URLs:
  48. http://www.woodmann.com/crackz/Getstart.htm
  49. http://www.uc-forum.com/forum/programming-beginners/63947-reverse-engineering-beginners-guide-x86-assembly-and-debugging-windows-apps.html
  50. http://en.wikipedia.org/wiki/Assembly_language
  51.  
  52. The term "function" will be used alot. If you know Objective-C or C++, you know it's not entirely
  53. correct to use it. Method would be more correct in this context. But some parts of this tutorial
  54. can be used to reverse other languages where the term function is correct. It shouldn't be a big
  55. deal for you to handle.
  56.  
  57. A word of caution: reversing/cracking is about exploring and thinking. You should get used to
  58. think and explore problems and find solutions for them. These days, Google and other search
  59. engines are your main friend and they can make your task much easier ! Get used to search, think
  60. and explore ! That's the beauty of Reverse Engineering, diving into the unknown !
  61.  
  62. And now, let's start the fun !
  63. fG!
  64.  
  65. 1 - Building our toolkit
  66. --------------------------
  67.  
  68. The first step is to build our reversing toolkit.
  69. For me, two tools are essential, a disassembler and a debugger (especially this one!).
  70. There are three available disassemblers and two debuggers. In disassemblers we have
  71. IDA Pro, Otool and OTX. IDA is the most famous and powerful but it's paid (there is a demo
  72. version available (HexRays released a native OS X demo version!), and a warez version is around of
  73. course) and it's expensive. If you are serious to RE field and can buy it, do it !
  74. If your company can buy it, ask them to buy it. It's worth the money!
  75. An excellent book about IDA is "The IDA Pro Book: The Unofficial Guide to the World's Most Popular Disassembler"
  76. by Chris Eagle. Buy it if you can (it's not that expensive and author deserves it!).
  77. The other two options are technically just one, since OTX is a frontend for Otool.
  78. OTX is available at: http://otx.osxninja.com/
  79. Otool is part of XCode, available at: http://developer.apple.com/ (open an account, it's free!)
  80. GDB is part of XCode, so you should download both.
  81.  
  82. The available debuggers are GDB and IDA (the debugger is integrated with the disassembler).
  83. GDB is free and part of XCode. This tutorial will use GDB since it's faster to use (because IDA uses remote
  84. debugging, meaning you will need two machines to debug) and it's capable to do everything we need
  85. for this tutorial and any future uses you may have.
  86.  
  87. To make GDB even more easier to use, you should grab gdbinit. This is a script for GDB that will
  88. enhance it's output and has macros to make our work easier and faster.
  89. Grab my modified version here: http://reverse.put.as/wp-content/uploads/2010/04/gdbinit73
  90.  
  91. To install gdbinit, you will need to copy it into your home folder with the name ".gdbinit".
  92.  
  93. For example, if you have downloaded the file gdbinit73 into your download folders, you can install
  94. it using Terminal.app with the following command:
  95. cp ~/Downloads/gdbinit73 ~/.gdbinit
  96.  
  97. ~ in Unix means your home folder.
  98.  
  99. There is a bug in Apple GDB version. You can read about it here: http://reverse.put.as/2008/11/28/apples-gdb-bug/
  100. It's annoying and not a big obstacle to our work, and it's useful to fix it.
  101. You might also want to give a look at http://reverse.put.as/2009/08/26/gdb-patches/ , which features other patches.
  102.  
  103. The next tool is an Hex Editor. I use 0xEd, available at http://www.suavetech.com/0xed/0xed.html.
  104. Hex-Fiend is another good alternative (http://ridiculousfish.com/hexfiend/)
  105.  
  106. You should be able to install everything without any problem.
  107.  
  108. To resume, our basic reversing toolkit is composed of gdb, OTX/otool/IDA and 0xED/Hex-Fiend.
  109.  
  110. 2 - How to use our tools
  111. ------------------------
  112.  
  113. 2.0 - Updating OTX
  114. ------------------
  115.  
  116. The binary version of OTX doesn't support 64bit binaries, so you should download the version from the
  117. SVN repository. The information is available here: http://otx.osxninja.com/subinfo.html
  118. You will need XCode to compile the project.
  119.  
  120. 2.1 - OTX
  121. ---------
  122.  
  123. Run OTX and you will get the program window. We need to open the binary file we want to disassemble.
  124. Open a Terminal.app windows (yes I really love Terminal, some things are done faster and better thru the command line) and
  125. go to the folder where you have the Cracking Challenge #1 application.
  126. List all available files with "ls" command.
  127. You should see a folder named Challenge #1.app. This is our target.
  128. Mac OS X programs have a nice program structure, where everything (almost) is contained into a single folder.
  129. Using Challenge #1.app as an example, we have the following structure inside it:
  130. Challenge\ #1.app/Contents/
  131. Then we have the following folders:
  132. Info.plist MacOS PkgInfo Resources
  133.  
  134. You can find the main binary inside the MacOS folder. This is where we should start.
  135. Frameworks folder (not present in this binary) might have interesting binaries to disassemble because
  136. some protections can reside there instead in the main binary.
  137. Listing the MacOS folder gives us:
  138. $ ls MacOS/
  139. Challenge #1
  140.  
  141. Challenge #1 is the binary we want to disassemble. The full path is:
  142. Challenge\ #1.app/Contents/MacOS/Challenge #1
  143.  
  144. Some information from the binary can be extracted with the "file" command or otool.
  145. To see if this is a fat binary (contains more than 1 architecture), you can use the following command:
  146. $ file Challenge\ #1.app/Contents/MacOS/Challenge\ #1
  147. Challenge #1.app/Contents/MacOS/Challenge #1: Mach-O universal binary with 2 architectures
  148. Challenge #1.app/Contents/MacOS/Challenge #1 (for architecture i386): Mach-O executable i386
  149. Challenge #1.app/Contents/MacOS/Challenge #1 (for architecture ppc): Mach-O executable ppc
  150.  
  151. The equivalent otool command is:
  152. $ otool -h Challenge\ #1.app/Contents/MacOS/Challenge\ #1
  153. Challenge #1.app/Contents/MacOS/Challenge #1 (architecture i386):
  154. Mach header
  155. magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
  156. 0xfeedface 7 3 0x00 2 19 2356 0x00000085
  157. Challenge #1.app/Contents/MacOS/Challenge #1 (architecture ppc):
  158. Mach header
  159. magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
  160. 0xfeedface 18 0 0x00 2 17 2412 0x00000085
  161.  
  162. So this binary contains two architectures, x86 32 bits and PowerPC.
  163.  
  164. Let's try to disassemble the x86 version.
  165. Select Open File in OTX and select that binary. You should select x86 as processor (it's the default).
  166. You might change the output name or just leave the default. Click Save and select where to save (usually
  167. Desktop or select one folder dedicated to your reversing project to have things organized).
  168. If you can also use the otx command line version (I have installed mine at /usr/local/bin).
  169. I usually use the following command "otx Challenge #1 >dump.txt".
  170.  
  171. And voila, you have disassembled your first binary. Very simple ! The output file is the disassembled listing of the
  172. selected binary, and it will be our main guide into reversing the target.
  173.  
  174. 2.2 - GDB
  175. ---------
  176.  
  177. Gdb is a very powerful debugger although not easy and not intuitive as Windows equivalents like OllyDbg
  178. or Softice (well, Softice as also text only).
  179. Nevertheless you can master it and do everything you should need for your RE projects.
  180. Let's give it a shot and introduce you the world of GDB !
  181.  
  182. Just a little note on the commands to be used:
  183. 1) Commands issued inside gdb will always use the following prompt: gdb$
  184. 2) Commands issued in a Terminal.app shell will always use the following prompt: shell$
  185.  
  186. To learn gdb we are going to use a simpler target so we can understand the basic commands.
  187. You will need to compile the following program example.c:
  188. ------------------- CUT HERE -----------------
  189. #include <stdio.h>
  190.  
  191. main(int argc, char *argv[])
  192. {
  193. printf("Hello GDB!\n");
  194. printf("Argument is: %s\n", argv[1]);
  195. }
  196. ------------------- CUT HERE -----------------
  197. Save this source code somewhere and compile it with (if you have called it example.c, else modify the name):
  198. $ gcc -arch i386 -o example example.c
  199.  
  200. Note:
  201. The -arch i386 option is required to compile the binary in 32bits instead of the default 64bits in Snow Leopard.
  202.  
  203. This small program will print 2 lines, where the second prints the argument from the command line.
  204. Example:
  205. $ ./example Test
  206. Hello GDB!
  207. Argument is: Test
  208.  
  209. GDB runs from the command line, so you will need to open a Terminal.App (at this moment you should already
  210. have a Terminal.app shortcut into your Dock hehehe). To start gdb, just type "gdb" at the prompt and press enter.
  211. You should get something like this (date should be different since this one was compiled by me on January):
  212. GNU gdb 6.3.50-20050815 (Apple version gdb-768) (Fri Jan 23 17:22:29 UTC 2009)
  213. Copyright 2004 Free Software Foundation, Inc.
  214. GDB is free software, covered by the GNU General Public License, and you are
  215. welcome to change it and/or distribute copies of it under certain conditions.
  216. Type "show copying" to see the conditions.
  217. There is absolutely no warranty for GDB. Type "show warranty" for details.
  218. This GDB was configured as "i386-apple-darwin".
  219. gdb$
  220.  
  221. To make sure gdbinit is installed correctly, type "help user". You should get a list of available commands,
  222. the ones created by gdbinit script.
  223.  
  224. There are two different ways to debug a program, one is to attach to a version already running and the other one to
  225. start the program from gdb.
  226. To attach you will need the PID (process ID) for your target. You can find it by issuing a "ps aux" command
  227. (or in Activity Monitor). The PID is the number in the second column. After you have the PID, you use the
  228. "attach <PID>" gdb command.
  229. To start the program from gdb, you can use the "exec-file <PATH_TO_EXECUTABLE_FILE>" (this is the best way to
  230. overcome the gdb bug described earlier, if you don't have a patched version).
  231. If you need to set parameters to the executable (usually not needed for our targets), you can use "set args" command
  232. or set the arguments when you start the program with "run" command.
  233.  
  234. Practical example:
  235. To start debugging our example code, open a command prompt and then type the following commands:
  236. $gdb
  237. (gdb is loaded)
  238. gdb$ exec-file "PATH/example"
  239. (substitute PATH for the full path where our example binary is)
  240.  
  241. or
  242.  
  243. $cd "PATH"
  244. (substitute PATH for the full path where our example binary is)
  245. $gdb
  246. (gdb is loaded)
  247. gdb$ exec-file ./example
  248.  
  249. In the first example we are using the full path to our binary, in the second example we change into the correct directory
  250. and just point to the binary. It's a matter of personal taste (you can use TAB completation inside gdb!).
  251.  
  252. The basic commands we need are related to breakpoints, stepping, change flags or memory, dump/evaluate memory locations.
  253.  
  254. What is a breakpoint ?
  255. From Wikipedia (http://en.wikipedia.org/wiki/Breakpoint):
  256. "A breakpoint, in software development, is an intentional stopping or pausing place in a program, put in place for debugging purposes.
  257. More generally, a breakpoint is a means of acquiring knowledge about a program during its execution. During the interruption, the
  258. programmer inspects the test environment (logs, memory, files, etc.) to find out whether the program functions as expected.
  259.  
  260. In practice, a breakpoint consists of one or more conditions that determine when a program's execution should be interrupted."
  261.  
  262. The breakpoint related commands interesting to us are:
  263. 1) bp/b (set a breakpoint)
  264.  
  265. You can set a breakpoint on a memory location (most used) or in a symbol (if GDB knows about it).
  266. For a memory breakpoint you just need to use the memory location where you want the program to stop.
  267. Example:
  268. gdb$ bp *0x1234
  269.  
  270. 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
  271. format for hexadecimal number. If program execution reaches that memory location, program execution will be interrupted and you will
  272. get back to gdb prompt!
  273.  
  274. 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
  275. other symbol that GDB can solve.
  276. An example is:
  277. gdb$bp [NSControl stringValue]
  278.  
  279. This means whenever the program calls the stringValue function gdb will halt it's execution and return control to us. This function can
  280. allow you to break on text input routines, so you can for example fish a valid serial.
  281.  
  282. 2) bpl (list all breakpoints)
  283. This command will list all breakpoints active or inactive.
  284. Example:
  285. gdb$ bpl
  286. Num Type Disp Enb Address What
  287. 1 breakpoint keep y 0x00001f44 <start>
  288. 2 breakpoint keep n 0x00001f46 <start+2>
  289.  
  290. 3) bpd/bpe (disable/enable a breakpoint)
  291. This will enable or disable a breakpoint.
  292. You should use the Num column from bpl output to select which one to enable or disable.
  293. Example:
  294. gdb$ bpd 1
  295. gdb$ bpl
  296. Num Type Disp Enb Address What
  297. 1 breakpoint keep n 0x00001f44 <start> <- we have disabled this one as you can see
  298. 2 breakpoint keep n 0x00001f46 <start+2>
  299.  
  300. 4) bpc (clear breakpoint)
  301. This will clear a breakpoint. Unlike bpe/bpd, you should use the memory location to remove from breakpoint list (same syntax as bp command).
  302. Example:
  303. gdb$ bpc *0x1f44
  304. gdb$ bpl
  305. Num Type Disp Enb Address What
  306. 2 breakpoint keep n 0x00001f46 <start+2>
  307.  
  308. 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]).
  309. Example:
  310. gdb$ delete 2
  311. gdb$ bpl
  312. No breakpoints or watchpoints.
  313.  
  314. Breakpoints are done, let's go to the step commands.
  315. Step commands will allow you to "browse" and run the assembly code for your target. All step commands
  316. allow you to advance to the next address pointed by EIP (meaning, executing the code pointed by EIP).
  317. But there is a distinction to be made. Some commands allow you to go into functions or subroutines, usually "calls".
  318. Making it easier to understand, if you find a call to another function and want to see what happens
  319. inside that function, you can step into that function and trace it, and then you get back to where
  320. you were (in reality you get back to the address after the call you traced). Or you maybe want
  321. to skip that call and just execute it without getting into it's details.
  322. The functions I regularly use are nexti (or it's shortcut ni) and stepo (if I want to skip over calls or subroutines).
  323. These should be enough for your reversing efforts.
  324.  
  325. Step commands interesting to us are (this is just a dump of help from gdb, should be enough):
  326. 1) next
  327. gdb$ help next
  328. Step program, proceeding through subroutine calls.
  329. Like the "step" command as long as subroutine calls do not happen;
  330. when they do, the call is treated as one instruction.
  331. Argument N means do this N times (or till program stops for another reason).
  332.  
  333. 2) nexti
  334. gdb$ help nexti
  335. Step one instruction, but proceed through subroutine calls.
  336. Argument N means do this N times (or till program stops for another reason).
  337.  
  338. 3) step
  339. gdb$ help step
  340. Step program until it reaches a different source line.
  341. Argument N means do this N times (or till program stops for another reason).
  342.  
  343. 4) stepi
  344. gdb$ help stepi
  345. Step one instruction exactly.
  346. Argument N means do this N times (or till program stops for another reason).
  347.  
  348. 5) stepo
  349. gdb$ help stepo
  350. Step over calls (interesting to bypass the ones to msgSend)
  351. This function will set a temporary breakpoint on next instruction after the call so the call will be bypassed
  352. You can safely use it instead nexti or n since it will single step code if it's not a call instruction
  353. (unless you want to go into the call function)
  354.  
  355. Try to play with these step commands and see what are the differences between them. Like I said,
  356. nexti and stepo should be enough!
  357.  
  358. The dump/evaluate commands will allow you to dump the contents of memory, cpu registers, variables,
  359. pointers, etc.
  360.  
  361. Dump/evaluate commands are:
  362. 1) x
  363. gdb$ help x
  364. Examine memory: x/FMT ADDRESS.
  365. ADDRESS is an expression for the memory address to examine.
  366. FMT is a repeat count followed by a format letter and a size letter.
  367. Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),
  368. t(binary), f(float), a(address), i(instruction), c(char) and s(string),
  369. T(OSType).
  370. Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).
  371. The specified number of objects of the specified size are printed
  372. according to the format.
  373.  
  374. Defaults for format and size letters are those previously used.
  375. Default count is 1. Default address is following last thing printed
  376. with this command or "print".
  377.  
  378. "x" will allow you to examine memory addresses and registers. It allows you to use formats for the output (something like printf).
  379. Usually you will want to use the "x" format (hexadecimal) and "s" format (string).
  380. For example, to dump EAX register contents in hexadecimal you would use gdb$ x/x $eax
  381. Check this live example, using our example.c code:
  382. gdb$
  383. 0x00001fb9 in main ()
  384. --------------------------------------------------------------------------[regs]
  385. EAX: 00001FE1 EBX: 00001FB2 ECX: BFFFF848 EDX: 00000000 o d I t S z a p c
  386. ESI: 00000000 EDI: 00000000 EBP: BFFFF828 ESP: BFFFF810 EIP: 00001FB9
  387. CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F
  388. [001F:BFFFF810]----------------------------------------------------------[stack]
  389. BFFFF860 : D2 F9 FF BF F1 F9 FF BF - 01 FA FF BF 3B FA FF BF ............;...
  390. BFFFF850 : 33 F9 FF BF 6C F9 FF BF - 88 F9 FF BF C1 F9 FF BF 3...l...........
  391. BFFFF840 : 00 00 00 00 01 00 00 00 - FC F8 FF BF 00 00 00 00 ................
  392. BFFFF830 : 01 00 00 00 48 F8 FF BF - 50 F8 FF BF BC F8 FF BF ....H...P.......
  393. BFFFF820 : 00 10 00 00 BC F8 FF BF - 40 F8 FF BF 7A 1F 00 00 ........@...z...
  394. BFFFF810 : 00 00 00 00 00 00 00 00 - 3C F8 FF BF 37 10 E0 8F ........<...7...
  395. [0017:00001FB9]-----------------------------------------------------------[code]
  396. 0x1fb9 <main+19>: mov DWORD PTR [esp],eax
  397. 0x1fbc <main+22>: call 0x300a <dyld_stub_puts>
  398. 0x1fc1 <main+27>: mov eax,DWORD PTR [ebp+0xc]
  399. 0x1fc4 <main+30>: add eax,0x4
  400. 0x1fc7 <main+33>: mov eax,DWORD PTR [eax]
  401. 0x1fc9 <main+35>: mov DWORD PTR [esp+0x4],eax
  402. 0x1fcd <main+39>: lea eax,[ebx+0x3a]
  403. 0x1fd3 <main+45>: mov DWORD PTR [esp],eax
  404. --------------------------------------------------------------------------------
  405. gdb$ x/s $eax
  406. 0x1fe1 <main+59>: "Hello GDB!"
  407.  
  408. We just printed the string that was pointed by EAX register.
  409. Still using the same example, if you increase count to 2 (x/2s), the next string is printed too.
  410. gdb$ x/2s $eax
  411. 0x1fe1 <main+59>: "Hello GDB!"
  412. 0x1fec <main+70>: "Argument is: %s\n"
  413.  
  414. 2) print
  415. This one is used more or less like "x". Usually used when you have the source, so you can print the program variables.
  416. Check it's help on gdb.
  417.  
  418. 3) po
  419. gdb$ help po
  420. Ask an Objective-C object to print itself.
  421.  
  422. This command will allow you to print Objective-C objects. This command is very handy when you are
  423. debugging Objective-C and you want to print the object.
  424. You can't simply see an object by using the "x" command.
  425. Little example:
  426. Breakpoint in 0x30001acf
  427. +548 30001acf 890424 movl %eax,(%esp,1) <- NSBundle </Users/aaaaaaaa/You Control Desktops.app/> (loaded)
  428. +551 30001ad2 e82eb50300 calll 0x3003d005 _objc_msgSend
  429.  
  430. In gdb:
  431. gdb $ x/s $eax
  432. 0x30a9c0: "?c??"
  433. gdb $ po $eax
  434. NSBundle </Users/username/reverse/You Control Desktops-newcrack.app> (loaded)
  435.  
  436. You can see the object where eax is pointing too. Much better than the first x/s $eax
  437.  
  438. Change flags or memory commands are:
  439. 1) cfX, where X can be a,c,d,i,o,p,s,t,z,s
  440. All the cfX commands are from gdbinit. These will allow you to change the cpu register flags (they will invert the current flag state).
  441. 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
  442. (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
  443. 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
  444. gdb$ cfz
  445. 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.
  446. The different cfX commands are:
  447. cfa -- Change Auxiliary Carry Flag
  448. cfc -- Change Carry Flag
  449. cfd -- Change Direction Flag
  450. cfi -- Change Interrupt Flag
  451. cfo -- Change Overflow Flag
  452. cfp -- Change Parity Flag
  453. cfs -- Change Sign Flag
  454. cft -- Change Trap Flag
  455. cfz -- Change Zero Flag
  456.  
  457. 2) set
  458. The set command has many available subcommands. We are interested in changing memory contents and/or registers contents.
  459. To change memory location the syntax is:
  460. gdb$ set *address = newvalue , where address is in the usual hexadecimal format.
  461. The memory location can be program code (if you want for example to live patch the program) or any
  462. other memory location (for example an address holding a variable).
  463.  
  464. If you want to change a register content, for example EAX, the syntax is:
  465. gdb$ set $eax = newvalue
  466.  
  467. You can use complex expressions with set, for example type casting. For example if you want to write a single byte you could use:
  468. gdb$ set $eax = (char) 0x12345
  469. gdb$ print $eax
  470. $3 = 0x45
  471. gdb$ set $eax = (int) 0x12345
  472. gdb$ print $eax
  473. $4 = 0x12345
  474.  
  475. Do you understand what happened with this example ? Think about it (should be easy to understand!).
  476.  
  477. 2.3 - Putting otx and gdb together
  478. ----------------------------------
  479.  
  480. Let's play a little bit with gdb so you can watch a debugging session.
  481. Disassemble the example binary with otx. You should have an output more or like this (I have added line
  482. numbers for easy reference here!):
  483. md5: 27cc7b61ed3322057d52b6b014d589e6
  484.  
  485. (__TEXT,__text) section
  486.  
  487. (Uninteresting code here for our purposes, we are just interested in the main function)
  488.  
  489. _main:
  490. 1: +0 00001fa6 55 pushl %ebp
  491. 2: +1 00001fa7 89e5 movl %esp,%ebp
  492. 3: +3 00001fa9 53 pushl %ebx
  493. 4: +4 00001faa 83ec14 subl $0x14,%esp
  494. 5: +7 00001fad e800000000 calll 0x00001fb2
  495. 6: +12 00001fb2 5b popl %ebx
  496. 7: +13 00001fb3 8d832f000000 leal 0x0000002f(%ebx),%eax Hello GDB!
  497. 8: +19 00001fb9 890424 movl %eax,(%esp)
  498. 9: +22 00001fbc e849100000 calll 0x0000300a _puts
  499. 10: +27 00001fc1 8b450c movl 0x0c(%ebp),%eax
  500. 11: +30 00001fc4 83c004 addl $0x04,%eax
  501. 12: +33 00001fc7 8b00 movl (%eax),%eax
  502. 13: +35 00001fc9 89442404 movl %eax,0x04(%esp)
  503. 14: +39 00001fcd 8d833a000000 leal 0x0000003a(%ebx),%eax Argument is: %s\n
  504. 15: +45 00001fd3 890424 movl %eax,(%esp)
  505. 16: +48 00001fd6 e82a100000 calll 0x00003005 _printf
  506. 17: +53 00001fdb 83c414 addl $0x14,%esp
  507. 18: +56 00001fde 5b popl %ebx
  508. 19: +57 00001fdf c9 leave
  509. 20: +58 00001fe0 c3 ret
  510.  
  511. Remember that our source version looks like:
  512. main(int argc, char *argv[])
  513. {
  514. printf("Hello GDB!\n");
  515. printf("Argument is: %s\n", argv[1]);
  516. }
  517.  
  518. You can easily see that the compiler used "puts" for our first printf and used printf for our second.
  519. This was a compiler optimization. Compilers usually optimized your source code and use the best options
  520. available to make your code shorter and faster.
  521. Since our first printf doesn't have any format string being used, it can be replaced by a shorter and
  522. faster function at compiler level, puts, and still do what we wanted in our source code, to print a
  523. simple "Hello GDB!" message.
  524.  
  525. Let's start debugging our little program. Open gdb and start our example program.
  526. shell$ gdb
  527. GNU gdb 6.3.50-20050815 (Apple version gdb-962) (Sat Jul 26 08:14:40 UTC 2008)
  528. Copyright 2004 Free Software Foundation, Inc.
  529. GDB is free software, covered by the GNU General Public License, and you are
  530. welcome to change it and/or distribute copies of it under certain conditions.
  531. Type "show copying" to see the conditions.
  532. There is absolutely no warranty for GDB. Type "show warranty" for details.
  533. This GDB was configured as "i386-apple-darwin".
  534. gdb$ exec-file ./example
  535. Reading symbols for shared libraries ... done
  536. gdb$
  537.  
  538. If you type the run command, our program will run and exit, since we haven't set any breakpoint yet.
  539. Let's give it a try:
  540. gdb$ run
  541. Reading symbols for shared libraries .++. done
  542. Hello GDB!
  543. Argument is: (null)
  544.  
  545. Program exited with code 024.
  546. --------------------------------------------------------------------------[regs]
  547. EAX:Error while running hook_stop:
  548. No registers.
  549. gdb$
  550.  
  551. You can easily see our messages printed.
  552. Let's try running our program with an argument:
  553. gdb$ run TESTING
  554. Hello GDB!
  555. Argument is: TESTING
  556.  
  557. Program exited with code 025.
  558. --------------------------------------------------------------------------[regs]
  559. EAX:Error while running hook_stop:
  560. No registers.
  561. gdb$
  562.  
  563. Now let's set our first breakpoint. We want to breakpoint the program before the first message "Hello GDB!"
  564. is printed. We already know that the function responsible to print that first message is "puts", and
  565. you can find the call to this function at line 9. Let's explain this line contents:
  566.  
  567. 9: +22 : local offset, meaning the offset inside this function (it's not interesting
  568. to us and you can configure otx to remove this)
  569. 00001fbc : code address (hexadecimal format), this is the address we are going to use
  570. for our breakpoint(s)
  571. e849100000 : opcodes, these are the bytes your cpu will read and form your instructions
  572. (and the ones we can modify to patch the code)
  573. calll 0x0000300a : this is the assembly mnemonic correspondent to the previous opcode bytes
  574. _puts : this is additional information that otx was able to identify, in this case
  575. it identified we are going to call the "puts" function
  576.  
  577. Hopefully you have understood otx output. So if we want to break on line 9, we should use memory
  578. address 0x1fbc. To be honest, since we have the source code, we could use source file line reference
  579. to create the breakpoint but since we usually don't have source for our targets, this will not be explored.
  580.  
  581. Set the breakpoint:
  582. gdb$ bp *0x1fbc
  583. Breakpoint 1 at 0x1fbc
  584. gdb$
  585.  
  586. And list:
  587. gdb$ bpl
  588. Num Type Disp Enb Address What
  589. 1 breakpoint keep y 0x00001fbc <main+22>
  590. gdb$
  591.  
  592. Our first breakpoint is set, we can run again our program (you should already have noted that we can
  593. run again and again the program after we have loaded it into gdb).
  594.  
  595. Let's go...
  596. gdb$ run
  597.  
  598. Breakpoint 1, 0x00001fbc in main ()
  599. --------------------------------------------------------------------------[regs]
  600. EAX: 00001FE1 EBX: 00001FB2 ECX: BFFFF848 EDX: 00000000 o d I t S z a p c
  601. ESI: 00000000 EDI: 00000000 EBP: BFFFF828 ESP: BFFFF810 EIP: 00001FBC
  602. CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F
  603. [001F:BFFFF810]----------------------------------------------------------[stack]
  604. BFFFF860 : D2 F9 FF BF F1 F9 FF BF - 01 FA FF BF 3B FA FF BF ............;...
  605. BFFFF850 : 33 F9 FF BF 6C F9 FF BF - 88 F9 FF BF C1 F9 FF BF 3...l...........
  606. BFFFF840 : 00 00 00 00 01 00 00 00 - FC F8 FF BF 00 00 00 00 ................
  607. BFFFF830 : 01 00 00 00 48 F8 FF BF - 50 F8 FF BF BC F8 FF BF ....H...P.......
  608. BFFFF820 : 00 10 00 00 BC F8 FF BF - 40 F8 FF BF 7A 1F 00 00 ........@...z...
  609. BFFFF810 : E1 1F 00 00 00 00 00 00 - 3C F8 FF BF 37 10 E0 8F ........<...7...
  610. [0017:00001FBC]-----------------------------------------------------------[code]
  611. 0x1fbc <main+22>: call 0x300a <dyld_stub_puts>
  612. 0x1fc1 <main+27>: mov eax,DWORD PTR [ebp+0xc]
  613. 0x1fc4 <main+30>: add eax,0x4
  614. 0x1fc7 <main+33>: mov eax,DWORD PTR [eax]
  615. 0x1fc9 <main+35>: mov DWORD PTR [esp+0x4],eax
  616. 0x1fcd <main+39>: lea eax,[ebx+0x3a]
  617. 0x1fd3 <main+45>: mov DWORD PTR [esp],eax
  618. 0x1fd6 <main+48>: call 0x3005 <dyld_stub_printf>
  619. --------------------------------------------------------------------------------
  620. gdb$
  621.  
  622. This is the output you will get. GDB did it's job correctly and program stopped at address 0x1fbc as we wanted.
  623. There are two areas of output interesting to us. The first one is [regs] and the seconde [code].
  624. In [regs] you can find the current state of cpu registers and flags at breakpoint moment. You should
  625. know the meaning of each register ;)
  626. In [code] you have disassembly output for the current memory address. The first line is always the
  627. next line code to be executed.
  628.  
  629. If you compare otx disassemble output and gdb output, you will see there are cosmetic differences.
  630. These are due to otx using AT&T syntax and gdb is configured for Intel syntax. You can modify gdb to
  631. use AT&T syntax if you aren't comfortable with different syntaxes. Refer to
  632. http://www.redhat.com/docs/manuals/enterprise/RHEL-3-Manual/gnu-assembler/i386-syntax.html if you
  633. are interested in understanding differences between the two.
  634.  
  635. At this moment, you can do various operations. For example, you can dump the contents of EAX register
  636. or any other memory location. Or you can step the code to understand it, or simply let the program
  637. continue running without any further interference.
  638.  
  639. If you use "c" or "continue" commands, program will continue running and eventually end. Let's try.
  640.  
  641. gdb$ c
  642. Hello GDB!
  643. Argument is: (null)
  644.  
  645. Program exited with code 024.
  646. --------------------------------------------------------------------------[regs]
  647. EAX:Error while running hook_stop:
  648. No registers.
  649. gdb$
  650.  
  651. Since our breakpoint is still set, we can run the program again and it will stop again at the same place. Try it...
  652. Assuming you did tried, we are back to our breakpoint. We want to follow and understand the code, so
  653. we are going to step each line of code.
  654. Since the next instruction to be executed is a call, you know we can step over it (meaning we don't
  655. want to analyse what "puts" function will do) or we can step into it (meaning we want to analyse
  656. what "puts" is going to do).
  657.  
  658. For this example, we are not interested in understanding how "puts" work (since we already know it
  659. will just print characters) and just want it to be executed.
  660. We can use either "n", "ni", "nexti", "stepo" gdb commands. If you use "stepi" you will get inside
  661. "puts" function. The safest bet is to use "stepo" if you want to skip over calls.
  662.  
  663. Let's try...
  664. gdb$ stepo
  665. Breakpoint 3 at 0x1fc1 <----------- you can ignore this, it's a temporary breakpoint used by stepo
  666. Hello GDB! <----------- OUR MESSAGE WAS PRINTED
  667.  
  668. Breakpoint 3, 0x00001fc1 in main ()
  669. --------------------------------------------------------------------------[regs]
  670. EAX: 0000000A EBX: 00001FB2 ECX: 0000000B EDX: 00000000 o d I t S z a P c
  671. ESI: 00000000 EDI: 00000000 EBP: BFFFF828 ESP: BFFFF810 EIP: 00001FC1
  672. CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F
  673. [001F:BFFFF810]----------------------------------------------------------[stack]
  674. BFFFF860 : D2 F9 FF BF F1 F9 FF BF - 01 FA FF BF 3B FA FF BF ............;...
  675. BFFFF850 : 33 F9 FF BF 6C F9 FF BF - 88 F9 FF BF C1 F9 FF BF 3...l...........
  676. BFFFF840 : 00 00 00 00 01 00 00 00 - FC F8 FF BF 00 00 00 00 ................
  677. BFFFF830 : 01 00 00 00 48 F8 FF BF - 50 F8 FF BF BC F8 FF BF ....H...P.......
  678. BFFFF820 : 00 10 00 00 BC F8 FF BF - 40 F8 FF BF 7A 1F 00 00 ........@...z...
  679. BFFFF810 : E1 1F 00 00 00 00 00 00 - 3C F8 FF BF 37 10 E0 8F ........<...7...
  680. [0017:00001FC1]-----------------------------------------------------------[code]
  681. 0x1fc1 <main+27>: mov eax,DWORD PTR [ebp+0xc]
  682. 0x1fc4 <main+30>: add eax,0x4
  683. 0x1fc7 <main+33>: mov eax,DWORD PTR [eax]
  684. 0x1fc9 <main+35>: mov DWORD PTR [esp+0x4],eax
  685. 0x1fcd <main+39>: lea eax,[ebx+0x3a]
  686. 0x1fd3 <main+45>: mov DWORD PTR [esp],eax
  687. 0x1fd6 <main+48>: call 0x3005 <dyld_stub_printf>
  688. 0x1fdb <main+53>: add esp,0x14
  689. --------------------------------------------------------------------------------
  690. gdb$
  691.  
  692. What we have here ? Next code to be executed is line 10: and we can clearly see that "puts" function
  693. was executed (Hello GDB! message is displayed!).
  694. As before, you can do whatever operations you want now. You can continue stepping thru the code, set
  695. more breakpoints, dump memory/registers, continue the program, etc...
  696.  
  697. As an exercise, now we want to stop at line 13. How many alternatives do you have to do that ? At
  698. least 2 ! Breakpoint on address correspondent to line 13 or step thru the code until you reach line 13.
  699. You should reach something like this:
  700. gdb$
  701. 0x00001fc9 in main ()
  702. --------------------------------------------------------------------------[regs]
  703. EAX: 00000000 EBX: 00001FB2 ECX: 0000000B EDX: 00000000 o d I t S z a p c
  704. ESI: 00000000 EDI: 00000000 EBP: BFFFF828 ESP: BFFFF810 EIP: 00001FC9
  705. CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F
  706. [001F:BFFFF810]----------------------------------------------------------[stack]
  707. BFFFF860 : D2 F9 FF BF F1 F9 FF BF - 01 FA FF BF 3B FA FF BF ............;...
  708. BFFFF850 : 33 F9 FF BF 6C F9 FF BF - 88 F9 FF BF C1 F9 FF BF 3...l...........
  709. BFFFF840 : 00 00 00 00 01 00 00 00 - FC F8 FF BF 00 00 00 00 ................
  710. BFFFF830 : 01 00 00 00 48 F8 FF BF - 50 F8 FF BF BC F8 FF BF ....H...P.......
  711. BFFFF820 : 00 10 00 00 BC F8 FF BF - 40 F8 FF BF 7A 1F 00 00 ........@...z...
  712. BFFFF810 : E1 1F 00 00 00 00 00 00 - 3C F8 FF BF 37 10 E0 8F ........<...7...
  713. --------------------------------------------------------------------[ObjectiveC]
  714. 0x0: <Address 0x0 out of bounds>
  715. [0017:00001FC9]-----------------------------------------------------------[code]
  716. 0x1fc9 <main+35>: mov DWORD PTR [esp+0x4],eax <---- first mov instruction
  717. 0x1fcd <main+39>: lea eax,[ebx+0x3a]
  718. 0x1fd3 <main+45>: mov DWORD PTR [esp],eax <---- 2nd mov instruction
  719. 0x1fd6 <main+48>: call 0x3005 <dyld_stub_printf>
  720. 0x1fdb <main+53>: add esp,0x14
  721. 0x1fde <main+56>: pop ebx
  722. 0x1fdf <main+57>: leave
  723. 0x1fe0 <main+58>: ret
  724. --------------------------------------------------------------------------------
  725. gdb$
  726.  
  727. For now you can ignore the ObjectiveC part. The code for our printf function is:
  728. printf("Argument is: %s\n", argv[1]);
  729. You can easily see that we have two arguments passed onto printf function, "Argument is: %s\n" and argv[1].
  730. You should already know that arguments are passed into the stack (ESP) in reverse order, from last to first.
  731. So this first mov instruction is moving the second argument into the stack and the second mov is moving
  732. the first argument.
  733.  
  734. You should be able to identify that in this case the was no argument to "run" command since EAX is empty.
  735. If you have used a parameter (or set args command) EAX would hold it's contents. Try it ! When you stop
  736. there, use the "x" command to dump EAX contents, like this:
  737. (I used run TESTING)
  738. gdb$ x/s $eax
  739. 0xbffff923: "TESTING"
  740.  
  741. You can step to line 15 (0x1fd3 address) and dump again the contents of EAX. You should see the first
  742. argument to printf function.
  743.  
  744. And that's it ! The basics are covered. You should now know how to set breakpoints, step code and
  745. dump memory/register contents.
  746.  
  747.  
  748. 3 - Reversing and cracking Challenge #1
  749. ---------------------------------------
  750.  
  751. 3.0 - Introduction and workflow
  752. -------------------------------
  753.  
  754. The first thing to do is reconnaissance. We need to understand what are the program limits and what
  755. messages (if any!) are being displayed about those limits.
  756. If we have an error message like "Bad serial", "Trial is expired" or something like this, the next
  757. step is to check if this message is present in the program binaries in plain text, which can give us
  758. fast clues where we should start our work.
  759.  
  760. The best tool for this job is "grep". If you have Unix experience you should already know it, else
  761. you are about to be introduced.
  762. We want to grep all files belonging to our application. Best way is like this:
  763.  
  764. shell$ cd Challenge\ #1.app/Contents/
  765. shell$ grep -r -i "message" *
  766. (-r means recursive and -i case insensitive)
  767.  
  768. When you start Challen #1 for the first time you have a message telling you about the goals of this crackme.
  769. Continue and insert a random name and a random serial. You get an error message:
  770. "The name and serial number combination you entered is incorrect."
  771. Try to search for that one...
  772. There is one hit at "Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib".
  773.  
  774. shell$ grep -r -i "you entered is incorrect" *
  775. Binary file Challenge #1.app/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib matches
  776.  
  777. This means that there are no direct references in the main binary to the string, so we need to
  778. use other methods.
  779.  
  780. Another classic way is to open the disassembly listing and search for methods with interesting names.
  781. If you browse the disassembly for this challenge, you will find an interesting string "isRegistered".
  782. Unfortunately, many developers for OS X use names like this for their registration/protection code,
  783. so it's very easy to track them.
  784.  
  785. The interesting place where you find this is here:
  786. -(void)[Level1 applicationDidFinishLaunching:]
  787. +0 0000251e 55 pushl %ebp
  788. +1 0000251f 89e5 movl %esp,%ebp
  789. +3 00002521 53 pushl %ebx
  790. +4 00002522 83ec24 subl $0x24,%esp
  791. +7 00002525 8b5d08 movl 0x08(%ebp),%ebx
  792. +10 00002528 a110400000 movl 0x00004010,%eax isRegistered
  793. +15 0000252d 891c24 movl %ebx,(%esp)
  794. +18 00002530 89442404 movl %eax,0x04(%esp)
  795. +22 00002534 e8252b0000 calll 0x0000505e -[(%esp,1) isRegistered]
  796. +27 00002539 84c0 testb %al,%al
  797. +29 0000253b 742b je 0x00002568
  798.  
  799. From Apple's documentation available at
  800. http://developer.apple.com/library/mac/#documentation/cocoa/reference/NSApplicationDelegate_Protocol/Reference/Reference.html
  801. you get the following about applicationDidFinishLaunching:
  802. Delegates can implement this method to perform further initialization. This method is called after
  803. the applicationÕs main run loop has been started but before it has processed any events. If the
  804. application was launched by the user opening a file, the delegateÕs application:openFile: method is
  805. called before this method. If you want to perform initialization before any files are opened, implement
  806. the applicationWillFinishLaunching: method in your delegate, which is called before application:openFile:.)
  807.  
  808. This is a good place to start in Cocoa apps, because many developers start checking here if trials are ok,
  809. if serial numbers are ok, etc.
  810. This is more or less the behaviour we have experienced with the crackme, because we got that initial
  811. message telling us about what we need to do (we can speculate that the message will not appear if the
  812. crackme is registered successfully).
  813.  
  814. Getting back to that piece of code:
  815. -(void)[Level1 applicationDidFinishLaunching:]
  816. +0 0000251e 55 pushl %ebp
  817. +1 0000251f 89e5 movl %esp,%ebp
  818. +3 00002521 53 pushl %ebx
  819. +4 00002522 83ec24 subl $0x24,%esp
  820. +7 00002525 8b5d08 movl 0x08(%ebp),%ebx
  821. +10 00002528 a110400000 movl 0x00004010,%eax isRegistered
  822. +15 0000252d 891c24 movl %ebx,(%esp)
  823. +18 00002530 89442404 movl %eax,0x04(%esp)
  824. +22 00002534 e8252b0000 calll 0x0000505e -[(%esp,1) isRegistered] <- call the routine
  825. +27 00002539 84c0 testb %al,%al
  826. +29 0000253b 742b je 0x00002568 <- if it's not registered, then it will show the bad message
  827. +31 0000253d a10c500000 movl 0x0000500c,%eax
  828. +36 00002542 8b10 movl (%eax),%edx
  829. +38 00002544 c744241800000000 movl $0x00000000,0x18(%esp)
  830. +46 0000254c c744241400000000 movl $0x00000000,0x14(%esp)
  831. +54 00002554 c744241000000000 movl $0x00000000,0x10(%esp)
  832. +62 0000255c 8b430c movl 0x0c(%ebx),%eax (id)mainWindow
  833. +65 0000255f 8944240c movl %eax,0x0c(%esp)
  834. +69 00002563 8b4314 movl 0x14(%ebx),%eax (id)registeredSheet <- the good message
  835. +72 00002566 eb29 jmp 0x00002591
  836.  
  837. What we got here is a classical (and very weak) test for available registration or not. If the function isRegistered
  838. returns true, then the good message will be shown, else the bad one will be shown since the program isn't registered.
  839.  
  840. Since that je is conditional we have two possible solutions for a crack:
  841. 1) Nop the conditional jump: JE to NOP
  842. 2) Patch the isRegistered routine to return always true
  843.  
  844. The first alternative is very easy to test with gdb, even before patching anything.
  845. Load the crackme into gdb and set a breakpoint at 0x0000253b (the address of the JE).
  846.  
  847. Sample session:
  848. $ gdb Challenge\ #1
  849. GNU gdb 6.3.50-20050815 (Apple version gdb-1344) (Mon Dec 28 15:21:35 UTC 2009)
  850. Copyright 2004 Free Software Foundation, Inc.
  851. GDB is free software, covered by the GNU General Public License, and you are
  852. welcome to change it and/or distribute copies of it under certain conditions.
  853. Type "show copying" to see the conditions.
  854. There is absolutely no warranty for GDB. Type "show warranty" for details.
  855. This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries ......b .. done
  856.  
  857. gdb$ b *0x0000253b
  858. Breakpoint 1 at 0x253b
  859. gdb$ r
  860. Reading symbols for shared libraries .+++++++.................................................................................. done
  861. Reading symbols for shared libraries . done
  862. Reading symbols for shared libraries . done
  863. Reading symbols for shared libraries . done
  864. Reading symbols for shared libraries . done
  865. Reading symbols for shared libraries . done
  866. Reading symbols for shared libraries . done
  867.  
  868. Breakpoint 1, 0x0000253b in -[Level1 applicationDidFinishLaunching:] ()
  869. --------------------------------------------------------------------------[regs]
  870. EAX: 0x00000000 EBX: 0x00415CC0 ECX: 0x00000001 EDX: 0x00000000 o d I t s Z a P c
  871. ESI: 0xBFFFEA50 EDI: 0x00000002 EBP: 0xBFFFEA18 ESP: 0xBFFFE9F0 EIP: 0x0000253B
  872. CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F Jump is taken (z=1)
  873. --------------------------------------------------------------------------[code]
  874. 0x253b: 74 2b je 0x2568
  875. 0x253d: a1 0c 50 00 00 mov eax,ds:0x500c
  876. 0x2542: 8b 10 mov edx,DWORD PTR [eax]
  877. 0x2544: c7 44 24 18 00 00 00 00 mov DWORD PTR [esp+0x18],0x0
  878. 0x254c: c7 44 24 14 00 00 00 00 mov DWORD PTR [esp+0x14],0x0
  879. 0x2554: c7 44 24 10 00 00 00 00 mov DWORD PTR [esp+0x10],0x0
  880. 0x255c: 8b 43 0c mov eax,DWORD PTR [ebx+0xc]
  881. 0x255f: 89 44 24 0c mov DWORD PTR [esp+0xc],eax
  882. --------------------------------------------------------------------------------
  883. gdb$
  884.  
  885. Gdb stopped before executing the JE and we can observe that the jump will be taken, so the not
  886. registered message will appear. To test our theory, you should use the "cfz" command.
  887. This will change the zero flag, from 1 to 0 (you know it's the zero flag because you have that
  888. information in the Jump is taken msg, z=1).
  889.  
  890. Change the flag and then issue the command "context". This will redraw gdb output without advancing
  891. any instruction.
  892.  
  893. gdb$ cfz
  894. gdb$ context
  895. --------------------------------------------------------------------------[regs]
  896. EAX: 0x00000000 EBX: 0x00416FC0 ECX: 0x00000001 EDX: 0x00000000 o d I t s z a P c
  897. ESI: 0xBFFFEA50 EDI: 0x00000002 EBP: 0xBFFFEA18 ESP: 0xBFFFE9F0 EIP: 0x0000253B
  898. CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F Jump is NOT taken (z!=1)
  899. --------------------------------------------------------------------------[code]
  900. 0x253b: 74 2b je 0x2568
  901. 0x253d: a1 0c 50 00 00 mov eax,ds:0x500c
  902. 0x2542: 8b 10 mov edx,DWORD PTR [eax]
  903. 0x2544: c7 44 24 18 00 00 00 00 mov DWORD PTR [esp+0x18],0x0
  904. 0x254c: c7 44 24 14 00 00 00 00 mov DWORD PTR [esp+0x14],0x0
  905. 0x2554: c7 44 24 10 00 00 00 00 mov DWORD PTR [esp+0x10],0x0
  906. 0x255c: 8b 43 0c mov eax,DWORD PTR [ebx+0xc]
  907. 0x255f: 89 44 24 0c mov DWORD PTR [esp+0xc],eax
  908. --------------------------------------------------------------------------------
  909.  
  910. You can observe that the message changed and the jump will not be executed.
  911. Issue the continue command and check the program... Voila, you have just bypassed the protection!
  912.  
  913. So the first method is to change the JE into a NOP. A nop mean no-operation, a harmless instruction
  914. will be executed. Since the instruction JE is two bytes (74 2b), and NOPs are a single byte (90),
  915. you will need two use two nops to replace 74 2b. More on patching later...
  916.  
  917. The alternative, is to modify the isRegistered method.
  918. The disassembly is:
  919. -(BOOL)[Level1 isRegistered]
  920. +0 00002a88 55 pushl %ebp
  921. +1 00002a89 89e5 movl %esp,%ebp
  922. +3 00002a8b 8b4508 movl 0x08(%ebp),%eax
  923. +6 00002a8e 0fb64020 movzbl 0x20(%eax),%eax
  924. +10 00002a92 c9 leave
  925. +11 00002a93 c3 ret
  926.  
  927. You can modify this method to always return 1 (true).
  928. The most common way to do this is to replace the beginning of this method with the following code:
  929. xor eax, eax
  930. inc eax
  931. ret
  932.  
  933. Using the assemble command from gdb:
  934. gdb$ assemble
  935. Instructions will be written to stdout.
  936. Type instructions, one per line. Do not forget to use NASM assembler syntax!
  937. End with a line saying just "end".
  938. >xor eax,eax
  939. >inc eax
  940. >ret
  941. >end
  942. 00000000 31C0 xor eax,eax
  943. 00000002 40 inc eax
  944. 00000003 C3 ret
  945.  
  946. Those are the bytes you need to use and replace in the original method, 31 C0 40 c3.
  947. You need to patch 4 bytes, starting at 0x00002a88. The two first instructions total 3 bytes, so you
  948. will "eat" space in the third instruction, which is 3 bytes long. Since you will patch a single byte
  949. in the third instruction, the rest of the code there will be most probably invalid. This isn't a
  950. problem because we will not execute any code after the ret (return). To make this cleaner you could
  951. NOP the two remaining bytes from the old third instruction.
  952.  
  953. A variation of patching isRegistered, is to patch the code before the method is called.
  954. The original code is:
  955. +7 00002525 8b5d08 movl 0x08(%ebp),%ebx
  956. +10 00002528 a110400000 movl 0x00004010,%eax isRegistered
  957. +15 0000252d 891c24 movl %ebx,(%esp)
  958. +18 00002530 89442404 movl %eax,0x04(%esp)
  959. +22 00002534 e8252b0000 calll 0x0000505e -[(%esp,1) isRegistered] <- call the routine
  960. +27 00002539 84c0 testb %al,%al
  961. +29 0000253b 742b je 0x00002568 <- if it's not registered, then it will show the bad message
  962.  
  963. For example, you could replace the code at address 0x00002534 by:
  964. xor eax, eax
  965. inc eax
  966.  
  967. and NOP the remaining bytes.
  968. So there are different ways to do this, based on available space, conditions and your lazyness ;-)
  969.  
  970. As with the first alternative, you can try this in gdb before patching. Breakpoint the isRegistered method
  971. at 0x00002a88 and run the crackme.
  972.  
  973. $ gdb Challenge\ #1
  974. GNU gdb 6.3.50-20050815 (Apple version gdb-1344) (Mon Dec 28 15:21:35 UTC 2009)
  975. Copyright 2004 Free Software Foundation, Inc.
  976. GDB is free software, covered by the GNU General Public License, and you are
  977. welcome to change it and/or distribute copies of it under certain conditions.
  978. Type "show copying" to see the conditions.
  979. There is absolutely no warranty for GDB. Type "show warranty" for details.
  980. This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries ........ done
  981.  
  982. gdb$ b *0x00002a88
  983. Breakpoint 1 at 0x2a88
  984. gdb$ r
  985. Reading symbols for shared libraries .+++++++.................................................................................. done
  986. Reading symbols for shared libraries . done
  987. Reading symbols for shared libraries . done
  988. Reading symbols for shared libraries . done
  989. Reading symbols for shared libraries . done
  990. Reading symbols for shared libraries . done
  991. Reading symbols for shared libraries . done
  992.  
  993. Breakpoint 1, 0x00002a88 in -[Level1 isRegistered] ()
  994. --------------------------------------------------------------------------[regs]
  995. EAX: 0x00002A88 EBX: 0x00418820 ECX: 0x00000001 EDX: 0x00000000 o d I t s Z a P c
  996. ESI: 0xBFFFEA50 EDI: 0x00000002 EBP: 0xBFFFEA18 ESP: 0xBFFFE9EC EIP: 0x00002A88
  997. CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F
  998. --------------------------------------------------------------------------[code]
  999. 0x2a88: 55 push ebp
  1000. 0x2a89: 89 e5 mov ebp,esp
  1001. 0x2a8b: 8b 45 08 mov eax,DWORD PTR [ebp+0x8]
  1002. 0x2a8e: 0f b6 40 20 movzx eax,BYTE PTR [eax+0x20]
  1003. 0x2a92: c9 leave
  1004. 0x2a93: c3 ret
  1005. 0x2a94: 55 push ebp
  1006. 0x2a95: b8 01 00 00 00 mov eax,0x1
  1007. --------------------------------------------------------------------------------
  1008. gdb$ set *0x2a88 = 0xc340c031
  1009. gdb$ context
  1010. --------------------------------------------------------------------------[regs]
  1011. EAX: 0x00002A88 EBX: 0x00418820 ECX: 0x00000001 EDX: 0x00000000 o d I t s Z a P c
  1012. ESI: 0xBFFFEA50 EDI: 0x00000002 EBP: 0xBFFFEA18 ESP: 0xBFFFE9EC EIP: 0x00002A88
  1013. CS: 0017 DS: 001F ES: 001F FS: 0000 GS: 0037 SS: 001F
  1014. --------------------------------------------------------------------------[code]
  1015. 0x2a88: 31 c0 xor eax,eax
  1016. 0x2a8a: 40 inc eax
  1017. 0x2a8b: c3 ret
  1018. 0x2a8c: 45 inc ebp
  1019. 0x2a8d: 08 0f or BYTE PTR [edi],cl
  1020. 0x2a8f: b6 40 mov dh,0x40
  1021. 0x2a91: 20 c9 and cl,cl
  1022. 0x2a93: c3 ret
  1023. --------------------------------------------------------------------------------
  1024. gdb$ c
  1025.  
  1026. Voila, it's cracked.
  1027. The set command will modify memory. As explained, we don't need to patch the remaining bytes, and
  1028. since our new bytes are 4 bytes (32bits) we don't need cast any values in the set command.
  1029. For example, if you just wanted to patch a single byte you would use the following:
  1030. set *(char *) address = 0x90
  1031.  
  1032. 3.1 - Patching the binary
  1033. -------------------------
  1034.  
  1035. To patch the binary, you will need to open it in an hex editor. Then you will need an offset. The offset is where the program is located.
  1036. Mac OS X has what is called fat binaries (or universal binaries), meaning that a PPC and x86 version will be present in the same file.
  1037. This obliges an extra step because you need to calculate the offset for the x86 part (this tutorial is for x86!).
  1038. I'm going to show you how to patch with the first alternative, the NOP.
  1039.  
  1040. To verify if the binary is fat or universal, we can use otool command.
  1041. $ otool -f Challenge\ #1
  1042. Fat headers
  1043. fat_magic 0xcafebabe
  1044. nfat_arch 2
  1045. architecture 0
  1046. cputype 7
  1047. cpusubtype 3
  1048. capabilities 0x0
  1049. offset 4096 <- HERE !
  1050. size 22548
  1051. align 2^12 (4096)
  1052. architecture 1
  1053. cputype 18
  1054. cpusubtype 0
  1055. capabilities 0x0
  1056. offset 28672
  1057. size 18560
  1058. align 2^12 (4096)
  1059.  
  1060. nfat_arch is equal to 2, meaning there are two architectures present in this binary. We are interested
  1061. in cputype 7, which is Intel x86. Cputype 18 is PPC.
  1062. You can see that x86 binary starts at offset 4096 (this is in decimal!), 0x1000 in hexadecimal.
  1063. To calculate the correct offset for address 0x0000253b (the one we want to patch), we just need to
  1064. add 0x1000 + 0x0000253b = 0x353B. So the formula is offset + offset_to_patch, where offset is the one
  1065. reported in otool.
  1066. Load the binary into an hex editor and go to offset 0x353B. If you use 0xED if you an input box at upper
  1067. right corner. Just insert 353B there and press return.
  1068. You should land at the correct offset. Check if the bytes match those we want to patch (742b). It should.
  1069. Now you just need to replace 74 by 90 and 2B by 90 and save.
  1070. Start Challenge #1 and voila, no more bad message! Our work is done...
  1071.  
  1072. A word of caution while trying to calculate the offset. The previous paragraph about the formula to calculate
  1073. correct offset is true if Intel x86 binary is the first one inside the fat binary. If PPC is first,
  1074. then the formula is (offset - 0x1000 + offset_to_patch). You need to subtract 0x1000 because that's the header
  1075. size of PPC part. Not that hard to remember (I'm coding a small utility to do this math :) ).
  1076.  
  1077. The easiest way to calculate the offset is to use the utility I created, offset.pl.
  1078. You can download the latest version at http://reverse.put.as/wp-content/uploads/2011/02/offset1.3.pl_.gz
  1079. or Ghalen's C version at http://reverse.put.as/wp-content/uploads/2009/06/ocalc.c
  1080.  
  1081. To practice your patching skills, try to patch the isRegistered method :-)
  1082.  
  1083. 3.2 - Fishing a valid serial number
  1084. -----------------------------------
  1085.  
  1086. The routine that verifies if the serial is valid can be easily found in the disassembly listing.
  1087. It's called -(BOOL)[Level1 validateSerial:forName:]. The name is very suggestive (another common mistake in
  1088. OS X developers).
  1089.  
  1090. You should study that routine to understand what's happening there. A basic scheme for a serial verification
  1091. routine is:
  1092. 1) Verify if user serial number length is ok. If ok continue, else give an error.
  1093. 2) Compute the good serial number.
  1094. 3) Compare the user serial number with the good serial number.
  1095.  
  1096. All these elements are present here. I will just dump my notes on what the code is doing. Keep in mind
  1097. that valid serial number should be different in your case.
  1098.  
  1099. Serial should be 8 chars in length, as this piece of code shows:
  1100. +29 00002abb 83f808 cmpl $0x08,%eax
  1101.  
  1102. A quick look at the whole method and we find the piece of code we are interested in:
  1103. +369 00002c0f 891c24 movl %ebx,(%esp) <- our serial first 4 chars
  1104. +372 00002c12 89c6 movl %eax,%esi <- esi with our serial next 4 chars
  1105. +374 00002c14 8b45d8 movl 0xd8(%ebp),%eax <- eax with 5680 (first part of good serial)
  1106. +377 00002c17 89442408 movl %eax,0x08(%esp)
  1107. +381 00002c1b a108400000 movl 0x00004008,%eax isEqual:
  1108. +386 00002c20 89442404 movl %eax,0x04(%esp)
  1109. +390 00002c24 e835240000 calll 0x0000505e -[(%esp,1) isEqual:]
  1110. +395 00002c29 84c0 testb %al,%al <- are they equal ?
  1111. +397 00002c2b 7421 je 0x00002c4e <- jump if our serial part is different from good serial part
  1112. +399 00002c2d 8b45dc movl 0xdc(%ebp),%eax <- eax holding second part of good serial
  1113. +402 00002c30 893424 movl %esi,(%esp) <- our second serial part
  1114. +405 00002c33 89442408 movl %eax,0x08(%esp)
  1115. +409 00002c37 a108400000 movl 0x00004008,%eax isEqual:
  1116. +414 00002c3c 89442404 movl %eax,0x04(%esp)
  1117. +418 00002c40 e819240000 calll 0x0000505e -[(%esp,1) isEqual:]
  1118. +423 00002c45 ba01000000 movl $0x00000001,%edx <- used to return that serial is GOOD
  1119. +428 00002c4a 84c0 testb %al,%al <- test if 2nd serial parts match
  1120. +430 00002c4c 7502 jne 0x00002c50 <- jump if they match
  1121. +432 00002c4e 31d2 xorl %edx,%edx <- this will clean edx, thus telling that serial is BAD
  1122. +434 00002c50 83c43c addl $0x3c,%esp
  1123. +437 00002c53 89d0 movl %edx,%eax <- if serial is ok, edx is equal to 1, so eax will return 1 meaning an ok serial!
  1124. (...)
  1125.  
  1126. Instead of a comparison with a single serial number, two comparisons are made, the first half and then the second half.
  1127. You just need to fish the two good pieces and you get your valid serial number.
  1128.  
  1129. 3.3 - Keygen
  1130. ------------
  1131.  
  1132. To create a keygen, you will need to study the previous routine and understand how it's created.
  1133. The algorithm is very simple and it contains a bug. The source for my dirty keygen follows.
  1134. The code is commented so it should be easy for you to follow.
  1135.  
  1136. ----- CUT HERE ---------
  1137. /* Keygen for Macserialjunkies Challenge '09
  1138.  
  1139. The serial algorithm has a bug because the format string has no zero padding.
  1140. For example with the following name "zeparreco" the valid serial is 39940081
  1141. but since there is lack of padding, the algorithm generates 399481.
  1142. Serial length must be equal to 8 so this username is impossible to keygen due to this small bug.
  1143.  
  1144. This code sucks, it was made in a hurry :/ It works but it's damn ugly hehehehe
  1145.  
  1146. */
  1147.  
  1148. #include <stdio.h>
  1149. #include <stdlib.h>
  1150. #include <string.h>
  1151.  
  1152. int main(int argc, char *argv[])
  1153. {
  1154. char name[256], *pname;
  1155.  
  1156. printf("Macserialjunkies.com challenge #1 Keygen v0.1\n\n");
  1157. printf("Insert name:\n");
  1158. fflush(stdout);
  1159. fgets(name, 256, stdin);
  1160. if ((pname = strchr(name, '\n')) != NULL)
  1161. {
  1162. *pname = '\0';
  1163. }
  1164.  
  1165. /* serial number is composed by 8 digits
  1166. there are two algorithms, one for the first 4 digits and the other for the remaining
  1167. */
  1168.  
  1169. // first block of four digits
  1170. int i=0;
  1171. int digit,multiplier=4;
  1172. // mov eax,0x68db8bad
  1173. int wtf = 0x68db8bad;
  1174. int accumulator=0;
  1175. int ecx=0;
  1176. unsigned long long temp1;
  1177. int temp2, temp3, temp4;
  1178. int x=0;
  1179. int stringsize = strlen(name);
  1180. int firstblock,secondblock;
  1181.  
  1182. for (x=0; x < stringsize ; x++)
  1183. {
  1184. // movsx eax,BYTE PTR [edi+ebx]
  1185. digit = name[i];
  1186. // inc ebx
  1187. i++;
  1188. // imul eax,esi
  1189. digit = digit * multiplier;
  1190. // add esi,0x4
  1191. multiplier += 4;
  1192. // shl edx,0x4
  1193. // sub edx,eax
  1194. digit = (digit << 4 ) - digit;
  1195. // lea ecx,[edx+ecx+0x29a]
  1196. ecx = digit + ecx + 0x29a;
  1197. // imul ecx
  1198. temp1 = (unsigned long long) ecx * wtf;
  1199. // this grabs the ecx value since long multiplication the result goes to EDX:EAX
  1200. temp1 = temp1 >> 32;
  1201. // mov eax,ecx
  1202. // sar eax,0x1f
  1203. temp2 = ecx >> 0x1f;
  1204. // sar edx,0xc
  1205. temp1 = temp1 >> 0xc;
  1206. // sub edx,eax
  1207. temp3 = temp1 - temp2;
  1208. // imul edx,edx,0x2710
  1209. temp4 = temp1 * 0x2710;
  1210. // sub eax,edx
  1211. ecx = ecx - temp4;
  1212.  
  1213. }
  1214. // the last ecx is the good first serial part
  1215. firstblock = ecx;
  1216.  
  1217. // second block
  1218. i=0;
  1219. multiplier = 4;
  1220. int edx;
  1221. x=0;
  1222. ecx=0;
  1223. int firstsar, secondsar;
  1224.  
  1225. for (x=0; x < stringsize ; x++)
  1226. {
  1227. //movsx eax,BYTE PTR [edi+ebx]
  1228. digit = name[i];
  1229. // inc ebx
  1230. i++;
  1231. // imul eax,esi
  1232. digit = digit * multiplier;
  1233. // add esi,0x8
  1234. multiplier += 8;
  1235. // lea edx,[eax+eax*4]
  1236. edx = digit + digit * 4;
  1237. // lea edx,[eax+edx*2+0x2d]
  1238. edx = digit + edx*2 + 0x2d;
  1239.  
  1240. ecx = ecx + edx;
  1241.  
  1242. temp1 = (unsigned long long) ecx * wtf;
  1243. edx = temp1 >> 32;
  1244.  
  1245. firstsar = ecx >> 0x1f;
  1246. secondsar = edx >> 0xc;
  1247.  
  1248. temp2 = secondsar - firstsar;
  1249.  
  1250. edx = secondsar * 0x2710;
  1251.  
  1252. temp3 = ecx - edx;
  1253. }
  1254. // 2nd part of good serial
  1255. secondblock = temp3;
  1256.  
  1257. // convert to decimal and print
  1258. printf("Serial number is: %04d%04d\n", firstblock, secondblock);
  1259. printf("Byeeeeeee!\n");
  1260. }
  1261. ----- CUT HERE ---------
  1262.  
  1263. 4 - Conclusion
  1264. --------------
  1265.  
  1266. And here we are, at the end of this long tutorial. I hope you have enjoyed it and learnt something with it.
  1267. Now you should have a basic framework and ability to work with the basic tools. To advance further, you need
  1268. to find more targets and practice with them. Breaking protections is a good way to learn reverse
  1269. engineering, because you always have a goal, breaking the protection. You will need to think and
  1270. research so you can advance, that is the really fun part about reversing.
  1271. Sometimes you will not be able to advance a target, maybe you should postpone it and get back at it
  1272. later when your skills improved. This was my contribution to introduce you to this world, the next step depends on you.
  1273.  
  1274. If you have any suggestions, doubts or found any error, please feel free to leave a comment at my
  1275. blog http://reverse.put.as or drop an email at reverse AT put.as
  1276.  
  1277. Have fun!
  1278. fG!
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement