Hacker News new | ask | show | jobs
by gp2000 3431 days ago
It is difficult to take a binary program and establish intent. I'd rather call these "interesting and unusual programming tricks" than "anti-emulation measures" until more evidence is presented.

Mirrored memory is a side effect of unconnected lines on the address bus thus making the content of those bits irrelevant. Code can take advantage of this to run faster or put tag values into addresses.

On a GBA, VRAM is faster than ordinary RAM. Programs can do well to use it for tight inner loops.

Using STM (store multiple) to DMA registers? Again, go faster.

Save type masquerading might be code that helps when running on a development kit, but I admit that I can't think of what use it might have.

Self-modifying code that depends on the pre-fetch queue might be the best place to look for intent. Might be easy to tell if the program is doing it for some larger purpose or simply to fail subtly or overtly if it sees unrealistic processor behavior.

Any why would a program do extra work writing to an audio FIFO than need be?

5 comments

Mirrored memory is a side effect of unconnected lines on the address bus thus making the content of those bits irrelevant. Code can take advantage of this to run faster or put tag values into addresses.

What does this have to do with speed?

On a GBA, VRAM is faster than ordinary RAM. Programs can do well to use it for tight inner loops.

Almost all programs use IWRAM for this. It's one of the things it's for. It's as fast if not faster than VRAM (depends on if the VRAM is being accessed by the PPU at the time).

Using STM (store multiple) to DMA registers? Again, go faster.

In retrospect, yeah this might actually be the case.

Save type masquerading might be code that helps when running on a development kit, but I admit that I can't think of what use it might have.

There are a handful of GBA games that lie about save type as anti-piracy and refuse to save or even boot if it finds the wrong one. It's also really the only anti-piracy technique that any other GBA games actually use, since it's quite effective against flash carts.

> What does this have to do with speed?

You generally need to mask potentially-tagged pointers before dereferencing them. (Ab)using virtual memory or unconnected lines lets you skip the mask, eliminating the cost in any code that's otherwise unconcerned about the tags. This in turn may let you save a byte or register here and there (and thus save memory bandwith / potentially spill fewer registers, maybe saving some performance).

GCs may abuse pointer tagging for keeping track of what they scaned. Ruby's VALUE type is pointer sized, and will point to Ruby objects such as strings and symbols - but it can also directly represent e.g. a 31-bit integer value ('Fixnum') on 32-bit systems without needing to be dereferenced, and without needing to consume a separate type field.

Also used in early revisions of the Amiga. (BCPL or Amiga Basic used pointer tags for something like garbage collect or frame pointers or something IIRC.) Mac had something called 32 bit clean which I imagined could have been pointer tagging.)
"32 bit clean" meant that the ROM didn't use pointer tagging; otherwise it was using the top 8 bits for its own purposes and wouldn't run on machines which used the full 32-bit address line.

http://lowendmac.com/2015/32-bit-addressing-on-older-macs/

Self-modifying code that depends on the pre-fetch queue might be the best place to look for intent. Might be easy to tell if the program is doing it for some larger purpose or simply to fail subtly or overtly if it sees unrealistic processor behavior.

Indeed, in the PC world taking advantage of the prefetch queue as a sort of "loop buffer" was relatively common in demos, where a loop would patch instructions to execute in the next iteration, squeezing out a few extra cycles. Here's a detailed application of this trick:

http://www.reenigne.org/blog/8088-pc-speaker-mod-player-how-...

...as seen in this awesome demo:

https://trixter.oldskool.org/2015/04/07/8088-mph-we-break-al...

That demo is insane. Is there some kind of archive that is keeping track of them?

It would be sad if they were to be lost in time.

pouet.net and scene.org

In particular, http://www.pouet.net/prod.php?which=65371

Yeah, putting tight loops into fast RAM for extra speed is a very old trick --- I've done it myself. Likewise multiple stores.

Using a non-standard copy of the address --- well, it's an emulator, on a slow system; the ARM requires 32-bit constants to be read from a constant pool. If it can use certain addresses that are cheaper to construct, somehow, that'd be a performance boost. Can't tell without knowing which addresses, though.

My first thought on the save type masquerading and the pre-fetch queue testing is that it's testing for particular hardware. e.g. if it's running on a cart with SRAM, do the SRAM thing, otherwise do the flash thing. Likewise, testing the pipeline size might be trying to figure out what processor there is. That doesn't explain why it just crashes rather than following some other code path --- if the code to do the SRAM thing was there, and the emulator tells the game that there's SRAM, then the emulator should see the game doing the SRAM thing.

It might be something as trivially stupid as that the game contains the code to check for development hardware, but that the run-time support for the development hardware isn't present and instead the game is just crashing. There may not be anything malicious here.

If I wanted some sort of antipiracy or antiemulation feature, I wouldn't put a big obvious crash up front. Instead I'd introduce some sort of random failure elsewhere in the game, so it superficially looks like it's working, but isn't any fun to play...

Instead I'd introduce some sort of random failure elsewhere in the game, so it superficially looks like it's working, but isn't any fun to play...

This isn't mentioned in the article, since one of the anti-piracy/-emulation techniques I didn't discover at the time of writing it (due to my dump being an overdump) is that many of the games do this. They screw up input so it either boots but you can't play it at all, or input is unplayably slow. It detects it by having an interesting memory mirroring quirk in the cartridges that no other GBA carts have.

This is one effect I discovered when I was working on getting around the anti-piracy effects of an arcade game[1][2] in order to run it on similar hardware. I think it is a more clever copy defeat mechanism than stopping the game from booting.

[1] http://mikejmoffitt.com/articles/0047-puyopuy2.html [2] https://tcrf.net/Puyo_Puyo_Tsuu_(Arcade)

> Instead I'd introduce some sort of random failure elsewhere in the game, so it superficially looks like it's working, but isn't any fun to play...

Doesn't that defeat the purpose? If people don't realize that they're being punished for pirating, you're just collecting bad review scores and not pushing anyone to buy a legitimate copy.

It's actually a not-unheard of trick. Arkham Asylum, for example, would have a failure case about halfway through the game where Batman's cape would fail to open when he jumped down into a deep (plot-required) pit if the game had been pirated. Batman would crash into the ground and die, the users would take to developer forums or the steam forums to complain that they couldn't get past this one section because of a gamebreaking bug, and then the developers would say, "Yes, that's an anti-piracy measure. If you purchase the game, it won't happen".

Another game, Game Developer Tycoon, would run as normal, but as you got further and further along, in-game pirates would pirate all the games you made and your profits would keep on dropping. People came to the developer forums to ask for ways to keep people from pirating their games, because they couldn't make any money because of all of the pirate. The irony was lost on some.

I think the Game Developer Tycoon one is the only actual success story, and that's because the story went viral.

For every person who goes out of their way to complain on the forums, there's probably five that just caution their friends not to buy the game.

I also recall (obviously difficult to verify) accounts from people who claimed that the Arkham Asylum (I recalled it was City...?) bug happened to them with legitimate copies. From a development perspective, an "Easter egg" of that sort requires a LOT of QA effort.

This is exactly what games like Spyro the Dragon do - the cracker would give up after fixing n protections
Yes, it makes it more time consuming to fix all the protections. It's like all debugging, the crash bugs are usually easier to fix. It's the little ones a long way in which are harder to fix.
I'd take a guess that the save tricks might be more anti piracy. After all the gba had flash carts, perhaps these carts contained sram and eeprom so checking for it was to block it. No idea about the pipeline stuff though, perhaps checking vram was working correctly?
Particularly given the "NES Classics" line, I would expect weird stuff to happen because these cartridges are effectively themselves emulations of games from different hardware.