As people have seen in the past, I tend to have a fun time finding edge-cases which break tools. Often you can find these types of edge-cases while reading documentation and cross referencing the implementation of that in the systems your validating. A pretty good example of this is highlighted in my BlackHat 2012 talk, where I was looking at the header section, which is described as always have the value of 0x70. When looking at the open source tools, some checked to make sure this was true - others ignored it. The actual code in the Dex Verifier is as follows;
1 | if (okay) { |
From this we can see the actual implementation doesn’t care what the size of, as long as it is larger than the current structure size, which is 0x70. This allows for the verifier to be forward compatible, though if anyone was creating a tool and only read the documentation - this might not be fully understood or assumed. This leads me to two extremely easy breakages which I never mentioned in my talk, but noticed IDA Pro 6.4 and Radare would fail against. The issue that IDA Pro and Radare broke against, was a bad file magic. According to the documentation the magic bytes are the following;
1 | DEX_FILE_MAGIC |
So one might assume that the currently accepted magic bytes will be exactly dex\n035\00
- though, they would be wrong in assuming this. If we take a look at the code in DexFile.h;
1 | /* DEX file magic number */ |
We can see that there are constant magic bytes of dex\n
, but the versioning afterwards - which is loosely explained in the documentation, has multiple options. Since API level 14 on, the verifier has accepted both “036\00” and “035\00” as valid versioning parts of the magic bytes. Since the magic bytes are not part of the checksum or the signature of the dex file, one can simply bump the version number without any specialized tools, just doing it with a hex editor would be fine. This lead to Radare failing to load the file and IDA Pro to thinking the file was corrupt with the following dialog and log output;
1 | Loading file '/Users/tstrazzere/reverse/targets/ida/classes-test.dex' into database... |
I originally reported this issue to January 22nd, 2013 and received a thank you and a fix back from them only two days later on the 24th. I’m unsure if they sent this out to all their customers or have it totally bundled into their latest packages, but you should easily be able to request it if not. For Radare I submitted a patch for this issue which was quickly merge upstream by the extremely proactive author of the tool. The second breakage, which only directly effected IDA Pro, was revolving around the file size as dictated by the dex_header vs the actual file size. IDA Pro was comparing the two, and if they where not actually equal - assumes the file is corrupt. The documentation states, “size of the entire file (including the header), in bytes”, though the implementation of the code doesn’t actually care - as seen from the DexSwapVerify.cpp file;
1 | if (okay) { |
As we can see from above, if the actual length must be at least as large as the expected length, most likely to avoid any truncated files. Though it can easily be larger, which will just produce a warning - though processing of the dex file will continue. However, the same corrupt file dialog with this logging message comes up when loaded in IDA Pro;
1 | Loading file '/Users/tstrazzere/reverse/targets/ida/classes-test.dex' into database... |
This was also fixed on the same timeline as the other issue I reported to Hex-Rays, so if you run across any files like this you will be prompted with this dialog; Just two small little issues that came about when looking at the implementation of the file format. These edge-cases always seem to exist in ever system, especially when creating reversing/disassembling/analyzing tools.