View Single Post
Old 08-01-2021, 05:55 AM   #4
geek1011 ought to be getting tired of karma fortunes by now.geek1011 ought to be getting tired of karma fortunes by now.geek1011 ought to be getting tired of karma fortunes by now.geek1011 ought to be getting tired of karma fortunes by now.geek1011 ought to be getting tired of karma fortunes by now.geek1011 ought to be getting tired of karma fortunes by now.geek1011 ought to be getting tired of karma fortunes by now.geek1011 ought to be getting tired of karma fortunes by now.geek1011 ought to be getting tired of karma fortunes by now.geek1011 ought to be getting tired of karma fortunes by now.geek1011 ought to be getting tired of karma fortunes by now.
Posts: 2,460
Karma: 5070984
Join Date: May 2016
Location: Ontario, Canada
Device: Kobo Mini, Aura Edition 2 v1, Clara HD
Originally Posted by halfdozen View Post
Thanks that's helpful, I've tried a few disassemblers but they haven't been particularly useful so far though I've only had a quick play. I will give Ghidra a try, I did have a look at Hopper but I'm on a Windows machine so will leave that as a last resort.
Ghidra's decompiler is far better than anything but IDA, and it's free. But, I recommend disabling the option which hides namespaces (it's on by default) or you'll have a hard time actually reading the output since the class names will be lost. Also, beware that it often gets function arguments wrong and has pretty aggressive code restructuring. And, Ghidra's UI is somewhat clunky, making the disassembly view difficult to use efficiently (symbol search is iffy and doesn't have good fuzzy search or namespace support, navigation of xrefs requires a lot of clicks, and I find the formatting a lot harder to read). Also, if you ever need to do lower level patching, note that Ghidra doesn't detect PLT offsets for functions (you'll need to supplement the data with stuff from IDA, Hopper, or my symdump too).

Hopper has a nice disassembly view (it's a lot more information-dense than the others), but the decompiler is garbage in general (it's too conservative with restructuring and simplification, and it doesn't do much with types, so it's output doesn't usually provide any benefit). There are a few quirks to be aware of: the back/forward navigation doesn't work properly, it sometimes fails to detect procedures with interspersed constant data (you need to null it then recreate the procedure), patching bytes in it will break many features, it leaks memory when loading a binary (so you should restart it after the initial analysis), it often doesn't detect short strings correctly, it doesn't detect enums automatically, and references to constant QStrings (which are initialized in an entry point) aren't detected. Also, don't trust what it tells you about stack variables; it makes a lot of mistakes with libnickel for some reason compared to other binaries.

I'm currently considering switching from Hopper to Binary Ninja, but I haven't had much experience with it yet.

Also, if you ever need to look at the embedded Qt resources, I wrote a tool for that (it should work with any Qt4/5/6 binary):

From what I've tried as well it seems NickelHook doesn't support multiple hooks to the same "end point", whoever hooks last seems to win - not surprising based on the complexity this adds.
That's a known bug, and I have a few ideas for how to fix it, but it hasn't been a high priority for me since the current mods hook relatively obscure functions which shouldn't need to be hooked my multiple mods. If you do decide to release what you're working on, ensure they don't conflict with the ones used by the current mods. If they do, tell me, and I'll fix this so there aren't issues from conflicts.

As a quick way to get started I wanted to hook into the main navigation bar whilst keeping NickelMenu active. Since that worked but prevented NickelMenu from appearing I figured I could hook into NM's override function but for some reason the symbol for that can never be found (this was all a very quick hack to get started so I might of missed something)
To hook into NM's hook functions (which I strongly recommend against for anything but testing since that's an implementation detail which may disappear or change in incompatible ways in the future), you'd need to ensure NM is loaded first, then reference libnm as the library to hook.


And as a general piece of advice, always think about forwards compatibility, and how your mod will break if something changes. In general, if you have to break, only do it after a user interaction. If you must hook things which run at boot, fail earlier rather than later so the failsafe can catch it. And try as hard as possible to avoid doing things which may cause memory corruption if something changes internally (e.g. use mangled C++ symbols if you can, try to avoid functions which return stuff on the stack, allocate more memory than necessary when calling constructors, figure out as much as possible at runtime, hook symbols which are intrinsically related to what you're doing [e.g. if you're trying to add a menu, don't hook the view's constructor then try to access the widget at a specific offset; hook the menu's constructor or an add item function instead and go from there] with as few offsets required as possible). And, try to avoid the C++ standard library at all costs (it can create dangerous incompatibilities if the toolchain is updated, especially with how old Kobo's libs are right now) and use the Qt or C versions of things wherever possible.

In addition, remember to consider alternative approaches for whatever you're trying to do, and keep in mind that NH is intended only for modifications which directly extend existing Nickel functionality rather than ones which add new functionality. While NickelHook can be convenient, apart from temporary mods to test things locally, try not to use it if you can help it; it's not the right tool for most kobo-related things. If you're trying the change the behaviour of something built-in rather than extend it, it should be done in kobopatch, not NickelHook. If you just need to access Nickel functionality from another application, use a NickelDBus.

In short, NH should only be used to create standalone mods which supplement user-facing parts of Nickel's existing functionality, not to add unrelated features or change the intended behavior of Nickel. And, safety (both during installation, usage, updates, and failure) should always be the first priority, with backwards/forwards compatibility the second. Stack corruption (from return values, function parameters, incorrect reference usage) and explicit offsets should be avoided at all costs since they can cause hard-to-debug instability in other parts of Nickel which the failsafe can't catch.


Also, you may find the Itanium C++ ABI document, the ARM EABI spec, and the Thumb2 encoding manual useful.

Last edited by geek1011; 08-01-2021 at 06:30 AM.
geek1011 is offline   Reply With Quote