Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
n0thhhing committed Oct 30, 2024
0 parents commit 73ca924
Show file tree
Hide file tree
Showing 21 changed files with 1,205 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# Linux start script should use lf
/gradlew text eol=lf

# These are Windows script files and should use crlf
*.bat text eol=crlf

# Binary files should be left untouched
*.jar binary

7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.gradle
libs
build
app/build
config.json
offsets.txt
out.txt
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 n0thhhing

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
105 changes: 105 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# IL2CPP AArch64 Offset Updater

## Overview

The Offset Updater is a tool designed to update
offsets for IL2CPP binaries between updates on the AArch64 architecture.
It utilizes Capstone for disassembly and provides a
user-friendly way to manage offsets for dynamic library
updates. The application is built in Kotlin and requires
Java 21 to run.

## Features

- Reads offset configurations from a JSON file.
- Supports pattern scanning in AArch64 binaries using the KMP algorithm.
- Configurable verbosity for detailed output during processing.
- Easy integration with existing projects via Gradle.

## Requirements

- **Java 21**: Ensure you have JDK 21 installed on your system.
- **Kotlin**(only for building): The project is built using Kotlin, ensure you have the necessary dependencies set up in your build configuration.

## Installation

1. Clone the repository or download the project files.
2. Navigate to the project directory.
3. Open the terminal and run the following command to build the project:

```bash
./gradlew build # or ./gradlew jar to package
```

## Configuration

Before running the updater, create a `config.json` file in the project root directory. Here’s an example of the configuration:

```json
{
"sigLen": 64,
"verbose": false,
"offsetFile": "offsets.txt",
"outputFile": "out.txt",
"newLib": "new.so",
"oldLib": "old.so"
}
```

- `sigLen`: Length of the signature for pattern matching.
- `verbose`: Enables detailed logging if set to true.
- `offsetFile`: The file containing the offsets to be updated.
- `outputFile`: Where the new offsets should go
- `newLib`: The new library file to scan.
- `oldLib`: The old library file for reference.

## Offset File Format
Offset File Format
The offsets.txt file must be formatted as follows:
```
Copy code
0xBEAF // comment
0xF00D
0x1234
// comment
```
Each line can contain a hexadecimal offset prefixed with 0x.
Comments can be added using // and will be ignored by the parser.
Empty lines or lines with only comments will be skipped.

## Usage

1. Prepare the `offsets.txt` file containing the offsets to be updated, following the specified format.

2. You can download the release JAR file from the [releases page](link-to-your-releases-page) and run the updater with the following command:

```bash
java -jar Updater-1.0.0.jar
```

Alternatively, if you built the project yourself, run:

```bash
java -jar build/libs/Updater-1.0.0.jar
```

3. The application will load the configuration, disassemble the old library, and search for patterns in the new library.

## Output

The application provides output regarding the status of the offset updates, like whether patterns were found a d the pattern itself. Verbose output can be enabled for detailed information.

## License

This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more information.

## Contributing

Contributions are welcome! Please open issues for any bugs you find or feature requests you may have.

## Acknowledgements

- [Capstone](https://www.capstone-engine.org/) - A lightweight multi-platform, multi-architecture disassembly framework.
- [Gson](https://github.com/google/gson) - A Java library to convert Java Objects into JSON and back.
- [Kotlin](https://kotlinlang.org/) - A modern programming language that makes programming easier and more enjoyable.
- [ktfmt-gradle](https://github.com/cortinico/ktfmt-gradle) A reliable kotlin formatter for gradle.
62 changes: 62 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.ktfmt)
application
}

repositories {
google()
mavenCentral()
maven("https://jitpack.io")
}

dependencies {
implementation(libs.guava)
implementation(libs.capstone)
implementation(libs.gson)
implementation(libs.slf4j)
}

testing {
suites {
val test by getting(JvmTestSuite::class) {
useKotlinTest("2.0.0")
}
}
}

java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}

application {
mainClass = "org.updater.UpdaterKt"
}

ktfmt {
kotlinLangStyle()
}

tasks.jar {
manifest {
attributes["Main-Class"] = application.mainClass.get()
}

duplicatesStrategy = DuplicatesStrategy.EXCLUDE

from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })

archiveBaseName.set("Updater")
archiveVersion.set("$version")
}

// Im not putting ktfmtFormat every time, wtf
tasks.register("fmt") {
dependsOn(tasks.ktfmtFormat)
}

tasks.named("build") {
dependsOn(tasks.jar)
}
112 changes: 112 additions & 0 deletions app/src/main/kotlin/org/updater/Updater.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package org.updater

import capstone.Capstone
import capstone.api.Disassembler
import capstone.api.DisassemblerFactory
import com.google.gson.Gson
import org.updater.utils.Color
import org.updater.utils.FileHandler
import org.updater.utils.KmpScanner
import org.updater.utils.OffsetFileParser
import org.updater.utils.getPattern

private const val CONFIG_FILE = "config.json"

var useVerbose = false

data class Config(
val sigLen: Int = 64,
val verbose: Boolean = false,
val offsetFile: String = "offsets.txt",
val outputFile: String = "out.txt",
val newLib: String = "new.so",
val oldLib: String = "old.so",
)

data class OffsetResult(val offset: String, val pattern: String, val foundOffsets: List<String>)

fun verbose(message: Any) {
if (useVerbose) {
println(message)
}
}

fun main() {
val startTime = System.currentTimeMillis()
val config = loadConfig(CONFIG_FILE)

useVerbose = config.verbose

val offsets = OffsetFileParser.parse(config.offsetFile)
val newLibBytes = FileHandler.readFileAsByteArr(config.newLib)
val oldLibBytes = FileHandler.readFileAsByteArr(config.oldLib)

var passCount = 0
var failCount = 0

val disassembler =
DisassemblerFactory.createDisassembler(Capstone.CS_ARCH_ARM64, Capstone.CS_MODE_ARM).apply {
setDetail(false)
}

FileHandler.writeFile(config.outputFile, "")

offsets.forEach { offset ->
val (result, found) = processOffset(disassembler, oldLibBytes, newLibBytes, offset, config)
appendResultToFile(config.outputFile, result)
if (found) passCount++ else failCount++
}

printSummary(startTime, offsets.size, passCount, failCount)
disassembler.close()
}

private fun loadConfig(filename: String): Config {
return Gson().fromJson(FileHandler.readFileAsStr(filename), Config::class.java)
}

private fun processOffset(
cs: Disassembler,
oldBytes: ByteArray,
newBytes: ByteArray,
offset: Int,
config: Config,
): Pair<OffsetResult, Boolean> {
val currentOffset = "0x${offset.toString(16)}"
verbose(Color.green("Processing Offset: ${Color.blue(currentOffset)}"))

val start = System.currentTimeMillis()
val pattern = getPattern(cs, oldBytes, offset, config.sigLen)
val occurrences = KmpScanner.scan(newBytes, pattern).map { "0x${it.toString(16)}" }
val found = occurrences.isNotEmpty()
verbose(
if (occurrences.isNotEmpty()) Color.green("Pattern found at positions: ") + occurrences
else Color.red("Pattern not found")
)
verbose(
Color.green("Total processing time: ${Color.blue(System.currentTimeMillis() - start)}ms")
)
verbose("--------------------------------------")

return Pair(OffsetResult(currentOffset, pattern, occurrences), found)
}

private fun appendResultToFile(filePath: String, result: OffsetResult) {
val content =
"""
Offset: ${result.offset}:
- Pattern: ${result.pattern}
- Found offsets: ${if (result.foundOffsets.isNotEmpty()) result.foundOffsets.joinToString(", ") else "None"}
"""
.trimIndent()

FileHandler.appendToFile(filePath, content)
}

private fun printSummary(startTime: Long, totalOffsets: Int, passCount: Int, failCount: Int) {
val totalTime = System.currentTimeMillis() - startTime
println(Color.green("Finished"))
verbose(Color.green("\n$passCount patterns found"))
verbose(Color.red("$failCount patterns not found"))
verbose("$totalOffsets total (${Color.blue(totalTime)}ms)")
}
Loading

0 comments on commit 73ca924

Please sign in to comment.