Sorry, have to take this video down… School now wants to sue me for this, and I nearly got expelled (I did lose my scholarship and I am on my only final warning)…

I guess it just doesn’t like having a bad name… Wondering whether it’s worth it really getting them a bad name by sending this info to the press or something.

What Happened: I posted a video of a huge fight that occurred at my school (I wasn’t involved in it, btw, just a spectator) to YouTube so I could show it to a few friends overseas. But this is South Africa… People here have never heard of freedom of speech, and they’re taking example on the government by censoring anything that could potentially give them a bad name. I guess it was to be expected…

An Example of Clever Design

Finally, one site that gets it.


Mint, unlike most other sites, doesn’t ask you which Time Zone you’re in, but asks you what time it is…
This is so much easier and cleverer.

A perfect example of good design!

Reasons Why You Don’t Want To Live In South Africa

South Africa, or “The Rainbow Nation”, as some call it, may seem like a beautiful country with amazing leaders. After all, 4 Nobel Peace Prize have been awarded to South African politicians.

But in reality, all is not well. Far from that. Here is why:

  1. Electricity shortages

    Since mid-2007, Cape Town has been experiencing repeated power outages, sometimes lasting a few days. Now electricity shortages have reached the whole of South Africa, and every day there’s 4h without any kind of power. If you do the Maths, this means that a sixth of the time, there is no electricity. For a year, there will be two months without electricity!

    Not only South Africa is affected, but all of Southern Africa. Countries like Swaziland, Botswana or Zimbabwe, who rely on South Africa for their electricity are also down. There are even rumors that Eskom (South Africa’s electricity utility company) is cutting neighboring countries’ power for every weekends.

    In 1997, we were warned this would happen. An official document described that if the target economy growth per year goal of 6% p.a. was reached, we wouldn’t have enough power by 2007. The actual growth rate for the past 10 year was 5% p.a. They were warned, and yet the incompetents in charge did nothing. This is how corrupt the country is. The wealthy men in charge use their power for personal gain, and they of course are safe while the rest of the country is in a chaos.

    No electricity sounds like a mere inconvenience. After all, our ancestors have lived without power for centuries. But it has far bigger consequences on the country as a whole. Car accidents are so common here that there isn’t a day going by where I don’t see at least one road accident. How much worse do you think not having traffic lights will make it? The road will be a total chaos. There will be traffic-jams everywhere.

    South Africa is a dangerous place. Every home is equipped with an alarm system. But of course, alarm systems require electricity. Perfect opportunity for someone to break in. Garage doors and gates too are powered by electricity. If you’ve left your door closed when the power cut arrises (which, by the way, is the safe thing to do if you don’t want your car stolen), you’re stuck at home.

    The biggest result of this that affects everybody first-hand is refrigeration. Food is kept in fridges and freezers for a reason. Otherwise, they rot, melt, or become inedible.

    In Cape Town, during one of those power cuts that lasted 5 hours, more than a hundred tourists were stuck hanging on a cable between Table Mountain and Cape Town. 900 were stuck at the top of the mountain. For FIVE HOURS!

    Entire businesses are going down. Any business that relies on computers now has major problems. No work is going to get done while the power is done. And on top of that, there is data loss, file corruption etc. Communication too is down. All modern wireless home phones rely on electricity, and thus and unreachable and unusable during the cuts.

    Do I really need to go on?

    This is supposed to continue regularly until 2013, when they will finally have finished building the first new power plant.

  2. Led by a rapist

    As if the electricity shortages weren’t enough.
    Have you ever heard of Jacob Zuma? He is president of the leading political party, the ANC, and soon-to-be president of South Africa. Problem is, this man is a RAPIST! And by rape I do not mean where the woman wakes up the next morning and realizes she’s hungover and probably shouldn’t have done what she did. By rape I mean violently forcing a woman into nonconsensual sex.

    That’s what Mr. Zuma did, and he got away with it. And now he is about to become president. You must wonder, how did this ever happen in a democracy? Yeah, that’s what I’m wondering too.

    In court, he claimed that he took a shower after the rape, thus protecting himself from HIV/AIDS and other diseases. What a great example for his country…

    To top it off, he is also facing corruption charges.

  3. Crime, Rape and AIDS


    from South African political satirist, Zapiro.

    South Africa is ranked N°1 for number in homicide per capita and rape.

    Statistically, a teenaged girl has more chances to be raped than to learn to read.

    Combined with AIDS, this makes South Africa the most dangerous country for women. One in five South Africans is infected. By 2010, we are expecting a cumulative death toll of 5.7 millions due to AIDS. Imagine if everybody in both Durban and Cape Town died. That’s how many people 5.7 million is. Alternatively, picture everyone living in Los Angeles and Paris combined dying. (Note: City populations include only the city itself)

    Due to the incompetence of our leaders, no effective action is taken to prevent the epidemic. Indigenous locals rape virgin girls because they traditionally believe that having sex with a virgin will cure them from AIDS. But obviously the only thing achieved is spreading of the epidemic.

DISCLAIMER: I am not South African, but I have lived here for more than 3 years, which is more than enough for me to be disgusted by this country forever.

 — 

Update (2012): I believe in free speech, so I did not censor any of the comments below. However, while I stand by my opinion in this post, I think it’s important to mention that I vehemently disagree with many of the hateful and racist things that have been said in the comments.

Exces one-year anniversary

Today is a big day, as it marks Exces’ first anniversary. For this occasion, there’s some big news:

  1. Exces 1.5 is released! Exces has come a long way since it was first released as a shareware app, exactly one year ago.

    The vision behind Exces was of an app that made putting a password on files simple and easy to use. Something that made this dull security task a little bit more fun.

    During this year, most of the new feature implemented were due to popular requests from it’s users, you. It is my pleasure today to introduce Exces 1.5. Thanks for making this possible!

    What’s new in Exces 1.5:

    • New Feature: Auto-lock. Have you ever left your desk for some time and then discovered, to your horror, that you forgot to lock a confidential Exces vault? Well, worry no more, with Exces’ new auto-lock feature, Exces automatically locks the vault after 10min of inactivity. To use this new feature, simply activate it by opening Preferences, and ticking the “auto-lock” checkbox. (Auto-lock does not work when files are open in the vault, to safeguard from data-corruption.)
    • Lots of polish. Little things have been changed all over the place to improve the global behavior of Exces. For example, Exces now checks whether it is running from the disk image and offers to install itself.
    • Bug fixes. Minor bugs that have cropped up have been fixed here and there.
  2. Pricing change: Due to the fall in value of the US dollar, I have no choice but to change the pricing. The new price will be €19.95.
  3. MacUpdate Promo: Exces will be available in the MUPromo tomorrow, 11th of Jan. Exces will sell for that day, and that day only, for €13.31 ($19.52)

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