diff --git a/.gitignore b/.gitignore index 8b809f4..f457933 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,30 @@ /target -/.vscode -/tests Cargo.lock + +# This part is taken from GitHub's macOS gitignore template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e1980a7 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/unildd.iml b/.idea/unildd.iml new file mode 100644 index 0000000..cf84ae4 --- /dev/null +++ b/.idea/unildd.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..62a5b3c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "unildd" +version = "0.1.0" +edition = "2021" +authors = ["nix-enthusiast"] +license = "BSD-3" + +[dependencies] +# Object parsing library +goblin = { version = "0.8.2"} + +# For creating static HashMaps +phf = { version = "0.11.2", features = ["macros"] } + +# Coloring +owo-colors = "4.1.0" + +# For old Windows CMD +anstream = "0.6.15" + +[lib] +name = "unildd" +crate-type = ["cdylib", "staticlib"] + +[profile.release] +strip = true diff --git a/LICENSE b/LICENSE index 8000a6f..5b0f50e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,504 +1,28 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random - Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! +BSD 3-Clause License + +Copyright (c) 2024, nix-enthusiast + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.md b/README.md index d851e66..08bd7c4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,51 @@ -# unildd -UniLDD - A Portable Object Parsing Library +![banner](media/banner/UniLDD%20Banner.png) + +### UniLDD is designed to bring parsing objects to any language (has a C FFI library). -Currently Work In Progress +### ⭐️ Features: + - Detailed information! Some of them are: + - Name of the OS (Windows, macOS, Linux, etc.) + - File type (Core dump, shared library, executable, etc.) + - ISA type (X86_64, ARM64, RISC-V, etc.) + - CPU Subtype[^1] + - Name of the linker[^2] + - Which libraries are linked against + - Parses without loading objects. Therefore, you can even parse shady objects like malwares![^3] + - Error codes and explanations to make error handling easier. + - A Basic and built-in logger to get real-time information. + +### Installation +Basically: +- Clone the git repository: + + `git clone https://github.com/nix-enthusiast/unildd.git` + +- Go into the git repository: + + `cd unildd` + +- Compile build with cargo: + + `cargo build --release` + +- Put the output files to desired destination: + + `cp target/release/{libunildd.so,libunildd.a} /my/amazing/project/` + +- Also do not forget to copy the header file: + + `cp header/unildd.h /my/amazing/project/` + +### License +This library is licensed with [BSD-3 Clause License](https://choosealicense.com/licenses/bsd-3-clause/) + +The resources used to make this library are cited as comments in the respective source files which they were used. + +### 🎉 Thanks to: + - [m4b](https://github.com/m4b) for the [goblin](https://github.com/m4b/goblin) crate which this library gets its power by! + +[^1]: CPU subtype is a macOS-only feature which tells what kind of CPU model the code is optimized for. + +[^2]: It has some caveats. See the wiki (currently work-in-progress) for further details. + +[^3]: That doesn't mean I am liable for any damages done by this project and files you parsed. Take your own risk! diff --git a/header/unildd.h b/header/unildd.h new file mode 100644 index 0000000..b32d657 --- /dev/null +++ b/header/unildd.h @@ -0,0 +1,162 @@ +#include +#include +#include +#include + +/** + * + * An error struct for making error handling easy. + * + * ## Error Codes + * - \>0: Magic number of the unknown object (as `i64` (or `ìnt64_t)) + * - -1: Binary is corrupted + * - -2: Unknown/Bad magic number + * - -3: Error at reading and interpreting bytes + * - -4: I/O Error at parsing the object + * - -5: Buffer is too short to hold + * - -6: Unknown error[^1] + * - -7: Unimplemented executable format + * + * [^1]: All errors thrown by goblin crate and my code are covered. Because of matching goblin's [`Error`](goblin::error::Error) is non-exhaustive, I included non-exhaustive path too. + * + */ +typedef struct ParsingError { + int64_t code; + char *explanation; +} ParsingError; + +/** + * A C-compatible vector for `Vec`. + */ +typedef struct CharVec { + uintptr_t capacity; + uintptr_t length; + char **vec; +} CharVec; + +/** + * + * A struct contains detailed information about the object. + * + * It contains some information even the object is an erroneous one to make error handling more verbose. + * + * If the error occurs on parsing: + * - A file: `file_name` and `member_name` + * - A Muti Architecture Mach-O file: `file_name`, `member_name` and `executable_format` + * - An archive: `file_name`, `member_name` and `file_type` + * + * fields will be filled correctly and the rest will be: + * - null (the fields which are string) + * - blank (`member_name` and `libraries`) + * - `false` (`is_64` and `is_stripped`). + * + */ +typedef struct ULDDObj { + /** + * The name of the object. + * + * Objects inside Muti Architecture Mach-O files will be named as "n. file" due to they don't have file names. + */ + char *file_name; + /** + * The location of objects in recursive files. + * + * This field is empty if the object is not in a recursive file (Like: Archives and Muti Architecture Mach-O files). + * + * The names in the vector is sorted as outer to inner. + */ + struct CharVec member_name; + /** + * The type of the executable format of the object. + */ + char *executable_format; + /** + * The field is true if the object is 64 bit otherwise it is 32 bit or the object is an erroneous one. + */ + bool is_64; + /** + * The name of the OS it was compiled for. + */ + char *os_type; + /** + * The type of the object. + */ + char *file_type; + /** + * The field is true if the object was stripped from debug symbols otherwise it is not stripped or the object is an erroneous one . + */ + bool is_stripped; + /** + * The ISA (CPU Architecture) the object compiled for. + */ + char *cpu_type; + /** + * The specific CPU model the object compiled for. + * + * macOS only field. It is null pointer in other executable formats. + */ + char *cpu_subtype; + /** + * The name/version of the linker. + * + * ELF/PE only field. It is null pointer in other executable formats. + * + * It returns the version of the linker in PE files. + */ + char *interpreter; + /** + * A vector of libraries linked against the object. + * + * It is blank in COFF files because they are mostly PE object files therefore they don't have linked libraries against them. + */ + struct CharVec libraries; +} ULDDObj; + +/** + * A struct packs (empty or filled) error and (successfully or not) read object. + */ +typedef struct ULDDObjResult { + struct ParsingError error; + struct ULDDObj obj; +} ULDDObjResult; + +/** + * A C-compatible vector for [`ULDDObjResult`]. + */ +typedef struct ULDDObjResultVec { + uintptr_t capacity; + uintptr_t length; + struct ULDDObjResult *vec; +} ULDDObjResultVec; + +/** + * + * Parses the given buffer and returns a vector of parsed binaries. + * + * # Safety + * + * This function is null pointer-safe. If the file name is an invalid UTF-8 string and/or buffer pointer is a null pointer it will panic. + * + * Since the function returns a [`ULDDObjResultVec`] created by rust it has to be [deallocated](free_obj) by rust if it is done by other languages errors may occur. + * + */ +struct ULDDObjResultVec read_obj(const char *file_name, + const uint8_t *buffer, + uintptr_t buffer_size, + bool debugging); + +/** + * + * # Safety + * + * This function is designed for deallocating [`ULDDObjResultVec`] created by rust. Trying to deallocating [`ULDDObjResultVec`] created by other languages may result with errors. + * + * It is null pointer-safe. + * + * ## Error codes: + * - 0: No errors + * - 1: `vec` field of [`ULDDObjResultVec`] is a null pointer + * + */ +uint8_t free_obj(struct ULDDObjResultVec obj, + bool debugging); diff --git a/media/banner/UniLDD Banner.png b/media/banner/UniLDD Banner.png old mode 100644 new mode 100755 index d480359..e1ccc62 Binary files a/media/banner/UniLDD Banner.png and b/media/banner/UniLDD Banner.png differ diff --git a/media/banner/init b/media/banner/init deleted file mode 100644 index 8b13789..0000000 --- a/media/banner/init +++ /dev/null @@ -1 +0,0 @@ - diff --git a/media/emblems/UniLDD-%100.png b/media/emblems/UniLDD-%100.png old mode 100644 new mode 100755 diff --git a/media/emblems/UniLDD-%1000.png b/media/emblems/UniLDD-%1000.png deleted file mode 100644 index 77939f9..0000000 Binary files a/media/emblems/UniLDD-%1000.png and /dev/null differ diff --git a/media/emblems/UniLDD-%200.png b/media/emblems/UniLDD-%200.png deleted file mode 100644 index 4d8c745..0000000 Binary files a/media/emblems/UniLDD-%200.png and /dev/null differ diff --git a/media/emblems/UniLDD-%300.png b/media/emblems/UniLDD-%300.png deleted file mode 100644 index 63329ff..0000000 Binary files a/media/emblems/UniLDD-%300.png and /dev/null differ diff --git a/media/emblems/UniLDD-%400.png b/media/emblems/UniLDD-%400.png old mode 100644 new mode 100755 diff --git a/media/emblems/UniLDD-%500.png b/media/emblems/UniLDD-%500.png deleted file mode 100644 index cc7d9f4..0000000 Binary files a/media/emblems/UniLDD-%500.png and /dev/null differ diff --git a/media/emblems/UniLDD-%600.png b/media/emblems/UniLDD-%600.png deleted file mode 100644 index 595f9b0..0000000 Binary files a/media/emblems/UniLDD-%600.png and /dev/null differ diff --git a/media/emblems/UniLDD-%700.png b/media/emblems/UniLDD-%700.png deleted file mode 100644 index 64d2ab8..0000000 Binary files a/media/emblems/UniLDD-%700.png and /dev/null differ diff --git a/media/emblems/UniLDD-%800.png b/media/emblems/UniLDD-%800.png deleted file mode 100644 index 4461703..0000000 Binary files a/media/emblems/UniLDD-%800.png and /dev/null differ diff --git a/media/emblems/UniLDD-%900.png b/media/emblems/UniLDD-%900.png deleted file mode 100644 index 9bd20be..0000000 Binary files a/media/emblems/UniLDD-%900.png and /dev/null differ diff --git a/media/emblems/init b/media/emblems/init deleted file mode 100644 index 8b13789..0000000 --- a/media/emblems/init +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/archive.rs b/src/archive.rs new file mode 100755 index 0000000..8d45f0d --- /dev/null +++ b/src/archive.rs @@ -0,0 +1,43 @@ +use crate::{ + debug::{debug_objects, find_error_type, merge_members}, + parse_objects, + structs::{CharVec, Debugging, ParsingError, StringPtr, ULDDObj, ULDDObjResult}, +}; +use goblin::archive::Archive; + +pub(crate) fn parse_archive<'a>( + file_name: &'a str, + buffer: &'a [u8], + archive: Archive<'a>, + member_names: &mut Vec<&'a str>, + objects: &mut Vec, + debugging: bool, +) { + for member in archive.members() { + member_names.push(file_name); + let member_buffer = match archive.extract(member, buffer) { + Ok(buf) => buf, + Err(error) => { + Debugging::Error(format!("Error while extracting the bytes of the member named '{}' from buffer of the file named '{}'{}\nDetails:\n{}", + member, + file_name, + merge_members(member_names), + error)).print(debugging); + return objects.push(ULDDObjResult { + error: ParsingError { + code: find_error_type(&error), + explanation: StringPtr::from(error.to_string()).0, + }, + obj: ULDDObj { + file_name: StringPtr::from(file_name).0, + member_name: CharVec::from(member_names), + file_type: StringPtr::from("Archive").0, + ..Default::default() + }, + }); + } + }; + debug_objects(file_name, member_names, "an archive file", debugging); + parse_objects(member, member_buffer, member_names, objects, debugging); + } +} diff --git a/src/coff.rs b/src/coff.rs new file mode 100755 index 0000000..701645c --- /dev/null +++ b/src/coff.rs @@ -0,0 +1,40 @@ +use crate::{ + debug::debug_objects, + structs::{CharVec, ParsingError, StringPtr, ULDDObj, ULDDObjResult}, + types::PE_ARCH, +}; +use goblin::pe::{ + characteristic::{IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_DEBUG_STRIPPED}, + Coff, +}; +use std::ptr::null_mut; + +pub(crate) fn parse_coff( + file_name: &str, + coff: Coff, + member_names: &mut Vec<&str>, + debugging: bool, +) -> ULDDObjResult { + // Thanks to developers of goblin for making me to find out that I can "bitwise and" characteristics and wanted characteristics to find out if the COFF file has the one we want + let is_64 = coff.header.characteristics & IMAGE_FILE_32BIT_MACHINE != IMAGE_FILE_32BIT_MACHINE; + let is_stripped = + coff.header.characteristics & IMAGE_FILE_DEBUG_STRIPPED == IMAGE_FILE_DEBUG_STRIPPED; + let cpu_type = StringPtr::from(PE_ARCH.get(&coff.header.machine)).0; + debug_objects(file_name, member_names, "a COFF binary", debugging); + ULDDObjResult { + error: ParsingError::default(), + obj: ULDDObj { + file_name: StringPtr::from(file_name).0, + member_name: CharVec::from(member_names), + executable_format: StringPtr::from("COFF").0, + is_64, + os_type: StringPtr::from("Windows").0, + file_type: StringPtr::from("Windows object file").0, + is_stripped, + cpu_type, + cpu_subtype: null_mut(), + interpreter: null_mut(), + libraries: CharVec::default(), + }, + } +} diff --git a/src/debug.rs b/src/debug.rs new file mode 100644 index 0000000..0e00ab0 --- /dev/null +++ b/src/debug.rs @@ -0,0 +1,37 @@ +use goblin::error::Error as ObjectError; + +use crate::structs::Debugging; + +pub(crate) fn find_error_type(error: &ObjectError) -> i64 { + match error { + ObjectError::Malformed(_) => -1, + ObjectError::BadMagic(_) => -2, + ObjectError::Scroll(_) => -3, + ObjectError::BufferTooShort(_, _) => -4, + ObjectError::IO(_) => -5, + _ => -6, + } +} + +pub(crate) fn merge_members(member_names: &mut [&str]) -> String { + if !member_names.is_empty() { + format!(" (Member of: {})", member_names.join(" -> ")) + } else { + String::new() + } +} + +pub(crate) fn debug_objects( + file_name: &str, + member_names: &mut [&str], + object_name: &str, + debugging: bool, +) { + Debugging::Info(format!( + "The binary named '{}'{} is {}", + file_name, + merge_members(member_names), + object_name + )) + .print(debugging) +} diff --git a/src/elf.rs b/src/elf.rs new file mode 100755 index 0000000..51e9f38 --- /dev/null +++ b/src/elf.rs @@ -0,0 +1,133 @@ +use std::ptr::null_mut; + +use crate::{ + debug::debug_objects, + structs::{CharVec, ParsingError, StringPtr, ULDDObj, ULDDObjResult}, + types::{ElfFileType, ElfOS, E_MACHINE, E_TYPE}, +}; +use goblin::elf::Elf; + +fn find_os_from_strtab_elf(elf: &Elf<'_>, pat: &[&str]) -> bool { + [ + elf.strtab.to_vec().unwrap_or(vec![""]), + elf.shdr_strtab.to_vec().unwrap_or(vec![""]), + elf.dynstrtab.to_vec().unwrap_or(vec![""]), + ] + .iter() + .flatten() + .any(|s| pat.iter().any(|i| s.to_lowercase().contains(i))) +} + +fn find_os_elf(elf: &Elf<'_>, os_abi: u8) -> (ElfOS, *mut i8) { + let os = { + match os_abi { + 0x00 => match true { + _ if find_os_from_strtab_elf(elf, &["fbsd"]) => ElfOS::FreeBSD, + _ if find_os_from_strtab_elf(elf, &["openbsd"]) => ElfOS::OpenBSD, + _ if find_os_from_strtab_elf(elf, &["musl", "glibc", "linux"]) => ElfOS::Linux, + _ if find_os_from_strtab_elf(elf, &["android"]) => ElfOS::Android, + _ if find_os_from_strtab_elf(elf, &["netbsd"]) => ElfOS::NetBSD, + _ if find_os_from_strtab_elf(elf, &["solaris"]) => ElfOS::Solaris, + _ if find_os_from_strtab_elf(elf, &["illumos"]) => ElfOS::Illumos, + _ if elf.interpreter.is_some_and(|v| v.contains("Loader.so")) => ElfOS::SerenityOS, + _ => return (ElfOS::Undefined, null_mut()), + }, + 0x01 => ElfOS::HPUX, + 0x02 => ElfOS::NetBSD, + 0x03 => ElfOS::Linux, + 0x04 => ElfOS::GNUHurd, + 0x06 => { + if find_os_from_strtab_elf(elf, &["illumos"]) { + ElfOS::Illumos + } else { + ElfOS::Solaris + } + } + 0x07 => ElfOS::AIXMonterey, + 0x08 => ElfOS::IRIX, + 0x09 => ElfOS::FreeBSD, + 0x10 => ElfOS::FenixOS, + 0x11 => ElfOS::CloudABI, + 0x12 => ElfOS::OpenVOS, + 0x0A => ElfOS::Tru64, + 0x0B => ElfOS::NovellModesto, + 0x0C => ElfOS::OpenBSD, + 0x0D => ElfOS::OpenVMS, + 0x0E => ElfOS::NonStopKernel, + 0x0F => ElfOS::AROS, + _ => return (ElfOS::Undefined, null_mut()), + } + }; + + (os, StringPtr::from(os.to_string()).0) +} + +fn find_linux_vdso(e_machine: u16, bit_type: bool) -> Option<&'static str> { + match e_machine { + 0x3E => Some("linux-vdso.so.1"), + 0x03 => Some("linux-vdso.so.1"), + 0x2A => Some("linux-gate.so.1"), + 0x16 => { + if bit_type { + Some("linux-vdso64.so.1") + } else { + Some("linux-vdso32.so.1") + } + } + 0xF3 => Some("linux-vdso.so.1"), + 0x15 => Some("linux-vdso64.so.1"), + 0x14 => Some("linux-vdso32.so.1"), + 0x08 => Some("linux-vdso.so.1"), + 0x32 => Some("linux-gate.so.1"), + 0x28 => Some("linux-vdso.so.1"), + 0xB7 => Some("linux-vdso.so.1"), + _ => None, + } +} + +fn convert_libraries_into_char_vec(elf: &mut Elf, os_abi: u8) -> CharVec { + let mut vector = std::mem::take(&mut elf.libraries); + if let (Some(vdso), ElfOS::Linux) = ( + find_linux_vdso(elf.header.e_machine, elf.is_64), + find_os_elf(elf, os_abi).0, + ) { + vector.push(vdso) + } + + CharVec::from(vector) +} + +pub(crate) fn parse_elf( + file_name: &str, + elf: Elf, + os_abi: u8, + member_names: &mut Vec<&str>, + debugging: bool, +) -> ULDDObjResult { + let mut elf = elf; + let cpu_type = StringPtr::from(E_MACHINE.get(&elf.header.e_machine)).0; + let file_type = match E_TYPE.get(&elf.header.e_type) { + _ if elf.header.e_type == 0x03 && elf.interpreter.is_some() => { + StringPtr::from(ElfFileType::Executable.to_string()).0 + } + rest => StringPtr::from(rest).0, + }; + let interpreter = StringPtr::from(elf.interpreter).0; + debug_objects(file_name, member_names, "an ELF binary", debugging); + ULDDObjResult { + error: ParsingError::default(), + obj: ULDDObj { + file_name: StringPtr::from(file_name).0, + member_name: CharVec::from(member_names), + executable_format: StringPtr::from("ELF").0, + is_64: elf.is_64, + os_type: find_os_elf(&elf, os_abi).1, + file_type, + is_stripped: elf.syms.is_empty(), + cpu_type, + cpu_subtype: null_mut(), + interpreter, + libraries: convert_libraries_into_char_vec(&mut elf, os_abi), + }, + } +} diff --git a/src/impls.rs b/src/impls.rs new file mode 100755 index 0000000..9e4b11f --- /dev/null +++ b/src/impls.rs @@ -0,0 +1,152 @@ +use crate::{ + structs::{CharVec, Debugging, ParsingError, StringPtr, ULDDObj}, + ULDDObjResult, ULDDObjResultVec, +}; +use anstream::{eprintln as a_eprintln, println as a_println}; +use owo_colors::OwoColorize; +use std::{fmt::Display, mem::ManuallyDrop, ptr::null_mut, ffi::{c_char, CString}}; + +impl From> for CharVec { + fn from(value: Vec<*mut c_char>) -> Self { + CharVec { + capacity: value.capacity(), + length: value.len(), + vec: if value.is_empty() { + null_mut() + } else { + ManuallyDrop::new(value).as_mut_ptr() + }, + } + } +} + +impl From> for ULDDObjResultVec { + fn from(value: Vec) -> Self { + ULDDObjResultVec { + capacity: value.capacity(), + length: value.len(), + vec: if value.is_empty() { + null_mut() + } else { + ManuallyDrop::new(value).as_mut_ptr() + }, + } + } +} + +impl Default for CharVec { + fn default() -> Self { + Self { + capacity: 0, + length: 0, + vec: null_mut(), + } + } +} + +impl From> for CharVec { + fn from(val: Vec<&str>) -> Self { + let vector: Vec<*mut c_char> = val + .into_iter() + .map(|item| unsafe { + CString::from_vec_unchecked(item.to_string().into_bytes()).into_raw() + }) + .collect(); + + CharVec::from(vector) + } +} + +impl From<&mut Vec<&str>> for CharVec { + fn from(val: &mut Vec<&str>) -> Self { + let vector: Vec<*mut c_char> = std::mem::take(val) + .into_iter() + .map(|item| unsafe { + CString::from_vec_unchecked(item.to_string().into_bytes()).into_raw() + }) + .collect(); + + CharVec::from(vector) + } +} + +impl From for StringPtr { + fn from(value: String) -> Self { + let mut value = value; + value.push('\0'); + let c_string = match CString::from_vec_with_nul(value.into_bytes()) { + Ok(string) => string, + Err(error) => { + Debugging::Fatal("converting the string into a C string".to_owned()).print(true); + panic!("{}", error) + } + }; + StringPtr(c_string.into_raw()) + } +} + +impl From<&str> for StringPtr { + fn from(value: &str) -> Self { + StringPtr::from(value.to_owned()) + } +} + +impl From> for StringPtr +where + T: Display, +{ + fn from(value: Option) -> Self { + let Some(t) = value else { + return StringPtr(null_mut()); + }; + StringPtr::from(t.to_string()) + } +} + +impl Default for ParsingError { + fn default() -> Self { + Self { + code: 0, + explanation: null_mut(), + } + } +} + +impl Default for ULDDObj { + fn default() -> Self { + Self { + file_name: null_mut(), + member_name: Default::default(), + executable_format: null_mut(), + is_64: false, + os_type: null_mut(), + file_type: null_mut(), + is_stripped: false, + cpu_type: null_mut(), + cpu_subtype: null_mut(), + interpreter: null_mut(), + libraries: Default::default(), + } + } +} + +impl Debugging { + pub(crate) fn print(self, debugging: bool) { + if debugging { + match self { + Debugging::Info(msg) => { + a_println!("{} {}", "[INFO]".yellow().bold(), msg); + } + Debugging::Affirmative(msg) => { + a_println!("{} {}", "[OK]".green().bold(), msg); + } + Debugging::Error(msg) => { + a_eprintln!("{} {}", "[ERROR]".red().bold(), msg); + } + Debugging::Fatal(msg) => { + a_eprintln!("{} Library got a fatal error while {}. Panic function will halt the library and provide a stacktrace.", "[FATAL]".red().bold(), msg); + } + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100755 index 0000000..c8ee01a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,286 @@ +#![doc( + html_favicon_url = "https://github.com/nix-enthusiast/unildd/blob/main/media/emblems/UniLDD-%25100.png?raw=true" +)] +#![doc( + html_logo_url = "https://github.com/nix-enthusiast/unildd/blob/main/media/emblems/UniLDD-%25400.png?raw=true" +)] +#![doc(html_playground_url = "https://play.rust-lang.org/")] +//! +//! ![banner](https://github.com/nix-enthusiast/unildd/blob/main/media/banner/UniLDD%20Banner.png?raw=true) +//! +//! ### UniLDD is designed for bringing parsing objects to any language (has a C FFI library). +//! +//! ### ⭐️ Features: +//! - Detailed information! Some of them are: +//! - Name of the OS +//! - File type (Core dump, shared library, executable, etc.) +//! - ISA type (X86_64, Aarch64, RISC-V, etc.) +//! - CPU Subtype[^1] +//! - Name of the linker[^2] +//! - Which libraries are linked +//! - Parses without loading objects. Therefore, you can even parse shady objects like malwares![^3] +//! - Error codes and explanations to make error handling easier. +//! - A Basic and built-in logger to get real-time information. +//! +//! [^1]: CPU subtype is a macOS-only feature which tells what kind of CPU model the code is optimized for. +//! +//! [^2]: It has some caveats. See [`ULDDObj`] for further details. +//! +//! [^3]: That doesn't mean I am liable for any damages done by this project and files you parsed. Take your own risk! +//! +use archive::parse_archive; +use coff::parse_coff; +use debug::{find_error_type, merge_members}; +use elf::parse_elf; +use goblin::Object; +use mach::parse_mach; +use owo_colors::OwoColorize; +use pe::parse_pe; +use std::ffi::{c_char, CStr, CString}; +use structs::{ + CharVec, Debugging, ParsingError, StringPtr, ULDDObj, ULDDObjResult, ULDDObjResultVec, +}; +#[doc(hidden)] +pub mod archive; +#[doc(hidden)] +pub mod coff; +#[doc(hidden)] +pub mod debug; +#[doc(hidden)] +pub mod elf; +#[doc(hidden)] +pub mod impls; +#[doc(hidden)] +pub mod mach; +#[doc(hidden)] +pub mod pe; + +pub mod structs; +pub mod types; + +fn parse_objects<'a>( + file_name: &'a str, + buffer: &'a [u8], + member_names: &mut Vec<&'a str>, + objects: &mut Vec, + debugging: bool, +) { + match Object::parse(buffer) { + Ok(Object::Archive(archive)) => { + parse_archive(file_name, buffer, archive, member_names, objects, debugging) + } + + Ok(Object::Mach(mach)) => { + parse_mach(file_name, buffer, mach, member_names, objects, debugging) + } + + Ok(Object::Elf(elf)) => { + objects.push(parse_elf( + file_name, + elf, + buffer[0x7], + member_names, + debugging, + )); + } + + Ok(Object::PE(pe)) => objects.push(parse_pe(file_name, pe, member_names, debugging)), + + Ok(Object::COFF(coff)) => { + objects.push(parse_coff(file_name, coff, member_names, debugging)); + } + + Ok(Object::Unknown(magic_number)) => { + let msg = format!( + "The binary named '{}'{} has a unknown magic number (in big-endian): {}", + file_name, + merge_members(member_names), + format!("{:02X?}", magic_number.to_be_bytes()).replace(['[', ']', ','], "") + ); + Debugging::Error(msg.to_owned()).print(debugging); + objects.push(ULDDObjResult { + error: ParsingError { + code: magic_number as i64, + explanation: StringPtr::from(msg).0, + }, + obj: ULDDObj { + file_name: StringPtr::from(file_name).0, + member_name: CharVec::from(member_names), + ..Default::default() + }, + }) + } + + Ok(_) => { + let msg = format!( + "The executable format of the file named '{}'{} is not yet implemented", + file_name, + merge_members(member_names), + ); + Debugging::Error(msg.to_string()).print(debugging); + Debugging::Info(format!( + "First 16 bytes of the file named '{}' are {}", + file_name, + format!("{:02X?}", &buffer[0..17]).replace(['[', ']', ','], "") + )) + .print(debugging); + + objects.push(ULDDObjResult { + error: ParsingError { + code: -7, + explanation: StringPtr::from(msg).0, + }, + obj: ULDDObj { + file_name: StringPtr::from(file_name).0, + member_name: CharVec::from(member_names), + ..Default::default() + }, + }) + } + + Err(error) => { + Debugging::Error(format!( + "Error while parsing the bytes of the given file named '{}'{}\nDetails:\n{}", + file_name, + merge_members(member_names), + error + )) + .print(debugging); + + objects.push(ULDDObjResult { + error: ParsingError { + code: find_error_type(&error), + explanation: StringPtr::from(error.to_string()).0, + }, + obj: ULDDObj { + file_name: StringPtr::from(file_name).0, + member_name: CharVec::from(member_names), + ..Default::default() + }, + }) + } + }; +} + +/// +/// Parses the given buffer and returns a vector of parsed binaries. +/// +/// # Safety +/// +/// This function is null pointer-safe. If the file name is an invalid UTF-8 string and/or buffer pointer is a null pointer it will panic. +/// +/// Since the function returns a [`ULDDObjResultVec`] created by rust it has to be [deallocated](free_obj) by rust if it is done by other languages errors may occur. +/// +#[no_mangle] +pub unsafe extern "C" fn read_obj( + file_name: *const c_char, + buffer: *const u8, + buffer_size: usize, + debugging: bool, +) -> ULDDObjResultVec { + let (buf, f_name) = unsafe { + let s = match CStr::from_ptr(file_name).to_str() { + Ok(string_slice) => string_slice, + Err(error) => { + Debugging::Fatal("converting the C string to a &str".to_owned()).print(true); + panic!("{}", error) + } + }; + let b = std::slice::from_raw_parts(buffer, buffer_size); + (b, s) + }; + + let mut objects = vec![]; + parse_objects(f_name, buf, &mut vec![], &mut objects, debugging); + let (total, success, failed): (usize, usize, usize) = { + let t = objects.len(); + let (mut s, mut f) = (0, 0); + objects.iter().for_each(|o| { + if o.error.code != 0 { + f += 1; + } else { + s += 1 + } + }); + (t, s, f) + }; + + Debugging::Affirmative(format!( + "{} binaries from the file(s) are parsed. Success/Fail rate of parsing(s) is {}/{}", + total, + success.green(), + failed.red() + )) + .print(debugging); + + ULDDObjResultVec::from(objects) +} + +unsafe fn drop_c_string(ptr: *mut i8) { + if !ptr.is_null() { + let _ = CString::from_raw(ptr); + } +} + +/// +/// # Safety +/// +/// This function is designed for deallocating [`ULDDObjResultVec`] created by rust. Trying to deallocating [`ULDDObjResultVec`] created by other languages may result with errors. +/// +/// It is null pointer-safe. +/// +/// ## Error codes: +/// - 0: No errors +/// - 1: `vec` field of [`ULDDObjResultVec`] is a null pointer +/// +#[no_mangle] +pub unsafe extern "C" fn free_obj(obj: ULDDObjResultVec, debugging: bool) -> u8 { + if obj.vec.is_null() { + Debugging::Error("Given object vector is invalid".to_owned()).print(debugging); + + Debugging::Error("Deallocation(s) is failed".to_owned()).print(debugging); + + return 1; + }; + + let object_vector = Vec::from_raw_parts(obj.vec, obj.length, obj.capacity); + for (index, object) in object_vector.into_iter().enumerate() { + Debugging::Info(format!("{}. object is being deallocated", index + 1)).print(debugging); + + let o = object.obj; + drop_c_string(object.error.explanation); + drop_c_string(o.file_name); + drop_c_string(o.executable_format); + drop_c_string(o.os_type); + drop_c_string(o.file_type); + drop_c_string(o.cpu_type); + drop_c_string(o.cpu_subtype); + drop_c_string(o.interpreter); + if !o.member_name.vec.is_null() { + let member_names = Vec::from_raw_parts( + o.member_name.vec, + o.member_name.length, + o.member_name.capacity, + ); + for name in member_names { + drop_c_string(name) + } + }; + if !o.libraries.vec.is_null() { + let libraries = + Vec::from_raw_parts(o.libraries.vec, o.libraries.length, o.libraries.capacity); + for library in libraries { + drop_c_string(library) + } + }; + Debugging::Affirmative(format!("{}. object is deallocated", index + 1)).print(debugging); + } + + Debugging::Affirmative(format!( + "Deallocation(s) is successful. {} object(s) is freed.", + obj.length + )) + .print(debugging); + + 0 +} diff --git a/src/mach.rs b/src/mach.rs new file mode 100755 index 0000000..ec57d7b --- /dev/null +++ b/src/mach.rs @@ -0,0 +1,206 @@ +use crate::{ + debug::{debug_objects, find_error_type, merge_members}, + structs::{CharVec, Debugging, ParsingError, StringPtr, ULDDObj, ULDDObjResult}, + types::{ + MachOCpuType, MachOOs, MACH_O_ARM_CPU_SUBTYPE, MACH_O_CPUTYPE, MACH_O_FILE_TYPE, + MACH_O_X86_CPU_SUBTYPE, + }, +}; +use goblin::mach::{load_command::CommandVariant::BuildVersion, Mach, MachO}; +use std::ptr::null_mut; + +fn find_os_mach(mach: &MachO<'_>) -> *mut i8 { + for lc in &mach.load_commands { + if let BuildVersion(build_version) = lc.command { + let os = match build_version.platform { + 0x01 => MachOOs::MacOS, + 0x02 => MachOOs::IOS, + 0x03 => MachOOs::AppleTVBox, + 0x04 => MachOOs::AppleWatch, + 0x05 => MachOOs::BridgeOS, + 0x06 => MachOOs::MacCatalyst, + 0x07 => MachOOs::IOSSimulator, + 0x08 => MachOOs::AppleTVSimulator, + 0x09 => MachOOs::AppleWatchSimulator, + 0x0A => MachOOs::DriverKit, + 0x0B => MachOOs::AppleVisionPro, + 0x0C => MachOOs::AppleVisionProSimulator, + _ => return null_mut(), + }; + return StringPtr::from(os.to_string()).0; + } + } + + null_mut() +} + +/* +I will leave it there because I may use later + +fn decode_further(mach: &MachO<'_>) { + for lc in &mach.load_commands { + if let BuildVersion(build_version) = lc.command { + let os = match build_version.platform { + 0x01 => MachOOs::MacOS, + 0x02 => MachOOs::IOS, + 0x03 => MachOOs::AppleTVBox, + 0x04 => MachOOs::AppleWatch, + 0x05 => MachOOs::BridgeOS, + 0x06 => MachOOs::MacCatalyst, + 0x07 => MachOOs::IOSSimulator, + 0x08 => MachOOs::AppleTVSimulator, + 0x09 => MachOOs::AppleWatchSimulator, + 0x0A => MachOOs::DriverKit, + 0x0B => MachOOs::AppleVisionPro, + 0x0C => MachOOs::AppleVisionProSimulator, + _ => MachOOs::Undefined, + }; + let os_ver = { + let [_, x, y, z] = build_version.minos.to_be_bytes(); + format!("{x}.{y}.{z}") + }; + let sdk_ver = { + let [_, x, y, z] = build_version.sdk.to_be_bytes(); + format!("{x}.{y}.{z}") + }; + let tool_type = match build_version.ntools { + 0x1 => "Clang", + 0x2 => "Swift", + 0x3 => "Linked with ld", + _ => "Unknown" + }; + } + } +} +*/ + +pub(crate) fn parse_mach<'a>( + file_name: &'a str, + buffer: &[u8], + mach: Mach, + member_names: &mut Vec<&'a str>, + objects: &mut Vec, + debugging: bool, +) { + match mach { + Mach::Fat(fat) => { + debug_objects( + file_name, + member_names, + "a multi architecture Mach-O", + debugging, + ); + let fat_arches = match fat.arches() { + Ok(arches) => arches, + Err(error) => { + Debugging::Error(format!("Error while reading the multi architecture Mach-O binary named '{}'{}\nDetails:\n{}", + file_name, + merge_members(member_names), + error)).print(debugging); + + return objects.push(ULDDObjResult { + error: ParsingError { + code: find_error_type(&error), + explanation: StringPtr::from(error.to_string()).0, + }, + obj: ULDDObj { + file_name: StringPtr::from(file_name).0, + member_name: CharVec::from(member_names), + executable_format: StringPtr::from("Mach-O").0, + ..Default::default() + }, + }); + } + }; + + for (index, arch) in fat_arches.iter().enumerate() { + match MachO::parse(buffer, arch.offset as usize) { + Ok(mach_o) => { + member_names.push(file_name); + objects.push(parse_mach_o( + &format!("{}. file", index + 1), + member_names, + mach_o, + debugging, + )) + } + Err(error) => { + Debugging::Error(format!("Error while processing the multi architecture Mach-O binary named '{}'{}\nDetails:\n{}", file_name, merge_members(member_names), + error)).print(debugging); + objects.push(ULDDObjResult { + error: ParsingError { + code: find_error_type(&error), + explanation: StringPtr::from(error.to_string()).0, + }, + obj: ULDDObj { + file_name: StringPtr::from(file_name).0, + member_name: CharVec::from(member_names.clone()), + executable_format: StringPtr::from("Mach-O").0, + ..Default::default() + }, + }) + } + } + } + } + Mach::Binary(binary) => { + objects.push(parse_mach_o(file_name, member_names, binary, debugging)) + } + } +} + +fn parse_mach_o( + file_name: &str, + member_names: &mut Vec<&str>, + mach_o: MachO, + debugging: bool, +) -> ULDDObjResult { + let mut mach_o = mach_o; + let file_type = StringPtr::from(MACH_O_FILE_TYPE.get(&mach_o.header.filetype)).0; + let (cpu_type, cpu_subtype) = { + if let Some(mach_o_cpu_type) = MACH_O_CPUTYPE.get(&mach_o.header.cputype) { + let mach_o_cpu_subtype = { + match mach_o_cpu_type { + MachOCpuType::ARM | MachOCpuType::ARM64 => { + StringPtr::from(MACH_O_ARM_CPU_SUBTYPE.get(&mach_o.header.cpusubtype)).0 + } + MachOCpuType::X86 | MachOCpuType::X86_64 => { + StringPtr::from(MACH_O_X86_CPU_SUBTYPE.get(&mach_o.header.cpusubtype)).0 + } + _ => null_mut(), + } + }; + ( + StringPtr::from(mach_o_cpu_type.to_string()).0, + mach_o_cpu_subtype, + ) + } else { + (null_mut(), null_mut()) + } + }; + + let is_stripped = !mach_o + .symbols + .as_ref() + .is_some_and(|v| v.iter().any(|s| s.is_ok_and(|(x, _)| x.contains("debug")))); + + mach_o.libs.retain(|lib| lib != &"self"); + debug_objects(file_name, member_names, "a Mach-O binary", debugging); + + ULDDObjResult { + error: ParsingError::default(), + obj: ULDDObj { + file_name: StringPtr::from(file_name).0, + member_name: CharVec::from(member_names), + executable_format: StringPtr::from("Mach-O").0, + is_64: mach_o.is_64, + os_type: find_os_mach(&mach_o), + file_type, + is_stripped, + cpu_type, + cpu_subtype, + interpreter: null_mut(), + libraries: CharVec::from(mach_o.libs), + }, + } +} diff --git a/src/pe.rs b/src/pe.rs new file mode 100755 index 0000000..37ad564 --- /dev/null +++ b/src/pe.rs @@ -0,0 +1,88 @@ +use crate::{ + debug::debug_objects, + structs::{CharVec, ParsingError, StringPtr, ULDDObj, ULDDObjResult}, + types::{PeOS, PeSubsystem, PE_ARCH, PE_SUBSYSTEM}, +}; +use goblin::pe::{characteristic::IMAGE_FILE_DEBUG_STRIPPED, PE}; +use std::ptr::null_mut; + +fn find_os_pe(pe: &PE<'_>) -> *mut i8 { + let Some(optional_header) = pe + .header + .optional_header + .and_then(|h| PE_SUBSYSTEM.get(&h.windows_fields.subsystem)) + else { + return null_mut(); + }; + + let os = match optional_header { + PeSubsystem::Xbox => PeOS::Xbox, + PeSubsystem::EFIApplication + | PeSubsystem::EFIBootServiceDriver + | PeSubsystem::EFIRom + | PeSubsystem::EFIRuntimeDriver => PeOS::UEFI, + PeSubsystem::WindowsCUI + | PeSubsystem::WindowsGUI + | PeSubsystem::Native + | PeSubsystem::OS2CUI + | PeSubsystem::PosixCUI + | PeSubsystem::NativeWindows + | PeSubsystem::WindowsCEGUI + | PeSubsystem::WindowsBootApplication => PeOS::Windows, + PeSubsystem::Unknown => return null_mut(), + }; + + StringPtr::from(os.to_string()).0 +} + +pub(crate) fn parse_pe( + file_name: &str, + pe: PE, + member_names: &mut Vec<&str>, + debugging: bool, +) -> ULDDObjResult { + let is_stripped = pe.header.coff_header.characteristics & IMAGE_FILE_DEBUG_STRIPPED + == IMAGE_FILE_DEBUG_STRIPPED; + let cpu_type = StringPtr::from(PE_ARCH.get(&pe.header.coff_header.machine)).0; + let file_type = pe + .header + .optional_header + .and_then(|h| PE_SUBSYSTEM.get(&h.windows_fields.subsystem)); + let interpreter = { + if let Some(optional_header) = pe.header.optional_header { + let linker_major_version = optional_header + .windows_fields + .major_operating_system_version; + let linker_minor_version = optional_header + .windows_fields + .minor_operating_system_version; + let linker_version = format!("{}.{}", linker_major_version, linker_minor_version); + StringPtr::from(linker_version).0 + } else { + null_mut() + } + }; + let executable_format = if pe.is_64 { + debug_objects(file_name, member_names, "a PE32+ binary", debugging); + StringPtr::from("PE32+").0 + } else { + debug_objects(file_name, member_names, "a PE32 binary", debugging); + StringPtr::from("PE32").0 + }; + ULDDObjResult { + error: ParsingError::default(), + obj: ULDDObj { + file_name: StringPtr::from(file_name).0, + member_name: CharVec::from(member_names), + executable_format, + is_64: pe.is_64, + os_type: find_os_pe(&pe), + file_type: StringPtr::from(file_type).0, + is_stripped, + cpu_type, + cpu_subtype: null_mut(), + interpreter, + libraries: CharVec::from(pe.libraries), + }, + } +} diff --git a/src/structs.rs b/src/structs.rs new file mode 100755 index 0000000..e41ad1b --- /dev/null +++ b/src/structs.rs @@ -0,0 +1,111 @@ +use std::ffi::c_char; + +/// A C-compatible vector for `Vec`. +#[repr(C)] +pub struct CharVec { + pub capacity: usize, + pub length: usize, + pub vec: *mut *mut c_char, +} + +/// +/// An error struct for making error handling easy. +/// +/// ## Error Codes +/// - \>0: Magic number of the unknown object (as `i64` (or `ìnt64_t)) +/// - -1: Binary is corrupted +/// - -2: Unknown/Bad magic number +/// - -3: Error at reading and interpreting bytes +/// - -4: I/O Error at parsing the object +/// - -5: Buffer is too short to hold +/// - -6: Unknown error[^1] +/// - -7: Unimplemented executable format +/// +/// [^1]: All errors thrown by goblin crate and my code are covered. Because of matching goblin's [`Error`](goblin::error::Error) is non-exhaustive, I included non-exhaustive path too. +/// +#[repr(C)] +pub struct ParsingError { + pub code: i64, + pub explanation: *mut c_char, +} + +/// +/// A struct contains detailed information about the object. +/// +/// It contains some information even the object is an erroneous one to make error handling more verbose. +/// +/// If the error occurs on parsing: +/// - A file: `file_name` and `member_name` +/// - A Muti Architecture Mach-O file: `file_name`, `member_name` and `executable_format` +/// - An archive: `file_name`, `member_name` and `file_type` +/// +/// fields will be filled correctly and the rest will be: +/// - null (the fields which are string) +/// - blank (`member_name` and `libraries`) +/// - `false` (`is_64` and `is_stripped`). +/// +#[repr(C)] +pub struct ULDDObj { + /// The name of the object. + /// + /// Objects inside Muti Architecture Mach-O files will be named as "n. file" due to they don't have file names. + pub file_name: *mut c_char, + /// The location of objects in recursive files. + /// + /// This field is empty if the object is not in a recursive file (Like: Archives and Muti Architecture Mach-O files). + /// + /// The names in the vector is sorted as outer to inner. + pub member_name: CharVec, + /// The type of the executable format of the object. + pub executable_format: *mut c_char, + /// The field is true if the object is 64 bit otherwise it is 32 bit or the object is an erroneous one. + pub is_64: bool, + /// The name of the OS it was compiled for. + pub os_type: *mut c_char, + /// The type of the object. + pub file_type: *mut c_char, + /// The field is true if the object was stripped from debug symbols otherwise it is not stripped or the object is an erroneous one . + pub is_stripped: bool, + /// The ISA (CPU Architecture) the object compiled for. + pub cpu_type: *mut c_char, + /// The specific CPU model the object compiled for. + /// + /// macOS only field. It is null pointer in other executable formats. + pub cpu_subtype: *mut c_char, + /// The name/version of the linker. + /// + /// ELF/PE only field. It is null pointer in other executable formats. + /// + /// It returns the version of the linker in PE files. + pub interpreter: *mut c_char, + /// A vector of libraries linked against the object. + /// + /// It is blank in COFF files because they are mostly PE object files therefore they don't have linked libraries against them. + pub libraries: CharVec, +} + +/// A struct packs (empty or filled) error and (successfully or not) read object. +#[repr(C)] +pub struct ULDDObjResult { + pub error: ParsingError, + pub obj: ULDDObj, +} + +/// A C-compatible vector for [`ULDDObjResult`]. +#[repr(C)] +pub struct ULDDObjResultVec { + pub capacity: usize, + pub length: usize, + pub vec: *mut ULDDObjResult, +} + +#[doc(hidden)] +pub struct StringPtr(pub *mut i8); + +#[doc(hidden)] +pub(crate) enum Debugging { + Info(String), + Affirmative(String), + Error(String), + Fatal(String), +} diff --git a/src/types.rs b/src/types.rs new file mode 100755 index 0000000..c14c7d8 --- /dev/null +++ b/src/types.rs @@ -0,0 +1,897 @@ +use phf::phf_map; +use std::fmt::{Display, Formatter, Result as FmtResult}; + +/* +Source: +https://en.wikipedia.org/wiki/Executable_and_Linkable_Format +https://en.wikipedia.org/wiki/Cell_(processor) +https://en.wikipedia.org/wiki/ETRAX_CRIS +https://developer.fedoraproject.org/deployment/secondary_architectures/s390.html#:~:text=s390%20is%2031%2Dbit%2Daddress,known%20as%20IBM%20System%20z. +https://www.infineon.com/cms/en/product/microcontroller/ +*/ + +/// MP Stands for Microprocessor +/// BPF Stands for Berkeley Packet Filter +#[allow(clippy::upper_case_acronyms)] +#[derive(Debug)] +pub enum ElfInstructionSet { + Undefined, + WE32100, + SPARC, + X86, + M68k, + M88k, + IntelMCU, + I860, + MIPS, + IBMSystem370, + MIPSRS3000Le, + FutureUse, + HPPPRISC, + I960, + PPC, + PPC64, + S390, + S390x, + // Wikipedia or Google doesn't provide healthy info about what IBM SPU/SPC is + IBMSPUSPC, + NECV800, + FR20, + RH32, + MotorolaRCE, + Arm32, + DigitalAlpha, + SuperH, + SPARCVersion9, + SiemensTriCore, + ArgonautRISCCore, + H8300, + H8300H, + H8S, + H8500, + IA64, + StanfordMIPSX, + MotorolaColdFire, + MotorolaM68HC12, + FujitsuMMA, + SiemensPCP, + SonyCellCPU, + DensoNDR1, + MotorolaStarCore, + ToyotaME16, + STMicroelectronicsST100, + AdvancedLogicCorpTinyJ, + X86_64, + SonyDSP, + PDP10, + PDP11, + SiemensFX66, + STMicroelectronicsST9Plus, + STMicroelectronicsST7, + MC68HC16, + MC68HC11, + MC68HC08, + MC68HC05, + SiliconGraphicsSVx, + STMicroelectronicsST19, + DigitalVAX, + ETRAXCRIS, + InfineonTechnologiesMP32, + Element14DSP64, + LSILogicDSP16, + TMS320C6000, + MCSTElbrusE2k, + Arm64, + ZilogZ80, + RISCV, + BPF, + WDC65C816, +} + +// Source: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format +pub const E_MACHINE: phf::Map = phf_map! { + 0x00_u16 => ElfInstructionSet::Undefined, + 0x01_u16 => ElfInstructionSet::WE32100, + 0x02_u16 => ElfInstructionSet::SPARC, + 0x03_u16 => ElfInstructionSet::X86, + 0x04_u16 => ElfInstructionSet::M68k, + 0x05_u16 => ElfInstructionSet::M88k, + 0x06_u16 => ElfInstructionSet::IntelMCU, + 0x07_u16 => ElfInstructionSet::I860, + 0x08_u16 => ElfInstructionSet::MIPS, + 0x09_u16 => ElfInstructionSet::IBMSystem370, + 0x0A_u16 => ElfInstructionSet::MIPSRS3000Le, + 0x0B_u16 => ElfInstructionSet::FutureUse, + 0x0C_u16 => ElfInstructionSet::FutureUse, + 0x0D_u16 => ElfInstructionSet::FutureUse, + 0x0E_u16 => ElfInstructionSet::FutureUse, + 0x0F_u16 => ElfInstructionSet::HPPPRISC, + 0x13_u16 => ElfInstructionSet::I960, + 0x14_u16 => ElfInstructionSet::PPC, + 0x15_u16 => ElfInstructionSet::PPC64, + 0x16_u16 => ElfInstructionSet::S390, + 0x17_u16 => ElfInstructionSet::S390x, + 0x18_u16 => ElfInstructionSet::FutureUse, + 0x19_u16 => ElfInstructionSet::FutureUse, + 0x20_u16 => ElfInstructionSet::FutureUse, + 0x21_u16 => ElfInstructionSet::FutureUse, + 0x22_u16 => ElfInstructionSet::FutureUse, + 0x23_u16 => ElfInstructionSet::FutureUse, + 0x24_u16 => ElfInstructionSet::NECV800, + 0x25_u16 => ElfInstructionSet::FR20, + 0x26_u16 => ElfInstructionSet::RH32, + 0x27_u16 => ElfInstructionSet::MotorolaRCE, + 0x28_u16 => ElfInstructionSet::Arm32, + 0x29_u16 => ElfInstructionSet::DigitalAlpha, + 0x2A_u16 => ElfInstructionSet::SuperH, + 0x2B_u16 => ElfInstructionSet::SPARCVersion9, + 0x2C_u16 => ElfInstructionSet::SiemensTriCore, + 0x2D_u16 => ElfInstructionSet::ArgonautRISCCore, + 0x2E_u16 => ElfInstructionSet::H8300, + 0x2F_u16 => ElfInstructionSet::H8300H, + 0x30_u16 => ElfInstructionSet::H8S, + 0x31_u16 => ElfInstructionSet::H8500, + 0x32_u16 => ElfInstructionSet::IA64, + 0x33_u16 => ElfInstructionSet::StanfordMIPSX, + 0x34_u16 => ElfInstructionSet::MotorolaColdFire, + 0x35_u16 => ElfInstructionSet::MotorolaM68HC12, + 0x36_u16 => ElfInstructionSet::FujitsuMMA, + 0x37_u16 => ElfInstructionSet::SiemensPCP, + 0x38_u16 => ElfInstructionSet::SonyCellCPU, + 0x39_u16 => ElfInstructionSet::DensoNDR1, + 0x3A_u16 => ElfInstructionSet::MotorolaStarCore, + 0x3B_u16 => ElfInstructionSet::ToyotaME16, + 0x3C_u16 => ElfInstructionSet::STMicroelectronicsST100, + 0x3D_u16 => ElfInstructionSet::AdvancedLogicCorpTinyJ, + 0x3E_u16 => ElfInstructionSet::X86_64, + 0x3F_u16 => ElfInstructionSet::SonyDSP, + 0x40_u16 => ElfInstructionSet::PDP10, + 0x41_u16 => ElfInstructionSet::PDP11, + 0x42_u16 => ElfInstructionSet::SiemensFX66, + 0x43_u16 => ElfInstructionSet::STMicroelectronicsST9Plus, + 0x44_u16 => ElfInstructionSet::STMicroelectronicsST7, + 0x45_u16 => ElfInstructionSet::MC68HC16, + 0x46_u16 => ElfInstructionSet::MC68HC11, + 0x47_u16 => ElfInstructionSet::MC68HC08, + 0x48_u16 => ElfInstructionSet::MC68HC05, + 0x49_u16 => ElfInstructionSet::SiliconGraphicsSVx, + 0x4A_u16 => ElfInstructionSet::STMicroelectronicsST19, + 0x4B_u16 => ElfInstructionSet::DigitalVAX, + 0x4C_u16 => ElfInstructionSet::ETRAXCRIS, + 0x4D_u16 => ElfInstructionSet::InfineonTechnologiesMP32, + 0x4E_u16 => ElfInstructionSet::Element14DSP64, + 0x4F_u16 => ElfInstructionSet::LSILogicDSP16, + 0x8C_u16 => ElfInstructionSet::TMS320C6000, + 0xAF_u16 => ElfInstructionSet::MCSTElbrusE2k, + 0xB7_u16 => ElfInstructionSet::Arm64, + 0xDC_u16 => ElfInstructionSet::ZilogZ80, + 0xF3_u16 => ElfInstructionSet::RISCV, + 0xF7_u16 => ElfInstructionSet::BPF, + 0x101_u16 => ElfInstructionSet::WDC65C816, +}; + +// Source: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format +#[allow(clippy::upper_case_acronyms)] +#[derive(Clone, Copy, Debug)] +pub enum ElfOS { + SystemV, + HPUX, + NetBSD, + Linux, + GNUHurd, + Solaris, + AIXMonterey, + IRIX, + FreeBSD, + Tru64, + NovellModesto, + OpenBSD, + OpenVMS, + NonStopKernel, + AROS, + FenixOS, + CloudABI, + OpenVOS, + Illumos, + SerenityOS, + Android, + Undefined, +} + +/* +Source: + https://en.wikipedia.org/wiki/Executable_and_Linkable_Format + https://stackoverflow.com/a/49248689 +*/ +#[derive(Debug)] +pub enum ElfFileType { + Undefined, + Relocatable, + Executable, + SharedObject, + CoreFile, + OsSpecific, + ProcessorSpecific, +} + +// Source: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format +pub const E_TYPE: phf::Map = phf_map! { + 0x00_u16 => ElfFileType::Undefined, + 0x01_u16 => ElfFileType::Relocatable, + 0x02_u16 => ElfFileType::Executable, + 0x03_u16 => ElfFileType::SharedObject, + 0x04_u16 => ElfFileType::CoreFile, + 0xFE00_u16 => ElfFileType::OsSpecific, + 0xFEFF_u16 => ElfFileType::OsSpecific, + 0xFF00_u16 => ElfFileType::ProcessorSpecific, + 0xFFFF_u16 => ElfFileType::ProcessorSpecific, +}; + +// Source: https://en.wikipedia.org/wiki/Mach-O +#[derive(Debug)] +pub enum MachOCpuType { + VAX, + ROMP, + NS32032, + NS32332, + MC680x0, + X86, + MIPS, + NS32352, + MC98000, + HPPA, + ARM, + MC88000, + SPARC, + I860Be, + I860Le, + RS6000, + PPC, + ARM64, + X86_64, + Unknown, +} + +/* +Source: + https://en.wikipedia.org/wiki/Mach-O + https://www.jviotti.com/2021/07/23/a-deep-dive-on-macos-universal-binaries.html +*/ +pub const MACH_O_CPUTYPE: phf::Map = phf_map! { + 0x01_u32 => MachOCpuType::VAX, + 0x02_u32 => MachOCpuType::ROMP, + 0x04_u32 => MachOCpuType::NS32032, + 0x05_u32 => MachOCpuType::NS32332, + 0x06_u32 => MachOCpuType::MC680x0, + 0x07_u32 => MachOCpuType::X86, + 0x08_u32 => MachOCpuType::MIPS, + 0x09_u32 => MachOCpuType::NS32352, + 0x0A_u32 => MachOCpuType::MC98000, + 0x0B_u32 => MachOCpuType::HPPA, + 0x0C_u32 => MachOCpuType::ARM, + 0x0D_u32 => MachOCpuType::MC88000, + 0x0E_u32 => MachOCpuType::SPARC, + 0x0F_u32 => MachOCpuType::I860Be, + 0x10_u32 => MachOCpuType::I860Le, + 0x11_u32 => MachOCpuType::RS6000, + 0x12_u32 => MachOCpuType::PPC, + 0x1000007_u32 => MachOCpuType::X86_64, + 0x100000C_u32 => MachOCpuType::ARM64, +}; + +// Source: https://en.wikipedia.org/wiki/Mach-O +#[derive(Debug)] +pub enum MachOArmSubType { + All, + A500ArchOrNewer, + A500OrNewer, + A440OrNewer, + M4OrNewer, + V4TOrNewer, + V6OrNewer, + V5TEJOrNewer, + XScaleOrNewer, + V7OrNewer, + V7FCortexA9OrNewer, + V7SSwiftOrNewer, + V7KKirkwood40OrNewer, + V8OrNewer, + V6MOrNewer, + V7MOrNewer, + V7EMOrNewer, + Unknown, +} + +// Source: https://en.wikipedia.org/wiki/Mach-O +pub const MACH_O_ARM_CPU_SUBTYPE: phf::Map = phf_map! { + 0x00_u32 => MachOArmSubType::All, + 0x01_u32 => MachOArmSubType::A500ArchOrNewer, + 0x02_u32 => MachOArmSubType::A500OrNewer, + 0x03_u32 => MachOArmSubType::A440OrNewer, + 0x04_u32 => MachOArmSubType::M4OrNewer, + 0x05_u32 => MachOArmSubType::V4TOrNewer, + 0x06_u32 => MachOArmSubType::V6OrNewer, + 0x07_u32 => MachOArmSubType::V5TEJOrNewer, + 0x08_u32 => MachOArmSubType::XScaleOrNewer, + 0x09_u32 => MachOArmSubType::V7OrNewer, + 0x0A_u32 => MachOArmSubType::V7FCortexA9OrNewer, + 0x0B_u32 => MachOArmSubType::V7SSwiftOrNewer, + 0x0C_u32 => MachOArmSubType::V7KKirkwood40OrNewer, + 0x0D_u32 => MachOArmSubType::V8OrNewer, + 0x0E_u32 => MachOArmSubType::V6MOrNewer, + 0x0F_u32 => MachOArmSubType::V7MOrNewer, + 0x10_u32 => MachOArmSubType::V7EMOrNewer, +}; + +// Source: https://en.wikipedia.org/wiki/Mach-O +#[derive(Debug)] +pub enum MachOX86SubType { + All, + I486OrNewer, + I486SXOrNewer, + PentiumM5OrNewer, + CeleronOrNewer, + CeleronMobile, + Pentium3OrNewer, + Pentium3MOrNewer, + Pentium3XeonOrNewer, + Pentium4OrNewer, + ItaniumOrNewer, + Itanium2OrNewer, + XeonOrNewer, + XeonMPOrNewer, + Undefined, +} + +// Source: https://en.wikipedia.org/wiki/Mach-O +pub const MACH_O_X86_CPU_SUBTYPE: phf::Map = phf_map! { + 0x03_u32 => MachOX86SubType::All, + 0x04_u32 => MachOX86SubType::I486OrNewer, + 0x84_u32 => MachOX86SubType::I486SXOrNewer, + 0x56_u32 => MachOX86SubType::PentiumM5OrNewer, + 0x67_u32 => MachOX86SubType::CeleronOrNewer, + 0x77_u32 => MachOX86SubType::CeleronMobile, + 0x08_u32 => MachOX86SubType::Pentium3OrNewer, + 0x18_u32 => MachOX86SubType::Pentium3MOrNewer, + 0x28_u32 => MachOX86SubType::Pentium3XeonOrNewer, + 0x0A_u32 => MachOX86SubType::Pentium4OrNewer, + 0x0B_u32 => MachOX86SubType::ItaniumOrNewer, + 0x1B_u32 => MachOX86SubType::Itanium2OrNewer, + 0x0C_u32 => MachOX86SubType::XeonOrNewer, + 0x1C_u32 => MachOX86SubType::XeonMPOrNewer, +}; + +#[derive(Debug)] +pub enum MachOCpuSubType { + Arm(MachOArmSubType), + X86(MachOX86SubType), +} + +// Source: https://en.wikipedia.org/wiki/Mach-O +#[derive(Debug)] +pub enum MachOOs { + MacOS, + IOS, + AppleTVBox, + AppleWatch, + BridgeOS, + MacCatalyst, + IOSSimulator, + AppleTVSimulator, + AppleWatchSimulator, + DriverKit, + AppleVisionPro, + AppleVisionProSimulator, + Undefined, +} + +// Source: https://en.wikipedia.org/wiki/Mach-O +pub const MACH_O_OS: phf::Map = phf_map! { + 0x1_u32 => MachOOs::MacOS, + 0x2_u32 => MachOOs::IOS, + 0x3_u32 => MachOOs::AppleTVBox, + 0x4_u32 => MachOOs::AppleWatch, + 0x5_u32 => MachOOs::BridgeOS, + 0x6_u32 => MachOOs::MacCatalyst, + 0x7_u32 => MachOOs::IOSSimulator, + 0x8_u32 => MachOOs::AppleTVSimulator, + 0x9_u32 => MachOOs::AppleWatchSimulator, + 0xA_u32 => MachOOs::DriverKit, + 0xB_u32 => MachOOs::AppleVisionPro, + 0xC_u32 => MachOOs::AppleVisionProSimulator, +}; + +// Source: https://en.wikipedia.org/wiki/Mach-O +#[derive(Debug)] +pub enum MachOFileType { + RelocatableObjectFile, + DemandPagedExecutableFile, + FixedVMSharedLibraryFile, + CoreFile, + PreloadedExecutableFile, + DynamicallyBoundSharedLibraryFile, + DynamicLinkEditor, + DynamicallyBoundBundleFile, + SharedLibraryStub, + CompanionFileWithDebugSections, + X86_64Kexts, + ComposedFile, + Undefined, +} + +// Source: https://en.wikipedia.org/wiki/Mach-O +pub const MACH_O_FILE_TYPE: phf::Map = phf_map! { + 0x1_u32 => MachOFileType::RelocatableObjectFile, + 0x2_u32 => MachOFileType::DemandPagedExecutableFile, + 0x3_u32 => MachOFileType::FixedVMSharedLibraryFile, + 0x4_u32 => MachOFileType::CoreFile, + 0x5_u32 => MachOFileType::PreloadedExecutableFile, + 0x6_u32 => MachOFileType::DynamicallyBoundSharedLibraryFile, + 0x7_u32 => MachOFileType::DynamicLinkEditor, + 0x8_u32 => MachOFileType::DynamicallyBoundBundleFile, + 0x9_u32 => MachOFileType::SharedLibraryStub, + 0xA_u32 => MachOFileType::CompanionFileWithDebugSections, + 0xB_u32 => MachOFileType::X86_64Kexts, + 0xC_u32 => MachOFileType::ComposedFile, +}; + +// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format +#[derive(Debug)] +pub enum PeArch { + Unknown, + AlphaAXP32, + AlphaAXP64, + MatsushitaAM33, + X64, + ARM, + ARM64, + ARMNT, + AXP64, + EBC, + I386, + IA64, + LoongArch32, + LoongArch64, + MitsubishiM32R, + MIPS16, + MIPSFPU, + MIPSFPU16, + PowerPC, + PowerPCFP, + MIPS, + RISCV32, + RISCV64, + RISCV128, + HitachiSH3, + HitachiSH3DSP, + HitachiSH4, + HitachiSH5, + Thumb, + MIPSWCE, +} + +// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format +pub const PE_ARCH: phf::Map = phf_map! { + 0x0000_u16 => PeArch::Unknown, + 0x0184_u16 => PeArch::AlphaAXP32, + 0x0284_u16 => PeArch::AlphaAXP64, + 0x01d3_u16 => PeArch::MatsushitaAM33, + 0x8664_u16 => PeArch::X64, + 0x01c0_u16 => PeArch::ARM, + 0xaa64_u16 => PeArch::ARM64, + 0x01c4_u16 => PeArch::ARMNT, + // Look at source to learn why there is a duplicate value + //0x0284_u16 => PeArch::AXP64, + 0xebc_u16 => PeArch::EBC, + 0x014c_u16 => PeArch::I386, + 0x0200_u16 => PeArch::IA64, + 0x6232_u16 => PeArch::LoongArch32, + 0x6264_u16 => PeArch::LoongArch64, + 0x9041_u16 => PeArch::MitsubishiM32R, + 0x0266_u16 => PeArch::MIPS16, + 0x0366_u16 => PeArch::MIPSFPU, + 0x0466_u16 => PeArch::MIPSFPU16, + 0x01f0_u16 => PeArch::PowerPC, + 0x01f1_u16 => PeArch::PowerPCFP, + 0x0166_u16 => PeArch::MIPS, + 0x5032_u16 => PeArch::RISCV32, + 0x5064_u16 => PeArch::RISCV64, + 0x5128_u16 => PeArch::RISCV128, + 0x01a2_u16 => PeArch::HitachiSH3, + 0x01a3_u16 => PeArch::HitachiSH3DSP, + 0x01a6_u16 => PeArch::HitachiSH4, + 0x01a8_u16 => PeArch::HitachiSH5, + 0x01c2_u16 => PeArch::Thumb, + 0x0169_u16 => PeArch::MIPSWCE, +}; + +// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format +#[derive(Debug)] +pub enum PeSubsystem { + Unknown, + Native, + WindowsGUI, + WindowsCUI, + OS2CUI, + PosixCUI, + NativeWindows, + WindowsCEGUI, + EFIApplication, + EFIBootServiceDriver, + EFIRuntimeDriver, + EFIRom, + Xbox, + WindowsBootApplication, +} + +// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format +pub const PE_SUBSYSTEM: phf::Map = phf_map! { + 0x0000_u16 => PeSubsystem::Unknown, + 0x0001_u16 => PeSubsystem::Native, + 0x0002_u16 => PeSubsystem::WindowsGUI, + 0x0003_u16 => PeSubsystem::WindowsCUI, + 0x0005_u16 => PeSubsystem::OS2CUI, + 0x0007_u16 => PeSubsystem::PosixCUI, + 0x0008_u16 => PeSubsystem::NativeWindows, + 0x0009_u16 => PeSubsystem::WindowsCEGUI, + 0x000A_u16 => PeSubsystem::EFIApplication, + 0x000B_u16 => PeSubsystem::EFIBootServiceDriver, + 0x000C_u16 => PeSubsystem::EFIRuntimeDriver, + 0x000D_u16 => PeSubsystem::EFIRom, + 0x000E_u16 => PeSubsystem::Xbox, + 0x0010_u16 => PeSubsystem::WindowsBootApplication, +}; + +#[derive(Debug)] +pub enum PeOS { + Xbox, + Windows, + UEFI, + Undefined, +} + +// Source of the names: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format +impl Display for ElfOS { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + ElfOS::SystemV => write!(f, "System V"), + ElfOS::HPUX => write!(f, "HP-UX"), + ElfOS::NetBSD => write!(f, "NetBSD"), + ElfOS::Linux => write!(f, "Linux"), + ElfOS::GNUHurd => write!(f, "GNU Hurd"), + ElfOS::Solaris => write!(f, "Solaris"), + ElfOS::AIXMonterey => write!(f, "AIX (Monterey)"), + ElfOS::IRIX => write!(f, "IRIX"), + ElfOS::FreeBSD => write!(f, "FreeBSD"), + ElfOS::Tru64 => write!(f, "Tru64"), + ElfOS::NovellModesto => write!(f, "Novell Modesto"), + ElfOS::OpenBSD => write!(f, "OpenBSD"), + ElfOS::OpenVMS => write!(f, "OpenVMS"), + ElfOS::NonStopKernel => write!(f, "NonStop Kernel"), + ElfOS::AROS => write!(f, "AROS"), + ElfOS::FenixOS => write!(f, "FenixOS"), + ElfOS::CloudABI => write!(f, "Nuxi CloudABI"), + ElfOS::OpenVOS => write!(f, "OpenVOS"), + ElfOS::Illumos => write!(f, "Illumos"), + ElfOS::SerenityOS => write!(f, "SerenityOS"), + ElfOS::Android => write!(f, "Android"), + ElfOS::Undefined => write!(f, "Undefined"), + } + } +} + +// Source of the names: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format +impl Display for ElfInstructionSet { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + ElfInstructionSet::Undefined => write!(f, "Undefined"), //0x00 no specific instruction set is defined + ElfInstructionSet::WE32100 => write!(f, "AT&T WE 32100"), + ElfInstructionSet::SPARC => write!(f, "SPARC"), + ElfInstructionSet::X86 => write!(f, "x86"), + ElfInstructionSet::M68k => write!(f, "Motorola 68000 (M68k)"), + ElfInstructionSet::M88k => write!(f, "Motorola 88000 (M88k)"), + ElfInstructionSet::IntelMCU => write!(f, "Intel MCU"), + ElfInstructionSet::I860 => write!(f, "Intel 80860"), + ElfInstructionSet::MIPS => write!(f, "MIPS"), + ElfInstructionSet::IBMSystem370 => write!(f, "IBM System/370"), + ElfInstructionSet::MIPSRS3000Le => write!(f, "MIPS RS3000 (Little-endian)"), + ElfInstructionSet::FutureUse => write!(f, "Reserved for future use"), + ElfInstructionSet::HPPPRISC => write!(f, "HP PA-RISC"), + ElfInstructionSet::I960 => write!(f, "Intel 80960"), + ElfInstructionSet::PPC => write!(f, "PowerPC"), + ElfInstructionSet::PPC64 => write!(f, "PowerPC (64-Bit)"), + ElfInstructionSet::S390 => write!(f, "S390"), + ElfInstructionSet::S390x => write!(f, "S390x"), + ElfInstructionSet::NECV800 => write!(f, "NEC V800"), + ElfInstructionSet::FR20 => write!(f, "Fujitsu FR20"), + ElfInstructionSet::RH32 => write!(f, "TRW RH-32"), + ElfInstructionSet::MotorolaRCE => write!(f, "Motorola RCE"), + ElfInstructionSet::Arm32 => write!(f, "Arm (32-Bit)"), + ElfInstructionSet::DigitalAlpha => write!(f, "Digital Alpha"), + ElfInstructionSet::SuperH => write!(f, "SuperH"), + ElfInstructionSet::SPARCVersion9 => write!(f, "SPARC version 9"), + ElfInstructionSet::SiemensTriCore => write!(f, "Siemens TriCore"), + ElfInstructionSet::ArgonautRISCCore => write!(f, "Argonaut RISC Core"), + ElfInstructionSet::H8300 => write!(f, "Hitachi H8/300"), + ElfInstructionSet::H8300H => write!(f, "Hitachi H8/300H"), + ElfInstructionSet::H8S => write!(f, "Hitachi H8S"), + ElfInstructionSet::H8500 => write!(f, "Hitachi H8/500"), + ElfInstructionSet::IA64 => write!(f, "Intel Itanium"), + ElfInstructionSet::StanfordMIPSX => write!(f, "Stanford MIPS-X"), + ElfInstructionSet::MotorolaColdFire => write!(f, "Motorola ColdFire"), + ElfInstructionSet::MotorolaM68HC12 => write!(f, "Motorola M68HC12"), + ElfInstructionSet::FujitsuMMA => write!(f, "Fujitsu MMA multimedia accelerator"), + ElfInstructionSet::SiemensPCP => write!(f, "Siemens PCP"), + ElfInstructionSet::SonyCellCPU => write!(f, "Sony nCPU Embedded RISC"), + ElfInstructionSet::DensoNDR1 => write!(f, "Denso NDR1"), + ElfInstructionSet::MotorolaStarCore => write!(f, "Motorola Star*Core"), + ElfInstructionSet::ToyotaME16 => write!(f, "Toyota ME16"), + ElfInstructionSet::STMicroelectronicsST100 => { + write!(f, "STMicroelectronics ST100") + } + ElfInstructionSet::AdvancedLogicCorpTinyJ => { + write!(f, "Advanced Logic Corp. TinyJ") + } + ElfInstructionSet::X86_64 => write!(f, "x86-64"), + ElfInstructionSet::SonyDSP => write!(f, "Sony DSP processor"), + ElfInstructionSet::PDP10 => write!(f, "Digital Equipment Corp. PDP-10"), + ElfInstructionSet::PDP11 => write!(f, "Digital Equipment Corp. PDP-11"), + ElfInstructionSet::SiemensFX66 => write!(f, "Siemens FX66 microcontroller"), + ElfInstructionSet::STMicroelectronicsST9Plus => { + write!(f, "STMicroelectronics ST9+ 8/16-Bit microcontroller") + } + ElfInstructionSet::STMicroelectronicsST7 => { + write!(f, "STMicroelectronics ST7 8-Bit microcontroller") + } + ElfInstructionSet::MC68HC16 => write!(f, "Motorola MC68HC16 microcontroller"), + ElfInstructionSet::MC68HC11 => write!(f, "Motorola MC68HC11 microcontroller"), + ElfInstructionSet::MC68HC08 => write!(f, "Motorola MC68HC08 microcontroller"), + ElfInstructionSet::MC68HC05 => write!(f, "Motorola MC68HC05 microcontroller"), + ElfInstructionSet::SiliconGraphicsSVx => write!(f, "Silicon Graphics SVx"), + ElfInstructionSet::STMicroelectronicsST19 => { + write!(f, "STMicroelectronics ST19 8-Bit microcontroller") + } + ElfInstructionSet::DigitalVAX => write!(f, "Digital VAX"), + ElfInstructionSet::ETRAXCRIS => { + write!(f, "Axis Communications (32-Bit) embedded processor") + } + ElfInstructionSet::InfineonTechnologiesMP32 => { + write!(f, "Infineon Technologies (32-Bit) embedded processor") + } + ElfInstructionSet::Element14DSP64 => write!(f, "Element 14 (64-Bit) DSP processor"), + ElfInstructionSet::LSILogicDSP16 => write!(f, "LSI Logic 16-Bit DSP processor"), + ElfInstructionSet::TMS320C6000 => write!(f, "TMS320C6000 family"), + ElfInstructionSet::MCSTElbrusE2k => write!(f, "MCST Elbrus e2k"), + ElfInstructionSet::Arm64 => write!(f, "Arm (64-Bit)"), + ElfInstructionSet::ZilogZ80 => write!(f, "Zilog Z80"), + ElfInstructionSet::RISCV => write!(f, "RISC-V"), + ElfInstructionSet::BPF => write!(f, "Berkeley packet filter"), + ElfInstructionSet::IBMSPUSPC => write!(f, "IBM SPU/SPC"), + ElfInstructionSet::WDC65C816 => write!(f, "WDC 65C816"), + } + } +} + +/* +Sources: + https://en.wikipedia.org/wiki/Executable_and_Linkable_Format + https://refspecs.linuxbase.org/elf/gabi4+/ch4.intro.html +*/ +impl Display for ElfFileType { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + ElfFileType::Undefined => write!(f, "Undefined"), + ElfFileType::Relocatable => write!(f, "Object file"), + ElfFileType::Executable => write!(f, "Executable"), + ElfFileType::SharedObject => write!(f, "Shared object"), + ElfFileType::CoreFile => write!(f, "Core file"), + // I couldn't get healthy info. about "OS/CPU specific" + ElfFileType::OsSpecific => write!(f, "OS-specific"), + ElfFileType::ProcessorSpecific => write!(f, "CPU-specific"), + } + } +} + +// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format +impl Display for PeArch { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + PeArch::Unknown => write!(f, "Unknown"), + PeArch::AlphaAXP32 => write!(f, "Alpha AXP (32-Bit)"), + PeArch::AlphaAXP64 | PeArch::AXP64 => write!(f, "Alpha 64 (64-Bit)"), + PeArch::MatsushitaAM33 => write!(f, "Matsushita AM33"), + PeArch::X64 => write!(f, "x64"), + PeArch::ARM => write!(f, "Arm"), + PeArch::ARM64 => write!(f, "Arm (64-Bit)"), + PeArch::ARMNT => write!(f, "ARM Thumb-2"), + PeArch::EBC => write!(f, "EFI bytecode"), + PeArch::I386 => write!(f, "Intel 386"), + PeArch::IA64 => write!(f, "Intel Itanium"), + PeArch::LoongArch32 => write!(f, "LoongArch (32-Bit)"), + PeArch::LoongArch64 => write!(f, "LoongArch (64-Bit)"), + PeArch::MitsubishiM32R => write!(f, "Mitsubishi M32R"), + PeArch::MIPS16 => write!(f, "MIPS16"), + PeArch::MIPSFPU => write!(f, "MIPS with FPU"), + PeArch::MIPSFPU16 => write!(f, "MIPS16 with FPU"), + PeArch::PowerPC => write!(f, "PowerPC"), + PeArch::PowerPCFP => write!(f, "PowerPC with floating point support"), + PeArch::MIPS => write!(f, "MIPS"), + PeArch::RISCV32 => write!(f, "RISC-V (32-Bit)"), + PeArch::RISCV64 => write!(f, "RISC-V (64-Bit)"), + PeArch::RISCV128 => write!(f, "RISC-V 128-Bit"), + PeArch::HitachiSH3 => write!(f, "Hitachi SH3"), + PeArch::HitachiSH3DSP => write!(f, "Hitachi SH3 DSP"), + PeArch::HitachiSH4 => write!(f, "Hitachi SH4"), + PeArch::HitachiSH5 => write!(f, "Hitachi SH5"), + PeArch::Thumb => write!(f, "Thumb"), + PeArch::MIPSWCE => write!(f, "MIPS (Little-endian) WCE v2"), + } + } +} + +/* + Sources: + https://learn.microsoft.com/en-us/windows/win32/debug/pe-format + CLI != CUI: https://github.com/avelino/awesome-go/issues/282#issuecomment-73395067 +*/ +impl Display for PeSubsystem { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + PeSubsystem::Unknown => write!(f, "Undefined"), + PeSubsystem::Native => write!(f, "Device drivers and native windows processes"), + PeSubsystem::WindowsGUI => write!(f, "GUI application"), + PeSubsystem::WindowsCUI => write!(f, "Windows CUI application"), + PeSubsystem::OS2CUI => write!(f, "OS/2 CUI application"), + PeSubsystem::PosixCUI => write!(f, "Posix CUI application"), + PeSubsystem::NativeWindows => write!(f, "Native Win9x driver"), + PeSubsystem::WindowsCEGUI => write!(f, "Windows CE application"), + PeSubsystem::EFIApplication => write!(f, "EFI application"), + PeSubsystem::EFIBootServiceDriver => write!(f, "EFI driver with boot services"), + PeSubsystem::EFIRuntimeDriver => write!(f, "EFI driver with runtime services"), + PeSubsystem::EFIRom => write!(f, "EFI ROM image"), + PeSubsystem::Xbox => write!(f, "XBOX"), + PeSubsystem::WindowsBootApplication => write!(f, "Windows boot application."), + } + } +} + +// Source: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format +impl Display for PeOS { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + PeOS::Xbox => write!(f, "Xbox"), + PeOS::Windows => write!(f, "Windows"), + PeOS::UEFI => write!(f, "UEFI"), + PeOS::Undefined => write!(f, "Undefined"), + } + } +} + +// Source: https://en.wikipedia.org/wiki/Mach-O +impl Display for MachOArmSubType { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + MachOArmSubType::All => write!(f, "All ARM processors"), + MachOArmSubType::A500ArchOrNewer => write!(f, "ARM-A500 ARCH or newer"), + MachOArmSubType::A500OrNewer => write!(f, "ARM-A500 or newer"), + MachOArmSubType::A440OrNewer => write!(f, "ARM-A440 or newer"), + MachOArmSubType::M4OrNewer => write!(f, "ARM-M4 or newer"), + MachOArmSubType::V4TOrNewer => write!(f, "ARM-V4T or newer"), + MachOArmSubType::V6OrNewer => write!(f, "ARM-V6 or newer"), + MachOArmSubType::V5TEJOrNewer => write!(f, "ARM-V5TEJ or newer"), + MachOArmSubType::XScaleOrNewer => write!(f, "ARM-XSCALE or newer"), + MachOArmSubType::V7OrNewer => write!(f, "ARM-V7 or newer"), + MachOArmSubType::V7FCortexA9OrNewer => write!(f, "ARM-V7F (Cortex A9) or newer"), + MachOArmSubType::V7SSwiftOrNewer => write!(f, "ARM-V7S (Swift) or newer"), + MachOArmSubType::V7KKirkwood40OrNewer => write!(f, "ARM-V7K (Kirkwood40) or newer"), + MachOArmSubType::V8OrNewer => write!(f, "ARM-V8 or newer"), + MachOArmSubType::V6MOrNewer => write!(f, "ARM-V6M or newer"), + MachOArmSubType::V7MOrNewer => write!(f, "ARM-V7M or newer"), + MachOArmSubType::V7EMOrNewer => write!(f, "ARM-V7EM or newer"), + MachOArmSubType::Unknown => write!(f, "Unknown"), + } + } +} + +// Source: https://en.wikipedia.org/wiki/Mach-O +impl Display for MachOX86SubType { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + MachOX86SubType::All => write!(f, "All x86 processors"), + MachOX86SubType::I486OrNewer => write!(f, "486 or newer"), + MachOX86SubType::I486SXOrNewer => write!(f, "486SX or newer"), + MachOX86SubType::PentiumM5OrNewer => write!(f, "Pentium M5 or newer"), + MachOX86SubType::CeleronOrNewer => write!(f, "Celeron or newer"), + MachOX86SubType::CeleronMobile => write!(f, "Celeron Mobile"), + MachOX86SubType::Pentium3OrNewer => write!(f, "Pentium 3 or newer"), + MachOX86SubType::Pentium3MOrNewer => write!(f, "Pentium 3-M or newer"), + MachOX86SubType::Pentium3XeonOrNewer => write!(f, "Pentium 3-XEON or newer"), + MachOX86SubType::Pentium4OrNewer => write!(f, "Pentium-4 or newer"), + MachOX86SubType::ItaniumOrNewer => write!(f, "Itanium or newer"), + MachOX86SubType::Itanium2OrNewer => write!(f, "Itanium-2 or newer"), + MachOX86SubType::XeonOrNewer => write!(f, "XEON or newer"), + MachOX86SubType::XeonMPOrNewer => write!(f, "XEON-MP or newer"), + MachOX86SubType::Undefined => write!(f, "Undefined"), + } + } +} + +// Source: https://en.wikipedia.org/wiki/Mach-O +impl Display for MachOCpuSubType { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + MachOCpuSubType::Arm(arm) => write!(f, "{}", arm), + MachOCpuSubType::X86(x86) => write!(f, "{}", x86), + } + } +} + +// Source: https://en.wikipedia.org/wiki/Mach-O +impl Display for MachOCpuType { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + MachOCpuType::VAX => write!(f, "VAX"), + MachOCpuType::ROMP => write!(f, "ROMP"), + MachOCpuType::NS32032 => write!(f, "NS32032"), + MachOCpuType::NS32332 => write!(f, "NS32332"), + MachOCpuType::MC680x0 => write!(f, "MC680x0"), + MachOCpuType::X86 => write!(f, "x86"), + MachOCpuType::MIPS => write!(f, "MIPS"), + MachOCpuType::NS32352 => write!(f, "NS32352"), + MachOCpuType::MC98000 => write!(f, "MC98000"), + MachOCpuType::HPPA => write!(f, "HP-PA"), + MachOCpuType::ARM => write!(f, "ARM"), + MachOCpuType::MC88000 => write!(f, "MC88000"), + MachOCpuType::SPARC => write!(f, "SPARC"), + MachOCpuType::I860Be => write!(f, "i860 (Big-endian)"), + MachOCpuType::I860Le => write!(f, "i860 (Little-endian)"), + MachOCpuType::RS6000 => write!(f, "RS/6000"), + MachOCpuType::PPC => write!(f, "PowerPC"), + MachOCpuType::ARM64 => write!(f, "ARM64"), + MachOCpuType::X86_64 => write!(f, "x86_64"), + MachOCpuType::Unknown => write!(f, "Unknown"), + } + } +} + +// Source: https://en.wikipedia.org/wiki/Mach-O +impl Display for MachOFileType { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + MachOFileType::RelocatableObjectFile => write!(f, "Object file"), + MachOFileType::DemandPagedExecutableFile => write!(f, "Executable"), + MachOFileType::FixedVMSharedLibraryFile => write!(f, "Fixed VM shared library file"), + MachOFileType::CoreFile => write!(f, "Core file"), + MachOFileType::PreloadedExecutableFile => write!(f, "Preloaded executable file"), + MachOFileType::DynamicallyBoundSharedLibraryFile => write!(f, "Shared object"), + MachOFileType::DynamicLinkEditor => write!(f, "Dynamic link editor"), + MachOFileType::DynamicallyBoundBundleFile => write!(f, "Dynamically bound bundle file"), + MachOFileType::SharedLibraryStub => write!(f, "Shared library stub for static linking only, no section contents"), + MachOFileType::CompanionFileWithDebugSections => write!(f, "Companion file with only debug sections"), + MachOFileType::X86_64Kexts => write!(f, "x86_64 kext"), + MachOFileType::ComposedFile => write!(f, "File composed of other Mach-Os to be run in the same userspace sharing a single linkedit"), + MachOFileType::Undefined => write!(f, "Undefined"), + } + } +} + +// Source: https://en.wikipedia.org/wiki/Mach-O +impl Display for MachOOs { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + MachOOs::MacOS => write!(f, "MacOS"), + MachOOs::IOS => write!(f, "IOS"), + MachOOs::AppleTVBox => write!(f, "Apple TV Box"), + MachOOs::AppleWatch => write!(f, "Apple Watch"), + MachOOs::BridgeOS => write!(f, "Bridge OS"), + MachOOs::MacCatalyst => write!(f, "Mac Catalyst"), + MachOOs::IOSSimulator => write!(f, "IOS simulator"), + MachOOs::AppleTVSimulator => write!(f, "Apple TV simulator"), + MachOOs::AppleWatchSimulator => write!(f, "Apple watch simulator"), + MachOOs::DriverKit => write!(f, "Driver KIT"), + MachOOs::AppleVisionPro => write!(f, "Apple Vision Pro"), + MachOOs::AppleVisionProSimulator => write!(f, "Apple Vision Pro simulator"), + MachOOs::Undefined => write!(f, "Undefined"), + } + } +}