From 4a421321c56be2be4dd63198bbf26101d69f86d2 Mon Sep 17 00:00:00 2001 From: *Nix Fanboy <63163893+nix-enthusiast@users.noreply.github.com> Date: Thu, 24 Oct 2024 23:50:39 +0300 Subject: [PATCH] Initial commit --- .gitattributes | 2 + .gitignore | 32 +++++++++++ LICENSE | 28 ++++++++++ README.md | 63 ++++++++++++++++++++++ build.py | 37 +++++++++++++ go.mod | 3 ++ main.go | 144 +++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 309 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 build.py create mode 100644 go.mod create mode 100644 main.go diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b7778f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +.idea +/build +/include/* +/lib/* + +# 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/LICENSE b/LICENSE new file mode 100644 index 0000000..5b0f50e --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +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 new file mode 100644 index 0000000..70239eb --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +# OBJDetect + +OBJDetect is a program made in Go as an example of how to use [unildd](https://github.com/nix-enthusiast/unildd) library + +## Requirements +- Python >= 3.10 +- Cargo +- Go >= 1.17 + +## Installation +- Clone this git repository: + + ```git clone https://github.com/nix-enthusiast/objdetect``` + +- Go into the repository: + + ```cd objdetect``` + +- Run the `build.py` file: + + ``` + python3 build.py --build # To build the program + python3 build.py --run # To directly run the program + python3 build.py --clean # To remove the build directory + ``` + +- Take the file named `objdetect` (or `objdetect.exe` in Windows) from the directory named `build` and put it anywhere you want! + +## ⚠️ A Small Warning + +Since it uses [unildd](https://github.com/nix-enthusiast/unildd) library, the library has to be accessible by the program. To do it on + +### Windows: + + You can put the library in any folder which is in the `%PATH` variable or put them in the same place + + ``` + cp build\target\release\unildd.dll \the\folder\in\the\path\var + #or + cp build\target\release\unildd.dll \the\folder\which\includes\objdetect + ``` + +### Linux and macOS: + The same thing as what we do in Windows but the variable is: + + - `LD_LIBRARY_PATH` for Linux[^1] + - `DYLD_LIBRARY_PATH` for macOS[^2] + + + ``` + cp build/target/release/unildd.dll /the/folder/in/the/variable + #or + cp build/target/release/unildd.dll /the/folder/which/includes/objdetect + ``` + +### Other OSes + If your OS is not listed on here, please take a look at the documentation of your OS to find the path and do the same (or similar since OSes work different) thing as what we did above + +## License +This library is licensed under [BSD-3 Clause License](https://choosealicense.com/licenses/bsd-3-clause/) + +[^1]: https://man7.org/linux/man-pages/man8/ld.so.8.html#:~:text=LD_LIBRARY_PATH%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20A%20list%20of%20directories%20in%20which%20to%20search%20for%20ELF%20libraries%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20at%20execution%20time. +[^2]: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/UsingDynamicLibraries.html#:~:text=You%20may%20also,DYLD_FALLBACK_LIBRARY_PATH diff --git a/build.py b/build.py new file mode 100644 index 0000000..b06ecb6 --- /dev/null +++ b/build.py @@ -0,0 +1,37 @@ +from os import system +from sys import argv, stderr +from platform import system as os_name + +def build(): + system("mkdir -p build") + system("git clone https://github.com/nix-enthusiast/unildd.git build/unildd") + system("cargo build --release --manifest-path=build/unildd/Cargo.toml") + system("mkdir lib") + system("mkdir include") + + # I know this logic is dodgy + match os_name(): + case "Windows": + system("cp build\\unildd\\target\\release\\libunildd.dll lib") + case "Darwin": + system("cp build/unildd/target/release/libunildd.dylib lib") + case _: + system("cp build/unildd/target/release/libunildd.so lib") + + system("cp build/unildd/header/unildd.h include") + + +match argv[1]: + case "--build" | "-b": + build() + system("go build -o build/objdetect") + + case "--run" | "-r": + build() + system("go run main.go " + ' '.join(argv[2:])) + + case "--clean" | "-c": + system("rm -rf build") + + case f: + print("Invalid flag '" + f + "'", file=stderr) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5dd2def --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module objdetect + +go 1.17 diff --git a/main.go b/main.go new file mode 100644 index 0000000..adc733b --- /dev/null +++ b/main.go @@ -0,0 +1,144 @@ +package main + +/* +#cgo CFLAGS: -I./include +#cgo LDFLAGS: -L./lib -lunildd +#include "unildd.h" +#include +#include +*/ +import "C" + +import ( + "fmt" + "os" + "unsafe" +) + +func toGoString(cStr *C.char) string { + if cStr == nil { + return "Undefined" + } else { + return C.GoString(cStr) + } +} + +func main() { + argv := os.Args[1:] + isMultiple := len(argv) > 1 + + for _, fileName := range argv { + CFileName := C.CString(fileName) + + fileContent, err := os.ReadFile(fileName) + + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + + if isMultiple { + fmt.Println() + fmt.Println() + continue + } else { + os.Exit(-25) + } + } + + buffer := (*C.uint8_t)(unsafe.Pointer(&fileContent[0])) + + size := C.size_t(len(fileContent)) + + readObjects := C.read_obj(CFileName, buffer, size, false) + objectsLength := int(readObjects.length) + objectArray := unsafe.Slice(readObjects.vec, objectsLength) + + for i := 0; i < objectsLength; i++ { + var objectResult C.ULDDObjResult = objectArray[i] + + object := objectResult.obj + err := objectResult.error + + errorCode := int64(err.code) + + if errorCode != 0 { + _, _ = fmt.Fprintln(os.Stderr, C.GoString(err.explanation)) + + if isMultiple { + fmt.Println() + fmt.Println() + continue + } else { + if errorCode < 0 { + os.Exit(int(err.code)) + } else { + os.Exit(-25) + } + } + } + + fmt.Println("File name: " + C.GoString(object.file_name)) + + memberName := "" + + memberNamesLength := int(object.member_name.length) + memberNames := unsafe.Slice(object.member_name.vec, memberNamesLength) + for j := 0; j < memberNamesLength; j++ { + member := memberNames[j] + memberName += C.GoString(member) + + if j+1 != int(object.member_name.length) { + memberName += " -> " + } + } + + fmt.Println("Member of: " + memberName) + + fmt.Println("Executable format: " + toGoString(object.executable_format)) + + is64 := "" + + if object.is_64 { + is64 = "64-bit" + } else { + is64 = "32-bit" + } + + fmt.Println("Word size: " + is64) + + fmt.Println("OS: " + toGoString(object.os_type)) + + fmt.Println("File type: " + toGoString(object.file_type)) + + isStripped := "" + + if object.is_stripped { + isStripped = "Yes" + } else { + isStripped = "No" + } + + fmt.Println("Is stripped: " + isStripped) + + fmt.Println("CPU type: " + toGoString(object.cpu_type)) + + fmt.Println("CPU subtype: " + toGoString(object.cpu_subtype)) + + fmt.Println("Linker: " + toGoString(object.interpreter)) + + fmt.Println("Libraries:") + librariesLength := int(object.libraries.length) + libraries := unsafe.Slice(object.libraries.vec, librariesLength) + for _, library := range libraries { + fmt.Println(" -" + toGoString(library)) + } + + if i+1 != int(readObjects.length) { + fmt.Println() + fmt.Println() + } + } + + C.free_obj(readObjects, false) + C.free(unsafe.Pointer(CFileName)) + } +}