An executable file parsing library, written in Kotlin Multiplatform.
Currently, this library can:
- PE: Read basic information (COFF header, optional header, sections)
- PE: Read version information (aka. VS_VERSIONINFO structure)
- PE: Read import/export symbol tables
- PE: Read resources and section data
- ELF: Read basic information (ELF Header, Section headers, Program headers)
- ELF: Read symbol tables
- ELF: Read section data
- Macho: Read basic information
- Chore: Jigsaw ready
This project is currently in the early stages of development. This means it is still evolving and may undergo frequent updates and changes.
Due to the current status of Kotlin/Multiplatform, it can be expected that for a period of time following the stable release, binary compatibility guarantees will only be provided for Kotlin/JVM.
- Kotlin/JVM: Java 8 or later (Jigsaw since Java 9 is supported by multi-release jar)
- Kotlin/JavaScript
If you need more targets, feel free to open an issue or pull request directly.
This project contains several modules on Maven Central:
- space.iseki.executables:executables-common contains the code shared by pe, elf, and macho
- space.iseki.executables:executables-pe contains the code for parsing PE files
- space.iseki.executables:executables-elf contains the code for parsing ELF files
- space.iseki.executables:executables-all (common + pe + elf)
If the dependency size is not a concern, you can use executables-all directly.
dependencies {
implementation("space.iseki.executables:executables-all:0.0.14")
}
Since the project is in Kotlin Multiplatform, for Maven user you have to specify the platform explicitly.
(The -jvm
suffix)
<dependency>
<groupId>space.iseki.executables</groupId>
<artifactId>executables-all-jvm</artifactId>
<version>0.0.14</version>
</dependency>
import java.nio.file.Path
import kotlinx.serialization.json.Json
import space.iseki.executables.pe.PEFile
fun main() {
val file = Path.of("C:\\System32\\notepad.exe")
PEFile.open(file).use { peFile: PEFile ->
println(peFile.coffHeader)
println(peFile.summary)
println(Json.encodeToString(peFile.summary))
println(peFile.versionInfo)
}
}
import java.nio.file.Path
import space.iseki.executables.common.ExecutableFile
import space.iseki.executables.common.ExecutableFileType
fun main() {
val file = Path.of("C:\\System32\\notepad.exe")
println(ExecutableFileType.detect(file))
}
This API also works for ELF files.
import java.nio.file.Path
import space.iseki.executables.pe.PEFile
fun main() {
val file = Path.of("C:\\System32\\notepad.exe")
PEFile.open(file).use { peFile ->
// Get all imported DLLs and functions
peFile.importSymbols.forEach { symbol ->
println("Imported: ${symbol.file}::${symbol.name}")
if (symbol.isOrdinal) {
println(" - Ordinal: ${symbol.ordinal}")
}
}
}
}
This API also works for ELF files.
import java.nio.file.Path
import space.iseki.executables.pe.PEFile
fun main() {
val file = Path.of("C:\\System32\\kernel32.dll")
PEFile.open(file).use { peFile ->
// Get all exported functions
val exportSymbols = peFile.exportSymbols
println("Number of exported functions: ${exportSymbols.size}")
// Print the first 10 exported functions
exportSymbols.take(10).forEach { symbol ->
println(" - ${symbol.name}, Ordinal: ${symbol.ordinal}")
if (symbol.isForwarder) {
println(" Forwards to: ${symbol.forwarderString}")
}
}
}
}
Since PE splits the symbol table into import/export, this API is ELF specified.
import java.nio.file.Path
import space.iseki.executables.elf.ELFFile
fun main() {
val file = Path.of("/bin/ls") // ELF file on Linux system
ELFFile.open(file).use { elfFile ->
// Get all symbols
elfFile.symbols.forEach { symbol ->
val name = symbol.name ?: "<unnamed>"
println(" - $name: Name=${symbol.name}, Binding=${symbol.binding}")
}
}
}