seoxys.com» Apple http://www.seoxys.com Sun, 30 Sep 2012 22:34:18 +0000 en hourly 1 http://wordpress.org/?v=3.0.1 The Sorry State of Apple Developer Relations http://www.seoxys.com/the-sorry-state-of-apple-developer-relations/ http://www.seoxys.com/the-sorry-state-of-apple-developer-relations/#comments Wed, 23 Sep 2009 19:54:42 +0000 kenneth http://www.seoxys.com/?p=229 iLaugh disappeared from the App Store about a week ago. My contract expired last week.

I had been trying to renew the contract through the Apple Store for over a month now. However, I initially signed up through the Swiss Apple Store, and that is the only store it will let me use.

The French Swiss store is broken, and will not work at all. The German Swss store works, but will only accept a Swiss credit card. Thankfully, I do have one, but for some obscure reason, it throws an “unexpected error” every time I try to use it. It won’t let me use my US Bank of America cards at all.

I’ve called and emailed Apple’s support team many times. Yet all they tell me is that they’ll forward it to some other team, which will (after waiting another week) email me proposing that I try “emptying my browser’s cache.”

I’m kind of unsure about what to do now. With every day that passes, I miss out on a substantial amount of money. Not only that, but not having the App in the Store causes many other problems, such as breaking links from my website, and more…

]]>
http://www.seoxys.com/the-sorry-state-of-apple-developer-relations/feed/ 1
Apple’s Increasingly Ridiculous Rejections http://www.seoxys.com/apples-increasingly-ridiculous-rejections/ http://www.seoxys.com/apples-increasingly-ridiculous-rejections/#comments Thu, 11 Jun 2009 23:40:39 +0000 kenneth http://www.seoxys.com/?p=195 Three months ago, I submitted an update to iLaugh and iLaugh Lite, numbered 1.1.1 that fixed many bugs but didn’t change anything to the functionality of the app.

Today, after three whole months in review (seriously, I’m not making this up!), they decided to finally tackle the issue and issue me a rejection for no other reason other than “because we said so.”

See for yourself.

Please note, this is for iLaugh 1.1.1. iLaugh 2.0 is still in review, as a new application, and there’s no reason it should be rejected. In fact, the premium edition has already been approved and is already live on the App Store.

Speaking of iLaugh 2.0 – the first public screenshot ever:

]]>
http://www.seoxys.com/apples-increasingly-ridiculous-rejections/feed/ 37
On The App Store Hype http://www.seoxys.com/on-the-app-store-hype/ http://www.seoxys.com/on-the-app-store-hype/#comments Sat, 30 May 2009 17:05:47 +0000 kenneth http://www.seoxys.com/?p=189 A while back, TechCrunch covered yet another article complaining about the App Store being more of a Lotto than a marketplace. Setting aside the App Store’s numerous other issues, coverage of iPhone app developers has been divided into two extremes: reassuring yet unlikely success stories, or depressing yet much more likely failure stories.

The general question in all of these articles is: “Can an average guy become a successful iPhone developer?”. The answer depends on how you define success, and on that topic I can speak from my own experience.

If, to you, success means making a million bucks overnight you will most likely be unsuccessful. To me, success is defined as the return on my investment (both in time and money) on the project. In my previous article, I mentioned making somewhere around a hundred dollars a day on iLaugh. However, I didn’t mention how much I invested in the project.

The first version of iLaugh and its subsequent revisions took me very little time to create. I estimate that I invested between ten to twenty hours of my time to create iLaugh 1.0. At my asking rate of $100 per hour, that represents a $1,000 to $2,000 investment. The server running the first iteration of the iLaugh API cost me about $100 per month to maintain.

If you look at the numbers for iLaugh from previous months, I make over $3,000 monthly (for a total of over $8,000 so far). Thus, I consider it a success.

Many people, in response to my previous article, said that I too, was one of the lucky ones, albeit on a smaller scale. And while that may be true, considering the low quality of that first iteration of iLaugh, a more carefully crafted app would likely have done better.

I believe the potential for success is relative to the investment put into anything.

If you look at the familiar success stories, many of them involve reinvestment and good marketing. For instance, Tapulous hit the jackpot with their Tap Tap games. Being good friends with one of their employees, I know exactly how much work goes into their production.

Perhaps one of the most talked-about success stories is Trism. Its developer, Steve Demeter, made an insane $250,000 in just two months. What I believe is the key to Steve’s long-term success, is that instead of buying a fancy sports car, he reinvested his money into founding a sustainable business.

Part of reinvesting, and a facet of development often ignored, are things that a typical developer can’t do. Most importantly: design, copywriting and marketing. These are things that will most likely have to be outsourced. Developers are reluctant to do that, because it’s very costly, but in the end, ignoring it is going to cost them the popularity of their application.

I view iLaugh 1.x as a catalyst towards bigger and, hopefully, even more successful endeavors.

In fact, I have already put a big part of my (in comparison to the numbers above, quite mediocre) earnings into the second iteration of iLaugh. I’ve hired a bunch of people much more talented than I am in their respective fields, and iLaugh 2.0 is coming along really nicely. It will be entirely different and nearly incomparable to the first iteration. There are some very cool things coming.

So, responding to my initial question: “Can an average guy become a successful iPhone developer?”. Yes! An average developer can be successful in the App Store. But it takes hard work, a lot of time, money, and perseverance.

]]>
http://www.seoxys.com/on-the-app-store-hype/feed/ 3
How Genius is a Genius Business Model http://www.seoxys.com/how-genius-is-a-genius-business-model/ http://www.seoxys.com/how-genius-is-a-genius-business-model/#comments Tue, 31 Mar 2009 15:34:45 +0000 kenneth http://www.seoxys.com/?p=145 Apple’s introduction of Genius into iTunes may have been one of the best business decisions they ever made.

First, it’s a great feature for the user. It’s a joy to just chose a beloved track, and instantly get plenty more of that awesomeness. I’ve been a great fan of Genius myself, and I use it all the time. It’s also great when picking out tracks for a DJ set.

But what probably goes unnoticed by the general public is the staggering amounts of money Apple will be able to make of this. They will own the data to what millions of people are listening to. They’ll have direct access to millions of people’s tastes, likes, dislikes. Many companies would kill for such data, and I wouldn’t be surprised if the labels were prepared to pay big for such statistics.

Additionally, Apple is using genius to sell more music on the iTunes Store through the sidebar. The iTunes Store is already the biggest music retailer in the US, but with Genius, it’ll only sell even more music to the people already buying music on the store.

And lastly, Apple could sell promotions for artists who want more exposure for their music. Since Apple controls what users are exposed to / listen to when they’re in Genius, they can now push an artist more often in their user’s Genius lists, and thus give the user the impression and the feeling of liking the music. They can thus manipulate the user’s tastes, and I’m willing to bet that many record labels would pay big money for that kind of exposure.

]]>
http://www.seoxys.com/how-genius-is-a-genius-business-model/feed/ 0
App Store = Paperwork Nightmare http://www.seoxys.com/app-store-paperwork-nightmare/ http://www.seoxys.com/app-store-paperwork-nightmare/#comments Wed, 24 Sep 2008 13:16:29 +0000 kenneth http://www.seoxys.com/?p=92 [Note: I hope this article doesn’t break the NDA, but if it find out it does and I get a Cease & Desist from Apple, I will have to take it down.]

When you upload an iPhone application to the App Store through iTunes Connect, you’re presented with a few screens of information to fill in. First, there’s the screen where you put the Application’s description, category, and any other textual information about it.

Then there’s the screen where you upload the binary, the icon(s), and screenshots. And lastly there’s a screen to set the price. Unlike what I thought would be the case, you cannot chose a specific price. You get to chose from several price groups. A price group has a price in US Dollars, and a price in different currencies usually of a similar value. (For example, a $0.99 app in Switzerland is CHF 1.10)

At the top of this page, there is a little warning message that says you need a contract with Apple if you’re going to put up non-free apps. I did not pay too much attention to it, and the rest of the process seemed to go smoothly, eventually leading back to a page where I could see my app was “In Review”.

I was still slightly confused about this contract message, and decided to find out what it was about. I asked a few fellow developers, and found out that Apple would not sell my app until the contract was taken care of.

In iTunes Connect, there is a section on contracts, with a link to create a new contract. A contract is made of three parts; Contact Details, Banking Details and Tax Details.

  • Contact Details

    This is very straightforward. I just had to fill in my full contact details. (Including physical address.)

  • Banking Details

    This is slightly more complicated. I’m with one of the smaller Swiss banks, and I wanted to use this account for my App Store revenue.

    One of the things Apple requires is a SWIFT code. Luckily, I’m with a Swiss bank, and these tend to be very professional. I just had to give my bank a phone call, and I had my SWIFT code. However, after reading a recent topic on the MacSB mailing list, it appears to be very common for many of the smaller banks in the US and other countries not to have SWIFT codes. In which case you’re screwed and you’ll have to open a new account with a bank that has a SWFT code. (Apple recommends Bank of America.)

    Another thing required by Apple is the IBAN. International Bank Account Number. My bank informed me that they printed these on all the bank statements they issued. However, I didn’t have any bank statement around. It wasn’t too hard getting this number. Switzerland has a standardized way of building these numbers from your CB Number (Clearing Banquaire - this is what we call Branch IDs) and your account number. A handy little script I found on the web would take this info and convert it into an IBAN. (I later found one of my Bank statements, and the IBAN generated did indeed match the one on the statement).

    Apple also asked for the Branch ID (I put my CB number for this) and account number, and another number called the SIC / Short Code. I researched it a bit, and it looks like I didn’t need it. I just left that field blank.

  • Tax Details

    This is where it gets nasty. Note that this is not an Apple thing, this is government tax regulation. Apple provides an online version of the government form W-8BEN. It seems I am not obligated to fill this form in, but if I don’t, Apples keeps another 30% of my revenue as anticipated taxes. This, with the 30% commission they take from every sale, leaves me with only 49% of my gross sales. (70% * 70% = 49%)

    This form is extremely cryptic, and I filled it in to the best of my knowledge. This, however, wasn’t enough for Apple. The form complained about missing information. It’s only then that I realized that Apple provides a handy tip sheet explaining how to fill the form in, and what are the most common answers.

    With this information, I was able to understand and fill in most of the form. Except for one field: Taxpayer Identification Number. Since I’m not a US resident (although I’m eligible for citizenship by blood, and plan to apply soon), I did not have this information. Apple’s tip sheet luckily had a small paragraph regarding this. An EIN (Employer Identification Number) would do. To get an EIN, I had to download another form entitled SS-4.

    This form was even more cryptic than the previous one. It is obviously made for more traditional companies, and had questions asking how many employees I have in different field, how much wages I paid them, where and when my company was incorporated, and a bunch of other tax-related questions. It also asked a few things I couldn’t fill in, such as my SSN (Social Security Number - I don’t have one). I phoned the IRS (Internal Revenue Service) - the government entity I had to submit the form to - and it turned out this field wasn’t necessary. In response to the question “Check one box that best describes the principal activity of your business”, there of course wasn’t anything about technology. I had to tick “Other (specify)” and enter “Royalties”.

    There is three way you can submit the form. Firstly, you can do it the traditional way of mailing it by post. But this would take a minimum of 4 weeks. Second way would be by fax, but this would also take at least 1 week. The third way is actually pretty clever. You fax while you’re on the phone.

    Problem: my phone and my fax are on the same phone line. Meaning I can’t do both at the same time. I do have a cellphone, but phoning oversees for a good half hour at least from a cellphone would be so outrageously expensive it didn’t make any sense. Luckily, I though of a brilliant idea, and opened a Skype Out account. The audio quality wasn’t very good, but at least it worked. After another hour of phoning, I finally had my EIN and could submit the W-8BEN form to Apple.

Everything seems to be in order as of now. My app is still in review, but expect it in the app store soon.

]]>
http://www.seoxys.com/app-store-paperwork-nightmare/feed/ 9
NanoLifeSaver http://www.seoxys.com/nanolifesaver/ http://www.seoxys.com/nanolifesaver/#comments Sat, 23 Feb 2008 23:06:43 +0000 kenneth http://www.seoxys.com/nanolifesaver/ I bring to you, NanoLifeSaver.

NanoLifeSaver is a slick Core Animation screensaver.


(This last one is a movie, Click to Play)

Download NanoLifeSaver

Credit goes to Scott Stevenson for coming up with the original animation code.

]]>
http://www.seoxys.com/nanolifesaver/feed/ 10
R.I.P. Hijack http://www.seoxys.com/rip-hijack/ http://www.seoxys.com/rip-hijack/#comments Fri, 22 Feb 2008 14:27:05 +0000 kenneth http://www.seoxys.com/rip-hijack/ Disappointingly, codename: Hijack / Spool is no more.

I have posted about this project before, and it was really something I was excited about.

Back in the day where I actually had time, I was a forum freak and was active in more than 10 forums… This would have been the dream app for me.

Unfortunately, Hijack has just been open-sourced. Which means that the project is essentially dead.

]]>
http://www.seoxys.com/rip-hijack/feed/ 2
Hacking mac apps: Direct Mail http://www.seoxys.com/hacking-mac-apps-direct-mail-archive/ http://www.seoxys.com/hacking-mac-apps-direct-mail-archive/#comments Tue, 18 Dec 2007 23:02:36 +0000 kenneth http://www.seoxys.com/2007/12/19/hacking-mac-apps-direct-mail/ Update: I rewrote this post with better language and better explanations. Please read the newer version first.

In this post, I will describe how to hack a mac shareware app.

The reason for this is to push the developers to create stronger protection, and to show common weaknesses in licensing code.

Before each hack is published, I get the concerned developer’s approval, and send them a note describing the hack, and suggesting ways to improve their protection. I also leave them some time to patch their app before I publish the hack.

I have no intention of promoting piracy, and this not meant to be used as a guide for would-be pirates to get those for free. What follows if of highly technical nature, and is intended for fellow developers.

Today is up: Direct Mail, a great app from e3 software useful for anyone doing mailing lists or press releases.

I did this hack on version 1.8.3, because it isn’t the latest.

First thing to do, is to class-dump the executable, which results in an interesting find:

@interface CAppDelegate : NSObject
{
    BOOL _registered;   // 4 = 0x4
    NSString *_registeredName;  // 8 = 0x8
    SUUpdater *sparkleUpdater;  // 12 = 0xc
}

+ (id)sharedDelegate;
+ (void)applyIconsToChangeStatusMenu:(id)fp8;
- (id)init;
- (BOOL)registered;
- (id)registeredName;
- (void)setRegisteredName:(id)fp8;
- (BOOL)validateMenuItem:(id)fp8;
- (void)loadRegistration;
- (BOOL)isValidCode:(id)fp8 forName:(id)fp12;
- (void)saveRegistrationCode:(id)fp8 forName:(id)fp12;
- (id)sparkleUpdater;
- (void)doPrefs:(id)fp8;
- (void)doRegister:(id)fp8;
- (void)doPurchase:(id)fp8;
- (BOOL)alertShowHelp:(id)fp8;
- (void)doAbout:(id)fp8;
- (void)doReportBug:(id)fp8;
- (void)doConnectionDoctor:(id)fp8;
- (void)openAppWebsite;
- (void)openRegisterWebsite;
- (void)runKRM;
- (id)lookupKagiAffiliate;
- (void)showPurchaseThankYou:(id)fp8;
- (void)showFirstRunAlert;
- (void)applicationWillFinishLaunching:(id)fp8;
- (void)applicationDidFinishLaunching:(id)fp8;
- (BOOL)crashReporterShouldDisplayException:(id)fp8;

@end

Now, there’s different ways to hack this. You could just edit the ivar _registered upon launch. Other option would be to hack registered or isValidCode:forName: to always return true.

I’m going to go with a slightly more complicated way, and hack the methods which call isValidCode:forName:.

Let’s set a breakpoint when isValidCode is called. Disassemble the whole thing, and check where isValidCode:forName: is called. For me, it returns at 0x00008fdc. Run. It hits the breakpoint immediately. Continue once, to let it finish its setting up etc. Now, using the app, go to the register menu and try to register (with a properly-formatted email-address). It will hit the breakpoint again. Do a nexti. You now are in “0x0002ffb7 in -[CRegisterPanelController doOK:] ()”

Let’s disassemble this method:

0x0002ff50 <-[CRegisterPanelController doOK:]+0>: push %ebp
0x0002ff51 <-[CRegisterPanelController doOK:]+1>: mov %esp,%ebp
0x0002ff53 <-[CRegisterPanelController doOK:]+3>: push %edi
0x0002ff54 <-[CRegisterPanelController doOK:]+4>: push %esi
0x0002ff55 <-[CRegisterPanelController doOK:]+5>: push %ebx
0x0002ff56 <-[CRegisterPanelController doOK:]+6>: sub $0x1c,%esp
0x0002ff59 <-[CRegisterPanelController doOK:]+9>: mov 0x8(%ebp),%edi
0x0002ff5c <-[CRegisterPanelController doOK:]+12>: mov 0x22091c,%eax
0x0002ff61 <-[CRegisterPanelController doOK:]+17>: mov %eax,0x4(%esp)
0x0002ff65 <-[CRegisterPanelController doOK:]+21>: mov 0x221fa4,%eax
0x0002ff6a <-[CRegisterPanelController doOK:]+26>: mov %eax,(%esp)
0x0002ff6d <-[CRegisterPanelController doOK:]+29>: call 0x21f395 <dyld_stub_objc_msgSend>
0x0002ff72 <-[CRegisterPanelController doOK:]+34>: mov %eax,%esi
0x0002ff74 <-[CRegisterPanelController doOK:]+36>: mov 0xc(%edi),%edx
0x0002ff77 <-[CRegisterPanelController doOK:]+39>: mov 0x221428,%eax
0x0002ff7c <-[CRegisterPanelController doOK:]+44>: mov %eax,0x4(%esp)
0x0002ff80 <-[CRegisterPanelController doOK:]+48>: mov %edx,(%esp)
0x0002ff83 <-[CRegisterPanelController doOK:]+51>: call 0x21f395 <dyld_stub_objc_msgSend>
0x0002ff88 <-[CRegisterPanelController doOK:]+56>: mov %eax,%ebx
0x0002ff8a <-[CRegisterPanelController doOK:]+58>: mov 0x8(%edi),%edx
0x0002ff8d <-[CRegisterPanelController doOK:]+61>: mov 0x221428,%eax
0x0002ff92 <-[CRegisterPanelController doOK:]+66>: mov %eax,0x4(%esp)
0x0002ff96 <-[CRegisterPanelController doOK:]+70>: mov %edx,(%esp)
0x0002ff99 <-[CRegisterPanelController doOK:]+73>: call 0x21f395 <dyld_stub_objc_msgSend>
0x0002ff9e <-[CRegisterPanelController doOK:]+78>: mov %ebx,0xc(%esp)
0x0002ffa2 <-[CRegisterPanelController doOK:]+82>: mov %eax,0x8(%esp)
0x0002ffa6 <-[CRegisterPanelController doOK:]+86>: mov 0x22084c,%eax
0x0002ffab <-[CRegisterPanelController doOK:]+91>: mov %eax,0x4(%esp)
0x0002ffaf <-[CRegisterPanelController doOK:]+95>: mov %esi,(%esp)
0x0002ffb2 <-[CRegisterPanelController doOK:]+98>: call 0x21f395 <dyld_stub_objc_msgSend>
0x0002ffb7 <-[CRegisterPanelController doOK:]+103>: test %al,%al
0x0002ffb9 <-[CRegisterPanelController doOK:]+105>: jne 0x2ffc7 <-[CRegisterPanelController doOK:]+119>
0x0002ffbb <-[CRegisterPanelController doOK:]+107>: add $0x1c,%esp
0x0002ffbe <-[CRegisterPanelController doOK:]+110>: pop %ebx
0x0002ffbf <-[CRegisterPanelController doOK:]+111>: pop %esi
0x0002ffc0 <-[CRegisterPanelController doOK:]+112>: pop %edi
0x0002ffc1 <-[CRegisterPanelController doOK:]+113>: pop %ebp
0x0002ffc2 <-[CRegisterPanelController doOK:]+114>: jmp 0x21f444 <dyld_stub_NSBeep>
0x0002ffc7 <-[CRegisterPanelController doOK:]+119>: mov 0x22091c,%eax
0x0002ffcc <-[CRegisterPanelController doOK:]+124>: mov %eax,0x4(%esp)
0x0002ffd0 <-[CRegisterPanelController doOK:]+128>: mov 0x221fa4,%eax
0x0002ffd5 <-[CRegisterPanelController doOK:]+133>: mov %eax,(%esp)
0x0002ffd8 <-[CRegisterPanelController doOK:]+136>: call 0x21f395 <dyld_stub_objc_msgSend>
0x0002ffdd <-[CRegisterPanelController doOK:]+141>: mov %eax,%esi
0x0002ffdf <-[CRegisterPanelController doOK:]+143>: mov 0xc(%edi),%edx
0x0002ffe2 <-[CRegisterPanelController doOK:]+146>: mov 0x221428,%eax
0x0002ffe7 <-[CRegisterPanelController doOK:]+151>: mov %eax,0x4(%esp)
0x0002ffeb <-[CRegisterPanelController doOK:]+155>: mov %edx,(%esp)
0x0002ffee <-[CRegisterPanelController doOK:]+158>: call 0x21f395 <dyld_stub_objc_msgSend>
0x0002fff3 <-[CRegisterPanelController doOK:]+163>: mov %eax,%ebx
0x0002fff5 <-[CRegisterPanelController doOK:]+165>: mov 0x8(%edi),%edx
0x0002fff8 <-[CRegisterPanelController doOK:]+168>: mov 0x221428,%eax
0x0002fffd <-[CRegisterPanelController doOK:]+173>: mov %eax,0x4(%esp)
0x00030001 <-[CRegisterPanelController doOK:]+177>: mov %edx,(%esp)
0x00030004 <-[CRegisterPanelController doOK:]+180>: call 0x21f395 <dyld_stub_objc_msgSend>
0x00030009 <-[CRegisterPanelController doOK:]+185>: mov %ebx,0xc(%esp)
0x0003000d <-[CRegisterPanelController doOK:]+189>: mov %eax,0x8(%esp)
0x00030011 <-[CRegisterPanelController doOK:]+193>: mov 0x220788,%eax
0x00030016 <-[CRegisterPanelController doOK:]+198>: mov %eax,0x4(%esp)
0x0003001a <-[CRegisterPanelController doOK:]+202>: mov %esi,(%esp)
0x0003001d <-[CRegisterPanelController doOK:]+205>: call 0x21f395 <dyld_stub_objc_msgSend>
0x00030022 <-[CRegisterPanelController doOK:]+210>: movl $0x219530,0x8(%esp)
0x0003002a <-[CRegisterPanelController doOK:]+218>: mov 0x220784,%eax
0x0003002f <-[CRegisterPanelController doOK:]+223>: mov %eax,0x4(%esp)
0x00030033 <-[CRegisterPanelController doOK:]+227>: mov 0x221fb4,%eax
0x00030038 <-[CRegisterPanelController doOK:]+232>: mov %eax,(%esp)
0x0003003b <-[CRegisterPanelController doOK:]+235>: call 0x21f395 <dyld_stub_objc_msgSend>
0x00030040 <-[CRegisterPanelController doOK:]+240>: mov 0x220780,%edx
0x00030046 <-[CRegisterPanelController doOK:]+246>: mov %edx,0x4(%esp)
0x0003004a <-[CRegisterPanelController doOK:]+250>: mov %eax,(%esp)
0x0003004d <-[CRegisterPanelController doOK:]+253>: call 0x21f395 <dyld_stub_objc_msgSend>
0x00030052 <-[CRegisterPanelController doOK:]+258>: mov 0x4(%edi),%edx
0x00030055 <-[CRegisterPanelController doOK:]+261>: mov 0x220900,%eax
0x0003005a <-[CRegisterPanelController doOK:]+266>: mov %eax,0xc(%ebp)
0x0003005d <-[CRegisterPanelController doOK:]+269>: mov %edx,0x8(%ebp)
0x00030060 <-[CRegisterPanelController doOK:]+272>: add $0x1c,%esp
0x00030063 <-[CRegisterPanelController doOK:]+275>: pop %ebx
0x00030064 <-[CRegisterPanelController doOK:]+276>: pop %esi
0x00030065 <-[CRegisterPanelController doOK:]+277>: pop %edi
0x00030066 <-[CRegisterPanelController doOK:]+278>: pop %ebp
0x00030067 <-[CRegisterPanelController doOK:]+279>: jmp 0x21f395 <dyld_stub_objc_msgSend>

We now are at this line: “0x0002ffb7 <-[CRegisterPanelController doOK:]+103>: test %al,%al”

That, in the right, is assembly code. This is basically some kind of “if” statement. (a TEST followed by a JNE (jump if not equal)).

What interests me is the next line: “0x0002ffb9 <-[CRegisterPanelController doOK:]+105>: jne 0x2ffc7 <-[CRegisterPanelController doOK:]+119>”

If we just reverse this test (turn the JNE into a JE (jump if equal)), any invalid code will be considered valid, and vice-versa. Let’s examine the memory for this statement.



(gdb) x/x 0x0002ffb9

0x2ffb9 <-[CRegisterPanelController doOK:]+105>: 0xc4830c75

Now, I’m working on a intel machine. And for some dumb reason, every block of four bytes is inverted. What this means, is that the byte that interests me is the rightmost one: 0x75. This is what a JNE looks like. Do some more tests by setting breakpoints until you find a JE, and read the memory for it: you will find that a JE is 0x74.

Let’s test if our theory is correct by editing the memory live, before we edit it in the binary. Do the following:



(gdb) set {char}0x0002ffb9=0x74
(gdb) x/x 0x0002ffb9
0x2ffb9 <-[CRegisterPanelController doOK:]+105>: 0xc4830c74
(gdb) disassemble 0x0002ffb7
Dump of assembler code for function -[CRegisterPanelController doOK:]:
[...edited out...]
0x0002ff99 <-[CRegisterPanelController doOK:]+73>: call 0x21f395
0x0002ff9e <-[CRegisterPanelController doOK:]+78>: mov %ebx,0xc(%esp)
0x0002ffa2 <-[CRegisterPanelController doOK:]+82>: mov %eax,0x8(%esp)
0x0002ffa6 <-[CRegisterPanelController doOK:]+86>: mov 0x22084c,%eax
0x0002ffab <-[CRegisterPanelController doOK:]+91>: mov %eax,0x4(%esp)
0x0002ffaf <-[CRegisterPanelController doOK:]+95>: mov %esi,(%esp)
0x0002ffb2 <-[CRegisterPanelController doOK:]+98>: call 0x21f395
0x0002ffb7 <-[CRegisterPanelController doOK:]+103>: test %al,%al
0x0002ffb9 <-[CRegisterPanelController doOK:]+105>: je 0x2ffc7 <-[CRegisterPanelController doOK:]+119>
0x0002ffbb <-[CRegisterPanelController doOK:]+107>: add $0x1c,%esp
0x0002ffbe <-[CRegisterPanelController doOK:]+110>: pop %ebx
0x0002ffbf <-[CRegisterPanelController doOK:]+111>: pop %esi
0x0002ffc0 <-[CRegisterPanelController doOK:]+112>: pop %edi
0x0002ffc1 <-[CRegisterPanelController doOK:]+113>: pop %ebp
0x0002ffc2 <-[CRegisterPanelController doOK:]+114>: jmp 0x21f444
0x0002ffc7 <-[CRegisterPanelController doOK:]+119>: mov 0x22091c,%eax
[...edited out...]
End of assembler dump.
(gdb)

Here we change the byte for the JNE, then test if we changed it correctly by re-reading it.

Then we disassemble the whole method again to see if the JNE was changed correctly. And yes — tah-da — - it now says JE. Perfect. Continue. You are now registered. To make this change permanent: do “x/8x 0x0002ffb9”. You will get 24 bytes of data. Open the binary in your favorite hex editor and find the bytes outputted by gdb. If you’re on intel, don’t forget you have to reverse all the blocks of four bytes before searching. When you find it, edit the 0x75 into 0x74. Bravo! You have now made the change permanent.

We are not finished yet. As you will now notice if you run the program, it makes your code valid, but you get an error message each launch, and you have to re-do the entering a code process every time. This is because the first check at launch doesn’t happen in doOk:.

Continue and quit normally (using cmd-Q in Direct Mail). Launch it again by doing run. But this time, don’t continue after hitting the breakpoint at launch. Do nexti. Ok, so now we are in loadRegistration. Disassemble this method. Similarly, there’s a JE this time, just after the call to isValidCode:forName: Turn this into a JNE by changing the 0x74 into a 0x75 at this location in memory. If you disassemble the method again, you can see that the JE turned into a JNE. Like before, change this in the binary.

Well Done! You have now fully hacked Direct Mail 1.8.3.

By now, the developer has probably fixed this security flaw, so you can’t use this to get this app for free. If you like it, buy it. It’s a great piece of software! Think about the poor developers who have to feed their family.

You can download the trial version here

]]>
http://www.seoxys.com/hacking-mac-apps-direct-mail-archive/feed/ 6
An introduction to Sean Collins http://www.seoxys.com/an-introduction-to-sean-collins/ http://www.seoxys.com/an-introduction-to-sean-collins/#comments Thu, 22 Nov 2007 08:59:12 +0000 kenneth http://www.seosoft.info/seolog/2007/11/22/an-introduction-to-sean-collins/

From: Sean Collins
Date: July 23, 2007 4:32:35 PM EDT
To: [anonymous@gmail.com]
Subject: Aquatic Prime

I recently read your blog post about Aquatic prime, after I was hunting around inside another application.

I would like to perhaps exchange some notes, because I think I might have found at least an individual application that uses the PHP authentication of the AquaticPrime framework, and I suspect that it would be vulnerable to SQL Injection attacks, as well as using what I believe to be, a cookie that never expires that is baked into the executable, which could lead to some other interesting things.

Let me know if you’d be interested in a chat!

Thank You,
Sean Collins

1:42:24 PM seanwdp: [Hey], it’s Sean C
1:42:48 PM anonymous: hey sean.
1:43:10 PM seanwdp: The app in question is called Exces
1:43:22 PM seanwdp: part of that MacHeist deal they were doing a week ago
1:43:35 PM anonymous: ok
1:43:58 PM anonymous: and what can you do exactly? (re-reading your email)
1:44:13 PM seanwdp: I don’t have any POC just yet, just some leads.
1:44:41 PM seanwdp: just looking through the executable, found some little things
1:45:04 PM seanwdp: the app uses the PHP part of the AP framework
1:45:14 PM seanwdp: to do registration keys and such
1:45:20 PM anonymous: k
1:45:44 PM seanwdp: let me give you the executable dump
1:45:55 PM anonymous: k
1:47:27 PM anonymous: can i just strings it?
1:47:57 PM seanwdp: yeah, already did and sent it to you as a txt
1:48:52 PM seanwdp: one of the stings contains his license check
1:48:53 PM anonymous: ok
1:48:59 PM seanwdp: it’s a PHP script
1:49:09 PM seanwdp: if you connect to it with just a browser you get a bunch of mysql errors
1:49:10 PM anonymous: http://www.seosoft.info/app_rsrc/exces_licence_check.plist.php
1:49:13 PM anonymous: yeah i see
1:49:14 PM seanwdp: exactly
1:49:23 PM seanwdp: so I think that the cookie is a few lines below
1:49:25 PM seanwdp: that has the login data
1:49:43 PM anonymous: and that is based on the AP sample code you think?
1:49:52 PM seanwdp: I’m not entirely sure
1:49:59 PM seanwdp: If it is the AP sample code
1:50:02 PM seanwdp: that’s pretty bad
1:50:11 PM seanwdp: I was going from the thinking that he tried to extend the AP
1:50:18 PM anonymous: so have you actually tried to inject anything?
1:50:32 PM seanwdp: I’ve been looking for a way to feed it some bad data
1:50:38 PM seanwdp: I was doing some pretty simple stuff
1:50:47 PM seanwdp: the license key I think is through stenography
1:50:57 PM seanwdp: so I was trying to see what it takes as a dragging source
1:51:12 PM seanwdp: see if I could craft some bad data, then capture the packets
1:51:22 PM anonymous: heh ok
1:51:30 PM seanwdp: What makes me wonder, is the fact that he has another part, his bug reporting
1:51:39 PM anonymous: ap uses real encryption though
1:51:51 PM seanwdp: right
1:51:52 PM anonymous: no stenagraphy no faking
1:52:13 PM seanwdp: but my thinking is that the app will send a user/pass
1:52:30 PM seanwdp: since you get the error about not having a user or database selected
1:52:35 PM seanwdp: when you visit that register page
1:53:22 PM anonymous: what user/pass?
1:53:28 PM anonymous: a bit confused
1:53:44 PM seanwdp: okay. Know how you visit that registration page with a regular browser?
1:53:53 PM anonymous: y
1:54:10 PM seanwdp: notice those mysql errors
1:54:16 PM anonymous: right right
1:54:22 PM seanwdp: Line 2 is the host
1:54:27 PM seanwdp: line 3 is the database
1:54:46 PM anonymous: looks like he’s on a dreamhost box
1:54:50 PM seanwdp: right
1:54:59 PM seanwdp: I’m thinking those variables
1:55:02 PM seanwdp: the PHP ones
1:55:22 PM seanwdp: that set the host, database name, and possibly user/password combo are in the app
1:55:26 PM anonymous: ok
1:55:32 PM anonymous: i’d be real surprised
1:55:36 PM seanwdp: as would I
1:55:48 PM anonymous: in fact i doubt its likely at all
1:56:05 PM anonymous: knowing dreamhost (used to be a customer) they firewall off the mysql server
1:56:24 PM anonymous: the info would be embedded in the php
1:56:33 PM anonymous: it looks to me as if the guy has a f-ed up php
1:56:45 PM anonymous: either the mysql server is down, or something is misconfigured
1:56:52 PM anonymous: i dont think the username password are in the app
1:56:56 PM anonymous: unless you’ve found them?
1:57:08 PM seanwdp: only guesses at this point, nothing jumped out in the strings
1:57:14 PM anonymous: what happens when you packet sniff?
1:57:23 PM seanwdp: still trying to get that running
1:57:27 PM anonymous: ok
1:57:29 PM seanwdp: I might have to do what you did
1:57:33 PM seanwdp: with the code injection
1:57:37 PM seanwdp: just force it to connect
1:57:43 PM anonymous: ah
1:57:54 PM anonymous: so it doesn’t connect to that url normally?
1:58:02 PM anonymous: until you register it perhaps?
1:58:05 PM seanwdp: yeah
1:58:08 PM seanwdp: and there’s a cookie
1:58:13 PM seanwdp: expires never
1:58:27 PM seanwdp: I wondered if that might be a good lead.
1:58:33 PM anonymous: AP is designed for client side validation
1:58:39 PM anonymous: he’s doing it server side too perhaps
1:59:03 PM seanwdp: I mean the guy just sold like 100k licenses or something
1:59:09 PM anonymous: no shit?
1:59:11 PM seanwdp: yeah
1:59:12 PM seanwdp: macheist
1:59:16 PM seanwdp: so I mean, it’s gotta work
1:59:19 PM anonymous: heh
1:59:20 PM anonymous: yeha
1:59:24 PM anonymous: unless it is a dead url
1:59:29 PM anonymous: isn’t used any more
1:59:33 PM anonymous: or is in there to throw you off ;-)
1:59:34 PM seanwdp: true, maybe he baked a new version for macheist
1:59:39 PM anonymous: maybe
1:59:53 PM seanwdp: I dunno, I can’t imagine him being too smart
2:00:06 PM seanwdp: his app just hands off the dirty work to disk utility
2:00:09 PM anonymous: i’d _hope_ he is if he’s releasing an encryption app
2:00:11 PM anonymous: ah
2:00:12 PM anonymous: haha
2:00:19 PM seanwdp: yet still manages to have a “limit” of 10gb
2:00:26 PM seanwdp: for his “vaults”
2:00:48 PM seanwdp: it’s right in the code, he calls hdiutil
2:01:03 PM seanwdp: all he’s got is a pretty GUI
2:01:31 PM anonymous: yeah
2:01:35 PM anonymous: another Disco app
2:01:38 PM seanwdp: yep.
2:02:00 PM seanwdp: At least Disco has “ismoke”
2:02:05 PM seanwdp: :D
2:03:30 PM seanwdp: so what are your thoughts?
2:04:17 PM anonymous: i dunno. i’d be really surprised if the app relies on it for registration
2:04:30 PM anonymous: AP is vulnerable once you have it in your hands.
2:04:44 PM anonymous: it just depends on how much work the guy has done to obfuscate it
2:04:56 PM anonymous: and even then you can always find (and then replace) the public key used
2:05:04 PM seanwdp: right
2:05:11 PM seanwdp: but what about the risks to his website
2:05:20 PM anonymous: i’d be surprised if there are any
2:05:28 PM anonymous: it could just be the mysql server is fubared
2:05:32 PM anonymous: something is misconfigured
2:05:41 PM anonymous: hard to say
2:05:50 PM anonymous: any badly written php could be vulnerable
2:05:54 PM seanwdp: right
2:06:04 PM anonymous: to find out for sure you need to sniff the packets and find out what it sends
2:06:07 PM seanwdp: well I mean he has a bug reporter, where all the stuff is sent using the $_GET array
2:06:19 PM anonymous: any suspicious looking printf style strings?
2:06:32 PM anonymous: stuff that could be a http url request?
2:06:47 PM anonymous: “%@&%@&%@” type stuff?
2:07:01 PM seanwdp: lemme see
2:07:09 PM anonymous: you could try hacking the bug reporter
2:07:11 PM seanwdp: I swear I saw some
2:07:22 PM anonymous: if that is vulnerable then the license check probably is too
2:07:27 PM seanwdp: yeah
2:07:40 PM seanwdp: I mean, it’s much easier to crack the bug reporter
2:07:52 PM seanwdp: since I guess the database connection info is in the script
2:07:56 PM seanwdp: *not guess
2:07:59 PM seanwdp: it is
2:08:07 PM anonymous: that makes no sense
2:08:08 PM anonymous: why do that?
2:08:16 PM seanwdp: pulled it out of a php book
2:08:16 PM anonymous: easier for it to be server side
2:08:24 PM anonymous: if he has to change the password he’d be fucked
2:08:26 PM seanwdp: right, that’s what I’m saying
2:08:27 PM anonymous: or whatever
2:08:34 PM seanwdp: he’s probably got a mysql_connect.php
2:08:46 PM seanwdp: that has a username, password, host, and all that
2:08:54 PM anonymous: but even then he’d have to jump through hoops to expose his mysql server to the world
2:08:59 PM anonymous: by default DH firewalls it
2:09:07 PM anonymous: so you have to assume he knows how to do that at least
2:09:12 PM seanwdp: yeah
2:09:21 PM anonymous: which is inconsistent with him putting his password in the client
2:09:31 PM seanwdp: it would be
2:09:46 PM seanwdp: it’s just that you don’t get the same error reporting on the bug page as the license page
2:10:15 PM seanwdp: but that could be because someone wrote the bug script better
2:10:24 PM seanwdp: and it doesn’t give out those errors to the user
2:10:38 PM seanwdp: meanwhile someone far dumber left the error reporting on, for the license script
2:11:59 PM anonymous: well focus on the bug reporter see if you can capture what it sends
2:12:05 PM anonymous: i’d be interested to see that
2:15:46 PM seanwdp: yeah
2:15:58 PM seanwdp: I’m pretty sure it just sends three or four variables
2:16:06 PM seanwdp: the PHP script gets them and off they go into the database
2:16:12 PM seanwdp: since they’re right in the url
2:16:23 PM seanwdp: http://www.seosoft.info/app_rsrc/bug_send.php?
lang=%@&product=Exces&name=%@&email=
%@&description=%@&explanation=%@
2:16:52 PM anonymous: yeah
2:17:15 PM anonymous: so do some injection :-)
2:24:07 PM seanwdp: I’ll let you know what I come up with
2:24:20 PM anonymous: cool
2:24:26 PM seanwdp: work finally threw up their hands and let me run our stuff on Apache
2:24:39 PM seanwdp: the guy running the server (win2003) has NFC
2:24:47 PM seanwdp: and i don’t like or care about IIS
2:24:56 PM seanwdp: thing spent more time broken then up and running

‘Nuff said.

]]>
http://www.seoxys.com/an-introduction-to-sean-collins/feed/ 1
Econ http://www.seoxys.com/econ-2/ http://www.seoxys.com/econ-2/#comments Mon, 19 Nov 2007 14:28:24 +0000 kenneth http://www.seoxys.com/econ-2/ Introducing Econ, the screensaver that uses your icons!

Note: This screenshot is UGLY. Screen capture just wouldn’t capture a smooth image…
Click on the screenshot to get a nice QuickTime preview of the screensaver.

Econ is Leopard-only and requires a decent graphics card & CPU.
Download Econ

Update: In Snow Leopard, you need to launch System Preferences in 32-bit mode in order to be able to select Econ from the list of screensavers. To open System Preferences in 32-bit mode, right-click on its icon, choose Get Info and check the Open In 32-bit Mode checkbox.

]]>
http://www.seoxys.com/econ-2/feed/ 67