Archive for April, 2021

Things I want in Ghidra

Wednesday, April 14th, 2021

Ghidra, as you should know already, is a disassembler and decompiler for unprofessional folks who can’t cough up a couple thousands dollars and pass background check to buy a disassembler and decompiler the experts use. And here’s a list of things that would make Ghidra better or much better for me. I know it’s opensource but I’d rather not touch large codebases written in Java (or any codebases written in Java really). Disclaimer: by the time of writing this I’m still using Ghidra 9.2 even if 9.2.2 has been available for months, but I doubt any of the things mentioned here are implemented already.

First of all, there’s a bug with x86 disassembly: while rep movsX is recognized and works fine, some of the code I’ve seen uses repne movsX which is treated as simple movsX even by disassembler. Initially I was confused by this bug and only disassembling instruction bytes with ndisasm proved that it’s not a compiler (or assembly author) missed a prefix but rather Ghidra ignoring it entirely. Some other rarely seen instructions that involve FPU operation and an addressing with segment registers (e.g. ES, FS or GS; if you don’t have an idea what those are for—be thankful for that) and explicit offsets are disassembled incorrectly, consuming a byte more than required (and thus making the following instruction to be disassembled incorrectly as well).

And speaking about assembly, current program text search is nice since you can search inside a specific part of an instruction (e.g. MOVSD.REP in instruction name or 0x800 in its operand) but it would be even better to have a more generic search by a regular expression. Quite often I want to locate a specific instruction doing e.g. shift left by five. The problem is that there are many shift instructions and even more instructions with an operand having 5 somewhere in it. And I don’t know the exact operand register so searching for shl eax, 5 first, then shl ebx, 5 and all the way to shl dh, 5 is tedious. The same can be said about dumping listing and searching there. It will work as intended though.

Beside the issues above and idiosyncratic x86 assembly syntax (it does not bother me much though) I have nothing else to complain in disassembler, so let’s move to the decompiler issues.

I suspect that decompiler output is not stored permanently, but it would be nice to mark some function as being “decompiled, it’s fine, do not touch it, I mean it”. Looks like the process of function being decompiled again and again even if you change something not related to it in any way is annoying not just to me. So it would be nice to mark some large decompiled function as permanently decompiled so it’s not re-decompiled on a subsequent visit to it.

And speaking of functions, it would be nice if functors (aka function pointers) would be supported instead of just detecting that this variable is a pointer to function. When arguments are passed by stack, decompiler usually can detect that. But when arguments are passed in registers you have to trace the registers and their values by hand. Of course you’d need a monstrous syntax to specify a type for e.g. a function that accepts three arguments in designated registers but I can still wish for it, can’t I?

Another thing I often wish for is being able to tell decompiler that after a certain point the variable is no longer valid and it should treat subsequent uses of that register or stack as a new variable. A very common example is when a first argument (usually some context pointer) is moved to a register (or it is passed in a register already), some fields are read from the context, context value is stored to some local variable and the initial register is used for example as a loop variable that gets decompiled to something monstrous like for (ctx = (Context*)0; ctx < (Context*)42; ctx = (Context*)((int)ctx + 1)) { ... } and it also screws types for variables involved in the same expression as this loop counter.

Of course not all of these things can be easily implemented, and maybe some of them would require architectural changes. But I prefer to cherish my ignorance on Ghidra internal details and just point out what I’d find good to have in principle.

I feel old

Sunday, April 4th, 2021

Probably it’s exactly when you start complaining about things changing you realize you’ve become old. And as you can guess this is my turn to complain about things changing.

The last tipping point for me was when I tried to update rustc from version 1.33 I’d been using. I wanted to do it mostly for three things: atomic types beside bool and usize (for the use in NihAV video player that should be written eventually), replacing now deprecated mem::uninitialized(), and being able to switch to a newer version of SDL2 bindings for the future video player (because old version depends on about 25 crates more than a newer ones).

So I tried latest-and-greatest rustc 1.51 and ran cargo clippy to see what has changed meanwhile. And beside seeing that now there’s a special macro matches!() as a convenient shorthand for checking object type to be some variant(s) I could not see anything useful because the linter spammed everything with “selected name is bad, you should change NASomething into NaSomething“. Which looks ugly and dropping the NA prefix entirely may make names too generic and collide with the standard ones. And before you tell me: I’m aware of the lint suppressor flag and that there’s a fix for it that makes it not to complain on public names. Still, I find this brain-damaged and thus I’ve settled on rustc 1.46 for now.

Then there’s an even funnier thing. I’ve discovered that crates.io (the site for navigating Rust packages) has stopped working in Firefox 52 (docs.rs still works fine—for now). Probably because of some JavaScript new feature (which is invoked inside rather large bundle) the scripts cannot be parsed and it simply gives you a cryptic message “Sorry, it looks like we were not able to load the page.” without explaining much. The problem is most likely at your side, you find it out.

My friend Luca actually wasted some time to create an issue for that and got an obvious reply that the browser is outdated and this is expected. For the record GitHub at least prints a message that the browser version is too old and not supported (yet the main functionality is still working), the same is true for WordPress instance where I’m typing this post.

So why don’t I update this four-year old browser? Because it’s painful. The browser is tied to the Linux distribution so either I should compile it myself (I tried that once with earlier Firefox, ran out of disk space and almost of swap space too; so I’m not eager to compile any browser more complex than elinks). The other alternative is updating the distribution and that is even more painful because of the drastic changes in software.

I’m not talking about desktop environments per se even if they expose the problem. I don’t care much about how the windows look like or where launch menu is located. But I do care about the programs I used to being no longer the part of the distributive or changing their interface in radical way. Simple example: for various reasons I like to have several input layouts and methods (for English, Ukrainian, Russian and Japanese language). On Ubuntu 12.04 I have keyboard layout switching between English and Ukrainian layouts (the latter can also produce Russian or Belarussian letters with AltGr) plus mozc to input Japanese (previously it was Anthy and who knows what will be the default Japanese IME in 2024). On Ubuntu 18.04 (which I use on a different machine) you can’t set it up the same way, Ukrainian layout does not have AltGr support and mozc by default outputs Latin characters with no setting or key combination to make it output kana by default (of course I can simply press kana mode change key on my Japanese keyboard—but that means connecting an external keyboard just for that). And even if my fingers are the wurst I have sausage fingers hardly hitting a correct key on the first time, I still want to perform keyboard actions using keyboard.

The sad thing is that I somewhat understand why this happens. Web sites get bloated and do not work with older browsers because of the browser war (no plural, you know The Browser) and shiny features developers are eager to try (and testing for older versions takes time and efforts better spent elsewhere—if people remember about it at all). Some programs need to be updated because of security issues (e.g. I upgraded from Ubuntu 10.04 mainly because of TLS troubles leading to programs not being able to open half of the sites over HTTPS). Some programs get replaced because the maintainer left and there’s nobody to step in. Some interfaces need to be adapted to the new reality (while Debian on Nokia smartphones is not so popular now, Ubuntu on tablets seems to be the next popular thing). And there’s GNOME and freedesktop.org which seem to be the main sources of disruptions. I can’t explain the logic by which they change things but it’s because of their view the mountpoint for network shares in the next release will probably be different from two previous places (and when you’re still using command line to access files on those shares like I do this feels annoying).

The sad thing is that all other non-toy OSes have the same problems. Windows users might still remember Windows Vista GUI affectionately and like how Windows 10 changes GUI elements time from time. *BSD seems to be more stable but they still support GNOME. macOS users might be still ashamed for their muscle memory failing them when OS update decided to reverse scroll direction. This is also why Linux kernel is still precious: it still cares about its interfaces being backward compatible so the userspace can rely on them while you can’t say the same about glibc 2.16.

And here we have it. As I said in the beginning this whining about programs and environments changing constantly mostly tells that I’ve become old. On the other hand if you think this “move fast and break things” motto is a good idea—remember who coined it and think again.