Elfcat: Visualize ELF Binaries
github.com
github.com
The three nulls in the load segment (between the code and data) are included in both the code and the data highlights as well as its own highlight, which is a bit unintuitive, as the start of the string looks to be /0/0/0Hello. It looks like these are supposed to be between spans like the other non-highlighted nulls, but they are included in a parent span, bin_segment0. (Issue submitted.)
Also, I wish the arrow heads did not opaquely overlap the numbers. Adding opacity="0.3" to the svg tag fixes this for me.
This is cool for a variety of reasons: It makes parsing a readelf output a bit easier, it's a nice/small/functional Rust demo (for Rust idiots like me), and the output can be redirected into html-based documentation easier than a command line tool's output.
Yes, this is a bug. Thanks for reporting it to the issue tracker.
> Also, I wish the arrow heads did not opaquely overlap the numbers. Adding opacity="0.3" to the svg tag fixes this for me.
Will put to toggle-able options. The arrows really hinder comprehension, perhaps arrowheads could be made smaller too.
I've seen similar tools to annotate other binary formats like gpg and asn.1
The original intent was simply debugging bfd while developing it, though people ended up using it for all sorts of things.
I like Elfcat.
Holy smokes, thank you!
I like Elfcat.
I can imagine the author is beaming right now. I would frame this comment on my desk were I them, I think.The most recent thing I did with objdump was use it to patch in a signature that needed to be computed over the text/data/bss segments after compilation. This was for a bare metal embedded system, and being able to do this at the elf level (1) made it easier, and (2) allowed me to use the same setup for multiple targets that each had their own oddball binary/ihex conversion and flashing machinery.
Kaitai [1] isn't perfect, but maybe suits your needs.
It works with ELF as well as many many other formats, and the online IDE is only a very small part of what you can do with it.
Speaking of visualizing virtual memory, one of the things that I haven't seen a nice prior tool for is breaking down the memory map of a process on a per-section basis--/proc/pid/maps only tells which libraries are providing which sections. I've built something like that for my own needs, but it's the sort of thing that I would have expected would easily come out of some other tool.
As such, they often won’t be of any help in a situation where you’re trying to use them to diagnose where exactly a corrupted piece of data is going wrong — which is one of the biggest use-cases for such tooling!
The object crate exposes all of the ELF types directly. The one thing it doesn't do is give you this from its format-agnostic object::read::File type, you have to start from object::read::elf::ElfFile instead. As a bonus, it also gives you all of the processor-specific defines so you don't have to look up what the value of, say, the x86-64 relocations are: https://docs.rs/object/0.25.3/object/elf/index.html#constant...
I'm using "high-level" here to mean "was successfully transformed through all the decoding/lexing/parsing/cross-reference stages", and "low[er]-level" to mean "failed to be transformed by some of those stages." Which is non-normative, I guess, but this sort of "layers of decoded-ness" representation is what you expect from tools like Wireshark or binwalk.
Yes, object/gimli are also this kind of low-level. Basically, when you parse the file, you're not actually parsing the file, but you're parsing each element of the structure one bit of a time.
So parsing FileHeader will make sure a) the data is correctly aligned [since it's UB in Rust to have underaligned data] and b) that the e_ident bits are actually the magic number for an ELF file. Want to list all the sections? That's when it's actually going to check that a) the section header offset actually points to valid data and b) the number of section headers exist and is sane, but again, it doesn't actually verify that the section headers themselves make any sense whatsoever.
[1] https://rizin.re
No. When I started the project I was expecting to just read data into the ELF structs, in style of C. (Un)fortunately, it's not possible to do safely, so I started looking into crates to do that, and was stumbling upon data deserialization ones. In particular, the first attempt was in nom. In hindsight, that wasn't particularly smart, and specific object-file-parsing ones would be better. I don't regret implementing reading manually, despite it looking pretty ugly, because attending to NIH syndrome is fun.
> Speaking of visualizing virtual memory, one of the things that I haven't seen a nice prior tool for is breaking down the memory map of a process on a per-section basis
That is planned. It's noted in readme, and in issue #3 I go over how it can look like[1].
[1]: https://github.com/ruslashev/elfcat/issues/3#issuecomment-86...
First I'd like to say that right now this is just the first release, and it's a bit raw so far. That's why I was hesitant to post on HN yet, expecting a more harsh but merited critique. I am reading through the thread for bugs and suggestions. Thanks for that.
I do wish that that there would be a key explaining the color coding.
Medium Purple (#99e) -> Elf Header
Light Salmon (#eb9) -> Program Header
"Violet Orange Gradient" -> Executable and data, I think (It looks like this is copied to address 0x10000+0x80 and executed, but I'm not familiar with x86.)
Violet (#f9f) -> Sections (symbol table, string table, etc.)
Sky Blue (#9be) -> Section Headers
Seems a bit complicated, would love to see better binary visualization tools on desktop.
The true value here is the backend and its ability to return data in a form that can be visualized, and the output format/UI can be adapted/enhanced as the project matures.
Doing this with Qt or GTK would be much much more work. Especially if you're using Rust which doesn't have any really good GUI options yet.
Way back in the day, in like, 1995, there was this thing called Perl. Perl was awesome. You'd think, "I want to make a custom LDAP client". And you'd look in CPAN for an LDAP module, and it'd be there (https://metacpan.org/pod/Net::LDAP), and you'd use it. A while later you realize you want to manipulate Active Directory SIDs. So you create a new module that inherits Net::LDAP, and publish it (https://metacpan.org/pod/Net::LDAP::SID).
On the plus side: everyone can install your module to get extra functionality with their existing code; people don't need to reinvent the wheel completely to do something a little different; and it's easy to see which module provides what/inherits from what.
On the down side: boring names for modules. (is that a downside?)