Reversing You Control Desktops v1.2 Tutorial - v1.0 (c) fG! 2008 Step 0) Introduction -------------------- Welcome! This tutorial objective is to understand You Control Desktops various protections and defeat them all. Since I got my Macbook, I wanted to test it's apps protections to understand how lagged they were against Windows ones. There's no interest whatsoever in piracy, but only in learning and improving things. The only way to improve is to beat current protections... There isn't much information about Mac OS X reversing in the Web so I wanted to improve that situation. This app was one of the first ones I tried to beat in Mac OS X. Previous ones were too easy (one or two bytes cracks...DUH!) but this one proved more challenging and interesting, allowed to learn some new tricks and developing some code. Very rudimentary anti-debug techniques are used (the ptrace trick). Encryption is used but it doesn't provide adequate protection in the way it was implemented. A complete keygen was created and source code is available. It's very useful as an example of OpenSSL API usage. It has a small problem on purpose, so keygen is not working unless it's fixed (all code is correct, except generated checksum is wrong due to that problem). I assume there is some experience using GDB (tutorial is already too long). Have fun, fG! Step 1) Pre reversing work -------------------------- First thing to do is disassemble main binary with OTX (or otool if you prefer). The interesting files to disassemble are: You Control Desktops.app/Contents/MacOS/You Control Desktops You Control Desktops.app/Contents/Frameworks/YSCommon.framework/YSCommon You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/MacOS/YouControlDesktopsEngine You Control Desktops.app/Contents/Frameworks/PhoenixFramework.framework/PhoenixFramework You Control Desktops.app/Contents/PlugIns/MultiDesktopModule.plugin/Contents/MacOS/MultiDesktopModule If you open disassembled files, you can find some strange calls inside. Something like: +1392 00006854 e884580000 calll 0x0000c0dd _IllIlllIIllIIlllIIlI This smells like obfuscated function names, so it's hard for the reverser to guess what is what and delay reversing time. Applying zen cracking thinking, I did a small search for this string into the whole app dir: grep -r IllIlllIIllIIlllIIlI You Control Desktops.app The result is: $ grep -r IllIlllIIllIIlllIIlI You\ Control\ Desktops-orig.app/ You Control Desktops.app/Contents/Frameworks/YSCommon.framework/Headers/YSLicense.h:#define checkBundleSignature IllIlllIIllIIlllIIlI You Control Desktops.app/Contents/Frameworks/YSCommon.framework/Versions/A/Headers/YSLicense.h:#define checkBundleSignature IllIlllIIllIIlllIIlI Binary file You Control Desktops.app/Contents/Frameworks/YSCommon.framework/Versions/A/YSCommon matches You Control Desktops.app/Contents/Frameworks/YSCommon.framework/Versions/Current/Headers/YSLicense.h:#define checkBundleSignature IllIlllIIllIIlllIIlI Binary file You Control Desktops.app/Contents/Frameworks/YSCommon.framework/Versions/Current/YSCommon matches Binary file You Control Desktops.app/Contents/Frameworks/YSCommon.framework/YSCommon matches Binary file You Control Desktops.app/Contents/MacOS/You Control Desktops matches You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/Frameworks/YSCommon.framework/Headers/YSLicense.h:#define checkBundleSignature IllIlllIIllIIlllIIlI You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/Frameworks/YSCommon.framework/Versions/A/Headers/YSLicense.h:#define checkBundleSignature IllIlllIIllIIlllIIlI Binary file You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/Frameworks/YSCommon.framework/Versions/A/YSCommon matches You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/Frameworks/YSCommon.framework/Versions/Current/Headers/YSLicense.h:#define checkBundleSignature IllIlllIIllIIlllIIlI Binary file You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/Frameworks/YSCommon.framework/Versions/Current/YSCommon matches Binary file You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/Frameworks/YSCommon.framework/YSCommon matches Binary file You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/MacOS/YouControlDesktopsEngine matches Those .h include files look very promising. If you edit for example You Control Desktops.app/Contents/Frameworks/YSCommon.framework/Headers/YSLicense.h, the contents are: #ifdef OBFUSCATE #define PUBLIC_KEY_CHECKSUM_DATA1 llIllIIIlIlIIllIIIll #define PUBLIC_KEY_CHECKSUM_DATA2 IIlIIllllIllIllIIIll #define PUBLIC_KEY_CHECKSUM_DATA3 lllIIlIIllIIIllIIlIl #define PUBLIC_KEY_CHECKSUM_DATA4 lIIlIlllIIlIIIIIlIlI #define PUBLIC_KEY_CHECKSUM_DATA5 llIlIllIIIIIIIIIllll #define licenseInit IIIIlIlllIllIlIIlIIl #define setLicensePublicKeyPath llIlIIllllIIIlIlIlIl #define setLicenseFileDirectory lIIlIlllllIIIlllIIII #define setLicenseAppVersion IIIIllIlIIllIIIIllII #define setLicenseAppName IIIIllIIIIllIIIIllII #define licenseAppName IIIIllIIIIllIIIIllIl #define licenseAppVersion IlIIllIIIIllIIIIllIl (...) BINGO !!!! Due to some reason (mistake ????) the include files with table between obfuscated and real function name were included in the program. We can write a little program to replace the obfuscated names by the real ones, making things much easier to read ! :) The interesting include files are: Contents/Frameworks/YSCommon.framework/Headers/YSLicense.h Contents/Frameworks/YSCommon.framework/Headers/YSLicenseRegistrationController.h The included unobfuscated.txt and unobfuscated.pl will replace obfuscated function names with real function names in any txt file. Usage syntax is: unobfuscate.pl Run it thru the disassembled txt files. Now you have a readable disassembly. Useful gdb stuff: ----------------- +Mammon's gdb init is very useful since it gives you that Softice look and display immediatly useful information, like disassembly and registers. A very useful gdb command for Mac OS X applications is "po", short for print object. This will allow you to print contents of Objective C objects (and sure you will need it!). Little example: Breakpoint in 0x30001acf +548 30001acf 890424 movl %eax,(%esp,1) <- NSBundle (loaded) +551 30001ad2 e82eb50300 calll 0x3003d005 _objc_msgSend In gdb: gdb $ x/s $eax 0x30a9c0: "?c??" gdb $ po $eax NSBundle (loaded) You can see the object where eax is pointing too. Much better than the first x/s $eax Changing mac address: --------------------- It's useful to change your mac address so you don't reveal your real one. It is as simple as: sudo ifconfig en0 lladdr XX:XX:XX:XX:XX:XX Tool tips: ---------- Check segments and their characteristics: otool -l filename Dump imported funcions: otool -I -v filename Check linked shared libraries: otool -L -v filename Check exported functions: otool -T -v filename or nm -g filename Monitor file system access (like Filemon in Windows): fs_usage pid All pre reversing work is done... Step 2) Rudimentary anti-debug aka Ptrace checks ------------------------------------------------ If we try to run You Control Desktops into gdb, program will exit with error code 055. Example: gdb $ r Reading symbols for shared libraries ...................................... done Program exited with code 055. The following url provides a very detailed description of this: http://www.steike.com/code/debugging-itunes-with-gdb/ Basically, there's a PT_DENY_ATTACH flag that is passed to ptrace function, that lets a process avoid being debugged. Example from You Control Desktops code: +142 00004b7d c744240c00000000 movl $0x00000000,0x0c(%esp,1) +150 00004b85 c744240800000000 movl $0x00000000,0x08(%esp,1) +158 00004b8d c744240400000000 movl $0x00000000,0x04(%esp,1) +166 00004b95 c704241f000000 movl $0x0000001f,(%esp,1) <- PT_DENY_ATTACH flag +173 00004b9c e8f6740000 calll 0x0000c097 _ptrace One way to bypass this is to NOP those ptrace calls...Dirty, fast and it works... Or maybe not... If there's a checksum check to verify binaries aren't patched, then all this patching will fail... If we try to patch all the ptrace calls, and open the patched program, it seems to run ok, but after a while it exits ! Oh... a checksum check must exist ! That will be step number 3! All ptrace calls are found at the following files and offset locations. Filename: You Control Desktops.app/Contents/MacOS/You Control Desktops Offset: 14b9c +173 00004b9c e8f6740000 calll 0x0000c097 _ptrace Offset: 16836 +1362 00006836 e85c580000 calll 0x0000c097 _ptrace Filename: You Control Desktops.app/Contents/Frameworks/YSCommon.framework/YSCommon Offset: 5aa0b +352 30001a0b e866b80300 calll 0x3003d276 _ptrace Offset: 5c076 +48 30003076 e8fba10300 calll 0x3003d276 _ptrace Offset: 742c1 +224 3001b2c1 e8b01f0200 calll 0x3003d276 _ptrace Offset: 767a0 +124 3001d7a0 e8d1fa0100 calll 0x3003d276 _ptrace Filename: You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/MacOS/YouControlDesktopsEngine Offset: 240d1 +670 0000c0d1 e851700000 calll 0x00013127 _ptrace So go to those offsets and nop those call bytes (you will need 5 NOPs for each call). Remember NOP is 0x90 (Intel CPU). Ready for Step number 3... 3) The checksum verification ... -------------------------------- After all ptrace calls are patched, if we run our patched apps, after a while it exits with error 360 ... Hummmm what the hell ? Whatever we do, the program always exists after a while... So there must be some kind of checksum that is triggering this ! Oh yes of course there is :) It's this nice function: checkBundleSignature From the main program it's called, at least, here: +1449 0000688d e84b580000 calll 0x0000c0dd _checkBundleSignature So let's analyse this function, located at YSCommon. This function reads a public key, calculates a checksum and then compares it. One of the ptrace calls is here, so this must be a really interesting routine for us to mess with. Keep browsing the _checkBundleSignature code until you see this: (...) +483 3001b3c4 8b55d4 movl 0xd4(%ebp),%edx +486 3001b3c7 8954240c movl %edx,0x0c(%esp,1) <- pkey +490 3001b3cb 89742408 movl %esi,0x08(%esp,1) <- siglen +494 3001b3cf 89442404 movl %eax,0x04(%esp,1) <- sigbuf -> You Control Desktops.signature +498 3001b3d3 8b45cc movl 0xcc(%ebp),%eax +501 3001b3d6 890424 movl %eax,(%esp,1) <- ctx +504 3001b3d9 e8a71e0200 calll 0x3003d285 _EVP_VerifyFinal +509 3001b3de 85c0 testl %eax,%eax +511 3001b3e0 0f8582000000 jnel 0x3001b468 <- patch here +517 3001b3e6 e8901e0200 calll 0x3003d27b _CFAbsoluteTimeGetCurrent (...) So what do we have here ? From openssl man pages: int EVP_VerifyFinal(EVP_MD_CTX *ctx,unsigned char *sigbuf, unsigned int siglen,EVP_PKEY *pkey); EVP_VerifyFinal() verifies the data in ctx using the public key pkey and against the siglen bytes at sigbuf. Hum... compare two checksums and after it a timer code, exactly what we are experiencing... So what do we need to do ? Patch the jnel to a jmp and bye bye timer :) We need to patch YSCommon at offset 743e0. So change 0f8582000000 to 90E982000000 and we have a jmp 0x3001b468 !!!! (You need to assemble the right opcodes!) Another trick cleaned... We can find another call to this function at YouControlDesktopsEngine: +700 0000c0ef e847700000 calll 0x0001313b _checkBundleSignature The final approach is to create a new signature (after we patch everything we need). We need to create the sha1 checksum of the whole binary and then sign it with our private key. Then replace the signature with ours... But for now patch that routine so we are able to use gdb. That means step number 4 ! 4) Breaking the castle aka replacing private and public keys ------------------------------------------------------------ In a public/private key scheme, You Software holds the private key and the public key is bundled with the program ( located at Resources directory). First thing to do is generate our own private/public so we can sign the binaries and other needed stuff. Using openssl, to create a private key use the following command: openssl genrsa -out private.pem 2048 And the public key: openssl rsa -in private.pem -pubout -out public.pem Now, it would be too easy to replace original keys with our own (here lies the problem with private/public key scheme applied here), so You Software must be sure they are using their private/public key and nothing else. Best thing to assure that ? A checksum around the bundled public key so we "can't" modify it easily. This idea is reinforced if you look at YSLicense.h file. #define PUBLIC_KEY_CHECKSUM_DATA1 llIllIIIlIlIIllIIIll #define PUBLIC_KEY_CHECKSUM_DATA2 IIlIIllllIllIllIIIll #define PUBLIC_KEY_CHECKSUM_DATA3 lllIIlIIllIIIllIIlIl #define PUBLIC_KEY_CHECKSUM_DATA4 lIIlIlllIIlIIIIIlIlI #define PUBLIC_KEY_CHECKSUM_DATA5 llIlIllIIIIIIIIIllll There's really a checksum for the public key!!! Since SHA1 is used everywhere, we assume this checksum uses SHA1. SHA1 is 160 bits, and if it's assumed each of this data is 32 bits long (the size of a cpu register), then 5 * 32 = 160 bits ! We have 5 checksum sections located in application binaries. We need to track them so we can replace. To do this, we need the sha1 digest for the original public key. The following comand will give us what is needed: openssl dgst -sha1 You Control Desktops.app/Contents/Resources/public.pem SHA1(public.pem)= 77c0af7e63da76036419e62671c25c69c594d997 Splitting in 5 data sections (32 bits each) we should have: PUBLIC_KEY_CHECKSUM_DATA1: 77c0af7e PUBLIC_KEY_CHECKSUM_DATA2: 63da7603 PUBLIC_KEY_CHECKSUM_DATA3: 6419e626 PUBLIC_KEY_CHECKSUM_DATA4: 71c25c69 PUBLIC_KEY_CHECKSUM_DATA5: c594d997 Try to find these bytes in the main program executable (You Control Desktops.app/Contents/MacOS/You Control Desktops). Nothing... Hum... Intel is little endian so the least significant byte is stored at the lowest address, meaning those bytes are stored in inverse order. Reversing things, we have: PUBLIC_KEY_CHECKSUM_DATA1: 7eafc077 PUBLIC_KEY_CHECKSUM_DATA2: 0376da63 PUBLIC_KEY_CHECKSUM_DATA3: 26e61964 PUBLIC_KEY_CHECKSUM_DATA4: 695cc271 PUBLIC_KEY_CHECKSUM_DATA5: 97d994c5 Search again for these bytes and you can find them at the following offsets: You Control Desktops.app/Contents/MacOS/You Control Desktops PUBLIC_KEY_CHECKSUM_DATA1 offset: 14B4D PUBLIC_KEY_CHECKSUM_DATA2 offset: 14B58 PUBLIC_KEY_CHECKSUM_DATA3 offset: 14B63 PUBLIC_KEY_CHECKSUM_DATA4 offset: 14B6E PUBLIC_KEY_CHECKSUM_DATA5 offset: 14B79 For engine application the offsets are: You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/MacOS/YouControlDesktopsEngine PUBLIC_KEY_CHECKSUM_DATA1 offset: 25DCE PUBLIC_KEY_CHECKSUM_DATA2 offset: 25DD9 PUBLIC_KEY_CHECKSUM_DATA3 offset: 25DE4 PUBLIC_KEY_CHECKSUM_DATA4 offset: 25DEF PUBLIC_KEY_CHECKSUM_DATA5 offset: 25DFA YSCommon doesn't have the checksum included, altough it has a signature file (uses public.pem from main resources). It's acceptable since the first would fail and would never arrive to this second check. To finish this step, we need to generate the digest for our public key, split and invert it into 5 pieces and replace at the correct offsets. Command: openssl dgst -sha1 public.pem Split into 5 sections and reverse their order. Now patch both files and replace original checksum sections with ours. After binaries are patched, do not forget to replace public.pem with ours. Locations for public.pem are: You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/Resources/public.pem You Control Desktops.app/Contents/Resources/public.pem The castle is broken. We can digest and sign every change we do to the binaries ! Hurrayy ! Extra step: How to make sure our key replaced sucessfully the original one... The piece of code handling this verification is _verifyPublicKey, located at YSCommon. Breakpoint at 0x3001ce2b (YSCommon) and check if the five checksum section checks are all ok ! They should be ! Bang, our key is injected :) Code: (...) +195 3001ce2b 0fb655b0 movzbl 0xb0(%ebp),%edx <- public.pem calculated digest +199 3001ce2f 8b83c2060200 movl 0x000206c2(%ebx),%eax <- good checksum PUBLIC_KEY_CHECKSUM_DATA1 +205 3001ce35 8b08 movl (%eax),%ecx +207 3001ce37 89c8 movl %ecx,%eax +209 3001ce39 c1e818 shrl $0x18,%eax +212 3001ce3c 39c2 cmpl %eax,%edx <- CHECKSUM_DATA1 in eax, calculated one in edx +214 3001ce3e 0f8480000000 jel 0x3001cec4 <- if equal, checkum is ok, else anti reversing bomb :) +220 3001ce44 e832040200 calll 0x3003d27b _CFAbsoluteTimeGetCurrent (...) Keep tracing the code and you will hit all the 5 checks. Step number 5 ahead ! 5) Replacing the You Control Desktops.signature with our own file ----------------------------------------------------------------- Once our public key is injected, we can generate a new signature file and finish step number 3. We need to sign a few binaries. The following command will be used to create the signature file for main binary: openssl sha1 -sign privatekey.pem -out You\ Control\ Desktops.signature You\ Control\ Desktops.app/Contents/MacOS/You\ Control\ Desktops Syntax is: openssl sha1 -sign -out Create signatures for the following binaries: You Control Desktops.app/Contents/MacOS/You Control Desktops You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/MacOS/YouControlDesktopsEngine You Control Desktops.app/Contents/Frameworks/YSCommon.framework/YSCommon Signature names and locations: You Control Desktops.app/Contents/Resources/You Control Desktops.signature You Control Desktops.app/Contents/MacOS/YouControlDesktopsEngine.app/Contents/Resources/YouControlDesktopsEngine.signature You Control Desktops.app/Contents/Frameworks/YSCommon.framework/Versions/A/Resources/YSCommon.signature Replace the original signatures with the ones generated and signature verification checkBundleSignature routine will be ok now. To verify if this worked, breakpoint at 0x3001b3de (located at checkBundleSignature). Eax should be equal to 1, meaning the verification was sucessful ! Voila ! Note: EVP_VerifyFinal() returns 1 for a correct signature, 0 for failure and -1 if some other error occurred. Anti debug and checksums are bypassed. Now we can start to work in the keygen ! Here comes step 6! 6) Using the demo key and decrypting server response ---------------------------------------------------- If you try to register, there's some delay in the response, which can be a sign of online registration scheme (or test it without internet connection). To sort that out, run tcpdump with a filter to port 80. Try again to register and yes, you see online communication with reg.yousoftware.com host. To snoop what is being sent, run tcpdump -s 1500 -A port 80 and host reg.yousoftware.com or use a webproxy like burpsuite (you need to configure the system proxy to use it). You will see something like: Request (my mac address cleaned from here) ------- GET /cgi-bin/YSLicenseActivator.3?appVersion=1&serialNumber=111111111111111111111&customerName=aaaaa%20aaaa&customerOrganization=&mac=00:00:00:00:00:00&appName=You%20Control%20Desktops&customerEmailAddress=aaaaa@aaaaa.com&customerContactFlags= HTTP/1.1 User-Agent: CFNetwork/129.21 Accept: */* Accept-Language: en Accept-Encoding: gzip, deflate Pragma: no-cache Connection: keep-alive Proxy-Connection: keep-alive Host: reg.yousoftware.com Answer ------ HTTP/1.1 200 OK Date: Sun, 01 Mar 2008 10:10:00 GMT Server: Apache Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/plain Content-Length: 338 oZVTX72US4usMzDhI0Jj8qvKdyxHmdJ//4xWTPUh1Mn/v/tBXmUgyu07hs1UAuiR /JcYDjoXktFDbdcdt/IpMbaIDa8H472/16++0v2tZ7okjpf3w/ED8xfCKT+ieh9s Jy3/5AHVpfXPXbmgtJ/d50sbqNHeogiyP0FHTIxyy2cNMsq6I9MDMkmQNsN1i6ru OzIalWG30+myghz6CI7knFmJ6QJXiPmxYSFgrvovR+X0X0J/DbNmL5+3A0TQj5i0 MO0gjzq//7zr9qmrjNBndw9+HBvKe5gVTj/1j0GLdViJnuYef+jg9J5MeyX2sWRW +6jyIKi9tw4= Since this program uses encryption, we can put the hypothesis this is a ciphered response. So we have to decrypt this in order to understand what is being received. We need to find where the request is built, then sent and where the answer is received and deciphered... Search for YSLicenseActivator.3 string and you find it in YSCommon at two locations: 0x3001b77c and 0x3001fc8e So break at the beginning of the function for these two addresses (0x3001b722 and 0x3001fc34) and try again to insert a serial number... It breaks in the second ! We have a path to trace :) If you keep tracing, the return from the call lands here: 0x3001fb75 Scroll back and you see function name, which is queryDictionary and you can see various fields there. Why the hell are they interested in host mac address ??? Keep tracing and we return back to 0x3001fd60, with a function name of -(void)[YSLicenseRegistrationController ok:] Seems we are on the right track... Here you can see the next function being called, registrationURLString. This function is the first address we tried to breakpoint. Next function is the escaping of the chars in the url and then the really interesting function: YSLicense updateLicenseFromURL:moduleInfo. +278 3001fdb0 e850d20100 calll 0x3003d005 +[YSLicense updateLicenseFromURL:moduleInfo:] Set a breakpoint at 0x3001fdb0 and step into it... We land here 0x3001c7af Here we have a call to dataWithContentsOfURL function. Checking with Apple documentation and we have: Returns a data object containing the data from the location specified by a given URL. + (id)dataWithContentsOfURL:(NSURL *)aURL Parameters aURL The URL from which to read data. Return Value A data object containing the data from the location specified by aURL. Returns nil if the data object could not be created. Conclusion: this is the function sending the request to reg.yousoftware.com website. Keep tracing until you reach this call: +927 3001cb4e e865e4ffff calll _decryptLicenseDictionary Nice name isn't it ??? :) This must be decrypting the website answer, which should be a xml file (because the use of the NSDictionary functions!) Reversing _decryptLicenseDictionary function: This function starts at 0x3001afb8 and if you browse thru it you find imediatly interesting things. For example: +167 3001b05f e8be200200 calll 0x3003d122 _BIO_push +172 3001b064 8945a0 movl %eax,0xa0(%ebp) +175 3001b067 e8ec210200 calll 0x3003d258 _EVP_bf_cbc +180 3001b06c 894598 movl %eax,0x98(%ebp) +183 3001b06f e8df210200 calll 0x3003d253 _BIO_f_cipher +188 3001b074 890424 movl %eax,(%esp,1) +191 3001b077 e8ce200200 calll 0x3003d14a _BIO_new +196 3001b07c 89c6 movl %eax,%esi +198 3001b07e c745b0596f7520 movl $0x20756f59,0xb0(%ebp) ' uoY' +205 3001b085 c745b4536f6674 movl $0x74666f53,0xb4(%ebp) 'tfoS' +212 3001b08c c745b877617265 movl $0x65726177,0xb8(%ebp) 'eraw' What we have here ? A Blowfish CBC cipher together with the key used to encrypt the data... Since Blowfish is symmetric encryption, key must be included so program is able to decrypt the website data. We just found the fundamental piece to decrypt website data. Keep browsing until you reach here: +363 3001b123 89459c movl %eax,0x9c(%ebp) +366 3001b126 89742408 movl %esi,0x08(%esp,1) <- length (the same as apache response) +370 3001b12a 89442404 movl %eax,0x04(%esp,1) <- output buffer (take note of the address eax points to) +374 3001b12e 8b7da4 movl 0xa4(%ebp),%edi +377 3001b131 893c24 movl %edi,(%esp,1) <- input (crypted data) +380 3001b134 e815210200 calll 0x3003d24e _BIO_read From openssl man pages: int BIO_read(BIO *b, void *buf, int len); BIO_read() attempts to read len bytes from BIO b and places the data in buf. This means that after BIO_read, we have the decrypted output located at output buffer (take note of the address eax is pointing to before BIO_read call!) After the BIO_read call we can dump the address eax was pointing to. For example: gdb $ x/10s 0xcd08410 0xcd08410: "\n\n\n\ninvalidCode\n1\n\n\n Cleaning this and we have: invalidCode 1 Here is the unencrypted answer, an invalid code answer :) So we have the format for the wrong code answer, but we would like to know how a good answer is formated. We can request a demo licence, since it's format should be something like the good one (or we can hack around the demo licence). Repeate the sniffing procedure, this time against a demo request (if your program is already expired, go to your_user_homedir/Library/Application Support/You Software/Licenses/ , and delete the key file or rename it). The request is something like: GET /cgi-bin/YSLicenseDemoActivator.3?appVersion=1&serialNumber=&customerName=AAAAA%20BBBBBB&customerOrganization=&mac=00:00:00:00:00:00&appName=You%20Control%20Desktops&customerEmailAddress=&customerContactFlags= HTTP/1.1 Now we can build http requests to request a demo license. Let's build one and retrieve the demo answer. One detail, you should change the mac address to something else, since I expect your mac address to be registered in their database, if your demo expired. Build a request: GET /cgi-bin/YSLicenseDemoActivator.3?appVersion=1&serialNumber=&customerName=Mr%20Kennedy&customerOrganization=&mac=00:11:22:33:44:55&appName=You%20Control%20Desktops&customerEmailAddress=&customerContactFlags= HTTP/1.1 User-Agent: CFNetwork/129.21 Accept: */* Accept-Language: en Accept-Encoding: gzip, deflate Pragma: no-cache Connection: keep-alive Proxy-Connection: keep-alive Host: reg.yousoftware.com Then telnet to reg.yousoftware.com port 80 and paste that request (don't forget to press return twice at the end!) The answer is: HTTP/1.1 200 OK Date: Mon, 01 Dec 2007 11:00:00 GMT Server: Apache Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/plain 582 u8843mnxS4udMzDhI0Jj8qvKdyxHmdJ//4xWTPUh1Mn/v/tBXmUgyu07hs1UAuiR /JcYDjoXktFDbdcdt/IpMbaIDa8H472/16++0v2tZ7okjpf3w/ED8xfCKT+ieh9s Jy3/5AHVpfXPXbmgtJ/d50jhyuHeogiyP0FHTIxyy2cNMsq6I9MDMkmQNsN1i6ru OzIalWG30+myghz6CI7knFmJ6QJXiPmxYShfyoovR+X0X0J/DbNmL/fdxdvTLJzl zuX8nMr1+XE8xCXPvcEzi1ScVNa2KLAvgV8LPxkLmkysRJtW6E6D/ZzzHphshtis PP3VOdss5UlNSz2J9z3WAnM2FHP8R767bdegIjJzm1ApICZLBL+Tu8ZW5pvILg91 la+JvQHdYBRDyfxB6mF1PiTvlVeWBZVS9ZxC9pZCq7d0DjVe7IaasaQcDSLbgvty NKozak7z57RfaFIjgjLUl3LwNpkw7VOtzheYrG2OopgmZ8jcDpsJQ2OADFwJ4qda ge5IEcXGpEuS0IDzIIdTTCqfmD823uhfNeH/whdLswktwsDbtbI1K+Do5S4MLxx6 GJ0CHG1161g00+pbZDg1LoWfhmfvSHjCFAXRg0tlGDsbffDMt6n24FSpNzsapfRN n6AmwhPZQ5M7CsJ/tjC206sZaW52//ZjkzLEtOBLxCRxT5mAuO4dtNNy7DNXE6u6 JzDYN+Do5ZGLno2/W2NOpSEM0glyx10rQgUv7KQBTP8IbTCwsEOrYAx0H08UwY3C acSw2vCtNbux96UhXPbDMxBho2EShgfb/u9A8qhpsi+Enxjig+MAaCIVmvzEkb4c 9PaRGbqdY0/V1+RqmxMmnq1Uj3fVxETF8wom1Ba/CCJ8Q/3stlCTf+oIZT7EDBCc oZ4YrKdvVzRSgpwhJkDBavZQgoulcEVLg01u6cyTh6GnJ4eH4nmLisG1zT/7Wp8/ uaIwzLZUnhPuMGpQu6nDapAAXzgrHnCQLexwNCpACwGHOAnQUJ9eLg0ym0AhiVwK 5z7nIfnRk8drLGJv9yK9seDppGKTTKXB9wS92f6AU/qaosrWgTgS1MDRnHRh/kd3 AiWZOqhuo43lGE03KLUrjSVjpOKQ/YxejVEiZzyV9bF5w+m6x22upDHhwkx4BiYA 5Pr59e2UaYkW3dkQ7bUickpehY48rHwvLCNIuujxMiOukk9MejS1+JfRgT3UAA4F lYqLzT5d083db8coAJ5TFQX76hLItrKgBwfG6vyeCmTSpOGf9Tp7P5WB9xpruO4V +WMIqfQEuKFp3GgQrn3x5kZZdu794dghu8xkwDKxk+uKmKqn0bQz/VBXOg23XdVx 8Kg/cWCet0MpjHv91pU+5sM1RjAETE68YlNOj+RXumc= To decrypt it's content, we can use the program itself. Just restart the program and break at the previous BIO_read location. Dump eax after the call and you have the unencrypted output: gdb $ x/30s 0x0181D000 emailAddress expirationDate 2007-12-16T00:00:00Z licenseVersion 1 mac 00:11:22:33:44:55 modules name Mr Kennedy productName You Control Desktops productVersion 1 serialNumber DME-100-0001-1ACD14U0 licenseSum Q12qS4utttlychnTdD+Nhfy0eefKUIL6YuoyR3edqazH0Ye8V7gzjTBd8bvSE/Uw hMfWkgWjmAEX5pCUKegaP7g8nhU+cntftaNSAujuJpH4V+yrslpFZKJddh5VYpnm 6YCYJkV2HiNktHd4dCXahwiWiXc+3HcOalhOg5OH2mnnx1a2mW+5AVYJYUmaJWCF EigkMHgV2W45rK1ajTzs1Cs69i0IofjB0c9EvpD6Wn0DFSFcxxA2xlyJT22NxGsr 4R7s2QS4o75RVMgBcqfuifbwkhveXe1f0t60SG+uk3dbqIAocC1CMv4dfz5QbaRk TbsF/W9ag9NoEwYjMgIdHw== Pretty nice uh ? :) Now we have the licence file format. Our attack strategy would be to expand expiration date to something really in the future. The licenseSum field should be protecting important fields, like expirationDate, name, mac address, else it would be too easy to change expirationDate to something else. We can write a program to decrypt and encrypt licence file, since we have information necessary for that task, key and algorithm. The source code for that program is decrypt.c, which allows you to decrypt and encrypt those licence files. Since we are trying to learn things, let's try to understand decryptLicenseDictionary: (...) +129 3001b039 c744240401000000 movl $0x00000001,0x04(%esp,1) +137 3001b041 891424 movl %edx,(%esp,1) +140 3001b044 e81e220200 calll 0x3003d267 _BIO_new_fp -------------------------------------------------------------------------------------------------------------------------- BIO *BIO_new_fp(FILE *stream, int flags); BIO_new_fp() creates a file BIO wrapping stream. Flags can be: BIO_CLOSE, BIO_NOCLOSE (the close flag) BIO_FP_TEXT (sets the underly-underlying ing stream to text mode, default is binary: this only has any effect under Win32). -------------------------------------------------------------------------------------------------------------------------- +145 3001b049 89c6 movl %eax,%esi +147 3001b04b e8d7200200 calll 0x3003d127 _BIO_f_base64 -------------------------------------------------------------------------------------------------------------------------- BIO_METHOD * BIO_f_base64(void); BIO_f_base64() returns the base64 BIO method. This is a filter BIO that base64 encodes any data written through it and decodes any data read through it. -------------------------------------------------------------------------------------------------------------------------- +152 3001b050 890424 movl %eax,(%esp,1) +155 3001b053 e8f2200200 calll 0x3003d14a _BIO_new -------------------------------------------------------------------------------------------------------------------------- BIO * BIO_new(BIO_METHOD *type); The BIO_new() function returns a new BIO using method type. -------------------------------------------------------------------------------------------------------------------------- +160 3001b058 89742404 movl %esi,0x04(%esp,1) +164 3001b05c 890424 movl %eax,(%esp,1) +167 3001b05f e8be200200 calll 0x3003d122 _BIO_push -------------------------------------------------------------------------------------------------------------------------- BIO * BIO_push(BIO *b,BIO *append); The BIO_push() function appends the BIO append to b, it returns b. -------------------------------------------------------------------------------------------------------------------------- +172 3001b064 8945a0 movl %eax,0xa0(%ebp) +175 3001b067 e8ec210200 calll 0x3003d258 _EVP_bf_cbc -------------------------------------------------------------------------------------------------------------------------- EVP_bf_cbc(void), EVP_bf_ecb(void), EVP_bf_cfb(void), EVP_bf_ofb(void); Blowfish encryption algorithm in CBC, ECB, CFB and OFB modes respectively. This is a variable key length cipher. -------------------------------------------------------------------------------------------------------------------------- +180 3001b06c 894598 movl %eax,0x98(%ebp) +183 3001b06f e8df210200 calll 0x3003d253 _BIO_f_cipher -------------------------------------------------------------------------------------------------------------------------- BIO_METHOD * BIO_f_cipher(void); BIO_f_cipher() returns the cipher BIO method. This is a filter BIO that encrypts any data written through it, and decrypts any data read from it. It is a BIO wrapper for the cipher routines EVP_CipherInit(), EVP_CipherUpdate() and EVP_CipherFinal(). -------------------------------------------------------------------------------------------------------------------------- +188 3001b074 890424 movl %eax,(%esp,1) +191 3001b077 e8ce200200 calll 0x3003d14a _BIO_new +196 3001b07c 89c6 movl %eax,%esi +198 3001b07e c745b0596f7520 movl $0x20756f59,0xb0(%ebp) ' uoY' +205 3001b085 c745b4536f6674 movl $0x74666f53,0xb4(%ebp) 'tfoS' +212 3001b08c c745b877617265 movl $0x65726177,0xb8(%ebp) 'eraw' +219 3001b093 c645bc00 movb $0x00,0xbc(%ebp) +223 3001b097 c744241000000000 movl $0x00000000,0x10(%esp,1) <- decrypt +231 3001b09f 8b4590 movl 0x90(%ebp),%eax +234 3001b0a2 8944240c movl %eax,0x0c(%esp,1) <- *iv +238 3001b0a6 8b5584 movl 0x84(%ebp),%edx +241 3001b0a9 89542408 movl %edx,0x08(%esp,1) <- *key 'You Software' +245 3001b0ad 8b7d98 movl 0x98(%ebp),%edi +248 3001b0b0 897c2404 movl %edi,0x04(%esp,1) <- bf-cbc +252 3001b0b4 893424 movl %esi,(%esp,1) <- *b +255 3001b0b7 e888210200 calll 0x3003d244 _BIO_set_cipher -------------------------------------------------------------------------------------------------------------------------- void BIO_set_cipher(BIO *b,const EVP_CIPHER *cipher,unsigned char *key, unsigned char *iv, int enc); BIO_set_cipher() sets the cipher of BIO b to cipher using key key and IV iv. enc should be set to 1 for encryption and zero for decryption. When reading from an encryption BIO the final block is automatically decrypted and checked when EOF is detected. BIO_get_cipher_status() is a BIO_ctrl() macro which can be called to determine whether the decryp-decryption operation was successful. -------------------------------------------------------------------------------------------------------------------------- +260 3001b0bc 8b45a0 movl 0xa0(%ebp),%eax +263 3001b0bf 89442404 movl %eax,0x04(%esp,1) +267 3001b0c3 893424 movl %esi,(%esp,1) +270 3001b0c6 e857200200 calll 0x3003d122 _BIO_push (...) +358 3001b11e e8eb1f0200 calll 0x3003d10e _malloc +363 3001b123 89459c movl %eax,0x9c(%ebp) +366 3001b126 89742408 movl %esi,0x08(%esp,1) <- length (the same as apache response) +370 3001b12a 89442404 movl %eax,0x04(%esp,1) <- output buffer +374 3001b12e 8b7da4 movl 0xa4(%ebp),%edi +377 3001b131 893c24 movl %edi,(%esp,1) <- input +380 3001b134 e815210200 calll 0x3003d24e _BIO_read -------------------------------------------------------------------------------------------------------------------------- int BIO_read(BIO *b, void *buf, int len); BIO_read() attempts to read len bytes from BIO b and places the data in buf. -------------------------------------------------------------------------------------------------------------------------- +385 3001b139 89c6 movl %eax,%esi +387 3001b13b c744240c00000000 movl $0x00000000,0x0c(%esp,1) +395 3001b143 c744240800000000 movl $0x00000000,0x08(%esp,1) +403 3001b14b c744240471000000 movl $0x00000071,0x04(%esp,1) 'q' +411 3001b153 893c24 movl %edi,(%esp,1) +414 3001b156 e808200200 calll 0x3003d163 _BIO_ctrl -------------------------------------------------------------------------------------------------------------------------- long BIO_ctrl(BIO *bp,int cmd,long larg,void *parg); BIO_ctrl(), BIO_callback_ctrl(), BIO_ptr_ctrl() and BIO_int_ctrl() are BIO "control" operations taking arguments of various types. These functions are not normally called directly, various macros are used instead. The standard macros are described below, macros specific to a particular type of BIO are described in the specific BIOs manual page as well as any special features of the standard calls. -------------------------------------------------------------------------------------------------------------------------- +419 3001b15b 85c0 testl %eax,%eax +421 3001b15d 751a jne 0x3001b179 We have exactly the openssl functions needed for our decryption program. License decryption is finished. Step number 7 ahead... 7) Reading and verifying licence file ------------------------------------- A probable execution flow could be: start application, verify application checksum, read licence file, decrypt it, verify its content and if ok continue running. The function we are interested in is applicationDidFinishLaunching2 (starts at 0x000062e4 in You Control Desktops). If you scroll down this function, you will see a ptrace call so this is a good sign ! We can see a trend of anti tracing in code parts we are interested in. First interesting call is for checking the bundle signature: +1392 00006854 e884580000 calll 0x0000c0dd _checkBundleSignature Follows a licence init: +1461 00006899 e821580000 calll 0x0000c0bf _licenseInit And then a licence status: +1573 00006909 e8b6570000 calll 0x0000c0c4 _licenseStatus Since we have already analysed checkBundleSignature we are interested at the other two functions. 7.1) Analysing licenseInit -------------------------- This functions starts at 0x300018ab in YSCommon. It's called two times. Start scrolling down until you reach this piece of code (hey one ptrace call is here :) ): +530 30001abd 8954240c movl %edx,0x0c(%esp,1) <- licenseKey +534 30001ac1 897c2408 movl %edi,0x08(%esp,1) <- SiteLicense.You Control Desktops.1 +538 30001ac5 8b9383410300 movl 0x00034183(%ebx),%edx +544 30001acb 89542404 movl %edx,0x04(%esp,1) <- pathForResource:ofType: +548 30001acf 890424 movl %eax,(%esp,1) <- NSBundle (loaded) +551 30001ad2 e82eb50300 calll 0x3003d005 _objc_msgSend +556 30001ad7 89c6 movl %eax,%esi <- eax equals 0 if file not found, else it's an object +558 30001ad9 85c0 testl %eax,%eax +560 30001adb 0f8470080000 jel 0x30002351 <- no file found ? jump !!! This code is looking for a site license at Resources dir. Function reference: pathForResource:ofType: Returns the full pathname for the resource identified by a given name and specified file extension. - (NSString *)pathForResource:(NSString *)name ofType:(NSString *)extension Parameters name The name of the resource file. extension The file extension of a resource with the name name. Return Value The full pathname for the resource file or nil if the file could not be located. So it seems we must put a site licence at this dir instead the License dir. Hum... how can we be sure of this ? We could try to find where the licence is created when a valid site licence is purchased. Since we only have a demo licence we aren't interested tracing this path. Keep scrolling down... What happens next is MAC address being retrieved and then searching for a valid licence file name, something like XX-XX-XX-XX-XX-XX.You Control Desktops.1.licenseKey . The interesting code from this function (apart from valid filename construction) is: +1714 30001f5d 8b833b4d0300 movl 0x00034d3b(%ebx),%eax licensesDirectory +1720 30001f63 89442404 movl %eax,0x04(%esp,1) <- licensesDirectory +1724 30001f67 891424 movl %edx,(%esp,1) +1727 30001f6a e896b00300 calll 0x3003d005 -[(%esp,1) licensesDirectory] +1732 30001f6f 89742408 movl %esi,0x08(%esp,1) <- xx-xx-xx-xx-xx-xx.You Control Desktops.1.licenseKey +1736 30001f73 8b9367460300 movl 0x00034667(%ebx),%edx stringByAppendingPathComponent: +1742 30001f79 89542404 movl %edx,0x04(%esp,1) <- stringByAppendingPathComponent: +1746 30001f7d 890424 movl %eax,(%esp,1) <- /Users/aaaa/Library/Application Support/You Software/Licenses +1749 30001f80 e880b00300 calll 0x3003d005 -[(%esp,1) stringByAppendingPathComponent:] +1754 30001f85 e82e900100 calll _decryptLicenseDictionary This is where the sucesfully read licence filename will be decrypted. We can move to licenseStatus... 7.2) Analysing licenseStatus ---------------------------- At the beggining we can see our ptrace friend... Yeah our path is still good. We can spot right there an interesting function name, __licenseFileIsValid. Code: (...) +112 300030b6 e869a60100 calll __licenseFileIsValid +117 300030bb 84c0 testb %al,%al +119 300030bd 750d jne 0x300030cc <- if invalid, then return 5 ! +121 300030bf b835000000 movl $0x00000035,%eax '5' +126 300030c4 83c42c addl $0x2c,%esp +129 300030c7 5b popl %ebx +130 300030c8 5e popl %esi +131 300030c9 5f popl %edi +132 300030ca 5d popl %ebp +133 300030cb c3 ret Hummm licenseFileIsValid seems to be the candy we are looking for. 7.3) Analysing _licenseFileIsValid ---------------------------------- This is where the fun begins, in a long long routine. This is where we collect necessary information to create a keygen. I think the best way to understand is to show all the code, with comments (it's damn long but worth it). Comments start with <- __licenseFileIsValid: +0 3001d724 55 pushl %ebp +1 3001d725 89e5 movl %esp,%ebp +3 3001d727 57 pushl %edi +4 3001d728 56 pushl %esi +5 3001d729 53 pushl %ebx +6 3001d72a 81ecac000000 subl $0x000000ac,%esp +12 3001d730 e82f560100 calll ___i686.get_pc_thunk.bx +17 3001d735 894594 movl %eax,0x94(%ebp) +20 3001d738 8b93ef6e0100 movl 0x00016eef(%ebx),%edx +26 3001d73e 85d2 testl %edx,%edx +28 3001d740 0f84c7080000 jel 0x3001e00d +34 3001d746 8bb3ef6e0100 movl 0x00016eef(%ebx),%esi +40 3001d74c e812eeffff calll _moduleName +45 3001d751 89442408 movl %eax,0x08(%esp,1) <- You Control Desktops:-:1 +49 3001d755 8b83f3840100 movl 0x000184f3(%ebx),%eax +55 3001d75b 89442404 movl %eax,0x04(%esp,1) <- objectForKey: +59 3001d75f 893424 movl %esi,(%esp,1) <- dictionary +62 3001d762 e89ef80100 calll 0x3003d005 _objc_msgSend +67 3001d767 85c0 testl %eax,%eax <- exists in dictionary ? +69 3001d769 7409 je 0x3001d774 <- no ? Jump! +71 3001d76b 80bbf36e010000 cmpb $0x00,0x00016ef3(%ebx) <- check if licence is flagged as invalid +78 3001d772 740d je 0x3001d781 <- no ? Jump! +80 3001d774 31c0 xorl %eax,%eax +82 3001d776 81c4ac000000 addl $0x000000ac,%esp +88 3001d77c 5b popl %ebx +89 3001d77d 5e popl %esi +90 3001d77e 5f popl %edi +91 3001d77f 5d popl %ebp +92 3001d780 c3 ret +93 3001d781 c744240c00000000 movl $0x00000000,0x0c(%esp,1) <- Continues here... +101 3001d789 c744240800000000 movl $0x00000000,0x08(%esp,1) +109 3001d791 c744240400000000 movl $0x00000000,0x04(%esp,1) +117 3001d799 c704241f000000 movl $0x0000001f,(%esp,1) +124 3001d7a0 e8d1fa0100 calll 0x3003d276 _ptrace +129 3001d7a5 e8bef5ffff calll _verifyPublicKey <- verifies public key (we already know this function, from step 4) +134 3001d7aa 8b4594 movl 0x94(%ebp),%eax +137 3001d7ad 89442408 movl %eax,0x08(%esp,1) <- arguments +141 3001d7b1 8b83c78e0100 movl 0x00018ec7(%ebx),%eax +147 3001d7b7 89442404 movl %eax,0x04(%esp,1) <- IIlIllIllIIllIllIlII -> siteLicense +151 3001d7bb 8b836f920100 movl 0x0001926f(%ebx),%eax +157 3001d7c1 890424 movl %eax,(%esp,1) <- YSLicense +160 3001d7c4 e83cf80100 calll 0x3003d005 _objc_msgSend <- checks if it's a site licence ? +165 3001d7c9 84c0 testb %al,%al +167 3001d7cb 0f84e8070000 jel 0x3001dfb9 <- Jumps, because we have no site licence (long jump) +173 3001d7d1 8b5594 movl 0x94(%ebp),%edx +176 3001d7d4 89542408 movl %edx,0x08(%esp,1) <- 0 +180 3001d7d8 8b83e78e0100 movl 0x00018ee7(%ebx),%eax +186 3001d7de 89442404 movl %eax,0x04(%esp,1) <- siteLicenseSiteName +190 3001d7e2 8b836f920100 movl 0x0001926f(%ebx),%eax +196 3001d7e8 890424 movl %eax,(%esp,1) <- YSLicense +199 3001d7eb e815f80100 calll 0x3003d005 _objc_msgSend +204 3001d7f0 8945a0 movl %eax,0xa0(%ebp) +207 3001d7f3 8b4594 movl 0x94(%ebp),%eax <- We arrive here from that long jump +210 3001d7f6 89442408 movl %eax,0x08(%esp,1) <- 0 +214 3001d7fa 8b83e38e0100 movl 0x00018ee3(%ebx),%eax +220 3001d800 89442404 movl %eax,0x04(%esp,1) <- serialNumber: +224 3001d804 8b836f920100 movl 0x0001926f(%ebx),%eax +230 3001d80a 890424 movl %eax,(%esp,1) <- YSLicense -> call to 0x3001e6cd +233 3001d80d e8f3f70100 calll 0x3003d005 _objc_msgSend +238 3001d812 8945a4 movl %eax,0xa4(%ebp) <- serial number in the licence file +241 3001d815 8b83ef6e0100 movl 0x00016eef(%ebx),%eax +247 3001d81b 85c0 testl %eax,%eax +249 3001d81d 0f84220a0000 jel 0x3001e245 <- no serial number ? Jump! +255 3001d823 8bb3ef6e0100 movl 0x00016eef(%ebx),%esi +261 3001d829 8b4594 movl 0x94(%ebp),%eax +264 3001d82c e832edffff calll _moduleName +269 3001d831 89442408 movl %eax,0x08(%esp,1) <- You Control Desktops:-:1 +273 3001d835 8b83f3840100 movl 0x000184f3(%ebx),%eax +279 3001d83b 89442404 movl %eax,0x04(%esp,1) <- objectForKey: +283 3001d83f 893424 movl %esi,(%esp,1) <- object +286 3001d842 e8bef70100 calll 0x3003d005 _objc_msgSend +291 3001d847 8d93b7670100 leal 0x000167b7(%ebx),%edx +297 3001d84d 89542408 movl %edx,0x08(%esp,1) <- licenseSum +301 3001d851 8b93f3840100 movl 0x000184f3(%ebx),%edx +307 3001d857 89542404 movl %edx,0x04(%esp,1) <- objectForKey: +311 3001d85b 890424 movl %eax,(%esp,1) <- object from licence dictionary +314 3001d85e e8a2f70100 calll 0x3003d005 _objc_msgSend +319 3001d863 89459c movl %eax,0x9c(%ebp) <- eax holds result of licenseSum field +322 3001d866 8b4594 movl 0x94(%ebp),%eax +325 3001d869 89442408 movl %eax,0x08(%esp,1) <- 0 +329 3001d86d 8b83df8e0100 movl 0x00018edf(%ebx),%eax +335 3001d873 89442404 movl %eax,0x04(%esp,1) <- expirationDate: +339 3001d877 8b836f920100 movl 0x0001926f(%ebx),%eax +345 3001d87d 890424 movl %eax,(%esp,1) <- YSLicense +348 3001d880 e880f70100 calll 0x3003d005 _objc_msgSend +353 3001d885 8d93c7670100 leal 0x000167c7(%ebx),%edx +359 3001d88b 89542408 movl %edx,0x08(%esp,1) <- %Y-%m-%d +363 3001d88f 8b93db8e0100 movl 0x00018edb(%ebx),%edx +369 3001d895 89542404 movl %edx,0x04(%esp,1) <- descriptionWithCalendarFormat +373 3001d899 890424 movl %eax,(%esp,1) <- 2008-01-01 00:00:00 +0100 +376 3001d89c e864f70100 calll 0x3003d005 _objc_msgSend +381 3001d8a1 8945a8 movl %eax,0xa8(%ebp) <- result Year-Month-Day +384 3001d8a4 8b83ef6e0100 movl 0x00016eef(%ebx),%eax +390 3001d8aa 85c0 testl %eax,%eax +392 3001d8ac 0f8414090000 jel 0x3001e1c6 <- is date retrieved ? no ? Jump! +398 3001d8b2 8bb3ef6e0100 movl 0x00016eef(%ebx),%esi +404 3001d8b8 8b4594 movl 0x94(%ebp),%eax <- 0 +407 3001d8bb e8a3ecffff calll _moduleName +412 3001d8c0 89442408 movl %eax,0x08(%esp,1) <- You Control Desktops:-:1 +416 3001d8c4 8b83f3840100 movl 0x000184f3(%ebx),%eax +422 3001d8ca 89442404 movl %eax,0x04(%esp,1) <- objectForKey: +426 3001d8ce 893424 movl %esi,(%esp,1) +429 3001d8d1 e82ff70100 calll 0x3003d005 _objc_msgSend +434 3001d8d6 8d93d7670100 leal 0x000167d7(%ebx),%edx +440 3001d8dc 89542408 movl %edx,0x08(%esp,1) <- productName +444 3001d8e0 8b93f3840100 movl 0x000184f3(%ebx),%edx +450 3001d8e6 89542404 movl %edx,0x04(%esp,1) <- objectForKey: +454 3001d8ea 890424 movl %eax,(%esp,1) +457 3001d8ed e813f70100 calll 0x3003d005 _objc_msgSend +462 3001d8f2 894598 movl %eax,0x98(%ebp) +465 3001d8f5 8b4594 movl 0x94(%ebp),%eax +468 3001d8f8 89442408 movl %eax,0x08(%esp,1) <- 0 +472 3001d8fc 8b83d78e0100 movl 0x00018ed7(%ebx),%eax +478 3001d902 89442404 movl %eax,0x04(%esp,1) <- customerName: +482 3001d906 8b836f920100 movl 0x0001926f(%ebx),%eax +488 3001d90c 890424 movl %eax,(%esp,1) <- YSLicense +491 3001d90f e8f1f60100 calll 0x3003d005 _objc_msgSend +496 3001d914 8945ac movl %eax,0xac(%ebp) +499 3001d917 8b5594 movl 0x94(%ebp),%edx +502 3001d91a 89542408 movl %edx,0x08(%esp,1) <- 0 +506 3001d91e 8b83d38e0100 movl 0x00018ed3(%ebx),%eax +512 3001d924 89442404 movl %eax,0x04(%esp,1) <- customerEmailAddress: +516 3001d928 8b836f920100 movl 0x0001926f(%ebx),%eax +522 3001d92e 890424 movl %eax,(%esp,1) <- YSLicense +525 3001d931 e8cff60100 calll 0x3003d005 _objc_msgSend +530 3001d936 8945b0 movl %eax,0xb0(%ebp) +533 3001d939 8b83ef6e0100 movl 0x00016eef(%ebx),%eax +539 3001d93f 85c0 testl %eax,%eax +541 3001d941 0f848f080000 jel 0x3001e1d6 +547 3001d947 8bb3ef6e0100 movl 0x00016eef(%ebx),%esi +553 3001d94d 8b4594 movl 0x94(%ebp),%eax +556 3001d950 e80eecffff calll _moduleName +561 3001d955 89442408 movl %eax,0x08(%esp,1) <- You Control Desktops:-:1 +565 3001d959 8b83f3840100 movl 0x000184f3(%ebx),%eax +571 3001d95f 89442404 movl %eax,0x04(%esp,1) <- objectForKey: +575 3001d963 893424 movl %esi,(%esp,1) +578 3001d966 e89af60100 calll 0x3003d005 _objc_msgSend +583 3001d96b 8d93e7670100 leal 0x000167e7(%ebx),%edx +589 3001d971 89542408 movl %edx,0x08(%esp,1) <- productVersion +593 3001d975 8b93f3840100 movl 0x000184f3(%ebx),%edx +599 3001d97b 89542404 movl %edx,0x04(%esp,1) <- objectForKey: +603 3001d97f 890424 movl %eax,(%esp,1) +606 3001d982 e87ef60100 calll 0x3003d005 _objc_msgSend +611 3001d987 8b93238e0100 movl 0x00018e23(%ebx),%edx +617 3001d98d 89542404 movl %edx,0x04(%esp,1) <- stringValue +621 3001d991 890424 movl %eax,(%esp,1) <- 1 (product version) +624 3001d994 e86cf60100 calll 0x3003d005 _objc_msgSend +629 3001d999 8945b4 movl %eax,0xb4(%ebp) +632 3001d99c 8b83ef6e0100 movl 0x00016eef(%ebx),%eax +638 3001d9a2 85c0 testl %eax,%eax +640 3001d9a4 0f84ab080000 jel 0x3001e255 +646 3001d9aa 8bb3ef6e0100 movl 0x00016eef(%ebx),%esi +652 3001d9b0 8b4594 movl 0x94(%ebp),%eax +655 3001d9b3 e8abebffff calll _moduleName +660 3001d9b8 89442408 movl %eax,0x08(%esp,1) <- You Control Desktops:-:1 +664 3001d9bc 8b83f3840100 movl 0x000184f3(%ebx),%eax +670 3001d9c2 89442404 movl %eax,0x04(%esp,1) <- objectForKey: +674 3001d9c6 893424 movl %esi,(%esp,1) +677 3001d9c9 e837f60100 calll 0x3003d005 _objc_msgSend +682 3001d9ce 8d93f7670100 leal 0x000167f7(%ebx),%edx +688 3001d9d4 89542408 movl %edx,0x08(%esp,1) <- licenseVersion +692 3001d9d8 8b93f3840100 movl 0x000184f3(%ebx),%edx +698 3001d9de 89542404 movl %edx,0x04(%esp,1) <- objectForKey: +702 3001d9e2 890424 movl %eax,(%esp,1) +705 3001d9e5 e81bf60100 calll 0x3003d005 _objc_msgSend +710 3001d9ea 8b93238e0100 movl 0x00018e23(%ebx),%edx +716 3001d9f0 89542404 movl %edx,0x04(%esp,1) <- stringValue +720 3001d9f4 890424 movl %eax,(%esp,1) <- 1 +723 3001d9f7 e809f60100 calll 0x3003d005 _objc_msgSend +728 3001d9fc 8945b8 movl %eax,0xb8(%ebp) +731 3001d9ff 8b83ef6e0100 movl 0x00016eef(%ebx),%eax +737 3001da05 85c0 testl %eax,%eax +739 3001da07 0f8458080000 jel 0x3001e265 +745 3001da0d 8bb3ef6e0100 movl 0x00016eef(%ebx),%esi +751 3001da13 8b4594 movl 0x94(%ebp),%eax +754 3001da16 e848ebffff calll _moduleName +759 3001da1b 89442408 movl %eax,0x08(%esp,1) <- You Control Desktops:-:1 +763 3001da1f 8b83f3840100 movl 0x000184f3(%ebx),%eax +769 3001da25 89442404 movl %eax,0x04(%esp,1) <- objectForKey: +773 3001da29 893424 movl %esi,(%esp,1) +776 3001da2c e8d4f50100 calll 0x3003d005 _objc_msgSend +781 3001da31 8d9307680100 leal 0x00016807(%ebx),%edx +787 3001da37 89542408 movl %edx,0x08(%esp,1) <- demoExtended +791 3001da3b 8b93f3840100 movl 0x000184f3(%ebx),%edx +797 3001da41 89542404 movl %edx,0x04(%esp,1) <- objectForKey: +801 3001da45 890424 movl %eax,(%esp,1) +804 3001da48 e8b8f50100 calll 0x3003d005 _objc_msgSend +809 3001da4d 8b93238e0100 movl 0x00018e23(%ebx),%edx +815 3001da53 89542404 movl %edx,0x04(%esp,1) <- stringValue +819 3001da57 890424 movl %eax,(%esp,1) <- 0 +822 3001da5a e8a6f50100 calll 0x3003d005 _objc_msgSend +827 3001da5f 8945bc movl %eax,0xbc(%ebp) +830 3001da62 e8f7f60100 calll 0x3003d15e _EVP_sha1 ---------------------------------------------------------------------------------------------------------- const EVP_MD *EVP_sha1(void); EVP_md2(), EVP_md5(), EVP_sha(), EVP_sha1(), EVP_mdc2() and EVP_ripemd160() return EVP_MD structures for the MD2, MD5, SHA, SHA1, MDC2 and RIPEMD160 digest algorithms respectively. The associated signature algorithm is RSA in each case. ---------------------------------------------------------------------------------------------------------- +835 3001da67 89442404 movl %eax,0x04(%esp,1) <- type +839 3001da6b 8d55c8 leal 0xc8(%ebp),%edx +842 3001da6e 895590 movl %edx,0x90(%ebp) +845 3001da71 891424 movl %edx,(%esp,1) <- ctx +848 3001da74 e8e0f60100 calll 0x3003d159 _EVP_DigestInit ---------------------------------------------------------------------------------------------------------- int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type); EVP_DigestInit_ex() sets up digest context ctx to use a digest type from ENGINE impl. ctx must be initialized before calling this function. type will typically be supplied by a functionsuch as EVP_sha1(). If impl is NULL then the default implementation of digest type is used. EVP_DigestInit() behaves in the same way as EVP_DigestInit_ex() except the passed context ctx does not have to be initialized, and it always uses the default digest implementation. ---------------------------------------------------------------------------------------------------------- +853 3001da79 8b7da8 movl 0xa8(%ebp),%edi +856 3001da7c 85ff testl %edi,%edi +858 3001da7e 743f je 0x3001dabf +860 3001da80 8b83cb830100 movl 0x000183cb(%ebx),%eax +866 3001da86 89442404 movl %eax,0x04(%esp,1) <- length +870 3001da8a 8b45a8 movl 0xa8(%ebp),%eax +873 3001da8d 890424 movl %eax,(%esp,1) <- date retrieved before +876 3001da90 e870f50100 calll 0x3003d005 _objc_msgSend +881 3001da95 89c6 movl %eax,%esi +883 3001da97 8b837f880100 movl 0x0001887f(%ebx),%eax +889 3001da9d 89442404 movl %eax,0x04(%esp,1) <- cString +893 3001daa1 8b55a8 movl 0xa8(%ebp),%edx +896 3001daa4 891424 movl %edx,(%esp,1) <- date retrieved before +899 3001daa7 e859f50100 calll 0x3003d005 _objc_msgSend +904 3001daac 89742408 movl %esi,0x08(%esp,1) <- size (cnt) +908 3001dab0 89442404 movl %eax,0x04(%esp,1) <- expiration date ! (d) +912 3001dab4 8b4590 movl 0x90(%ebp),%eax +915 3001dab7 890424 movl %eax,(%esp,1) <- ctx +918 3001daba e854f60100 calll 0x3003d113 _EVP_DigestUpdate ---------------------------------------------------------------------------------------------------------- int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt); EVP_DigestUpdate() hashes cnt bytes of data at d into the digest con-context text ctx. This function can be called several times on the same ctx to hash additional data. ---------------------------------------------------------------------------------------------------------- +923 3001dabf 8b83cb830100 movl 0x000183cb(%ebx),%eax +929 3001dac5 89442404 movl %eax,0x04(%esp,1) <- length +933 3001dac9 8b55a4 movl 0xa4(%ebp),%edx +936 3001dacc 891424 movl %edx,(%esp,1) <- serial number +939 3001dacf e831f50100 calll 0x3003d005 _objc_msgSend +944 3001dad4 89c6 movl %eax,%esi +946 3001dad6 8b837f880100 movl 0x0001887f(%ebx),%eax +952 3001dadc 89442404 movl %eax,0x04(%esp,1) <- cString +956 3001dae0 8b45a4 movl 0xa4(%ebp),%eax +959 3001dae3 890424 movl %eax,(%esp,1) <- serial number +962 3001dae6 e81af50100 calll 0x3003d005 _objc_msgSend +967 3001daeb 89742408 movl %esi,0x08(%esp,1) <- cnt +971 3001daef 89442404 movl %eax,0x04(%esp,1) <- d <- serial number! +975 3001daf3 8b5590 movl 0x90(%ebp),%edx +978 3001daf6 891424 movl %edx,(%esp,1) <- EVP_MD_CTX +981 3001daf9 e815f60100 calll 0x3003d113 _EVP_DigestUpdate ---------------------------------------------------------------------------------------------------------- int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt); EVP_DigestUpdate() hashes cnt bytes of data at d into the digest context ctx. This function can be called several times on the same ctx to hash additional data. ---------------------------------------------------------------------------------------------------------- +992 3001db04 89442404 movl %eax,0x04(%esp,1) <- length +996 3001db08 8b45a0 movl 0xa0(%ebp),%eax +999 3001db0b 890424 movl %eax,(%esp,1) <- MAC Address +1002 3001db0e e8f2f40100 calll 0x3003d005 _objc_msgSend +1007 3001db13 89c6 movl %eax,%esi +1009 3001db15 8b837f880100 movl 0x0001887f(%ebx),%eax +1015 3001db1b 89442404 movl %eax,0x04(%esp,1) <- cString +1019 3001db1f 8b55a0 movl 0xa0(%ebp),%edx +1022 3001db22 891424 movl %edx,(%esp,1) <- MAC Address +1025 3001db25 e8dbf40100 calll 0x3003d005 _objc_msgSend +1030 3001db2a 89742408 movl %esi,0x08(%esp,1) <- cnt +1034 3001db2e 89442404 movl %eax,0x04(%esp,1) <- d (mac address!) +1038 3001db32 8b4590 movl 0x90(%ebp),%eax +1041 3001db35 890424 movl %eax,(%esp,1) <- EVP_MD_CTX +1044 3001db38 e8d6f50100 calll 0x3003d113 _EVP_DigestUpdate +1049 3001db3d 8bb3036f0100 movl 0x00016f03(%ebx),%esi +1055 3001db43 85f6 testl %esi,%esi +1057 3001db45 0f841c060000 jel 0x3001e167 <- failed ? Jump ! +1063 3001db4b 8b83036f0100 movl 0x00016f03(%ebx),%eax +1069 3001db51 8944240c movl %eax,0x0c(%esp,1) <- pkey public key to decrypt ctx +1073 3001db55 c744240800000000 movl $0x00000000,0x08(%esp,1) <- siglen +1081 3001db5d c744240400000000 movl $0x00000000,0x04(%esp,1) <- sigbuf which holds the good digest (in this case nothing) +1089 3001db65 8b5590 movl 0x90(%ebp),%edx +1092 3001db68 891424 movl %edx,(%esp,1) <- ctx our digest created by each DigestUpdate +1095 3001db6b e815f70100 calll 0x3003d285 _EVP_VerifyFinal ---------------------------------------------------------------------------------------------------------- int EVP_VerifyFinal(EVP_MD_CTX *ctx,unsigned char *sigbuf, unsigned int siglen,EVP_PKEY *pkey); EVP_VerifyFinal() verifies the data in ctx using the public key pkey and against the siglen bytes at sigbuf. EVP_VerifyFinal() returns 1 for a correct signature, 0 for failure and -1 if some other error occurred. ---------------------------------------------------------------------------------------------------------- +1100 3001db70 83e801 subl $0x01,%eax <- result is zero, which means verification failed. Nevertheless, this seems to be checking for an empty licence file, since it will always give this result with filled fields and the program flow isn't affected. The next check is the one we are interested in. Since sigbug is being filled with 0, this verify would never work unless licence file is empty. +1103 3001db73 0f8471050000 jel 0x3001e0ea +1109 3001db79 8b4590 movl 0x90(%ebp),%eax +1112 3001db7c 890424 movl %eax,(%esp,1) +1115 3001db7f e8e4f50100 calll 0x3003d168 _EVP_MD_CTX_cleanup ---------------------------------------------------------------------------------------------------------- int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx); EVP_MD_CTX_cleanup() cleans up digest context ctx, it should be called after a digest context is no longer needed. ---------------------------------------------------------------------------------------------------------- +1120 3001db84 e8d5f50100 calll 0x3003d15e _EVP_sha1 +1125 3001db89 89442404 movl %eax,0x04(%esp,1) <- type +1129 3001db8d 8d55d8 leal 0xd8(%ebp),%edx +1132 3001db90 89558c movl %edx,0x8c(%ebp) +1135 3001db93 891424 movl %edx,(%esp,1) <- ctx +1138 3001db96 e8bef50100 calll 0x3003d159 _EVP_DigestInit +1143 3001db9b 8b4db8 movl 0xb8(%ebp),%ecx +1146 3001db9e 85c9 testl %ecx,%ecx +1148 3001dba0 0f8477040000 jel 0x3001e01d +1154 3001dba6 8b83038f0100 movl 0x00018f03(%ebx),%eax +1160 3001dbac 89442404 movl %eax,0x04(%esp,1) <- UTF8String +1164 3001dbb0 8b55b0 movl 0xb0(%ebp),%edx +1167 3001dbb3 891424 movl %edx,(%esp,1) +1170 3001dbb6 e84af40100 calll 0x3003d005 _objc_msgSend +1175 3001dbbb 89c7 movl %eax,%edi +1177 3001dbbd fc cld +1178 3001dbbe b9ffffffff movl $0xffffffff,%ecx +1183 3001dbc3 31c0 xorl %eax,%eax +1185 3001dbc5 f2ae repnz/scasb %al,(%edi) +1187 3001dbc7 f7d1 notl %ecx +1189 3001dbc9 8d71ff leal 0xff(%ecx),%esi +1192 3001dbcc 8b83038f0100 movl 0x00018f03(%ebx),%eax +1198 3001dbd2 89442404 movl %eax,0x04(%esp,1) <- UTF8String +1202 3001dbd6 8b45b0 movl 0xb0(%ebp),%eax +1205 3001dbd9 890424 movl %eax,(%esp,1) +1208 3001dbdc e824f40100 calll 0x3003d005 _objc_msgSend +1213 3001dbe1 89742408 movl %esi,0x08(%esp,1) <- nr of bytes to hash (0) +1217 3001dbe5 89442404 movl %eax,0x04(%esp,1) <- data to hash (empty) +1221 3001dbe9 8b558c movl 0x8c(%ebp),%edx +1224 3001dbec 891424 movl %edx,(%esp,1) <- context to hash into +1227 3001dbef e81ff50100 calll 0x3003d113 _EVP_DigestUpdate +1232 3001dbf4 8b45a8 movl 0xa8(%ebp),%eax <- eax with expiration date +1235 3001dbf7 85c0 testl %eax,%eax +1237 3001dbf9 743f je 0x3001dc3a +1239 3001dbfb 8b83cb830100 movl 0x000183cb(%ebx),%eax +1245 3001dc01 89442404 movl %eax,0x04(%esp,1) <- length +1249 3001dc05 8b45a8 movl 0xa8(%ebp),%eax +1252 3001dc08 890424 movl %eax,(%esp,1) <- expiration date +1255 3001dc0b e8f5f30100 calll 0x3003d005 _objc_msgSend +1260 3001dc10 89c6 movl %eax,%esi <- expiration date length in EAX +1262 3001dc12 8b837f880100 movl 0x0001887f(%ebx),%eax +1268 3001dc18 89442404 movl %eax,0x04(%esp,1) <- cString +1272 3001dc1c 8b55a8 movl 0xa8(%ebp),%edx +1275 3001dc1f 891424 movl %edx,(%esp,1) <- expiration date +1278 3001dc22 e8def30100 calll 0x3003d005 _objc_msgSend +1283 3001dc27 89742408 movl %esi,0x08(%esp,1) <- expiration date length +1287 3001dc2b 89442404 movl %eax,0x04(%esp,1) <- expiration date +1291 3001dc2f 8b458c movl 0x8c(%ebp),%eax +1294 3001dc32 890424 movl %eax,(%esp,1) <- ctx +1297 3001dc35 e8d9f40100 calll 0x3003d113 _EVP_DigestUpdate <- HASH EXPIRATION DATE +1302 3001dc3a 8b45bc movl 0xbc(%ebp),%eax +1305 3001dc3d 85c0 testl %eax,%eax +1307 3001dc3f 743f je 0x3001dc80 <- Jump! +1309 3001dc41 8b83cb830100 movl 0x000183cb(%ebx),%eax +1315 3001dc47 89442404 movl %eax,0x04(%esp,1) +1319 3001dc4b 8b55bc movl 0xbc(%ebp),%edx +1322 3001dc4e 891424 movl %edx,(%esp,1) +1325 3001dc51 e8aff30100 calll 0x3003d005 _objc_msgSend +1330 3001dc56 89c6 movl %eax,%esi +1332 3001dc58 8b837f880100 movl 0x0001887f(%ebx),%eax +1338 3001dc5e 89442404 movl %eax,0x04(%esp,1) +1342 3001dc62 8b45bc movl 0xbc(%ebp),%eax +1345 3001dc65 890424 movl %eax,(%esp,1) +1348 3001dc68 e898f30100 calll 0x3003d005 _objc_msgSend +1353 3001dc6d 89742408 movl %esi,0x08(%esp,1) +1357 3001dc71 89442404 movl %eax,0x04(%esp,1) +1361 3001dc75 8b558c movl 0x8c(%ebp),%edx +1364 3001dc78 891424 movl %edx,(%esp,1) +1367 3001dc7b e893f40100 calll 0x3003d113 _EVP_DigestUpdate +1372 3001dc80 8b83cb830100 movl 0x000183cb(%ebx),%eax +1378 3001dc86 89442404 movl %eax,0x04(%esp,1) <- length +1382 3001dc8a 8b45b8 movl 0xb8(%ebp),%eax +1385 3001dc8d 890424 movl %eax,(%esp,1) <- 1 -> license version ? +1388 3001dc90 e870f30100 calll 0x3003d005 _objc_msgSend +1393 3001dc95 89c6 movl %eax,%esi +1395 3001dc97 8b837f880100 movl 0x0001887f(%ebx),%eax +1401 3001dc9d 89442404 movl %eax,0x04(%esp,1) <- cString +1405 3001dca1 8b55b8 movl 0xb8(%ebp),%edx +1408 3001dca4 891424 movl %edx,(%esp,1) <- 1 +1411 3001dca7 e859f30100 calll 0x3003d005 _objc_msgSend +1416 3001dcac 89742408 movl %esi,0x08(%esp,1) <- length +1420 3001dcb0 89442404 movl %eax,0x04(%esp,1) <- string "1" +1424 3001dcb4 8b458c movl 0x8c(%ebp),%eax +1427 3001dcb7 890424 movl %eax,(%esp,1) <- ctx +1430 3001dcba e854f40100 calll 0x3003d113 _EVP_DigestUpdate <- HASH LICENSE VERSION +1435 3001dcbf 8b83cb830100 movl 0x000183cb(%ebx),%eax +1441 3001dcc5 89442404 movl %eax,0x04(%esp,1) <- length +1445 3001dcc9 8b55a0 movl 0xa0(%ebp),%edx +1448 3001dccc 891424 movl %edx,(%esp,1) <- MAC Address +1451 3001dccf e831f30100 calll 0x3003d005 _objc_msgSend +1456 3001dcd4 89c6 movl %eax,%esi +1458 3001dcd6 8b837f880100 movl 0x0001887f(%ebx),%eax +1464 3001dcdc 89442404 movl %eax,0x04(%esp,1) <- cString +1468 3001dce0 8b45a0 movl 0xa0(%ebp),%eax +1471 3001dce3 890424 movl %eax,(%esp,1) <- MAC Address +1474 3001dce6 e81af30100 calll 0x3003d005 _objc_msgSend +1479 3001dceb 89742408 movl %esi,0x08(%esp,1) <- length +1483 3001dcef 89442404 movl %eax,0x04(%esp,1) <- mac address +1487 3001dcf3 8b558c movl 0x8c(%ebp),%edx +1490 3001dcf6 891424 movl %edx,(%esp,1) <- ctx +1493 3001dcf9 e815f40100 calll 0x3003d113 _EVP_DigestUpdate <- HASH MAC ADDRESS +1498 3001dcfe 8b4594 movl 0x94(%ebp),%eax +1501 3001dd01 89442408 movl %eax,0x08(%esp,1) <- 0 +1505 3001dd05 8b83cf8e0100 movl 0x00018ecf(%ebx),%eax +1511 3001dd0b 89442404 movl %eax,0x04(%esp,1) <- modules: (licence modules) +1515 3001dd0f 8b836f920100 movl 0x0001926f(%ebx),%eax +1521 3001dd15 890424 movl %eax,(%esp,1) <- YSLicense +1524 3001dd18 e8e8f20100 calll 0x3003d005 _objc_msgSend +1529 3001dd1d 8b93e7820100 movl 0x000182e7(%ebx),%edx +1535 3001dd23 89542404 movl %edx,0x04(%esp,1) <- objectEnumerator +1539 3001dd27 890424 movl %eax,(%esp,1) <- empty array +1542 3001dd2a e8d6f20100 calll 0x3003d005 _objc_msgSend +1547 3001dd2f 8945c4 movl %eax,0xc4(%ebp) +1550 3001dd32 89c2 movl %eax,%edx +1552 3001dd34 e9ca000000 jmpl 0x3001de03 <- Jumps +1557 3001dd39 8d8317680100 leal 0x00016817(%ebx),%eax +1563 3001dd3f 89442408 movl %eax,0x08(%esp,1) +1567 3001dd43 8b83f3840100 movl 0x000184f3(%ebx),%eax +1573 3001dd49 89442404 movl %eax,0x04(%esp,1) +1577 3001dd4d 893424 movl %esi,(%esp,1) +1580 3001dd50 e8b0f20100 calll 0x3003d005 _objc_msgSend +1585 3001dd55 89c7 movl %eax,%edi +1587 3001dd57 8d8327680100 leal 0x00016827(%ebx),%eax +1593 3001dd5d 89442408 movl %eax,0x08(%esp,1) +1597 3001dd61 8b83f3840100 movl 0x000184f3(%ebx),%eax +1603 3001dd67 89442404 movl %eax,0x04(%esp,1) +1607 3001dd6b 893424 movl %esi,(%esp,1) +1610 3001dd6e e892f20100 calll 0x3003d005 _objc_msgSend +1615 3001dd73 8b93238e0100 movl 0x00018e23(%ebx),%edx +1621 3001dd79 89542404 movl %edx,0x04(%esp,1) +1625 3001dd7d 890424 movl %eax,(%esp,1) +1628 3001dd80 e880f20100 calll 0x3003d005 _objc_msgSend +1633 3001dd85 8945c0 movl %eax,0xc0(%ebp) +1636 3001dd88 8b83cb830100 movl 0x000183cb(%ebx),%eax +1642 3001dd8e 89442404 movl %eax,0x04(%esp,1) +1646 3001dd92 893c24 movl %edi,(%esp,1) +1649 3001dd95 e86bf20100 calll 0x3003d005 _objc_msgSend +1654 3001dd9a 89c6 movl %eax,%esi +1656 3001dd9c 8b837f880100 movl 0x0001887f(%ebx),%eax +1662 3001dda2 89442404 movl %eax,0x04(%esp,1) +1666 3001dda6 893c24 movl %edi,(%esp,1) +1669 3001dda9 e857f20100 calll 0x3003d005 _objc_msgSend +1674 3001ddae 89742408 movl %esi,0x08(%esp,1) +1678 3001ddb2 89442404 movl %eax,0x04(%esp,1) +1682 3001ddb6 8b558c movl 0x8c(%ebp),%edx +1685 3001ddb9 891424 movl %edx,(%esp,1) +1688 3001ddbc e852f30100 calll 0x3003d113 _EVP_DigestUpdate +1693 3001ddc1 8b83cb830100 movl 0x000183cb(%ebx),%eax +1699 3001ddc7 89442404 movl %eax,0x04(%esp,1) +1703 3001ddcb 8b45c0 movl 0xc0(%ebp),%eax +1706 3001ddce 890424 movl %eax,(%esp,1) +1709 3001ddd1 e82ff20100 calll 0x3003d005 _objc_msgSend +1714 3001ddd6 89c6 movl %eax,%esi +1716 3001ddd8 8b837f880100 movl 0x0001887f(%ebx),%eax +1722 3001ddde 89442404 movl %eax,0x04(%esp,1) +1726 3001dde2 8b55c0 movl 0xc0(%ebp),%edx +1729 3001dde5 891424 movl %edx,(%esp,1) +1732 3001dde8 e818f20100 calll 0x3003d005 _objc_msgSend +1737 3001dded 89742408 movl %esi,0x08(%esp,1) +1741 3001ddf1 89442404 movl %eax,0x04(%esp,1) +1745 3001ddf5 8b458c movl 0x8c(%ebp),%eax +1748 3001ddf8 890424 movl %eax,(%esp,1) +1751 3001ddfb e813f30100 calll 0x3003d113 _EVP_DigestUpdate +1756 3001de00 8b55c4 movl 0xc4(%ebp),%edx +1759 3001de03 8b83e3820100 movl 0x000182e3(%ebx),%eax <- Land here +1765 3001de09 89442404 movl %eax,0x04(%esp,1) <- nextObject +1769 3001de0d 891424 movl %edx,(%esp,1) <- +1772 3001de10 e8f0f10100 calll 0x3003d005 _objc_msgSend +1777 3001de15 89c6 movl %eax,%esi +1779 3001de17 85c0 testl %eax,%eax +1781 3001de19 0f851affffff jnel 0x3001dd39 <- no jump +1787 3001de1f 8b45ac movl 0xac(%ebp),%eax +1790 3001de22 85c0 testl %eax,%eax +1792 3001de24 744e je 0x3001de74 <- no jump +1794 3001de26 8b83038f0100 movl 0x00018f03(%ebx),%eax +1800 3001de2c 89442404 movl %eax,0x04(%esp,1) <- UTF8String +1804 3001de30 8b45ac movl 0xac(%ebp),%eax +1807 3001de33 890424 movl %eax,(%esp,1) <- registration name +1810 3001de36 e8caf10100 calll 0x3003d005 _objc_msgSend +1815 3001de3b 89c7 movl %eax,%edi +1817 3001de3d fc cld +1818 3001de3e b9ffffffff movl $0xffffffff,%ecx +1823 3001de43 31c0 xorl %eax,%eax +1825 3001de45 f2ae repnz/scasb %al,(%edi) <- registration name in EDI +1827 3001de47 f7d1 notl %ecx +1829 3001de49 8d71ff leal 0xff(%ecx),%esi +1832 3001de4c 8b83038f0100 movl 0x00018f03(%ebx),%eax +1838 3001de52 89442404 movl %eax,0x04(%esp,1) <- UTF8String +1842 3001de56 8b55ac movl 0xac(%ebp),%edx +1845 3001de59 891424 movl %edx,(%esp,1) <- registration name +1848 3001de5c e8a4f10100 calll 0x3003d005 _objc_msgSend +1853 3001de61 89742408 movl %esi,0x08(%esp,1) <- length +1857 3001de65 89442404 movl %eax,0x04(%esp,1) <- registration name +1861 3001de69 8b458c movl 0x8c(%ebp),%eax +1864 3001de6c 890424 movl %eax,(%esp,1) <- ctx +1867 3001de6f e89ff20100 calll 0x3003d113 _EVP_DigestUpdate <- HASH REGISTRATION NAME +1872 3001de74 8b4598 movl 0x98(%ebp),%eax +1875 3001de77 85c0 testl %eax,%eax +1877 3001de79 743f je 0x3001deba <- no jump +1879 3001de7b 8b83cb830100 movl 0x000183cb(%ebx),%eax +1885 3001de81 89442404 movl %eax,0x04(%esp,1) <- length +1889 3001de85 8b5598 movl 0x98(%ebp),%edx +1892 3001de88 891424 movl %edx,(%esp,1) <- "You Control Desktops" +1895 3001de8b e875f10100 calll 0x3003d005 _objc_msgSend +1900 3001de90 89c6 movl %eax,%esi +1902 3001de92 8b837f880100 movl 0x0001887f(%ebx),%eax +1908 3001de98 89442404 movl %eax,0x04(%esp,1) <- cString +1912 3001de9c 8b4598 movl 0x98(%ebp),%eax +1915 3001de9f 890424 movl %eax,(%esp,1) <- "You Control Desktops" +1918 3001dea2 e85ef10100 calll 0x3003d005 _objc_msgSend +1923 3001dea7 89742408 movl %esi,0x08(%esp,1) <- length +1927 3001deab 89442404 movl %eax,0x04(%esp,1) <- Application Name: "You Control Desktops" +1931 3001deaf 8b558c movl 0x8c(%ebp),%edx +1934 3001deb2 891424 movl %edx,(%esp,1) <- ctx +1937 3001deb5 e859f20100 calll 0x3003d113 _EVP_DigestUpdate <- HASH APPLICATION NAME +1942 3001deba 8b45b4 movl 0xb4(%ebp),%eax +1945 3001debd 85c0 testl %eax,%eax +1947 3001debf 743f je 0x3001df00 +1949 3001dec1 8b83cb830100 movl 0x000183cb(%ebx),%eax +1955 3001dec7 89442404 movl %eax,0x04(%esp,1) <- length +1959 3001decb 8b45b4 movl 0xb4(%ebp),%eax +1962 3001dece 890424 movl %eax,(%esp,1) <- 1 +1965 3001ded1 e82ff10100 calll 0x3003d005 _objc_msgSend +1970 3001ded6 89c6 movl %eax,%esi +1972 3001ded8 8b837f880100 movl 0x0001887f(%ebx),%eax +1978 3001dede 89442404 movl %eax,0x04(%esp,1) <- cString +1982 3001dee2 8b55b4 movl 0xb4(%ebp),%edx +1985 3001dee5 891424 movl %edx,(%esp,1) <- 1 +1988 3001dee8 e818f10100 calll 0x3003d005 _objc_msgSend +1993 3001deed 89742408 movl %esi,0x08(%esp,1) <- length +1997 3001def1 89442404 movl %eax,0x04(%esp,1) <- 1 (product version) +2001 3001def5 8b458c movl 0x8c(%ebp),%eax +2004 3001def8 890424 movl %eax,(%esp,1) <- ctx +2007 3001defb e813f20100 calll 0x3003d113 _EVP_DigestUpdate <- HASH PRODUCT VERSION +2012 3001df00 8b83cb830100 movl 0x000183cb(%ebx),%eax +2018 3001df06 89442404 movl %eax,0x04(%esp,1) <- length +2022 3001df0a 8b55a4 movl 0xa4(%ebp),%edx +2025 3001df0d 891424 movl %edx,(%esp,1) <- serial number +2028 3001df10 e8f0f00100 calll 0x3003d005 _objc_msgSend +2033 3001df15 89c6 movl %eax,%esi +2035 3001df17 8b837f880100 movl 0x0001887f(%ebx),%eax +2041 3001df1d 89442404 movl %eax,0x04(%esp,1) <- cString +2045 3001df21 8b45a4 movl 0xa4(%ebp),%eax +2048 3001df24 890424 movl %eax,(%esp,1) <- serial number +2051 3001df27 e8d9f00100 calll 0x3003d005 _objc_msgSend +2056 3001df2c 89742408 movl %esi,0x08(%esp,1) <- length +2060 3001df30 89442404 movl %eax,0x04(%esp,1) <- serial number +2064 3001df34 8b558c movl 0x8c(%ebp),%edx +2067 3001df37 891424 movl %edx,(%esp,1) <- ctx +2070 3001df3a e8d4f10100 calll 0x3003d113 _EVP_DigestUpdate <- HASH SERIAL NUMBER +2075 3001df3f 8b83036f0100 movl 0x00016f03(%ebx),%eax +2081 3001df45 85c0 testl %eax,%eax +2083 3001df47 0f8499020000 jel 0x3001e1e6 <- no jump +2089 3001df4d 8bbb036f0100 movl 0x00016f03(%ebx),%edi +2095 3001df53 8b83cb830100 movl 0x000183cb(%ebx),%eax +2101 3001df59 89442404 movl %eax,0x04(%esp,1) <- length +2105 3001df5d 8b459c movl 0x9c(%ebp),%eax +2108 3001df60 890424 movl %eax,(%esp,1) <- checksum ! +2111 3001df63 e89df00100 calll 0x3003d005 _objc_msgSend +2116 3001df68 89c6 movl %eax,%esi +2118 3001df6a 8b83f78e0100 movl 0x00018ef7(%ebx),%eax +2124 3001df70 89442404 movl %eax,0x04(%esp,1) <- bytes +2128 3001df74 8b559c movl 0x9c(%ebp),%edx +2131 3001df77 891424 movl %edx,(%esp,1) <- checksum! +2134 3001df7a e886f00100 calll 0x3003d005 _objc_msgSend +2139 3001df7f 897c240c movl %edi,0x0c(%esp,1) <- pkey : public key to decrypt +2143 3001df83 89742408 movl %esi,0x08(%esp,1) <- siglen +2147 3001df87 89442404 movl %eax,0x04(%esp,1) <- sigbuf (licenseSum field) <- base64 decoded !!!! +2151 3001df8b 8b458c movl 0x8c(%ebp),%eax +2154 3001df8e 890424 movl %eax,(%esp,1) <- ctx : our generated hash +2157 3001df91 e8eff20100 calll 0x3003d285 _EVP_VerifyFinal <- THE REAL DECISION ! Is our generated hash equal to licenseSum field ? If yes, then licence file is valid, else it's invalid aka someone messed with it. +2162 3001df96 89c7 movl %eax,%edi +2164 3001df98 8b558c movl 0x8c(%ebp),%edx +2167 3001df9b 891424 movl %edx,(%esp,1) +2170 3001df9e e8c5f10100 calll 0x3003d168 _EVP_MD_CTX_cleanup +2175 3001dfa3 89f8 movl %edi,%eax +2177 3001dfa5 84c0 testb %al,%al +2179 3001dfa7 7530 jne 0x3001dfd9 <- Line ends here. If no jump, then checkum failed ! +2181 3001dfa9 89fa movl %edi,%edx +2183 3001dfab 0fbec2 movsbl %dl,%eax +2186 3001dfae 81c4ac000000 addl $0x000000ac,%esp +2192 3001dfb4 5b popl %ebx +2193 3001dfb5 5e popl %esi +2194 3001dfb6 5f popl %edi +2195 3001dfb7 5d popl %ebp +2196 3001dfb8 c3 ret +2197 3001dfb9 8b83c78a0100 movl 0x00018ac7(%ebx),%eax <- We land here ... Start the fun +2203 3001dfbf 89442404 movl %eax,0x04(%esp,1) <- currentHostMAC +2207 3001dfc3 8b836b920100 movl 0x0001926b(%ebx),%eax +2213 3001dfc9 890424 movl %eax,(%esp,1) <- NSHost +2216 3001dfcc e834f00100 calll 0x3003d005 _objc_msgSend +2221 3001dfd1 8945a0 movl %eax,0xa0(%ebp) <- object with en0 mac address +2224 3001dfd4 e91af8ffff jmpl 0x3001d7f3 <- and get back to where we started +2229 3001dfd9 8bb3eb6e0100 movl 0x00016eeb(%ebx),%esi <- SUCESS !!! +2235 3001dfdf 8b4594 movl 0x94(%ebp),%eax +2238 3001dfe2 e87ce5ffff calll _moduleName +2243 3001dfe7 89442408 movl %eax,0x08(%esp,1) +2247 3001dfeb 8b8307840100 movl 0x00018407(%ebx),%eax +2253 3001dff1 89442404 movl %eax,0x04(%esp,1) +2257 3001dff5 893424 movl %esi,(%esp,1) +2260 3001dff8 e808f00100 calll 0x3003d005 _objc_msgSend +2265 3001dffd 89fa movl %edi,%edx +2267 3001dfff 0fbec2 movsbl %dl,%eax +2270 3001e002 81c4ac000000 addl $0x000000ac,%esp +2276 3001e008 5b popl %ebx +2277 3001e009 5e popl %esi +2278 3001e00a 5f popl %edi +2279 3001e00b 5d popl %ebp +2280 3001e00c c3 ret +2281 3001e00d 890424 movl %eax,(%esp,1) +2284 3001e010 e89638feff calll _licenseInit +2289 3001e015 8b4594 movl 0x94(%ebp),%eax +2292 3001e018 e929f7ffff jmpl 0x3001d746 +2297 3001e01d 8b83cb830100 movl 0x000183cb(%ebx),%eax +2303 3001e023 89442404 movl %eax,0x04(%esp,1) <- length +2307 3001e027 8b45a0 movl 0xa0(%ebp),%eax +2310 3001e02a 890424 movl %eax,(%esp,1) +2313 3001e02d e8d3ef0100 calll 0x3003d005 _objc_msgSend +2318 3001e032 89c6 movl %eax,%esi +2320 3001e034 8b837f880100 movl 0x0001887f(%ebx),%eax +2326 3001e03a 89442404 movl %eax,0x04(%esp,1) <- cString +2330 3001e03e 8b55a0 movl 0xa0(%ebp),%edx +2333 3001e041 891424 movl %edx,(%esp,1) +2336 3001e044 e8bcef0100 calll 0x3003d005 _objc_msgSend +2341 3001e049 89742408 movl %esi,0x08(%esp,1) <- cnt +2345 3001e04d 89442404 movl %eax,0x04(%esp,1) <- d (mac address!) +2349 3001e051 8b458c movl 0x8c(%ebp),%eax +2352 3001e054 890424 movl %eax,(%esp,1) <- ctx +2355 3001e057 e8b7f00100 calll 0x3003d113 _EVP_DigestUpdate +2360 3001e05c 8b83cb830100 movl 0x000183cb(%ebx),%eax +2366 3001e062 89442404 movl %eax,0x04(%esp,1) <- length +2370 3001e066 8b55a4 movl 0xa4(%ebp),%edx +2373 3001e069 891424 movl %edx,(%esp,1) +2376 3001e06c e894ef0100 calll 0x3003d005 _objc_msgSend +2381 3001e071 89c6 movl %eax,%esi +2383 3001e073 8b837f880100 movl 0x0001887f(%ebx),%eax +2389 3001e079 89442404 movl %eax,0x04(%esp,1) <- cString +2393 3001e07d 8b45a4 movl 0xa4(%ebp),%eax +2396 3001e080 890424 movl %eax,(%esp,1) +2399 3001e083 e87def0100 calll 0x3003d005 _objc_msgSend +2404 3001e088 89742408 movl %esi,0x08(%esp,1) <- cnt +2408 3001e08c 89442404 movl %eax,0x04(%esp,1) <- d (vazio) +2412 3001e090 8b558c movl 0x8c(%ebp),%edx +2415 3001e093 891424 movl %edx,(%esp,1) <- ctx +2418 3001e096 e878f00100 calll 0x3003d113 _EVP_DigestUpdate +2423 3001e09b 8b55a8 movl 0xa8(%ebp),%edx +2426 3001e09e 85d2 testl %edx,%edx +2428 3001e0a0 0f8499feffff jel 0x3001df3f +2434 3001e0a6 8b83cb830100 movl 0x000183cb(%ebx),%eax +2440 3001e0ac 89442404 movl %eax,0x04(%esp,1) +2444 3001e0b0 8b45a8 movl 0xa8(%ebp),%eax +2447 3001e0b3 890424 movl %eax,(%esp,1) +2450 3001e0b6 e84aef0100 calll 0x3003d005 _objc_msgSend +2455 3001e0bb 89c6 movl %eax,%esi +2457 3001e0bd 8b837f880100 movl 0x0001887f(%ebx),%eax +2463 3001e0c3 89442404 movl %eax,0x04(%esp,1) +2467 3001e0c7 8b55a8 movl 0xa8(%ebp),%edx +2470 3001e0ca 891424 movl %edx,(%esp,1) +2473 3001e0cd e833ef0100 calll 0x3003d005 _objc_msgSend +2478 3001e0d2 89742408 movl %esi,0x08(%esp,1) +2482 3001e0d6 89442404 movl %eax,0x04(%esp,1) +2486 3001e0da 8b458c movl 0x8c(%ebp),%eax +2489 3001e0dd 890424 movl %eax,(%esp,1) +2492 3001e0e0 e82ef00100 calll 0x3003d113 _EVP_DigestUpdate +2497 3001e0e5 e955feffff jmpl 0x3001df3f +2502 3001e0ea e88cf10100 calll 0x3003d27b _CFAbsoluteTimeGetCurrent +2507 3001e0ef dd5d80 fstpl 0x80(%ebp) +2510 3001e0f2 f20f104580 movsd 0x80(%ebp),%xmm0 +2515 3001e0f7 c744242000000000 movl $0x00000000,0x20(%esp,1) +2523 3001e0ff 8b83eefc0100 movl 0x0001fcee(%ebx),%eax +2529 3001e105 8944241c movl %eax,0x1c(%esp,1) +2533 3001e109 c744241800000000 movl $0x00000000,0x18(%esp,1) +2541 3001e111 c744241400000000 movl $0x00000000,0x14(%esp,1) +2549 3001e119 c744240c00000000 movl $0x00000000,0x0c(%esp,1) +2557 3001e121 c744241000000000 movl $0x00000000,0x10(%esp,1) +2565 3001e129 f20f58833b580100 addsd 0x0001583b(%ebx),%xmm0 +2573 3001e131 f20f11442404 movsd %xmm0,0x04(%esp,1) +2579 3001e137 c7042400000000 movl $0x00000000,(%esp,1) +2586 3001e13e e806f10100 calll 0x3003d249 _CFRunLoopTimerCreate +2591 3001e143 89c7 movl %eax,%edi +2593 3001e145 8b83fafc0100 movl 0x0001fcfa(%ebx),%eax +2599 3001e14b 8b30 movl (%eax),%esi +2601 3001e14d e870f00100 calll 0x3003d1c2 _CFRunLoopGetCurrent +2606 3001e152 89742408 movl %esi,0x08(%esp,1) +2610 3001e156 897c2404 movl %edi,0x04(%esp,1) +2614 3001e15a 890424 movl %eax,(%esp,1) +2617 3001e15d e841f10100 calll 0x3003d2a3 _CFRunLoopAddTimer +2622 3001e162 e912faffff jmpl 0x3001db79 +2627 3001e167 8b83038f0100 movl 0x00018f03(%ebx),%eax +2633 3001e16d 89442404 movl %eax,0x04(%esp,1) +2637 3001e171 8b83076f0100 movl 0x00016f07(%ebx),%eax +2643 3001e177 890424 movl %eax,(%esp,1) +2646 3001e17a e886ee0100 calll 0x3003d005 _objc_msgSend +2651 3001e17f 8d93b72d0100 leal 0x00012db7(%ebx),%edx +2657 3001e185 89542404 movl %edx,0x04(%esp,1) +2661 3001e189 890424 movl %eax,(%esp,1) +2664 3001e18c e8eff00100 calll 0x3003d280 _BIO_new_file +2669 3001e191 89c6 movl %eax,%esi +2671 3001e193 c744240c00000000 movl $0x00000000,0x0c(%esp,1) +2679 3001e19b c744240800000000 movl $0x00000000,0x08(%esp,1) +2687 3001e1a3 c744240400000000 movl $0x00000000,0x04(%esp,1) +2695 3001e1ab 890424 movl %eax,(%esp,1) +2698 3001e1ae e8aff00100 calll 0x3003d262 _PEM_read_bio_PUBKEY +2703 3001e1b3 8983036f0100 movl %eax,0x00016f03(%ebx) +2709 3001e1b9 893424 movl %esi,(%esp,1) +2712 3001e1bc e8b0f00100 calll 0x3003d271 _BIO_free +2717 3001e1c1 e985f9ffff jmpl 0x3001db4b +2722 3001e1c6 8b5594 movl 0x94(%ebp),%edx +2725 3001e1c9 891424 movl %edx,(%esp,1) +2728 3001e1cc e8da36feff calll _licenseInit +2733 3001e1d1 e9dcf6ffff jmpl 0x3001d8b2 +2738 3001e1d6 8b4594 movl 0x94(%ebp),%eax +2741 3001e1d9 890424 movl %eax,(%esp,1) +2744 3001e1dc e8ca36feff calll _licenseInit +2749 3001e1e1 e961f7ffff jmpl 0x3001d947 +2754 3001e1e6 8b83038f0100 movl 0x00018f03(%ebx),%eax +2760 3001e1ec 89442404 movl %eax,0x04(%esp,1) +2764 3001e1f0 8b83076f0100 movl 0x00016f07(%ebx),%eax +2770 3001e1f6 890424 movl %eax,(%esp,1) +2773 3001e1f9 e807ee0100 calll 0x3003d005 _objc_msgSend +2778 3001e1fe 8d93b72d0100 leal 0x00012db7(%ebx),%edx +2784 3001e204 89542404 movl %edx,0x04(%esp,1) +2788 3001e208 890424 movl %eax,(%esp,1) +2791 3001e20b e870f00100 calll 0x3003d280 _BIO_new_file +2796 3001e210 89c6 movl %eax,%esi +2798 3001e212 c744240c00000000 movl $0x00000000,0x0c(%esp,1) +2806 3001e21a c744240800000000 movl $0x00000000,0x08(%esp,1) +2814 3001e222 c744240400000000 movl $0x00000000,0x04(%esp,1) +2822 3001e22a 890424 movl %eax,(%esp,1) +2825 3001e22d e830f00100 calll 0x3003d262 _PEM_read_bio_PUBKEY +2830 3001e232 8983036f0100 movl %eax,0x00016f03(%ebx) +2836 3001e238 893424 movl %esi,(%esp,1) +2839 3001e23b e831f00100 calll 0x3003d271 _BIO_free +2844 3001e240 e908fdffff jmpl 0x3001df4d +2849 3001e245 8b5594 movl 0x94(%ebp),%edx +2852 3001e248 891424 movl %edx,(%esp,1) +2855 3001e24b e85b36feff calll _licenseInit +2860 3001e250 e9cef5ffff jmpl 0x3001d823 +2865 3001e255 8b5594 movl 0x94(%ebp),%edx +2868 3001e258 891424 movl %edx,(%esp,1) +2871 3001e25b e84b36feff calll _licenseInit +2876 3001e260 e945f7ffff jmpl 0x3001d9aa +2881 3001e265 8b4594 movl 0x94(%ebp),%eax +2884 3001e268 890424 movl %eax,(%esp,1) +2887 3001e26b e83b36feff calll _licenseInit +2892 3001e270 e998f7ffff jmpl 0x3001da0d Resume of all this code: First there is a check for invalid key flag, then anti debugging is activated. Next the current en0 mac address is retrieved and the fun starts. The site licence part can be ignored. Next we have a bunch of fields being digested and compared against a null value. This could be used to make sure required fields are filled. After this, a new digest will be created and a bunch of fields hashed. The result is then compared against the licenseSum field. If they match, then licence is valid, else something was tampered with and licence is invalid. To create a keygen, we just need to hash the required fields with the correct order and sign with our private key, and then replace licenseSum with ours. licenseSum is base64 encoded. Keygen is simple as this :) 8) The missing protection in MultiDesktop plugin ------------------------------------------------ After creating the keygen, the verify routine would be passed without any problem but the program would exit right after... Something else was being verified and shutting down the program. That could only mean another check or something wrong with the keygen. I lost some time trying to find where the problem was. Traced lots of code from YSCommon and main program, and couldn't find anything there related to this. The only thing I could see was some kind of timer being activated, because program would exit in different places while I was tracing it. After a few tries, I decided to grep all the files, searching for License functions. I found this call checkModuleLicenses in YouControlDesktopsEngine binary. To see if this is correct, trace the return value from this call with a good licence file and with our generated licence file. The result is diferent, meaning this is the right place! +996 0000c217 c744240835000000 movl $0x00000035,0x08(%esp,1) '5' +1004 0000c21f 8b15a84a0100 movl 0x00014aa8,%edx checkModuleLicenses: <- on phoenix framework +1010 0000c225 89542404 movl %edx,0x04(%esp,1) +1014 0000c229 890424 movl %eax,(%esp,1) +1017 0000c22c e8836e0000 calll 0x000130b4 -[(%esp,1) checkModuleLicenses:] +1022 0000c231 85c0 testl %eax,%eax <- original returns 1, keygen returns 0 !! +1024 0000c233 0f842b010000 jel 0x0000c364 <- jump and terminate !!! In the main program, if this jump isn't called, engine loads with no problems: (...) +1990 00006aaa 890424 movl %eax,(%esp,1) +1993 00006aad e8b3550000 calll 0x0000c065 -[(%esp,1) connectWithTimeout:] <- fails here when check fails +1998 00006ab2 84c0 testb %al,%al +2000 00006ab4 7442 je 0x00006af8 <- if timeout then jump <- nop this and the engine goes ok ! +2002 00006ab6 a120d30000 movl 0x0000d320,%eax checkServerVersion +2007 00006abb 89442404 movl %eax,0x04(%esp,1) But with this, we still haven't cracked everything, because when we try to launch configuration it fails giving a no licence error. We are still missing some check(s). Zen cracking to the rescue again... I tried to grep everything in the application dir for "signature", hoping to find something. And voila, we have one result at: You Control Desktops.app/Contents/PlugIns/MultiDesktopModule.plugin/Contents/Resources inside the file MultiDesktopModule.plist Check the file and you have this inside: (...) YSModuleSignature Vrtnw/a7vHvCYwB4y/1IAaMrvaK7oaIDfW2giJgCztrNDBEf15xIpdwje1sCCKMmIaTS BuUJPw+zKfCmA9vXCbmbvLJ1M6ijKk6Or0VaNuFi5O8vEa6cfvPWsptrjnxZvrMqGO8X sgcnvoTMcwgmJ+HGVB71w+EBfKbNgg3un8h29PoUcGKtl+Ibpu4ngh9E6PISTl1zDpxs pP7CARdUXFCRGF47Nko8uJSvTC8zxR8QFDpNGdz4R0GCsUScSka7suLChYMYisRFrSPd t6XGzFl1qroHIpzgmwYFbUuQ+DucpHNaeKjkiWixvZL4Gw/w4NrbJYhqln8u2xaZWQ36 bw== (...) There must be a piece of code searching for YSModuleSignature dictionary key. Grep the disassembled files and you find it here in PhoenixFramework file PhoenixFramework: -(BOOL)[YSPluginMgr validateModuleConfig:] +0 3fffbadf 55 pushl %ebp +1 3fffbae0 89e5 movl %esp,%ebp +3 3fffbae2 57 pushl %edi +4 3fffbae3 56 pushl %esi +5 3fffbae4 53 pushl %ebx +6 3fffbae5 83ec3c subl $0x3c,%esp +9 3fffbae8 e8bbeb0100 calll ___i686.get_pc_thunk.bx +14 3fffbaed 8b7510 movl 0x10(%ebp),%esi +17 3fffbaf0 8b83ebf50100 movl 0x0001f5eb(%ebx),%eax YSModuleSignature <- key +23 3fffbaf6 89442408 movl %eax,0x08(%esp,1) +27 3fffbafa 8b8347330200 movl 0x00023347(%ebx),%eax objectForKey: +33 3fffbb00 89442404 movl %eax,0x04(%esp,1) +37 3fffbb04 893424 movl %esi,(%esp,1) <- dictionary from MultiDesktop.plist +40 3fffbb07 e8fe140200 calll 0x4001d00a -[(%esp,1) objectForKey:] (...) +251 3fffbbda e83d160200 calll 0x4001d21c _licenseSignatureIsValid <- What we look for :) +256 3fffbbdf 83c43c addl $0x3c,%esp <- eax holds 1 when licence is valid ! (...) This function is called from Phoenix framework at 0x3fffc237 ( activateModuleInBundle:config:), which is called from activatePlugin (0x3fffc698), and then from activatePlugins (0x3fffba57), starting at load (0x3fffb8fa). Load is called from YouControlDesktopEngine at: +784 0000c143 89442404 movl %eax,0x04(%esp,1) <- load +788 0000c147 893c24 movl %edi,(%esp,1) +791 0000c14a e8656f0000 calll 0x000130b4 -[(%esp,1) load] We just need to calculate the new checksum for the module file. To trace the licenseSignatureIsValid is what we need :) 8.1) Tracing licenseSignatureIsValid This function is located in YSCommon and it's very easy and short to understand. _licenseSignatureIsValid: +0 300033d8 55 pushl %ebp +1 300033d9 89e5 movl %esp,%ebp +3 300033db 57 pushl %edi +4 300033dc 56 pushl %esi +5 300033dd 53 pushl %ebx +6 300033de 83ec2c subl $0x2c,%esp +9 300033e1 e87ef90200 calll ___i686.get_pc_thunk.bx +14 300033e6 e8739d0300 calll 0x3003d15e _EVP_sha1 +19 300033eb 89442404 movl %eax,0x04(%esp,1) +23 300033ef 8d7dd8 leal 0xd8(%ebp),%edi +26 300033f2 893c24 movl %edi,(%esp,1) +29 300033f5 e85f9d0300 calll 0x3003d159 _EVP_DigestInit +34 300033fa 8b450c movl 0x0c(%ebp),%eax +37 300033fd 89442408 movl %eax,0x08(%esp,1) <- cnt +41 30003401 8b4508 movl 0x08(%ebp),%eax +44 30003404 89442404 movl %eax,0x04(%esp,1) <- pointer to data, which is: "YSMultiDesktopModule 0" +48 30003408 893c24 movl %edi,(%esp,1) <- ctx +51 3000340b e8039d0300 calll 0x3003d113 _EVP_DigestUpdate ---------------------------------------------------------------------------------------------------------- int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt); ---------------------------------------------------------------------------------------------------------- +56 30003410 8b8352120300 movl 0x00031252(%ebx),%eax +62 30003416 85c0 testl %eax,%eax +64 30003418 743a je 0x30003454 +66 3000341a 8b8352120300 movl 0x00031252(%ebx),%eax +72 30003420 8944240c movl %eax,0x0c(%esp,1) <- pkey +76 30003424 8b4514 movl 0x14(%ebp),%eax +79 30003427 89442408 movl %eax,0x08(%esp,1) <- siglen +83 3000342b 8b4510 movl 0x10(%ebp),%eax +86 3000342e 89442404 movl %eax,0x04(%esp,1) <- sigbuf +90 30003432 893c24 movl %edi,(%esp,1) <- ctx +93 30003435 e84b9e0300 calll 0x3003d285 _EVP_VerifyFinal ---------------------------------------------------------------------------------------------------------- int EVP_VerifyFinal(EVP_MD_CTX *ctx,unsigned char *sigbuf, unsigned int siglen,EVP_PKEY *pkey); ---------------------------------------------------------------------------------------------------------- +98 3000343a 89c6 movl %eax,%esi +100 3000343c 893c24 movl %edi,(%esp,1) +103 3000343f e8249d0300 calll 0x3003d168 _EVP_MD_CTX_cleanup +108 30003444 31c0 xorl %eax,%eax +110 30003446 83fe01 cmpl $0x01,%esi +113 30003449 0f94c0 sete %al +116 3000344c 83c42c addl $0x2c,%esp +119 3000344f 5b popl %ebx +120 30003450 5e popl %esi +121 30003451 5f popl %edi +122 30003452 5d popl %ebp +123 30003453 c3 ret +124 30003454 8b8352320300 movl 0x00033252(%ebx),%eax UTF8String +130 3000345a 89442404 movl %eax,0x04(%esp,1) +134 3000345e 8b8356120300 movl 0x00031256(%ebx),%eax +140 30003464 890424 movl %eax,(%esp,1) +143 30003467 e8999b0300 calll 0x3003d005 -[(%esp,1) UTF8String] +148 3000346c 8d9306d10200 leal 0x0002d106(%ebx),%edx r +154 30003472 89542404 movl %edx,0x04(%esp,1) +158 30003476 890424 movl %eax,(%esp,1) +161 30003479 e8029e0300 calll 0x3003d280 _BIO_new_file +166 3000347e 89c6 movl %eax,%esi +168 30003480 c744240c00000000 movl $0x00000000,0x0c(%esp,1) +176 30003488 c744240800000000 movl $0x00000000,0x08(%esp,1) +184 30003490 c744240400000000 movl $0x00000000,0x04(%esp,1) +192 30003498 890424 movl %eax,(%esp,1) +195 3000349b e8c29d0300 calll 0x3003d262 _PEM_read_bio_PUBKEY +200 300034a0 898352120300 movl %eax,0x00031252(%ebx) +206 300034a6 893424 movl %esi,(%esp,1) +209 300034a9 e8c39d0300 calll 0x3003d271 _BIO_free +214 300034ae e967ffffff jmpl 0x3000341a +219 300034b3 90 nop As we can see, the only thing being hashed is the string "YSMultiDesktopModule 0". Keygen must calculate this digest and sign with our private key. Nothing else needed... 9) Serial number ---------------- The serial number isn't tied to the expiration date ! If we try to modify the expiration date for the same serial number, program will run fine. 10) Recommendations ------------------- Altough ptrace is easy to beat, calling it near interesting code isn't a good idea, because that signals the attacker something interesting is due to happen. Another important mistake was the inclusion of header files in the final package. I think this was a mistake, but a costly one. And finally, public key must be more protected. Altough it's always possible to beat this scheme, public key checksum was easily findable, making things much easier to beat. For example, the checksum could be obfuscated by some complex algorithm, making it harder to find by a simple search. 11) The end ----------- We have reached the end of this long tutorial. Keygen was created, keys replaced and a few bytes patched. It's not easy to write such a long tutorial about reverse engineering after many ideas and notes. I have tried my best to make things clear and understandable. Once again, while all this information can be used to release a cracked version, that's not my intention. I got challenged about it's protection and tried to beat it to improve my knowledge about Mac OS X reversing. I hope you can gain something from it. I would recommend "reg.yousoftware.com" added to /etc/hosts and pointing to 127.0.0.1 or else firewall it and don't let it connect there :) Thanks, fG!