diff --git a/.gitignore b/.gitignore index 39b6783..02f673b 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,5 @@ fastlane/Preview.html fastlane/screenshots fastlane/test_output fastlane/readme.md + +artifacts diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..2effb56 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.4.1) + +project(StaticInjector + VERSION 1.0 + LANGUAGES CXX C + ) + + +add_subdirectory(src) +#add_subdirectory(test) +IF (ANDROID) + add_subdirectory(androidTest) # with linux we include linuxTest here! +endif (ANDROID) + +if (UNIX AND NOT APPLE AND NOT ANDROID) + set(LINUX true) +ENDIF () +IF (LINUX) + add_subdirectory(linuxTest) +ENDIF (LINUX) \ No newline at end of file diff --git a/README.md b/README.md index e69de29..d1135f4 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,55 @@ +# ChickenHook - StaticInjector + +## Intrudiction + +The StaticInjector is build for injecting code into an already compiled binary (shared object or executable). + +This injected code can use ChickenHook (https://github.com/ChickenHook/ChickenHook) for hook some functions to manipulate the behaviour at runtime. + +## How it works + +## Build + +### Linux +``` +ant configure-linux compile-linux test-linux install-linux +``` + +### Android +WIP + + +## Build your own attack + +This chapter explains how to use StaticInjector for your needs. + +### Linux + +``` +./staticInjector [binaryToInjectInto] [dependency to replace] [path to dependency to generate the stubs] +``` + + +Example: + +``` +./staticInjector victimTest libgcc_s.so.1 /lib/x86_64-linux-gnu/libgcc_s.so.1 +``` +WIP + + +### Android +WIP + + +### Example attacks + +# Firefox + +Check this video (Please enable subtitles): + +[![](http://img.youtube.com/vi/_4K2d7FFHqo/0.jpg)](http://www.youtube.com/watch?v=_4K2d7FFHqo "Linux attack firefox") + +# Skype + +(WIP) \ No newline at end of file diff --git a/androidTest/.gitignore b/androidTest/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/androidTest/.gitignore @@ -0,0 +1 @@ +/build diff --git a/androidTest/CMakeLists.txt b/androidTest/CMakeLists.txt new file mode 100644 index 0000000..f1e4c64 --- /dev/null +++ b/androidTest/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.4.1) + +add_library (native-lib SHARED interface.cpp) + +target_link_libraries(native-lib + ${PROJECT_NAME} + ) \ No newline at end of file diff --git a/androidTest/build.gradle b/androidTest/build.gradle new file mode 100644 index 0000000..361a12f --- /dev/null +++ b/androidTest/build.gradle @@ -0,0 +1,50 @@ +apply plugin: 'com.android.application' + +apply plugin: 'kotlin-android' + +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 29 + buildToolsVersion "29.0.2" + defaultConfig { + applicationId "com.chickenhook.staticinjector" + minSdkVersion 19 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + externalNativeBuild { + cmake { + cppFlags "-std=c++14" + } + } + ndk { + abiFilters 'arm64-v8a', 'x86', 'x86_64' + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + externalNativeBuild { + cmake { + path "../CMakeLists.txt" + version "3.6.0" + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.core:core-ktx:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' +} diff --git a/androidTest/interface.cpp b/androidTest/interface.cpp new file mode 100644 index 0000000..e69de29 diff --git a/androidTest/proguard-rules.pro b/androidTest/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/androidTest/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/androidTest/src/androidTest/java/com/chickenhook/staticinjector/ExampleInstrumentedTest.kt b/androidTest/src/androidTest/java/com/chickenhook/staticinjector/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..fed15c3 --- /dev/null +++ b/androidTest/src/androidTest/java/com/chickenhook/staticinjector/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.chickenhook.staticinjector + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.chickenhook.staticinjector", appContext.packageName) + } +} diff --git a/androidTest/src/main/AndroidManifest.xml b/androidTest/src/main/AndroidManifest.xml new file mode 100644 index 0000000..97f223f --- /dev/null +++ b/androidTest/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/androidTest/src/main/java/com/chickenhook/staticinjector/MainActivity.kt b/androidTest/src/main/java/com/chickenhook/staticinjector/MainActivity.kt new file mode 100644 index 0000000..0d81cef --- /dev/null +++ b/androidTest/src/main/java/com/chickenhook/staticinjector/MainActivity.kt @@ -0,0 +1,12 @@ +package com.chickenhook.staticinjector + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle + +class MainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + } +} diff --git a/androidTest/src/main/res/drawable-v24/ic_launcher_foreground.xml b/androidTest/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..1f6bb29 --- /dev/null +++ b/androidTest/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/androidTest/src/main/res/drawable/ic_launcher_background.xml b/androidTest/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..0d025f9 --- /dev/null +++ b/androidTest/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/androidTest/src/main/res/layout/activity_main.xml b/androidTest/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..4fc2444 --- /dev/null +++ b/androidTest/src/main/res/layout/activity_main.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/androidTest/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/androidTest/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/androidTest/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/androidTest/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/androidTest/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/androidTest/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/androidTest/src/main/res/mipmap-hdpi/ic_launcher.png b/androidTest/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..898f3ed Binary files /dev/null and b/androidTest/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/androidTest/src/main/res/mipmap-hdpi/ic_launcher_round.png b/androidTest/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..dffca36 Binary files /dev/null and b/androidTest/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/androidTest/src/main/res/mipmap-mdpi/ic_launcher.png b/androidTest/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..64ba76f Binary files /dev/null and b/androidTest/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/androidTest/src/main/res/mipmap-mdpi/ic_launcher_round.png b/androidTest/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..dae5e08 Binary files /dev/null and b/androidTest/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/androidTest/src/main/res/mipmap-xhdpi/ic_launcher.png b/androidTest/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..e5ed465 Binary files /dev/null and b/androidTest/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/androidTest/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/androidTest/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..14ed0af Binary files /dev/null and b/androidTest/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/androidTest/src/main/res/mipmap-xxhdpi/ic_launcher.png b/androidTest/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..b0907ca Binary files /dev/null and b/androidTest/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/androidTest/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/androidTest/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..d8ae031 Binary files /dev/null and b/androidTest/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/androidTest/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/androidTest/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..2c18de9 Binary files /dev/null and b/androidTest/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/androidTest/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/androidTest/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..beed3cd Binary files /dev/null and b/androidTest/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/androidTest/src/main/res/values/colors.xml b/androidTest/src/main/res/values/colors.xml new file mode 100644 index 0000000..69b2233 --- /dev/null +++ b/androidTest/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #008577 + #00574B + #D81B60 + diff --git a/androidTest/src/main/res/values/strings.xml b/androidTest/src/main/res/values/strings.xml new file mode 100644 index 0000000..db34723 --- /dev/null +++ b/androidTest/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + StaticInjector + diff --git a/androidTest/src/main/res/values/styles.xml b/androidTest/src/main/res/values/styles.xml new file mode 100644 index 0000000..5885930 --- /dev/null +++ b/androidTest/src/main/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/androidTest/src/test/java/com/chickenhook/staticinjector/ExampleUnitTest.kt b/androidTest/src/test/java/com/chickenhook/staticinjector/ExampleUnitTest.kt new file mode 100644 index 0000000..001257a --- /dev/null +++ b/androidTest/src/test/java/com/chickenhook/staticinjector/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.chickenhook.staticinjector + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..e3245e7 --- /dev/null +++ b/build.gradle @@ -0,0 +1,28 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + + } + dependencies { + classpath 'com.android.tools.build:gradle:3.5.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..ca9be7f --- /dev/null +++ b/build.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${prop.dist.contents} + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..23339e0 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..f6b961f Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..049175e --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sun Nov 03 12:11:17 CET 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/linuxTest/CMakeLists.txt b/linuxTest/CMakeLists.txt new file mode 100644 index 0000000..7b8d852 --- /dev/null +++ b/linuxTest/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.4.1) + +add_executable (staticInjector + main.cpp + ) + +target_link_libraries(staticInjector + ${PROJECT_NAME} + ) + +set_property(TARGET staticInjector PROPERTY CXX_STANDARD 11) + +add_subdirectory(exampleAttack) + +set_property(TARGET staticInjector PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/linuxTest/exampleAttack/CMakeLists.txt b/linuxTest/exampleAttack/CMakeLists.txt new file mode 100644 index 0000000..57b5e52 --- /dev/null +++ b/linuxTest/exampleAttack/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.4.1) + +add_library (linuxAttack SHARED + hook.cpp + libgcc_s.so.1.cpp + libkrb5support.so.0.cpp + ) + +target_include_directories(linuxAttack PUBLIC + ${CMAKE_SOURCE_DIR}/artifacts/ChickenHook/${CMAKE_LIBRARY_ARCHITECTURE}/include/ + ) +target_link_libraries(linuxAttack + # add chickenhook here + ${CMAKE_SOURCE_DIR}/artifacts/ChickenHook/${CMAKE_LIBRARY_ARCHITECTURE}/lib/libChickenHook.a + dl + pthread + ) + +set_property(TARGET linuxAttack PROPERTY CXX_STANDARD 11) +set_property(TARGET linuxAttack PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/linuxTest/exampleAttack/README.md b/linuxTest/exampleAttack/README.md new file mode 100644 index 0000000..e9f70cd --- /dev/null +++ b/linuxTest/exampleAttack/README.md @@ -0,0 +1,11 @@ +# Linux example attack + +This folder contains an example attack for linux. + +## Folder structure + +### hook.cpp + +### libgcc_so.so.1.cpp + +### libkrb5support.so.0.cpp \ No newline at end of file diff --git a/linuxTest/exampleAttack/hook.cpp b/linuxTest/exampleAttack/hook.cpp new file mode 100644 index 0000000..1afeb4e --- /dev/null +++ b/linuxTest/exampleAttack/hook.cpp @@ -0,0 +1,174 @@ + +#include + +#include +#include +#include +#include +#include +#include + + +#define gettid() syscall(SYS_gettid) + + +bool updatePermissions(void *addr, int permissions) { + size_t pagesize = (size_t) sysconf(_SC_PAGESIZE); + void *lowerBoundary = (void *) ((long long) addr - ((long long) addr % pagesize)); + + if (mprotect(lowerBoundary, pagesize, permissions) != 0) { + return false; + } + return true; +} + + +void logCallback(const std::string logtext) { + + printf("%s\n", logtext.c_str()); + +} + +template +static inline void +hex_dump(const void *aData, std::size_t aLength, std::basic_ostream &aStream, + std::size_t aWidth = 16) { + const char *const start = static_cast(aData); + const char *const end = start + aLength; + const char *line = start; + while (line != end) { + aStream.width(4); + aStream.fill('0'); + aStream << std::hex << line - start << " : "; + std::size_t lineLength = std::min(aWidth, static_cast(end - line)); + for (std::size_t pass = 1; pass <= 2; ++pass) { + for (const char *next = line; next != end && next != line + aWidth; ++next) { + char ch = *next; + switch (pass) { + case 1: + aStream << (ch < 32 ? '.' : ch); + break; + case 2: + if (next != line) + aStream << " "; + aStream.width(2); + aStream.fill('0'); + aStream << std::hex << std::uppercase + << static_cast(static_cast(ch)); + break; + } + } + if (pass == 1 && lineLength != aWidth) + aStream << std::string(aWidth - lineLength, ' '); + aStream << " "; + } + aStream << std::endl; + line = line + lineLength; + } +} + +ssize_t my_read(int __fd, void *__buf, size_t __count) { + //printf("read called [-] %d", __fd); + int res = -1; + ChickenHook::Trampoline trampoline; + if (ChickenHook::Hooking::getInstance().getTrampolineByAddr((void *) &read, trampoline)) { + //printf("hooked function call original function"); + // printLines(hexdump(static_cast(__buf), __count, "read")); + trampoline.copyOriginal(); + res = read(__fd, __buf, __count); + trampoline.reinstall(); + hex_dump(__buf, __count, std::cout); + return res; + } else { + printf("hooked function cannot call original function"); + } + return res; +} + +char *my_strcpy(char *__dst, const char *__src) { + printf("strcpy called [-] "); + hex_dump(__src, strlen(__src), std::cout); + char *res = nullptr; + ChickenHook::Trampoline trampoline; + if (ChickenHook::Hooking::getInstance().getTrampolineByAddr((void *) &strcpy, trampoline)) { + printf("hooked function call original function"); + // printLines(hexdump(static_cast(__buf), __count, "read")); + trampoline.copyOriginal(); + res = strcpy(__dst, __src); + trampoline.reinstall(); + return res; + } else { + printf("hooked function cannot call original function"); + } + return res; +} + +int my_open(const char *__path, int __flags, ...) { + printf("open called [-] %s\n", __path); + + int res = -1; + ChickenHook::Trampoline trampoline; + if (ChickenHook::Hooking::getInstance().getTrampolineByAddr((void *) &open, trampoline)) { + printf("hooked function call original function\n"); + + trampoline.copyOriginal(); + res = open(__path, __flags); + trampoline.reinstall(); + return res; + } else { + printf("hooked function cannot call original function\n"); + } + return -1; +} + + +pthread_t hooksInstallThread; + +void installWithThread(); + + +void pseudoSleep(int iterations) { + for (int i = 0; i < gettid() * iterations;) { + i++; + } +} + +void *installHooks(void *) { // install hooks only once! + char *hinit = getenv("HINIT"); + printf("installHooks <%ld> <%s>\n", gettid(), hinit); + //usleep(gettid()); + //pseudoSleep(100); + + if (hinit == nullptr) { + putenv("HINIT=true"); + + printf("Waiting for hooks... \n"); + //sleep(1); + usleep(20 * 1000 * 1000); + //usleep(5*1000 * 1000); + printf("Started install hooks\n"); + ChickenHook::Hooking::getInstance().setLoggingCallback(&logCallback); + printf("Using chickenhook instance <%p>\n", &ChickenHook::Hooking::getInstance()); + ChickenHook::Hooking::getInstance().hook((void *) &read, (void *) &my_read); + + //ChickenHook::Hooking::getInstance().hook((void *) &strcpy, (void *) &my_strcpy); + //ChickenHook::Hooking::getInstance().hook((void *) &open, (void *) &my_open); + printf("Install hooks finished\n");/**/ + + } + + return nullptr; +} + +void installWithThread() { + if (pthread_create(&hooksInstallThread, NULL, &installHooks, nullptr)) { + printf("Error creating hooking thread!"); + } +} + +void __attribute__ ((constructor (102))) testInit() { + printf("You are hacked %ld\n", gettid()); + //pseudoSleep(100); + installWithThread(); + //installHooks(nullptr); +} \ No newline at end of file diff --git a/linuxTest/exampleAttack/libgcc_s.so.1.cpp b/linuxTest/exampleAttack/libgcc_s.so.1.cpp new file mode 100644 index 0000000..93bcff9 --- /dev/null +++ b/linuxTest/exampleAttack/libgcc_s.so.1.cpp @@ -0,0 +1,675 @@ +#include +#include +#include + +#include "symbolhook.h" + +static void *handle; + +void funA() { + printf("ERROR, THIS SHOULD NEVER APPEAR\n"); +} +extern "C" __attribute__((used)) void *p__Unwind_Backtrace = (void *) funA; +extern "C" void _Unwind_Backtrace() { + SYMBOL_HOOK( p__Unwind_Backtrace); +} +extern "C" __attribute__((used)) void *p__Unwind_DeleteException = (void *) funA; +extern "C" void _Unwind_DeleteException() { + SYMBOL_HOOK( p__Unwind_DeleteException); +} +extern "C" __attribute__((used)) void *p__Unwind_FindEnclosingFunction = (void *) funA; +extern "C" void _Unwind_FindEnclosingFunction() { + SYMBOL_HOOK( p__Unwind_FindEnclosingFunction); +} +extern "C" __attribute__((used)) void *p__Unwind_Find_FDE = (void *) funA; +extern "C" void _Unwind_Find_FDE() { + SYMBOL_HOOK( p__Unwind_Find_FDE); +} +extern "C" __attribute__((used)) void *p__Unwind_ForcedUnwind = (void *) funA; +extern "C" void _Unwind_ForcedUnwind() { + SYMBOL_HOOK( p__Unwind_ForcedUnwind); +} +extern "C" __attribute__((used)) void *p__Unwind_GetCFA = (void *) funA; +extern "C" void _Unwind_GetCFA() { + SYMBOL_HOOK( p__Unwind_GetCFA); +} +extern "C" __attribute__((used)) void *p__Unwind_GetDataRelBase = (void *) funA; +extern "C" void _Unwind_GetDataRelBase() { + SYMBOL_HOOK( p__Unwind_GetDataRelBase); +} +extern "C" __attribute__((used)) void *p__Unwind_GetGR = (void *) funA; +extern "C" void _Unwind_GetGR() { + SYMBOL_HOOK( p__Unwind_GetGR); +} +extern "C" __attribute__((used)) void *p__Unwind_GetIP = (void *) funA; +extern "C" void _Unwind_GetIP() { + SYMBOL_HOOK( p__Unwind_GetIP); +} +extern "C" __attribute__((used)) void *p__Unwind_GetIPInfo = (void *) funA; +extern "C" void _Unwind_GetIPInfo() { + SYMBOL_HOOK( p__Unwind_GetIPInfo); +} +extern "C" __attribute__((used)) void *p__Unwind_GetLanguageSpecificData = (void *) funA; +extern "C" void _Unwind_GetLanguageSpecificData() { + SYMBOL_HOOK( p__Unwind_GetLanguageSpecificData); +} +extern "C" __attribute__((used)) void *p__Unwind_GetRegionStart = (void *) funA; +extern "C" void _Unwind_GetRegionStart() { + SYMBOL_HOOK( p__Unwind_GetRegionStart); +} +extern "C" __attribute__((used)) void *p__Unwind_GetTextRelBase = (void *) funA; +extern "C" void _Unwind_GetTextRelBase() { + SYMBOL_HOOK( p__Unwind_GetTextRelBase); +} +extern "C" __attribute__((used)) void *p__Unwind_RaiseException = (void *) funA; +extern "C" void _Unwind_RaiseException() { + SYMBOL_HOOK( p__Unwind_RaiseException); +} +extern "C" __attribute__((used)) void *p__Unwind_Resume = (void *) funA; +extern "C" void _Unwind_Resume() { + SYMBOL_HOOK( p__Unwind_Resume); +} +extern "C" __attribute__((used)) void *p__Unwind_Resume_or_Rethrow = (void *) funA; +extern "C" void _Unwind_Resume_or_Rethrow() { + SYMBOL_HOOK( p__Unwind_Resume_or_Rethrow); +} +extern "C" __attribute__((used)) void *p__Unwind_SetGR = (void *) funA; +extern "C" void _Unwind_SetGR() { + SYMBOL_HOOK( p__Unwind_SetGR); +} +extern "C" __attribute__((used)) void *p__Unwind_SetIP = (void *) funA; +extern "C" void _Unwind_SetIP() { + SYMBOL_HOOK( p__Unwind_SetIP); +} +extern "C" __attribute__((used)) void *p___absvdi2 = (void *) funA; +extern "C" void __absvdi2() { + SYMBOL_HOOK( p___absvdi2); +} +extern "C" __attribute__((used)) void *p___absvsi2 = (void *) funA; +extern "C" void __absvsi2() { + SYMBOL_HOOK( p___absvsi2); +} +extern "C" __attribute__((used)) void *p___absvti2 = (void *) funA; +extern "C" void __absvti2() { + SYMBOL_HOOK( p___absvti2); +} +extern "C" __attribute__((used)) void *p___addtf3 = (void *) funA; +extern "C" void __addtf3() { + SYMBOL_HOOK( p___addtf3); +} +extern "C" __attribute__((used)) void *p___addvdi3 = (void *) funA; +extern "C" void __addvdi3() { + SYMBOL_HOOK( p___addvdi3); +} +extern "C" __attribute__((used)) void *p___addvsi3 = (void *) funA; +extern "C" void __addvsi3() { + SYMBOL_HOOK( p___addvsi3); +} +extern "C" __attribute__((used)) void *p___addvti3 = (void *) funA; +extern "C" void __addvti3() { + SYMBOL_HOOK( p___addvti3); +} +extern "C" __attribute__((used)) void *p___ashlti3 = (void *) funA; +extern "C" void __ashlti3() { + SYMBOL_HOOK( p___ashlti3); +} +extern "C" __attribute__((used)) void *p___ashrti3 = (void *) funA; +extern "C" void __ashrti3() { + SYMBOL_HOOK( p___ashrti3); +} +extern "C" __attribute__((used)) void *p___bswapdi2 = (void *) funA; +extern "C" void __bswapdi2() { + SYMBOL_HOOK( p___bswapdi2); +} +extern "C" __attribute__((used)) void *p___bswapsi2 = (void *) funA; +extern "C" void __bswapsi2() { + SYMBOL_HOOK( p___bswapsi2); +} +extern "C" __attribute__((used)) void *p___clear_cache = (void *) funA; +extern "C" void __clear_cache() { + SYMBOL_HOOK( p___clear_cache); +} +extern "C" __attribute__((used)) void *p___clrsbdi2 = (void *) funA; +extern "C" void __clrsbdi2() { + SYMBOL_HOOK( p___clrsbdi2); +} +extern "C" __attribute__((used)) void *p___clrsbti2 = (void *) funA; +extern "C" void __clrsbti2() { + SYMBOL_HOOK( p___clrsbti2); +} +extern "C" __attribute__((used)) void *p___clzdi2 = (void *) funA; +extern "C" void __clzdi2() { + SYMBOL_HOOK( p___clzdi2); +} +extern "C" __attribute__((used)) void *p___clzti2 = (void *) funA; +extern "C" void __clzti2() { + SYMBOL_HOOK( p___clzti2); +} +extern "C" __attribute__((used)) void *p___cmpti2 = (void *) funA; +extern "C" void __cmpti2() { + SYMBOL_HOOK( p___cmpti2); +} +extern "C" __attribute__((used)) void *p___cpu_indicator_init = (void *) funA; +extern "C" void __cpu_indicator_init() { + SYMBOL_HOOK( p___cpu_indicator_init); +} +extern "C" __attribute__((used)) void *p___ctzdi2 = (void *) funA; +extern "C" void __ctzdi2() { + SYMBOL_HOOK( p___ctzdi2); +} +extern "C" __attribute__((used)) void *p___ctzti2 = (void *) funA; +extern "C" void __ctzti2() { + SYMBOL_HOOK( p___ctzti2); +} +extern "C" __attribute__((used)) void *p___deregister_frame = (void *) funA; +extern "C" void __deregister_frame() { + SYMBOL_HOOK( p___deregister_frame); +} +extern "C" __attribute__((used)) void *p___deregister_frame_info = (void *) funA; +extern "C" void __deregister_frame_info() { + SYMBOL_HOOK( p___deregister_frame_info); +} +extern "C" __attribute__((used)) void *p___deregister_frame_info_bases = (void *) funA; +extern "C" void __deregister_frame_info_bases() { + SYMBOL_HOOK( p___deregister_frame_info_bases); +} +extern "C" __attribute__((used)) void *p___divdc3 = (void *) funA; +extern "C" void __divdc3() { + SYMBOL_HOOK( p___divdc3); +} +extern "C" __attribute__((used)) void *p___divmodti4 = (void *) funA; +extern "C" void __divmodti4() { + SYMBOL_HOOK( p___divmodti4); +} +extern "C" __attribute__((used)) void *p___divsc3 = (void *) funA; +extern "C" void __divsc3() { + SYMBOL_HOOK( p___divsc3); +} +extern "C" __attribute__((used)) void *p___divtc3 = (void *) funA; +extern "C" void __divtc3() { + SYMBOL_HOOK( p___divtc3); +} +extern "C" __attribute__((used)) void *p___divtf3 = (void *) funA; +extern "C" void __divtf3() { + SYMBOL_HOOK( p___divtf3); +} +extern "C" __attribute__((used)) void *p___divti3 = (void *) funA; +extern "C" void __divti3() { + SYMBOL_HOOK( p___divti3); +} +extern "C" __attribute__((used)) void *p___divxc3 = (void *) funA; +extern "C" void __divxc3() { + SYMBOL_HOOK( p___divxc3); +} +extern "C" __attribute__((used)) void *p___emutls_get_address = (void *) funA; +extern "C" void __emutls_get_address() { + SYMBOL_HOOK( p___emutls_get_address); +} +extern "C" __attribute__((used)) void *p___emutls_register_common = (void *) funA; +extern "C" void __emutls_register_common() { + SYMBOL_HOOK( p___emutls_register_common); +} +extern "C" __attribute__((used)) void *p___enable_execute_stack = (void *) funA; +extern "C" void __enable_execute_stack() { + SYMBOL_HOOK( p___enable_execute_stack); +} +extern "C" __attribute__((used)) void *p___eqtf2 = (void *) funA; +extern "C" void __eqtf2() { + SYMBOL_HOOK( p___eqtf2); +} +extern "C" __attribute__((used)) void *p___extenddftf2 = (void *) funA; +extern "C" void __extenddftf2() { + SYMBOL_HOOK( p___extenddftf2); +} +extern "C" __attribute__((used)) void *p___extendsftf2 = (void *) funA; +extern "C" void __extendsftf2() { + SYMBOL_HOOK( p___extendsftf2); +} +extern "C" __attribute__((used)) void *p___extendxftf2 = (void *) funA; +extern "C" void __extendxftf2() { + SYMBOL_HOOK( p___extendxftf2); +} +extern "C" __attribute__((used)) void *p___ffsdi2 = (void *) funA; +extern "C" void __ffsdi2() { + SYMBOL_HOOK( p___ffsdi2); +} +extern "C" __attribute__((used)) void *p___ffsti2 = (void *) funA; +extern "C" void __ffsti2() { + SYMBOL_HOOK( p___ffsti2); +} +extern "C" __attribute__((used)) void *p___fixdfti = (void *) funA; +extern "C" void __fixdfti() { + SYMBOL_HOOK( p___fixdfti); +} +extern "C" __attribute__((used)) void *p___fixsfti = (void *) funA; +extern "C" void __fixsfti() { + SYMBOL_HOOK( p___fixsfti); +} +extern "C" __attribute__((used)) void *p___fixtfdi = (void *) funA; +extern "C" void __fixtfdi() { + SYMBOL_HOOK( p___fixtfdi); +} +extern "C" __attribute__((used)) void *p___fixtfsi = (void *) funA; +extern "C" void __fixtfsi() { + SYMBOL_HOOK( p___fixtfsi); +} +extern "C" __attribute__((used)) void *p___fixtfti = (void *) funA; +extern "C" void __fixtfti() { + SYMBOL_HOOK( p___fixtfti); +} +extern "C" __attribute__((used)) void *p___fixunsdfdi = (void *) funA; +extern "C" void __fixunsdfdi() { + SYMBOL_HOOK( p___fixunsdfdi); +} +extern "C" __attribute__((used)) void *p___fixunsdfti = (void *) funA; +extern "C" void __fixunsdfti() { + SYMBOL_HOOK( p___fixunsdfti); +} +extern "C" __attribute__((used)) void *p___fixunssfdi = (void *) funA; +extern "C" void __fixunssfdi() { + SYMBOL_HOOK( p___fixunssfdi); +} +extern "C" __attribute__((used)) void *p___fixunssfti = (void *) funA; +extern "C" void __fixunssfti() { + SYMBOL_HOOK( p___fixunssfti); +} +extern "C" __attribute__((used)) void *p___fixunstfdi = (void *) funA; +extern "C" void __fixunstfdi() { + SYMBOL_HOOK( p___fixunstfdi); +} +extern "C" __attribute__((used)) void *p___fixunstfsi = (void *) funA; +extern "C" void __fixunstfsi() { + SYMBOL_HOOK( p___fixunstfsi); +} +extern "C" __attribute__((used)) void *p___fixunstfti = (void *) funA; +extern "C" void __fixunstfti() { + SYMBOL_HOOK( p___fixunstfti); +} +extern "C" __attribute__((used)) void *p___fixunsxfdi = (void *) funA; +extern "C" void __fixunsxfdi() { + SYMBOL_HOOK( p___fixunsxfdi); +} +extern "C" __attribute__((used)) void *p___fixunsxfti = (void *) funA; +extern "C" void __fixunsxfti() { + SYMBOL_HOOK( p___fixunsxfti); +} +extern "C" __attribute__((used)) void *p___fixxfti = (void *) funA; +extern "C" void __fixxfti() { + SYMBOL_HOOK( p___fixxfti); +} +extern "C" __attribute__((used)) void *p___floatditf = (void *) funA; +extern "C" void __floatditf() { + SYMBOL_HOOK( p___floatditf); +} +extern "C" __attribute__((used)) void *p___floatsitf = (void *) funA; +extern "C" void __floatsitf() { + SYMBOL_HOOK( p___floatsitf); +} +extern "C" __attribute__((used)) void *p___floattidf = (void *) funA; +extern "C" void __floattidf() { + SYMBOL_HOOK( p___floattidf); +} +extern "C" __attribute__((used)) void *p___floattisf = (void *) funA; +extern "C" void __floattisf() { + SYMBOL_HOOK( p___floattisf); +} +extern "C" __attribute__((used)) void *p___floattitf = (void *) funA; +extern "C" void __floattitf() { + SYMBOL_HOOK( p___floattitf); +} +extern "C" __attribute__((used)) void *p___floattixf = (void *) funA; +extern "C" void __floattixf() { + SYMBOL_HOOK( p___floattixf); +} +extern "C" __attribute__((used)) void *p___floatunditf = (void *) funA; +extern "C" void __floatunditf() { + SYMBOL_HOOK( p___floatunditf); +} +extern "C" __attribute__((used)) void *p___floatunsitf = (void *) funA; +extern "C" void __floatunsitf() { + SYMBOL_HOOK( p___floatunsitf); +} +extern "C" __attribute__((used)) void *p___floatuntidf = (void *) funA; +extern "C" void __floatuntidf() { + SYMBOL_HOOK( p___floatuntidf); +} +extern "C" __attribute__((used)) void *p___floatuntisf = (void *) funA; +extern "C" void __floatuntisf() { + SYMBOL_HOOK( p___floatuntisf); +} +extern "C" __attribute__((used)) void *p___floatuntitf = (void *) funA; +extern "C" void __floatuntitf() { + SYMBOL_HOOK( p___floatuntitf); +} +extern "C" __attribute__((used)) void *p___floatuntixf = (void *) funA; +extern "C" void __floatuntixf() { + SYMBOL_HOOK( p___floatuntixf); +} +extern "C" __attribute__((used)) void *p___gcc_personality_v0 = (void *) funA; +extern "C" void __gcc_personality_v0() { + SYMBOL_HOOK( p___gcc_personality_v0); +} +extern "C" __attribute__((used)) void *p___getf2 = (void *) funA; +extern "C" void __getf2() { + SYMBOL_HOOK( p___getf2); +} +extern "C" __attribute__((used)) void *p___gttf2 = (void *) funA; +extern "C" void __gttf2() { + SYMBOL_HOOK( p___gttf2); +} +extern "C" __attribute__((used)) void *p___letf2 = (void *) funA; +extern "C" void __letf2() { + SYMBOL_HOOK( p___letf2); +} +extern "C" __attribute__((used)) void *p___lshrti3 = (void *) funA; +extern "C" void __lshrti3() { + SYMBOL_HOOK( p___lshrti3); +} +extern "C" __attribute__((used)) void *p___lttf2 = (void *) funA; +extern "C" void __lttf2() { + SYMBOL_HOOK( p___lttf2); +} +extern "C" __attribute__((used)) void *p___modti3 = (void *) funA; +extern "C" void __modti3() { + SYMBOL_HOOK( p___modti3); +} +extern "C" __attribute__((used)) void *p___muldc3 = (void *) funA; +extern "C" void __muldc3() { + SYMBOL_HOOK( p___muldc3); +} +extern "C" __attribute__((used)) void *p___mulsc3 = (void *) funA; +extern "C" void __mulsc3() { + SYMBOL_HOOK( p___mulsc3); +} +extern "C" __attribute__((used)) void *p___multc3 = (void *) funA; +extern "C" void __multc3() { + SYMBOL_HOOK( p___multc3); +} +extern "C" __attribute__((used)) void *p___multf3 = (void *) funA; +extern "C" void __multf3() { + SYMBOL_HOOK( p___multf3); +} +extern "C" __attribute__((used)) void *p___multi3 = (void *) funA; +extern "C" void __multi3() { + SYMBOL_HOOK( p___multi3); +} +extern "C" __attribute__((used)) void *p___mulvdi3 = (void *) funA; +extern "C" void __mulvdi3() { + SYMBOL_HOOK( p___mulvdi3); +} +extern "C" __attribute__((used)) void *p___mulvsi3 = (void *) funA; +extern "C" void __mulvsi3() { + SYMBOL_HOOK( p___mulvsi3); +} +extern "C" __attribute__((used)) void *p___mulvti3 = (void *) funA; +extern "C" void __mulvti3() { + SYMBOL_HOOK( p___mulvti3); +} +extern "C" __attribute__((used)) void *p___mulxc3 = (void *) funA; +extern "C" void __mulxc3() { + SYMBOL_HOOK( p___mulxc3); +} +extern "C" __attribute__((used)) void *p___negtf2 = (void *) funA; +extern "C" void __negtf2() { + SYMBOL_HOOK( p___negtf2); +} +extern "C" __attribute__((used)) void *p___negti2 = (void *) funA; +extern "C" void __negti2() { + SYMBOL_HOOK( p___negti2); +} +extern "C" __attribute__((used)) void *p___negvdi2 = (void *) funA; +extern "C" void __negvdi2() { + SYMBOL_HOOK( p___negvdi2); +} +extern "C" __attribute__((used)) void *p___negvsi2 = (void *) funA; +extern "C" void __negvsi2() { + SYMBOL_HOOK( p___negvsi2); +} +extern "C" __attribute__((used)) void *p___negvti2 = (void *) funA; +extern "C" void __negvti2() { + SYMBOL_HOOK( p___negvti2); +} +extern "C" __attribute__((used)) void *p___netf2 = (void *) funA; +extern "C" void __netf2() { + SYMBOL_HOOK( p___netf2); +} +extern "C" __attribute__((used)) void *p___paritydi2 = (void *) funA; +extern "C" void __paritydi2() { + SYMBOL_HOOK( p___paritydi2); +} +extern "C" __attribute__((used)) void *p___parityti2 = (void *) funA; +extern "C" void __parityti2() { + SYMBOL_HOOK( p___parityti2); +} +extern "C" __attribute__((used)) void *p___popcountdi2 = (void *) funA; +extern "C" void __popcountdi2() { + SYMBOL_HOOK( p___popcountdi2); +} +extern "C" __attribute__((used)) void *p___popcountti2 = (void *) funA; +extern "C" void __popcountti2() { + SYMBOL_HOOK( p___popcountti2); +} +extern "C" __attribute__((used)) void *p___powidf2 = (void *) funA; +extern "C" void __powidf2() { + SYMBOL_HOOK( p___powidf2); +} +extern "C" __attribute__((used)) void *p___powisf2 = (void *) funA; +extern "C" void __powisf2() { + SYMBOL_HOOK( p___powisf2); +} +extern "C" __attribute__((used)) void *p___powitf2 = (void *) funA; +extern "C" void __powitf2() { + SYMBOL_HOOK( p___powitf2); +} +extern "C" __attribute__((used)) void *p___powixf2 = (void *) funA; +extern "C" void __powixf2() { + SYMBOL_HOOK( p___powixf2); +} +extern "C" __attribute__((used)) void *p___register_frame = (void *) funA; +extern "C" void __register_frame() { + SYMBOL_HOOK( p___register_frame); +} +extern "C" __attribute__((used)) void *p___register_frame_info = (void *) funA; +extern "C" void __register_frame_info() { + SYMBOL_HOOK( p___register_frame_info); +} +extern "C" __attribute__((used)) void *p___register_frame_info_bases = (void *) funA; +extern "C" void __register_frame_info_bases() { + SYMBOL_HOOK( p___register_frame_info_bases); +} +extern "C" __attribute__((used)) void *p___register_frame_info_table = (void *) funA; +extern "C" void __register_frame_info_table() { + SYMBOL_HOOK( p___register_frame_info_table); +} +extern "C" __attribute__((used)) void *p___register_frame_info_table_bases = (void *) funA; +extern "C" void __register_frame_info_table_bases() { + SYMBOL_HOOK( p___register_frame_info_table_bases); +} +extern "C" __attribute__((used)) void *p___register_frame_table = (void *) funA; +extern "C" void __register_frame_table() { + SYMBOL_HOOK( p___register_frame_table); +} +extern "C" __attribute__((used)) void *p___subtf3 = (void *) funA; +extern "C" void __subtf3() { + SYMBOL_HOOK( p___subtf3); +} +extern "C" __attribute__((used)) void *p___subvdi3 = (void *) funA; +extern "C" void __subvdi3() { + SYMBOL_HOOK( p___subvdi3); +} +extern "C" __attribute__((used)) void *p___subvsi3 = (void *) funA; +extern "C" void __subvsi3() { + SYMBOL_HOOK( p___subvsi3); +} +extern "C" __attribute__((used)) void *p___subvti3 = (void *) funA; +extern "C" void __subvti3() { + SYMBOL_HOOK( p___subvti3); +} +extern "C" __attribute__((used)) void *p___trunctfdf2 = (void *) funA; +extern "C" void __trunctfdf2() { + SYMBOL_HOOK( p___trunctfdf2); +} +extern "C" __attribute__((used)) void *p___trunctfsf2 = (void *) funA; +extern "C" void __trunctfsf2() { + SYMBOL_HOOK( p___trunctfsf2); +} +extern "C" __attribute__((used)) void *p___trunctfxf2 = (void *) funA; +extern "C" void __trunctfxf2() { + SYMBOL_HOOK( p___trunctfxf2); +} +extern "C" __attribute__((used)) void *p___ucmpti2 = (void *) funA; +extern "C" void __ucmpti2() { + SYMBOL_HOOK( p___ucmpti2); +} +extern "C" __attribute__((used)) void *p___udivmodti4 = (void *) funA; +extern "C" void __udivmodti4() { + SYMBOL_HOOK( p___udivmodti4); +} +extern "C" __attribute__((used)) void *p___udivti3 = (void *) funA; +extern "C" void __udivti3() { + SYMBOL_HOOK( p___udivti3); +} +extern "C" __attribute__((used)) void *p___umodti3 = (void *) funA; +extern "C" void __umodti3() { + SYMBOL_HOOK( p___umodti3); +} +extern "C" __attribute__((used)) void *p___unordtf2 = (void *) funA; +extern "C" void __unordtf2() { + SYMBOL_HOOK( p___unordtf2); +} +void __attribute__ ((constructor (103))) hookInit() { +handle = dlopen("libgcc_s.so.1", RTLD_LAZY); +p__Unwind_Backtrace = dlsym(handle, "_Unwind_Backtrace"); +p__Unwind_DeleteException = dlsym(handle, "_Unwind_DeleteException"); +p__Unwind_FindEnclosingFunction = dlsym(handle, "_Unwind_FindEnclosingFunction"); +p__Unwind_Find_FDE = dlsym(handle, "_Unwind_Find_FDE"); +p__Unwind_ForcedUnwind = dlsym(handle, "_Unwind_ForcedUnwind"); +p__Unwind_GetCFA = dlsym(handle, "_Unwind_GetCFA"); +p__Unwind_GetDataRelBase = dlsym(handle, "_Unwind_GetDataRelBase"); +p__Unwind_GetGR = dlsym(handle, "_Unwind_GetGR"); +p__Unwind_GetIP = dlsym(handle, "_Unwind_GetIP"); +p__Unwind_GetIPInfo = dlsym(handle, "_Unwind_GetIPInfo"); +p__Unwind_GetLanguageSpecificData = dlsym(handle, "_Unwind_GetLanguageSpecificData"); +p__Unwind_GetRegionStart = dlsym(handle, "_Unwind_GetRegionStart"); +p__Unwind_GetTextRelBase = dlsym(handle, "_Unwind_GetTextRelBase"); +p__Unwind_RaiseException = dlsym(handle, "_Unwind_RaiseException"); +p__Unwind_Resume = dlsym(handle, "_Unwind_Resume"); +p__Unwind_Resume_or_Rethrow = dlsym(handle, "_Unwind_Resume_or_Rethrow"); +p__Unwind_SetGR = dlsym(handle, "_Unwind_SetGR"); +p__Unwind_SetIP = dlsym(handle, "_Unwind_SetIP"); +p___absvdi2 = dlsym(handle, "__absvdi2"); +p___absvsi2 = dlsym(handle, "__absvsi2"); +p___absvti2 = dlsym(handle, "__absvti2"); +p___addtf3 = dlsym(handle, "__addtf3"); +p___addvdi3 = dlsym(handle, "__addvdi3"); +p___addvsi3 = dlsym(handle, "__addvsi3"); +p___addvti3 = dlsym(handle, "__addvti3"); +p___ashlti3 = dlsym(handle, "__ashlti3"); +p___ashrti3 = dlsym(handle, "__ashrti3"); +p___bswapdi2 = dlsym(handle, "__bswapdi2"); +p___bswapsi2 = dlsym(handle, "__bswapsi2"); +p___clear_cache = dlsym(handle, "__clear_cache"); +p___clrsbdi2 = dlsym(handle, "__clrsbdi2"); +p___clrsbti2 = dlsym(handle, "__clrsbti2"); +p___clzdi2 = dlsym(handle, "__clzdi2"); +p___clzti2 = dlsym(handle, "__clzti2"); +p___cmpti2 = dlsym(handle, "__cmpti2"); +p___cpu_indicator_init = dlsym(handle, "__cpu_indicator_init"); +p___ctzdi2 = dlsym(handle, "__ctzdi2"); +p___ctzti2 = dlsym(handle, "__ctzti2"); +p___deregister_frame = dlsym(handle, "__deregister_frame"); +p___deregister_frame_info = dlsym(handle, "__deregister_frame_info"); +p___deregister_frame_info_bases = dlsym(handle, "__deregister_frame_info_bases"); +p___divdc3 = dlsym(handle, "__divdc3"); +p___divmodti4 = dlsym(handle, "__divmodti4"); +p___divsc3 = dlsym(handle, "__divsc3"); +p___divtc3 = dlsym(handle, "__divtc3"); +p___divtf3 = dlsym(handle, "__divtf3"); +p___divti3 = dlsym(handle, "__divti3"); +p___divxc3 = dlsym(handle, "__divxc3"); +p___emutls_get_address = dlsym(handle, "__emutls_get_address"); +p___emutls_register_common = dlsym(handle, "__emutls_register_common"); +p___enable_execute_stack = dlsym(handle, "__enable_execute_stack"); +p___eqtf2 = dlsym(handle, "__eqtf2"); +p___extenddftf2 = dlsym(handle, "__extenddftf2"); +p___extendsftf2 = dlsym(handle, "__extendsftf2"); +p___extendxftf2 = dlsym(handle, "__extendxftf2"); +p___ffsdi2 = dlsym(handle, "__ffsdi2"); +p___ffsti2 = dlsym(handle, "__ffsti2"); +p___fixdfti = dlsym(handle, "__fixdfti"); +p___fixsfti = dlsym(handle, "__fixsfti"); +p___fixtfdi = dlsym(handle, "__fixtfdi"); +p___fixtfsi = dlsym(handle, "__fixtfsi"); +p___fixtfti = dlsym(handle, "__fixtfti"); +p___fixunsdfdi = dlsym(handle, "__fixunsdfdi"); +p___fixunsdfti = dlsym(handle, "__fixunsdfti"); +p___fixunssfdi = dlsym(handle, "__fixunssfdi"); +p___fixunssfti = dlsym(handle, "__fixunssfti"); +p___fixunstfdi = dlsym(handle, "__fixunstfdi"); +p___fixunstfsi = dlsym(handle, "__fixunstfsi"); +p___fixunstfti = dlsym(handle, "__fixunstfti"); +p___fixunsxfdi = dlsym(handle, "__fixunsxfdi"); +p___fixunsxfti = dlsym(handle, "__fixunsxfti"); +p___fixxfti = dlsym(handle, "__fixxfti"); +p___floatditf = dlsym(handle, "__floatditf"); +p___floatsitf = dlsym(handle, "__floatsitf"); +p___floattidf = dlsym(handle, "__floattidf"); +p___floattisf = dlsym(handle, "__floattisf"); +p___floattitf = dlsym(handle, "__floattitf"); +p___floattixf = dlsym(handle, "__floattixf"); +p___floatunditf = dlsym(handle, "__floatunditf"); +p___floatunsitf = dlsym(handle, "__floatunsitf"); +p___floatuntidf = dlsym(handle, "__floatuntidf"); +p___floatuntisf = dlsym(handle, "__floatuntisf"); +p___floatuntitf = dlsym(handle, "__floatuntitf"); +p___floatuntixf = dlsym(handle, "__floatuntixf"); +p___gcc_personality_v0 = dlsym(handle, "__gcc_personality_v0"); +p___getf2 = dlsym(handle, "__getf2"); +p___gttf2 = dlsym(handle, "__gttf2"); +p___letf2 = dlsym(handle, "__letf2"); +p___lshrti3 = dlsym(handle, "__lshrti3"); +p___lttf2 = dlsym(handle, "__lttf2"); +p___modti3 = dlsym(handle, "__modti3"); +p___muldc3 = dlsym(handle, "__muldc3"); +p___mulsc3 = dlsym(handle, "__mulsc3"); +p___multc3 = dlsym(handle, "__multc3"); +p___multf3 = dlsym(handle, "__multf3"); +p___multi3 = dlsym(handle, "__multi3"); +p___mulvdi3 = dlsym(handle, "__mulvdi3"); +p___mulvsi3 = dlsym(handle, "__mulvsi3"); +p___mulvti3 = dlsym(handle, "__mulvti3"); +p___mulxc3 = dlsym(handle, "__mulxc3"); +p___negtf2 = dlsym(handle, "__negtf2"); +p___negti2 = dlsym(handle, "__negti2"); +p___negvdi2 = dlsym(handle, "__negvdi2"); +p___negvsi2 = dlsym(handle, "__negvsi2"); +p___negvti2 = dlsym(handle, "__negvti2"); +p___netf2 = dlsym(handle, "__netf2"); +p___paritydi2 = dlsym(handle, "__paritydi2"); +p___parityti2 = dlsym(handle, "__parityti2"); +p___popcountdi2 = dlsym(handle, "__popcountdi2"); +p___popcountti2 = dlsym(handle, "__popcountti2"); +p___powidf2 = dlsym(handle, "__powidf2"); +p___powisf2 = dlsym(handle, "__powisf2"); +p___powitf2 = dlsym(handle, "__powitf2"); +p___powixf2 = dlsym(handle, "__powixf2"); +p___register_frame = dlsym(handle, "__register_frame"); +p___register_frame_info = dlsym(handle, "__register_frame_info"); +p___register_frame_info_bases = dlsym(handle, "__register_frame_info_bases"); +p___register_frame_info_table = dlsym(handle, "__register_frame_info_table"); +p___register_frame_info_table_bases = dlsym(handle, "__register_frame_info_table_bases"); +p___register_frame_table = dlsym(handle, "__register_frame_table"); +p___subtf3 = dlsym(handle, "__subtf3"); +p___subvdi3 = dlsym(handle, "__subvdi3"); +p___subvsi3 = dlsym(handle, "__subvsi3"); +p___subvti3 = dlsym(handle, "__subvti3"); +p___trunctfdf2 = dlsym(handle, "__trunctfdf2"); +p___trunctfsf2 = dlsym(handle, "__trunctfsf2"); +p___trunctfxf2 = dlsym(handle, "__trunctfxf2"); +p___ucmpti2 = dlsym(handle, "__ucmpti2"); +p___udivmodti4 = dlsym(handle, "__udivmodti4"); +p___udivti3 = dlsym(handle, "__udivti3"); +p___umodti3 = dlsym(handle, "__umodti3"); +p___unordtf2 = dlsym(handle, "__unordtf2"); + +} \ No newline at end of file diff --git a/linuxTest/exampleAttack/libkrb5support.so.0.cpp b/linuxTest/exampleAttack/libkrb5support.so.0.cpp new file mode 100644 index 0000000..ad04575 --- /dev/null +++ b/linuxTest/exampleAttack/libkrb5support.so.0.cpp @@ -0,0 +1,445 @@ +#include +#include +#include + +#include "symbolhook.h" + +static void *handle; + +static void funA() { + printf("!WARNING!, SYMBOL HOOK CALLED BEFORE RELOCATION INSTALLED\n"); +} +extern "C" __attribute__((used)) void *p_k5_base64_decode = (void *) funA; +extern "C" void k5_base64_decode() { + SYMBOL_HOOK( p_k5_base64_decode); +} +extern "C" __attribute__((used)) void *p_k5_base64_encode = (void *) funA; +extern "C" void k5_base64_encode() { + SYMBOL_HOOK( p_k5_base64_encode); +} +extern "C" __attribute__((used)) void *p_k5_bcmp = (void *) funA; +extern "C" void k5_bcmp() { + SYMBOL_HOOK( p_k5_bcmp); +} +extern "C" __attribute__((used)) void *p_k5_buf_add = (void *) funA; +extern "C" void k5_buf_add() { + SYMBOL_HOOK( p_k5_buf_add); +} +extern "C" __attribute__((used)) void *p_k5_buf_add_fmt = (void *) funA; +extern "C" void k5_buf_add_fmt() { + SYMBOL_HOOK( p_k5_buf_add_fmt); +} +extern "C" __attribute__((used)) void *p_k5_buf_add_len = (void *) funA; +extern "C" void k5_buf_add_len() { + SYMBOL_HOOK( p_k5_buf_add_len); +} +extern "C" __attribute__((used)) void *p_k5_buf_free = (void *) funA; +extern "C" void k5_buf_free() { + SYMBOL_HOOK( p_k5_buf_free); +} +extern "C" __attribute__((used)) void *p_k5_buf_get_space = (void *) funA; +extern "C" void k5_buf_get_space() { + SYMBOL_HOOK( p_k5_buf_get_space); +} +extern "C" __attribute__((used)) void *p_k5_buf_init_dynamic = (void *) funA; +extern "C" void k5_buf_init_dynamic() { + SYMBOL_HOOK( p_k5_buf_init_dynamic); +} +extern "C" __attribute__((used)) void *p_k5_buf_init_fixed = (void *) funA; +extern "C" void k5_buf_init_fixed() { + SYMBOL_HOOK( p_k5_buf_init_fixed); +} +extern "C" __attribute__((used)) void *p_k5_buf_status = (void *) funA; +extern "C" void k5_buf_status() { + SYMBOL_HOOK( p_k5_buf_status); +} +extern "C" __attribute__((used)) void *p_k5_buf_truncate = (void *) funA; +extern "C" void k5_buf_truncate() { + SYMBOL_HOOK( p_k5_buf_truncate); +} +extern "C" __attribute__((used)) void *p_k5_clear_error = (void *) funA; +extern "C" void k5_clear_error() { + SYMBOL_HOOK( p_k5_clear_error); +} +extern "C" __attribute__((used)) void *p_k5_free_error = (void *) funA; +extern "C" void k5_free_error() { + SYMBOL_HOOK( p_k5_free_error); +} +extern "C" __attribute__((used)) void *p_k5_get_error = (void *) funA; +extern "C" void k5_get_error() { + SYMBOL_HOOK( p_k5_get_error); +} +extern "C" __attribute__((used)) void *p_k5_json_array_add = (void *) funA; +extern "C" void k5_json_array_add() { + SYMBOL_HOOK( p_k5_json_array_add); +} +extern "C" __attribute__((used)) void *p_k5_json_array_create = (void *) funA; +extern "C" void k5_json_array_create() { + SYMBOL_HOOK( p_k5_json_array_create); +} +extern "C" __attribute__((used)) void *p_k5_json_array_fmt = (void *) funA; +extern "C" void k5_json_array_fmt() { + SYMBOL_HOOK( p_k5_json_array_fmt); +} +extern "C" __attribute__((used)) void *p_k5_json_array_get = (void *) funA; +extern "C" void k5_json_array_get() { + SYMBOL_HOOK( p_k5_json_array_get); +} +extern "C" __attribute__((used)) void *p_k5_json_array_length = (void *) funA; +extern "C" void k5_json_array_length() { + SYMBOL_HOOK( p_k5_json_array_length); +} +extern "C" __attribute__((used)) void *p_k5_json_array_set = (void *) funA; +extern "C" void k5_json_array_set() { + SYMBOL_HOOK( p_k5_json_array_set); +} +extern "C" __attribute__((used)) void *p_k5_json_bool_create = (void *) funA; +extern "C" void k5_json_bool_create() { + SYMBOL_HOOK( p_k5_json_bool_create); +} +extern "C" __attribute__((used)) void *p_k5_json_bool_value = (void *) funA; +extern "C" void k5_json_bool_value() { + SYMBOL_HOOK( p_k5_json_bool_value); +} +extern "C" __attribute__((used)) void *p_k5_json_decode = (void *) funA; +extern "C" void k5_json_decode() { + SYMBOL_HOOK( p_k5_json_decode); +} +extern "C" __attribute__((used)) void *p_k5_json_encode = (void *) funA; +extern "C" void k5_json_encode() { + SYMBOL_HOOK( p_k5_json_encode); +} +extern "C" __attribute__((used)) void *p_k5_json_get_tid = (void *) funA; +extern "C" void k5_json_get_tid() { + SYMBOL_HOOK( p_k5_json_get_tid); +} +extern "C" __attribute__((used)) void *p_k5_json_null_create = (void *) funA; +extern "C" void k5_json_null_create() { + SYMBOL_HOOK( p_k5_json_null_create); +} +extern "C" __attribute__((used)) void *p_k5_json_null_create_val = (void *) funA; +extern "C" void k5_json_null_create_val() { + SYMBOL_HOOK( p_k5_json_null_create_val); +} +extern "C" __attribute__((used)) void *p_k5_json_number_create = (void *) funA; +extern "C" void k5_json_number_create() { + SYMBOL_HOOK( p_k5_json_number_create); +} +extern "C" __attribute__((used)) void *p_k5_json_number_value = (void *) funA; +extern "C" void k5_json_number_value() { + SYMBOL_HOOK( p_k5_json_number_value); +} +extern "C" __attribute__((used)) void *p_k5_json_object_count = (void *) funA; +extern "C" void k5_json_object_count() { + SYMBOL_HOOK( p_k5_json_object_count); +} +extern "C" __attribute__((used)) void *p_k5_json_object_create = (void *) funA; +extern "C" void k5_json_object_create() { + SYMBOL_HOOK( p_k5_json_object_create); +} +extern "C" __attribute__((used)) void *p_k5_json_object_get = (void *) funA; +extern "C" void k5_json_object_get() { + SYMBOL_HOOK( p_k5_json_object_get); +} +extern "C" __attribute__((used)) void *p_k5_json_object_iterate = (void *) funA; +extern "C" void k5_json_object_iterate() { + SYMBOL_HOOK( p_k5_json_object_iterate); +} +extern "C" __attribute__((used)) void *p_k5_json_object_set = (void *) funA; +extern "C" void k5_json_object_set() { + SYMBOL_HOOK( p_k5_json_object_set); +} +extern "C" __attribute__((used)) void *p_k5_json_release = (void *) funA; +extern "C" void k5_json_release() { + SYMBOL_HOOK( p_k5_json_release); +} +extern "C" __attribute__((used)) void *p_k5_json_retain = (void *) funA; +extern "C" void k5_json_retain() { + SYMBOL_HOOK( p_k5_json_retain); +} +extern "C" __attribute__((used)) void *p_k5_json_string_create = (void *) funA; +extern "C" void k5_json_string_create() { + SYMBOL_HOOK( p_k5_json_string_create); +} +extern "C" __attribute__((used)) void *p_k5_json_string_create_base64 = (void *) funA; +extern "C" void k5_json_string_create_base64() { + SYMBOL_HOOK( p_k5_json_string_create_base64); +} +extern "C" __attribute__((used)) void *p_k5_json_string_create_len = (void *) funA; +extern "C" void k5_json_string_create_len() { + SYMBOL_HOOK( p_k5_json_string_create_len); +} +extern "C" __attribute__((used)) void *p_k5_json_string_unbase64 = (void *) funA; +extern "C" void k5_json_string_unbase64() { + SYMBOL_HOOK( p_k5_json_string_unbase64); +} +extern "C" __attribute__((used)) void *p_k5_json_string_utf8 = (void *) funA; +extern "C" void k5_json_string_utf8() { + SYMBOL_HOOK( p_k5_json_string_utf8); +} +extern "C" __attribute__((used)) void *p_k5_once = (void *) funA; +extern "C" void k5_once() { + SYMBOL_HOOK( p_k5_once); +} +extern "C" __attribute__((used)) void *p_k5_os_mutex_destroy = (void *) funA; +extern "C" void k5_os_mutex_destroy() { + SYMBOL_HOOK( p_k5_os_mutex_destroy); +} +extern "C" __attribute__((used)) void *p_k5_os_mutex_init = (void *) funA; +extern "C" void k5_os_mutex_init() { + SYMBOL_HOOK( p_k5_os_mutex_init); +} +extern "C" __attribute__((used)) void *p_k5_os_mutex_lock = (void *) funA; +extern "C" void k5_os_mutex_lock() { + SYMBOL_HOOK( p_k5_os_mutex_lock); +} +extern "C" __attribute__((used)) void *p_k5_os_mutex_unlock = (void *) funA; +extern "C" void k5_os_mutex_unlock() { + SYMBOL_HOOK( p_k5_os_mutex_unlock); +} +extern "C" __attribute__((used)) void *p_k5_path_isabs = (void *) funA; +extern "C" void k5_path_isabs() { + SYMBOL_HOOK( p_k5_path_isabs); +} +extern "C" __attribute__((used)) void *p_k5_path_join = (void *) funA; +extern "C" void k5_path_join() { + SYMBOL_HOOK( p_k5_path_join); +} +extern "C" __attribute__((used)) void *p_k5_path_split = (void *) funA; +extern "C" void k5_path_split() { + SYMBOL_HOOK( p_k5_path_split); +} +extern "C" __attribute__((used)) void *p_k5_set_error = (void *) funA; +extern "C" void k5_set_error() { + SYMBOL_HOOK( p_k5_set_error); +} +extern "C" __attribute__((used)) void *p_k5_set_error_info_callout_fn = (void *) funA; +extern "C" void k5_set_error_info_callout_fn() { + SYMBOL_HOOK( p_k5_set_error_info_callout_fn); +} +extern "C" __attribute__((used)) void *p_k5_strerror_r = (void *) funA; +extern "C" void k5_strerror_r() { + SYMBOL_HOOK( p_k5_strerror_r); +} +extern "C" __attribute__((used)) void *p_k5_utf16le_to_utf8 = (void *) funA; +extern "C" void k5_utf16le_to_utf8() { + SYMBOL_HOOK( p_k5_utf16le_to_utf8); +} +extern "C" __attribute__((used)) void *p_k5_utf8_to_utf16le = (void *) funA; +extern "C" void k5_utf8_to_utf16le() { + SYMBOL_HOOK( p_k5_utf8_to_utf16le); +} +extern "C" __attribute__((used)) void *p_k5_vset_error = (void *) funA; +extern "C" void k5_vset_error() { + SYMBOL_HOOK( p_k5_vset_error); +} +extern "C" __attribute__((used)) void *p_krb5int_close_plugin = (void *) funA; +extern "C" void krb5int_close_plugin() { + SYMBOL_HOOK( p_krb5int_close_plugin); +} +extern "C" __attribute__((used)) void *p_krb5int_close_plugin_dirs = (void *) funA; +extern "C" void krb5int_close_plugin_dirs() { + SYMBOL_HOOK( p_krb5int_close_plugin_dirs); +} +extern "C" __attribute__((used)) void *p_krb5int_free_plugin_dir_data = (void *) funA; +extern "C" void krb5int_free_plugin_dir_data() { + SYMBOL_HOOK( p_krb5int_free_plugin_dir_data); +} +extern "C" __attribute__((used)) void *p_krb5int_free_plugin_dir_func = (void *) funA; +extern "C" void krb5int_free_plugin_dir_func() { + SYMBOL_HOOK( p_krb5int_free_plugin_dir_func); +} +extern "C" __attribute__((used)) void *p_krb5int_freeaddrinfo = (void *) funA; +extern "C" void krb5int_freeaddrinfo() { + SYMBOL_HOOK( p_krb5int_freeaddrinfo); +} +extern "C" __attribute__((used)) void *p_krb5int_gai_strerror = (void *) funA; +extern "C" void krb5int_gai_strerror() { + SYMBOL_HOOK( p_krb5int_gai_strerror); +} +extern "C" __attribute__((used)) void *p_krb5int_get_plugin_data = (void *) funA; +extern "C" void krb5int_get_plugin_data() { + SYMBOL_HOOK( p_krb5int_get_plugin_data); +} +extern "C" __attribute__((used)) void *p_krb5int_get_plugin_dir_data = (void *) funA; +extern "C" void krb5int_get_plugin_dir_data() { + SYMBOL_HOOK( p_krb5int_get_plugin_dir_data); +} +extern "C" __attribute__((used)) void *p_krb5int_get_plugin_dir_func = (void *) funA; +extern "C" void krb5int_get_plugin_dir_func() { + SYMBOL_HOOK( p_krb5int_get_plugin_dir_func); +} +extern "C" __attribute__((used)) void *p_krb5int_get_plugin_func = (void *) funA; +extern "C" void krb5int_get_plugin_func() { + SYMBOL_HOOK( p_krb5int_get_plugin_func); +} +extern "C" __attribute__((used)) void *p_krb5int_getaddrinfo = (void *) funA; +extern "C" void krb5int_getaddrinfo() { + SYMBOL_HOOK( p_krb5int_getaddrinfo); +} +extern "C" __attribute__((used)) void *p_krb5int_getnameinfo = (void *) funA; +extern "C" void krb5int_getnameinfo() { + SYMBOL_HOOK( p_krb5int_getnameinfo); +} +extern "C" __attribute__((used)) void *p_krb5int_getspecific = (void *) funA; +extern "C" void krb5int_getspecific() { + SYMBOL_HOOK( p_krb5int_getspecific); +} +extern "C" __attribute__((used)) void *p_krb5int_gmt_mktime = (void *) funA; +extern "C" void krb5int_gmt_mktime() { + SYMBOL_HOOK( p_krb5int_gmt_mktime); +} +extern "C" __attribute__((used)) void *p_krb5int_key_delete = (void *) funA; +extern "C" void krb5int_key_delete() { + SYMBOL_HOOK( p_krb5int_key_delete); +} +extern "C" __attribute__((used)) void *p_krb5int_key_register = (void *) funA; +extern "C" void krb5int_key_register() { + SYMBOL_HOOK( p_krb5int_key_register); +} +extern "C" __attribute__((used)) void *p_krb5int_mutex_alloc = (void *) funA; +extern "C" void krb5int_mutex_alloc() { + SYMBOL_HOOK( p_krb5int_mutex_alloc); +} +extern "C" __attribute__((used)) void *p_krb5int_mutex_free = (void *) funA; +extern "C" void krb5int_mutex_free() { + SYMBOL_HOOK( p_krb5int_mutex_free); +} +extern "C" __attribute__((used)) void *p_krb5int_mutex_lock = (void *) funA; +extern "C" void krb5int_mutex_lock() { + SYMBOL_HOOK( p_krb5int_mutex_lock); +} +extern "C" __attribute__((used)) void *p_krb5int_mutex_unlock = (void *) funA; +extern "C" void krb5int_mutex_unlock() { + SYMBOL_HOOK( p_krb5int_mutex_unlock); +} +extern "C" __attribute__((used)) void *p_krb5int_open_plugin = (void *) funA; +extern "C" void krb5int_open_plugin() { + SYMBOL_HOOK( p_krb5int_open_plugin); +} +extern "C" __attribute__((used)) void *p_krb5int_open_plugin_dirs = (void *) funA; +extern "C" void krb5int_open_plugin_dirs() { + SYMBOL_HOOK( p_krb5int_open_plugin_dirs); +} +extern "C" __attribute__((used)) void *p_krb5int_pthread_loaded = (void *) funA; +extern "C" void krb5int_pthread_loaded() { + SYMBOL_HOOK( p_krb5int_pthread_loaded); +} +extern "C" __attribute__((used)) void *p_krb5int_setspecific = (void *) funA; +extern "C" void krb5int_setspecific() { + SYMBOL_HOOK( p_krb5int_setspecific); +} +extern "C" __attribute__((used)) void *p_krb5int_strlcat = (void *) funA; +extern "C" void krb5int_strlcat() { + SYMBOL_HOOK( p_krb5int_strlcat); +} +extern "C" __attribute__((used)) void *p_krb5int_strlcpy = (void *) funA; +extern "C" void krb5int_strlcpy() { + SYMBOL_HOOK( p_krb5int_strlcpy); +} +extern "C" __attribute__((used)) void *p_krb5int_ucs4_to_utf8 = (void *) funA; +extern "C" void krb5int_ucs4_to_utf8() { + SYMBOL_HOOK( p_krb5int_ucs4_to_utf8); +} +extern "C" __attribute__((used)) void *p_krb5int_utf8_next = (void *) funA; +extern "C" void krb5int_utf8_next() { + SYMBOL_HOOK( p_krb5int_utf8_next); +} +extern "C" __attribute__((used)) void *p_krb5int_utf8_to_ucs4 = (void *) funA; +extern "C" void krb5int_utf8_to_ucs4() { + SYMBOL_HOOK( p_krb5int_utf8_to_ucs4); +} +extern "C" __attribute__((used)) void *p_krb5int_zap = (void *) funA; +extern "C" void krb5int_zap() { + SYMBOL_HOOK( p_krb5int_zap); +} +static void __attribute__ ((constructor (103))) hookInit() { +handle = dlopen("libkrb5support.so.0", RTLD_LAZY); +p_k5_base64_decode = dlsym(handle, "k5_base64_decode"); +p_k5_base64_encode = dlsym(handle, "k5_base64_encode"); +p_k5_bcmp = dlsym(handle, "k5_bcmp"); +p_k5_buf_add = dlsym(handle, "k5_buf_add"); +p_k5_buf_add_fmt = dlsym(handle, "k5_buf_add_fmt"); +p_k5_buf_add_len = dlsym(handle, "k5_buf_add_len"); +p_k5_buf_free = dlsym(handle, "k5_buf_free"); +p_k5_buf_get_space = dlsym(handle, "k5_buf_get_space"); +p_k5_buf_init_dynamic = dlsym(handle, "k5_buf_init_dynamic"); +p_k5_buf_init_fixed = dlsym(handle, "k5_buf_init_fixed"); +p_k5_buf_status = dlsym(handle, "k5_buf_status"); +p_k5_buf_truncate = dlsym(handle, "k5_buf_truncate"); +p_k5_clear_error = dlsym(handle, "k5_clear_error"); +p_k5_free_error = dlsym(handle, "k5_free_error"); +p_k5_get_error = dlsym(handle, "k5_get_error"); +p_k5_json_array_add = dlsym(handle, "k5_json_array_add"); +p_k5_json_array_create = dlsym(handle, "k5_json_array_create"); +p_k5_json_array_fmt = dlsym(handle, "k5_json_array_fmt"); +p_k5_json_array_get = dlsym(handle, "k5_json_array_get"); +p_k5_json_array_length = dlsym(handle, "k5_json_array_length"); +p_k5_json_array_set = dlsym(handle, "k5_json_array_set"); +p_k5_json_bool_create = dlsym(handle, "k5_json_bool_create"); +p_k5_json_bool_value = dlsym(handle, "k5_json_bool_value"); +p_k5_json_decode = dlsym(handle, "k5_json_decode"); +p_k5_json_encode = dlsym(handle, "k5_json_encode"); +p_k5_json_get_tid = dlsym(handle, "k5_json_get_tid"); +p_k5_json_null_create = dlsym(handle, "k5_json_null_create"); +p_k5_json_null_create_val = dlsym(handle, "k5_json_null_create_val"); +p_k5_json_number_create = dlsym(handle, "k5_json_number_create"); +p_k5_json_number_value = dlsym(handle, "k5_json_number_value"); +p_k5_json_object_count = dlsym(handle, "k5_json_object_count"); +p_k5_json_object_create = dlsym(handle, "k5_json_object_create"); +p_k5_json_object_get = dlsym(handle, "k5_json_object_get"); +p_k5_json_object_iterate = dlsym(handle, "k5_json_object_iterate"); +p_k5_json_object_set = dlsym(handle, "k5_json_object_set"); +p_k5_json_release = dlsym(handle, "k5_json_release"); +p_k5_json_retain = dlsym(handle, "k5_json_retain"); +p_k5_json_string_create = dlsym(handle, "k5_json_string_create"); +p_k5_json_string_create_base64 = dlsym(handle, "k5_json_string_create_base64"); +p_k5_json_string_create_len = dlsym(handle, "k5_json_string_create_len"); +p_k5_json_string_unbase64 = dlsym(handle, "k5_json_string_unbase64"); +p_k5_json_string_utf8 = dlsym(handle, "k5_json_string_utf8"); +p_k5_once = dlsym(handle, "k5_once"); +p_k5_os_mutex_destroy = dlsym(handle, "k5_os_mutex_destroy"); +p_k5_os_mutex_init = dlsym(handle, "k5_os_mutex_init"); +p_k5_os_mutex_lock = dlsym(handle, "k5_os_mutex_lock"); +p_k5_os_mutex_unlock = dlsym(handle, "k5_os_mutex_unlock"); +p_k5_path_isabs = dlsym(handle, "k5_path_isabs"); +p_k5_path_join = dlsym(handle, "k5_path_join"); +p_k5_path_split = dlsym(handle, "k5_path_split"); +p_k5_set_error = dlsym(handle, "k5_set_error"); +p_k5_set_error_info_callout_fn = dlsym(handle, "k5_set_error_info_callout_fn"); +p_k5_strerror_r = dlsym(handle, "k5_strerror_r"); +p_k5_utf16le_to_utf8 = dlsym(handle, "k5_utf16le_to_utf8"); +p_k5_utf8_to_utf16le = dlsym(handle, "k5_utf8_to_utf16le"); +p_k5_vset_error = dlsym(handle, "k5_vset_error"); +p_krb5int_close_plugin = dlsym(handle, "krb5int_close_plugin"); +p_krb5int_close_plugin_dirs = dlsym(handle, "krb5int_close_plugin_dirs"); +p_krb5int_free_plugin_dir_data = dlsym(handle, "krb5int_free_plugin_dir_data"); +p_krb5int_free_plugin_dir_func = dlsym(handle, "krb5int_free_plugin_dir_func"); +p_krb5int_freeaddrinfo = dlsym(handle, "krb5int_freeaddrinfo"); +p_krb5int_gai_strerror = dlsym(handle, "krb5int_gai_strerror"); +p_krb5int_get_plugin_data = dlsym(handle, "krb5int_get_plugin_data"); +p_krb5int_get_plugin_dir_data = dlsym(handle, "krb5int_get_plugin_dir_data"); +p_krb5int_get_plugin_dir_func = dlsym(handle, "krb5int_get_plugin_dir_func"); +p_krb5int_get_plugin_func = dlsym(handle, "krb5int_get_plugin_func"); +p_krb5int_getaddrinfo = dlsym(handle, "krb5int_getaddrinfo"); +p_krb5int_getnameinfo = dlsym(handle, "krb5int_getnameinfo"); +p_krb5int_getspecific = dlsym(handle, "krb5int_getspecific"); +p_krb5int_gmt_mktime = dlsym(handle, "krb5int_gmt_mktime"); +p_krb5int_key_delete = dlsym(handle, "krb5int_key_delete"); +p_krb5int_key_register = dlsym(handle, "krb5int_key_register"); +p_krb5int_mutex_alloc = dlsym(handle, "krb5int_mutex_alloc"); +p_krb5int_mutex_free = dlsym(handle, "krb5int_mutex_free"); +p_krb5int_mutex_lock = dlsym(handle, "krb5int_mutex_lock"); +p_krb5int_mutex_unlock = dlsym(handle, "krb5int_mutex_unlock"); +p_krb5int_open_plugin = dlsym(handle, "krb5int_open_plugin"); +p_krb5int_open_plugin_dirs = dlsym(handle, "krb5int_open_plugin_dirs"); +p_krb5int_pthread_loaded = dlsym(handle, "krb5int_pthread_loaded"); +p_krb5int_setspecific = dlsym(handle, "krb5int_setspecific"); +p_krb5int_strlcat = dlsym(handle, "krb5int_strlcat"); +p_krb5int_strlcpy = dlsym(handle, "krb5int_strlcpy"); +p_krb5int_ucs4_to_utf8 = dlsym(handle, "krb5int_ucs4_to_utf8"); +p_krb5int_utf8_next = dlsym(handle, "krb5int_utf8_next"); +p_krb5int_utf8_to_ucs4 = dlsym(handle, "krb5int_utf8_to_ucs4"); +p_krb5int_zap = dlsym(handle, "krb5int_zap"); + +} \ No newline at end of file diff --git a/linuxTest/exampleAttack/symbolHook.cpp b/linuxTest/exampleAttack/symbolHook.cpp new file mode 100644 index 0000000..1777d54 --- /dev/null +++ b/linuxTest/exampleAttack/symbolHook.cpp @@ -0,0 +1,23 @@ + +#include +#include +#include + +#include "symbolhook.h" + +void *handle; + +void funA() { + printf("ERROR, THIS SHOULD NEVER APPEAR"); +} + +extern "C" __attribute__((used)) void *p = (void *) funA; + +extern "C" void _Unwind_Resume() { + SYMBOL_HOOK(p); +} + +static void __attribute__ ((constructor (103))) hookInit() { + handle = dlopen("libgcc_s.so.1", RTLD_LAZY); + p = dlsym(handle, "_Unwind_Resume"); +} \ No newline at end of file diff --git a/linuxTest/exampleAttack/symbolhook.h b/linuxTest/exampleAttack/symbolhook.h new file mode 100644 index 0000000..f341da3 --- /dev/null +++ b/linuxTest/exampleAttack/symbolhook.h @@ -0,0 +1,10 @@ +#pragma once + +#define STRINGIZE2(s) #s +#define STRINGIZE(s) STRINGIZE2(s) + +#ifdef __x86_64__ +#define SYMBOL_HOOK(a) asm __volatile__ ("pop %%rbp \njmp *%0 \npush %%rbp\n" : : "m" (a)) +#else +#error "UNSUPPORTED ARCHITECTURE" +#endif \ No newline at end of file diff --git a/linuxTest/main.cpp b/linuxTest/main.cpp new file mode 100644 index 0000000..dc847a4 --- /dev/null +++ b/linuxTest/main.cpp @@ -0,0 +1,68 @@ +// +// Created by Sascha Roth on 03.11.19. +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*extern "C" void _Unwind_Resume(){ + +}*/ +void logCallback(const std::string &logtext) { + std::cout << logtext << std::endl; +} + +void printHelp() { + std::cout << "ChickenHook - StaticInjector" << std::endl << "Usage:" << std::endl << std::endl + << " ./staticInjector [binaryToInjectInto] [dependency to replace] [path to dependency to generate the stubs]" + << std::endl << std::endl << "ex.:" << std::endl + << " ./staticInjector victimTest libgcc_s.so.1 /lib/x86_64-linux-gnu/libgcc_s.so.1" + << std::endl + << "Read more at: https://github.com/ChickenHook/StaticInjector" << std::endl; +} + +bool exist(const char *name) { + struct stat buffer; + return (stat(name, &buffer) == 0); +} + +int main(int argc, char *argv[]) { + // ./linuxTest victimTest libgcc_s.so.1 /lib/x86_64-linux-gnu/libgcc_s.so.1 + if (argc < 4) { + printHelp(); + return 1; + }// TODO add nice user interface here + + if (!exist(argv[1])) { + std::cout << "given target file <%s> does not exist" << argv[1] << std::endl; + printHelp(); + return 1; + } + + if (!exist(argv[3])) { + std::cout << "given target file <%s> does not exist" << argv[1] << std::endl; + printHelp(); + return 2; + } + std::cout << "Trying to parse file <" << argv[1] << ">" << std::endl; + ChickenHook::BinaryEditor binaryEditor; + binaryEditor.setLoggingCallback(logCallback); + auto binary = binaryEditor.open(argv[1]); + binary->replaceDependency(argv[2]); + auto dependency = binaryEditor.open(argv[3]); + if (dependency != nullptr) { + dependency->generateSymbolHooks(argv[2], (std::string(argv[2]) + ".cpp").c_str()); + } + + //binary->addLibraryDependency(argv[2]); + + return 0; +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..3451971 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +include ':androidTest' +rootProject.name='StaticInjector' diff --git a/src/BinaryEditor.cpp b/src/BinaryEditor.cpp new file mode 100644 index 0000000..6c6b3c9 --- /dev/null +++ b/src/BinaryEditor.cpp @@ -0,0 +1,25 @@ +// +// Created by Sascha Roth on 03.11.19. +// + +#include +#include "chickenHook/staticInjector/BinaryEditor.h" + +namespace ChickenHook { + std::unique_ptr BinaryEditor::open(const std::string &path) { + auto header = IBinary::parseHeader(path); + if (!(*header).open()) { + log("BinaryEditor [-] open [-] could not open file <%s>", path.c_str()); + return nullptr; + } + return header; + } + + bool BinaryEditor::close() { + return false; + } + + void BinaryEditor::setLoggingCallback(void (*logCallback)(const std::string &)) { + setLogFunction(logCallback); + } +} \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..13f8125 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,38 @@ + +cmake_minimum_required(VERSION 3.4.1) + +# Creates and names a library, sets it as either STATIC +# or SHARED, and provides the relative paths to its source _original_code. +# You can define multiple libraries, and CMake builds them for you. +# Gradle automatically packages shared libraries with your APK. + +add_library( # Sets the name of the library. + ${PROJECT_NAME} + + # Sets the library as a shared library. + STATIC + + # Provides a relative path to your source file(s). + BinaryEditor.cpp + platforms/IBinary.cpp + platforms/linux/Elf.cpp + platforms/darwin/Macho.cpp + tools/HexDump.cpp + tools/LoggingCallback.cpp + generators/SymbolHookGenerator.cpp + platforms/linux/parser/Elf64Parser.cpp + platforms/linux/parser/Elf32Parser.cpp + platforms/linux/parser/IElfParser.cpp) + +target_include_directories(${PROJECT_NAME} INTERFACE + $ + $ # /include/mylib + ) + +target_include_directories(${PROJECT_NAME} PUBLIC + include/ + ./ + ) + +set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14) +set_property(TARGET ${PROJECT_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/src/generators/SymbolHookGenerator.cpp b/src/generators/SymbolHookGenerator.cpp new file mode 100644 index 0000000..d1d6aee --- /dev/null +++ b/src/generators/SymbolHookGenerator.cpp @@ -0,0 +1,105 @@ +// +// Created by Sascha Roth on 10.11.19. +// + +#include "SymbolHookGenerator.h" + +#include "tools/LoggingCallback.h" + + + +namespace ChickenHook { + +// some code snippets to inject + + constexpr const char *cppProlog("#include \n" + "#include \n" + "#include \n" + "\n" + "#include \"symbolhook.h\"\n" + "\n" + "static void *handle;\n" + "\n" + "static void funA() {\n" + " printf(\"!WARNING!, SYMBOL HOOK CALLED BEFORE RELOCATION INSTALLED\\n\");\n" + "}"); + + constexpr const char *symbolAddrPart1( + "extern \"C\" __attribute__((used)) void *");// place after this string the symbol variable name + constexpr const char *symbolAddrPart2(" = (void *) funA;"); + + constexpr const char *symbolPart1("extern \"C\" void "); // place symbol name here + constexpr const char *symbolPart2("() {\n" + " SYMBOL_HOOK( "); // place symbol variable here + constexpr const char *symbolPart3(");\n" + "}"); + + constexpr const char *dlopenPart1( + "static void __attribute__ ((constructor (103))) hookInit() {\n"); + constexpr const char *dlopenPart2("handle = dlopen(\""); // add library name here + constexpr const char *dlopenPart3("\", RTLD_LAZY);\n"); // add dlsym after this line + constexpr const char *dlopenPart4("\n" + "}"); + + constexpr const char *dlsymPart1( + " = dlsym(handle, \""); // symbol variable before this string, add symbol after this string + constexpr const char *dlsymPart2("\");\n"); + + + SymbolHookGenerator::SymbolHookGenerator() : _os() { + + } + + bool SymbolHookGenerator::open(const std::string &file) { + _os.open(file); + return _os.good(); + } + + void SymbolHookGenerator::addSymbol(const std::string &symbol) { + /*for (auto _symbol : _symbols) { // check if symbol is already added + if (_symbol.compare(symbol) == 0) { + log("addSymbol [-] symbol <%s> already added, skipping..."); + return; + } + }*/ + _symbols.insert(symbol); + + } + + void SymbolHookGenerator::apply() { + if (_os.good()) { + // prolog + _os << cppProlog << std::endl; + // vars and symbols + for (auto symbol : _symbols) { + _os << symbolAddrPart1 << "p_" << symbol << symbolAddrPart2 << std::endl; + _os << symbolPart1 << symbol << symbolPart2 << "p_" << symbol << symbolPart3 + << std::endl; + } + + // constructor + + _os << dlopenPart1 << dlopenPart2 << _library_name << dlopenPart3; + for (auto symbol : _symbols) { + _os << "p_" << symbol << dlsymPart1 << symbol << dlsymPart2; + } + _os << dlopenPart4; + } + } + + void SymbolHookGenerator::close() { + apply(); + if (_os.good()) { + _os.close(); + } + } + + void SymbolHookGenerator::addString(const std::string &content) { + _os << content; + } + + void SymbolHookGenerator::addDlOpen(const std::string &library) { + _library_name = library; + } + +} \ No newline at end of file diff --git a/src/generators/SymbolHookGenerator.h b/src/generators/SymbolHookGenerator.h new file mode 100644 index 0000000..fef0258 --- /dev/null +++ b/src/generators/SymbolHookGenerator.h @@ -0,0 +1,38 @@ +// +// Created by Sascha Roth on 10.11.19. +// + + +#pragma once + +#include +#include +#include +#include +#include + +namespace ChickenHook { + + class SymbolHookGenerator { + public: + SymbolHookGenerator(); + + bool open(const std::string &file); + + void addDlOpen(const std::string &library); + + void addSymbol(const std::string &symbol); + + void close(); + + private: + std::ofstream _os; + std::set _symbols; + std::string _library_name; + + void addString(const std::string &file); + + + void apply(); + }; +} \ No newline at end of file diff --git a/src/include/chickenHook/staticInjector/BinaryEditor.h b/src/include/chickenHook/staticInjector/BinaryEditor.h new file mode 100644 index 0000000..1bea4bf --- /dev/null +++ b/src/include/chickenHook/staticInjector/BinaryEditor.h @@ -0,0 +1,36 @@ +// +// Created by Sascha Roth on 03.11.19. +// + +#pragma once + +#include "IBinary.h" +#include +#include + +namespace ChickenHook { + + class BinaryEditor { + public: + /** + * + * @param path to binary or shared library + * @return + */ + static std::unique_ptr open(const std::string &path); + + /** + * Close file + * @return + */ + bool close(); + + /** + * + * @param path to static library + * @return + */ + void setLoggingCallback(void (*logCallback)(const std::string &)); + }; + +} \ No newline at end of file diff --git a/src/include/chickenHook/staticInjector/IBinary.h b/src/include/chickenHook/staticInjector/IBinary.h new file mode 100644 index 0000000..1adf849 --- /dev/null +++ b/src/include/chickenHook/staticInjector/IBinary.h @@ -0,0 +1,76 @@ +// +// Created by Sascha Roth on 03.11.19. +// + +#pragma once + + +#include +#include + + +namespace ChickenHook { + + class IBinary { + public: + + /** + * Parses the first few of the given binary and instantiates a object representation + * + * We have to check if the given file is a elf file or a macho file... + * + * @param path the path to the binary + * @return the object representation + */ + static std::unique_ptr parseHeader(const std::string &path); + + /** + * Open the elf file + * @return true on success + */ + virtual bool open() = 0; + + /** + * close the elf file + * @return true on success + */ + virtual bool close() = 0; + + /** + * Replace the given dependency name with a random generated name + * @param libraryToReplace the library to be replaced + * @return the new dependency's libname + */ + virtual const std::string replaceDependency(const std::string &) = 0; + + /** + * Generates a cpp file that contains implementations of all exported symbols of the given library. + * + * This cpp file automatically loads the correct library at runtime and calls the corresponding symbol + * + * @param libraryName the name of the library to generate the implementations for + * @param outputFileName the output filename of the headers + */ + virtual void + generateSymbolHooks(const std::string &libraryName, const std::string &outputFileName) = 0; + + /** + * Print some information about the binary + */ + virtual void printInfo() = 0; + + virtual void addLibraryDependency(const std::string &library) = 0; + + + protected: + IBinary(const std::string &); + + /** + * Returns the architecture. + */ + virtual uint32_t getArchitecture() = 0; + + private: + }; + +} \ No newline at end of file diff --git a/src/platforms/IBinary.cpp b/src/platforms/IBinary.cpp new file mode 100644 index 0000000..f429864 --- /dev/null +++ b/src/platforms/IBinary.cpp @@ -0,0 +1,39 @@ +// +// Created by Sascha Roth on 03.11.19. +// + +#include "chickenHook/staticInjector/IBinary.h" +#include +#include +#include + +constexpr int MAGIC_BUFF_SIZE(64); +namespace ChickenHook { + + /** + * Parses the first few of the given binary and instantiates a object representation + * + * We have to check if the given file is a elf file or a macho file... + * + * @param path the path to the binary + * @return the object representation + */ + std::unique_ptr IBinary::parseHeader(const std::string &path) { + std::ifstream fis(path); + std::vector magic_buffer; + magic_buffer.resize(MAGIC_BUFF_SIZE); + + fis.read(reinterpret_cast(&magic_buffer[0]), magic_buffer.size()); + if (fis) { + // test elf and macho + if (Elf::isElf(magic_buffer)) { + return std::unique_ptr(new Elf(path)); + } // add macho here! + } + + return std::unique_ptr(); // throw exception!? + } + + IBinary::IBinary(const std::string &) { + } +} diff --git a/src/platforms/darwin/Macho.cpp b/src/platforms/darwin/Macho.cpp new file mode 100644 index 0000000..5ca13a3 --- /dev/null +++ b/src/platforms/darwin/Macho.cpp @@ -0,0 +1,5 @@ +// +// Created by sascharoth on 03.11.19. +// + +#include "Macho.h" diff --git a/src/platforms/darwin/Macho.h b/src/platforms/darwin/Macho.h new file mode 100644 index 0000000..b0c0f30 --- /dev/null +++ b/src/platforms/darwin/Macho.h @@ -0,0 +1,18 @@ +// +// Created by Sascha Roth on 03.11.19. +// + +#pragma once + + +#include + +namespace ChickenHook { + + + class Macho : public IBinary { + + }; + + +} \ No newline at end of file diff --git a/src/platforms/linux/Elf.cpp b/src/platforms/linux/Elf.cpp new file mode 100644 index 0000000..2984592 --- /dev/null +++ b/src/platforms/linux/Elf.cpp @@ -0,0 +1,324 @@ +// +// Created by Sascha Roth on 03.11.19. +// + +#include "Elf.h" +#include "tools/HexDump.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "generators/SymbolHookGenerator.h" +#include "platforms/linux/parser/Elf64Parser.h" + +constexpr uint8_t ELF_MAGIC[]{ + 0x7f, + 0x45, + 0x4c, + 0x46 +}; + +namespace ChickenHook { + + /** + * Determine if the given magic equals elf magic + * @param magic the magic bytes + * @return true if magic indicates an elf file + */ + bool Elf::isElf(std::vector &magic) { + if (magic.empty()) { + log("Magic array empty"); + return false; + } + if (magic.size() < sizeof(ELF_MAGIC)) { + log("Magic array size to small"); + return false; + } + HexDump::hex_dump(&magic[0], magic.size(), std::cout); + + int i = 0; + for (auto b:ELF_MAGIC) { + if (b != magic[i]) { + log("Magic doesn't match elf (%d) <%x> : <%x>", i, b, magic[i]); + return false; + } + i++; + } + log("Found elf file"); + return true; + } + + /** + * Open the elf file + * @return true on success + */ + bool Elf::open() { + _is.open(_path, std::ifstream::in | std::ifstream::binary | std::ifstream::ate); + if (_is.good()) { + std::ifstream::pos_type pos = _is.tellg(); + auto length = static_cast(pos); + _data.resize(length); + _is.seekg(0, std::ios::beg); + _is.read(reinterpret_cast(&_data[0]), length); + printInfo(); + if (is64()) { + _elf_parser = std::make_unique(_data); + } else { + + } + return true; + } + return false; + } + + /** + * close the elf file + * @return true on success + */ + bool Elf::close() { + if (_is.good()) + _is.close(); + return true; + } + + Elf::Elf(std::string path) : IBinary(path), _is(), _path(std::move(path)) { + } + + /** + * @return true if 64 bit + */ + bool Elf::is64() { + bool is64 = false; + switch (_data[EI_CLASS]) { + case ELFCLASS64: + is64 = true; + break; + case ELFCLASS32: + break; + default: + log("UNKNOWN ARCHITECTURE"); + break; // TODO throw exception! + } + return is64; + } + + /** + * Tells us the endian format + * @return true if endian format is little endian + */ + bool Elf::isLittleEndian() { + switch (_data[EI_DATA]) { + case ELFDATA2LSB: + return true; + case ELFDATA2MSB: + return false; + default: + log("INVALID endian format"); // TODO exception + break; + } + return false; + } + + /** + * + * Returns the architecture. + * + * You can use the following switch case to determine the architecture + * switch (header->e_machine) { + * case EM_NONE: + * log("None (0x0)"); + * break; + * + * case EM_386: + * log("INTEL x86 (0x%x)", EM_386); + * break; + * + * case EM_X86_64: + * log("AMD x86_64 (0x%x)", EM_X86_64); + * break; + * + * case EM_AARCH64: + * log("AARCH64 (0x%x)", EM_AARCH64); + * break; + * + * case EM_ARM: + * log("ARM (0x%x)", EM_ARM); + * break; + * default: + * log(" 0x%x", header->e_machine); + * break; + }*/ + uint32_t Elf::getArchitecture() { + if (is64()) { + auto *header = (Elf64_Ehdr *) &_data[0]; + return header->e_machine; + } else { + auto *header = (Elf32_Ehdr *) &_data[0]; + return header->e_machine; + } + } + + + + + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////// REPLACE DEPENDENCY ////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + /** + * Generates a cpp file that contains implementations of all exported symbols of the given library. + * + * This cpp file automatically loads the correct library at runtime and calls the corresponding symbol + * + * @param libraryName the name of the library to generate the implementations for + * @param outputFileName the output filename of the headers + */ + void + Elf::generateSymbolHooks(const std::string &libraryName, const std::string &outputFileName) { + SymbolHookGenerator symbolHookGenerator; + if (!symbolHookGenerator.open(outputFileName)) { + log("generateSymbolHooks [-] could not open <%s>", outputFileName); + return; + } + + std::vector types; + types.push_back(SHT_SYMTAB); + types.push_back(SHT_DYNSYM); + + if (!_elf_parser->iterateSymbolTable(types, + [this, &symbolHookGenerator](int type, + char *symbolName, + uint64_t st_value, + uint8_t st_info) { + + log("Adding: <%s> type<%lx> st_value<%lx> st_info<%lx> st_other<%lx>", + symbolName, type, st_value, st_info); + symbolHookGenerator.addSymbol(symbolName); + return true; + })) { + log("Error while iterate symbols, abort..."); + return; + } + symbolHookGenerator.addDlOpen(libraryName); + log("Symbol hooks generation finished"); + symbolHookGenerator.close(); + } + + /** + * Replace the given dependency name with a random generated name + * @param libraryToReplace the library to be replaced + * @return the new dependency's libname + */ + const std::string Elf::replaceDependency(const std::string &libraryToReplace) { + std::string newLibName("lib"); + + if (!_elf_parser->iterateNeeded([this, &libraryToReplace, &newLibName](char *needed) { + + std::string lib(needed); + if (lib == libraryToReplace) { + int chars = strlen(needed) - 6;// reduce by .so and lib + if (chars <= 0) { + log("Invalid library name length, skip"); + return true; // can happen + } + for (int k = 0; k < chars; k++) { + newLibName += "a"; + } + newLibName += ".so"; + log("Replace <%s> with <%s>", needed, newLibName.c_str()); + strcpy(needed, newLibName.c_str()); + } + return true; + })) { + log("Error while iterate needed, abort..."); + return ""; + } + + // write changes + _is.close(); + //_is.open(_path, std::ifstream::in | std::ifstream::binary | std::ifstream::ate); + std::ofstream _os(_path); + _os.write(reinterpret_cast(&_data[0]), _data.size()); + _os.close(); + open(); + return newLibName; + } + + /** + * Print some information about the binary + */ + void Elf::printInfo() { + log("Library info:"); + log(" Name: <%s>", _path.c_str()); + switch (getArchitecture()) { + case EM_NONE: + log(" Arch: None (0x0)"); + break; + + case EM_386: + log(" Arch: INTEL x86 (0x%x)", EM_386); + break; + + case EM_X86_64: + log(" Arch: AMD x86_64 (0x%x)", EM_X86_64); + break; + + case EM_AARCH64: + log(" Arch: AARCH64 (0x%x)", EM_AARCH64); + break; + + case EM_ARM: + log(" Arch: ARM (0x%x)", EM_ARM); + break; + default: + log(" Arch: 0x%x", getArchitecture()); + break; + + } + if (isLittleEndian()) { + log(" Endian format: LSB"); + } else if (isLittleEndian()) { + log(" Endian format: MSB"); + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////// INJECT DEPENDENCY *** EXPERIMENTAL *** ** WIP ** //////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void Elf::addLibraryDependency(const std::string &library) { + log("NOT IMPLEMENTED"); + } +} \ No newline at end of file diff --git a/src/platforms/linux/Elf.h b/src/platforms/linux/Elf.h new file mode 100644 index 0000000..3965f71 --- /dev/null +++ b/src/platforms/linux/Elf.h @@ -0,0 +1,98 @@ +// +// Created by Sascha Roth on 03.11.19. +// + +#pragma once + + +#include +#include +#include +#include + +namespace ChickenHook { + + + class Elf : public IBinary { + public: + public: + Elf(std::string string); + + public: + + /** + * Determine if the given magic equals elf magic + * @param magic the magic bytes + * @return true if magic indicates an elf file + */ + static bool isElf(std::vector &); + + /** + * Open the elf file + * @return true on success + */ + bool open() override; + + /** + * close the elf file + * @return true on success + */ + bool close() override; + + /** + * Replace the given dependency name with a random generated name + * @param libraryToReplace the library to be replaced + * @return the new dependency's libname + */ + virtual const std::string replaceDependency(const std::string &libraryToReplace); + + /** + * Print some information about the binary + */ + virtual void printInfo(); + + /** + * NOT IMPLEMENTED YET + * @param library + */ + virtual void addLibraryDependency(const std::string &library); + + /** + * Generates a cpp file that contains implementations of all exported symbols of the given library. + * + * This cpp file automatically loads the correct library at runtime and calls the corresponding symbol + * + * @param libraryName the name of the library to generate the implementations for + * @param outputFileName the output filename of the headers + */ + void generateSymbolHooks(const std::string &libraryName, const std::string &outputFileName); + + + protected: + /** + * Returns the architecture. + */ + uint32_t getArchitecture() override; + +private: + std::string _path; + std::ifstream _is; + std::vector _data; + std::unique_ptr _elf_parser; + + + /** + * @return true if 64 bit + */ + bool is64(); + + + /** + * Tells us the endian format + * @return true if endian format is little endian + */ + bool isLittleEndian(); + + }; + +} \ No newline at end of file diff --git a/src/platforms/linux/backupSymbolAdder.txt b/src/platforms/linux/backupSymbolAdder.txt new file mode 100644 index 0000000..1802b6f --- /dev/null +++ b/src/platforms/linux/backupSymbolAdder.txt @@ -0,0 +1,426 @@ +// +// template +// std::string Elf::getSectionName(K *Tsection) { +// if (is64()) { +// Elf64_Shdr *section = (Elf64_Shdr *) Tsection; +// auto *header = (Elf64_Ehdr *) &_data[0]; +// uint64_t off = (((Elf64_Shdr *) &_data[header->e_shoff]))[header->e_shstrndx].sh_offset; +// char *data = reinterpret_cast(&_data[off]); +// std::string sectionName(data + section->sh_name); +// return sectionName; +// } +// return ""; +// } +// +// /** +// * Returns the corresponding section by the given name +// * @tparam K the type of the section (Elf64_Ehdr, or Elf32_Ehdr) +// * @param name The name of the section +// * @return null on failure +// * the section on success +// */ +// template +// K *Elf::getSectionByName(const std::string &name) { +// if (is64()) { +// auto *header = (Elf64_Ehdr *) &_data[0]; +// //shdrs[shstrtabIndex].sh_offset +// for (int k = 0; k < header->e_shnum; k++) { +// auto shdr = &((Elf64_Shdr *) &_data[header->e_shoff])[k]; +// uint64_t off = (((Elf64_Shdr *) &_data[header->e_shoff]))[header->e_shstrndx].sh_offset; +// char *data = reinterpret_cast(&_data[off]); +// std::string sectionName(data + shdr->sh_name); +// //log("Found section <%s> off:<%lx> info<%lx> addr<%lx>", sectionName.c_str(), +// // shdr->sh_offset, shdr->sh_info, shdr->sh_addr); +// //log("shdr %d %p %d %s", off, data, shdr->sh_name, sectionName.c_str()); +// if (sectionName == name) { +// //Elf64_Dyn *dynamic = reinterpret_cast(&_data[shdr.sh_offset]); +// +// return (K *) shdr; +// } +// } +// } else { +// auto *header = (Elf32_Ehdr *) &_data[0]; +// //shdrs[shstrtabIndex].sh_offset +// for (int k = 0; k < header->e_shnum; k++) { +// auto shdr = &((Elf32_Shdr *) &_data[header->e_shoff])[k]; +// int off = (((Elf32_Shdr *) &_data[header->e_shoff]))[header->e_shstrndx].sh_offset; +// char *data = reinterpret_cast(&_data[off]); +// std::string sectionName(data + shdr->sh_name); +// +// //log("Found section <%s> off:<%lx> info<%lx> addr<%lx>", sectionName.c_str(), +// // shdr->sh_offset, shdr->sh_info, shdr->sh_addr); +// //log("shdr %d %p %d %s", off, data, shdr->sh_name, sectionName.c_str()); +// if (sectionName == name) { +// //Elf64_Dyn *dynamic = reinterpret_cast(&_data[shdr.sh_offset]); +// +// return (K *) shdr; +// } +// } +// } +// +// return nullptr; +// } +// +// /** +// * Returns the corresponding section by the given name +// * @tparam K the type of the section (Elf64_Ehdr, or Elf32_Ehdr) +// * @param name The name of the section +// * @return null on failure +// * the section on success +// */ +// template +// K *Elf::getSectionById(const int id) { +// if (is64()) { +// auto *header = (Elf64_Ehdr *) &_data[0]; +// +// if (id > header->e_shnum) { +// log("Error while retrieve section by id, invalid id"); +// return nullptr; +// } +// return &((K *) &_data[header->e_shoff])[id]; +// +// } else { +// auto *header = (Elf32_Ehdr *) &_data[0]; +// +// if (id > header->e_shnum) { +// log("Error while retrieve section by id, invalid id"); +// return nullptr; +// } +// return &((K *) &_data[header->e_shoff])[id]; +// } +// +// return nullptr; +// } + + + + + + + + + +/// down + + + +// +// void Elf::patchVerneed(int additionalEntriesCount, int newOffset, int newVerSymOffset) { +// if (is64()) { +// auto *dynamic = getSectionByName(std::string(".dynamic")); +// if (dynamic == nullptr) { +// log("Could not find dynamic section!"); +// return; +// } +// auto *dynstr = getSectionByName(".dynstr"); +// if (dynstr == nullptr) { +// log("Could not find dynstr section!"); +// return; +// } +// char *strTab = reinterpret_cast(&_data[dynstr->sh_offset]); +// +// /// strtab2 +// char *rpath = nullptr; +// log("Searching for libraries in dynamic section"); +// +// auto *dyn = (Elf64_Dyn *) (&_data[(dynamic->sh_offset)]); +// for (; dyn->d_tag != DT_NULL; dyn++) { +// if (dyn->d_tag == DT_VERNEEDNUM) { +// if (dyn->d_un.d_val != 0) { +// log("Found VERNEEDNUM <%lx> <%p>", dyn->d_un.d_val, dyn->d_un.d_ptr); +// dyn->d_un.d_val = dyn->d_un.d_val + additionalEntriesCount; +// dyn->d_un.d_ptr = dyn->d_un.d_ptr + additionalEntriesCount; +// } +// } else if (dyn->d_tag == DT_VERNEED) { +// if (dyn->d_un.d_val != 0) { +// log("Found VERNEED <%lx> <%p>", dyn->d_un.d_val, dyn->d_un.d_ptr); +// dyn->d_un.d_val = newOffset; +// dyn->d_un.d_ptr = newOffset; +// } +// } else if (dyn->d_tag == DT_VERSYM) { +// log("Found DT_VERSYM <%lx> <%p>", dyn->d_un.d_val, dyn->d_un.d_ptr); +// //dyn->d_un.d_val = newVerSymOffset; +// //dyn->d_un.d_ptr = newVerSymOffset; +// +// } else if (dyn->d_tag == DT_VERDEF) { +// log("Found DT_VERDEF <%lx> <%p>", dyn->d_un.d_val, dyn->d_un.d_ptr); +// //dyn->d_un.d_val = newVerSymOffset; +// //dyn->d_un.d_ptr = newVerSymOffset; +// +// } /*else if(dyn->d_tag == DT_NEEDED) { +// log("Found DT_NEEDED <%lx> <%p>", dyn->d_un.d_val, dyn->d_un.d_ptr); +// }*/ +// } +// } +// } +// +// void +// Elf::addVersionDependency(const std::string &name, const int strId, const int newDystrOffset) { +// if (is64()) { +// Elf64_Shdr *gnuVersionSection = getSectionByName(".gnu.version_r"); //_r +// +// Elf64_Shdr *gnuVersionStringsSection = getSectionById( +// gnuVersionSection->sh_link); +// +// +// char *strTab = reinterpret_cast(&_data[gnuVersionStringsSection->sh_offset]); +// +// std::string versionStringsSectionName = getSectionName( +// gnuVersionStringsSection); +// log("versionStringsSectionName: <%s>", versionStringsSectionName.c_str()); +// if (versionStringsSectionName.compare(".dynstr") != 0) { +// log("version dependency strings not in .dynstr... not supported yet"); +// return; // TODO crash? +// } +// //gnuVersionSection->sh_link = newDystrOffset; +// +// char *rpath = nullptr; +// int rel_offset = 0; +// Elf64_Verneed *verneed = (Elf64_Verneed *) &_data[gnuVersionSection->sh_offset]; +// while (verneed != nullptr) { +// rpath = strTab + verneed->vn_file; +// log("Found verneed vn_file<%lx> vn_version<%lx> vn_next<%lx> vn_file<%lx> name<%s> vn_aux<%lx> rel_offset<%lx>", +// verneed->vn_file, verneed->vn_version, verneed->vn_next, verneed->vn_file, +// rpath, verneed->vn_aux, +// rel_offset); +// if (verneed->vn_next == 0) { +// log("No more verneeds found"); +// break; +// } +// rel_offset += verneed->vn_next; +// verneed = reinterpret_cast((char *) verneed + verneed->vn_next); +// } +// +// // modify +// Elf64_Verneed newVerneed; +// newVerneed.vn_file = strId; +// newVerneed.vn_next = 0; +// newVerneed.vn_cnt = 1; +// newVerneed.vn_aux = 0x10; +// newVerneed.vn_version = 1; +// +// int oldVersionSectionSize = gnuVersionSection->sh_size; +// +// +// int oldSize = gnuVersionSection->sh_size; +// int oldOff = gnuVersionSection->sh_offset; +// int newSize = sizeof(Elf64_Verneed) + sizeof(Elf64_Vernaux); +// int newOffset = moveSectionToEndAndResize(".gnu.version_r", +// newSize, false, false); +// +// Elf64_Verneed *testVerneed = reinterpret_cast(&_data[newOffset]); +// +// log("new verneed address <%p> ", testVerneed); +// log("Add new verneed <%p> vn_file<%lx> vn_version<%lx> vn_next<%lx> name<%s> vn_aux<%lx>", +// ((char *) testVerneed) + oldVersionSectionSize, +// newVerneed.vn_file, newVerneed.vn_version, newVerneed.vn_next, name.c_str(), +// newVerneed.vn_aux); +// +// memcpy(((char *) testVerneed) + oldVersionSectionSize, &newVerneed, +// sizeof(Elf64_Verneed)); +// //gnuVersionSection->sh_size = gnuVersionSection->sh_size + sizeof(Elf64_Verneed); // update sh size +// Elf64_Vernaux newVernaux; +// newVernaux.vna_name = strId; +// newVernaux.vna_flags = 0; +// newVernaux.vna_hash = 0; +// newVernaux.vna_other = 2; +// newVernaux.vna_next = 0; +// memcpy(((char *) testVerneed) + oldVersionSectionSize + sizeof(Elf64_Verneed), +// &newVernaux, +// sizeof(Elf64_Vernaux)); +// +// // test +// Elf64_Shdr *newGnuVersionSection = getSectionByName(".gnu.version_r"); //_r +// newGnuVersionSection->sh_info = newGnuVersionSection->sh_info + 1; +// verneed = (Elf64_Verneed *) &_data[newGnuVersionSection->sh_offset]; +// log("new verneed address <%p> ", verneed); +// rel_offset = 0; +// while (verneed != nullptr) { +// rpath = strTab + verneed->vn_file; +// log("AFTER MODIFY: Found verneed <%p> vn_file<%lx> vn_version<%lx> vn_next<%lx> vn_file<%lx> name<%s> vn_aux<%lx> rel_offset<%lx>", +// verneed, +// verneed->vn_file, verneed->vn_version, verneed->vn_next, verneed->vn_file, +// rpath, verneed->vn_aux, +// rel_offset); +// Elf64_Vernaux *vernaux = (Elf64_Vernaux *) (((char *) verneed + verneed->vn_aux)); +// while (vernaux != nullptr) { +// log("AFTER MODIFY: Found vernaux <%p> vna_hash<%lx> vna_flags<%lx> vna_other<%lx> vna_name<%lx>", +// vernaux, +// vernaux->vna_hash, vernaux->vna_flags, vernaux->vna_other, +// vernaux->vna_name); +// if (vernaux->vna_next == 0) { +// break; +// } +// vernaux = reinterpret_cast(((char *) vernaux + +// vernaux->vna_next)); +// } +// +// if (verneed->vn_next == 0) { +// log("No more verneeds found"); +// break; +// } +// rel_offset += verneed->vn_next; +// verneed = reinterpret_cast((char *) verneed + verneed->vn_next); +// } +// verneed->vn_next = +// (oldSize - rel_offset); // calculate offset to our new verneed +// patchVerneed(1, newOffset, newDystrOffset); +// +// } +// +// +// } + + + + + + + + + + + + + + +// void Elf::addLibraryDependency(const std::string &library) { +// log("add library dependency <%s>", library.c_str()); +// if (is64()) { +// // retrieve dynamic and dynstr sections +// Elf64_Shdr *dynstrSectionAddr = getSectionByName(".dynstr"); +// +// // calculate size of bytes to inject +// int additionalDynamicLen = sizeof(Elf64_Dyn); +// int additionalDynstrLen = library.size() + 1;// string size + \0 +// +// +// int off = moveSectionToEndAndResize(".dynamic", +// additionalDynamicLen, true, false); +// off = moveSectionToEndAndResize(".dynamic", +// additionalDynamicLen, true, true); +// // edit dynamic +// +// Elf64_Dyn *testDyn = reinterpret_cast(&_data[off]); +// memcpy(testDyn, dynstrSectionAddr, sizeof(Elf64_Dyn)); +// testDyn->d_un.d_ptr = dynstrSectionAddr->sh_size;//dynstrSectionAddr->sh_size +// testDyn->d_un.d_val = dynstrSectionAddr->sh_size;//dynstrSectionAddr->sh_size +// testDyn->d_tag = DT_NEEDED; +// +// +//// wri(newDyn.d_un.d_val, j); +// +// +// int newOffset = moveSectionToEndAndResize(".dynstr", +// additionalDynstrLen, false, false); +// const char *newLibName = library.c_str(); +// memcpy(&_data[newOffset + dynstrSectionAddr->sh_size], newLibName, +// strlen(newLibName) + 1); +// +// addVersionDependency(library, testDyn->d_un.d_val, newOffset); +// +// // write changes +// _is.close(); // TODO put into function +// //_is.open(_path, std::ifstream::in | std::ifstream::binary | std::ifstream::ate); +// std::ofstream _os(_path); +// _os.write(reinterpret_cast(&_data[0]), _data.size()); +// _os.close(); +// open(); +// +// } else { +// +// } +// } + + + +// void Elf::resize(uint32_t newLen) { +// this->_data.resize(newLen); +// } +// +// int +// Elf::moveSectionToEndAndResize(const std::string §ion, uint32_t newAdditionalSectionLen, +// bool end, bool searchPhdr) { +// log("moveSectionToEndAndResize [-] move section <%s>", section.c_str()); +// if (is64()) { +// Elf64_Shdr *sectionHeader = getSectionByName(section); +// +// Elf64_Off oldOffset = sectionHeader->sh_offset; +// Elf64_Xword oldSize = sectionHeader->sh_size; +// uint32_t newLen = oldSize + newAdditionalSectionLen; +// Elf64_Off newOffset = _data.size(); +// +// log("moveSectionToEndAndResize [-] lib addr <%p>", &_data[0]); +// log("moveSectionToEndAndResize [-] section addr <%p>", sectionHeader); +// log("moveSectionToEndAndResize [-] section offset addr <%p>", +// §ionHeader->sh_offset); +// log("moveSectionToEndAndResize [-] old section offset <%lx>", oldOffset); +// log("moveSectionToEndAndResize [-] new section offset <%lx>", newOffset); +// log("moveSectionToEndAndResize [-] old section size <%lx>", oldSize); +// log("moveSectionToEndAndResize [-] new section size <%lx>", newLen); +// +// int newLibSize = _data.size() + newLen; +// log("moveSectionToEndAndResize [-] old lib size <%d>", _data.size()); +// log("moveSectionToEndAndResize [-] new lib size <%d>", newLibSize); +// _data.resize(newLibSize); +// +// // copy this sh +// Elf64_Shdr newHeader; +// memcpy(&newHeader, sectionHeader, sizeof(Elf64_Shdr)); +// // set new offset +// newHeader.sh_offset = newOffset; +// newHeader.sh_addr = newOffset; +// +// +// // set new len +// newHeader.sh_size = newLen; +// memcpy(sectionHeader, &newHeader, sizeof(Elf64_Shdr)); +// Elf64_Shdr *sectionHeader2 = getSectionByName(section); +// log("moveSectionToEndAndResize [-] updated section offset <%p> <%lx> <%lx> <%lx>", +// §ionHeader2->sh_offset, sectionHeader2->sh_offset, sectionHeader->sh_offset, +// newHeader.sh_offset); +// +// +// // copy the section +// if (end) { +// memcpy(&_data[newOffset + newAdditionalSectionLen], &_data[oldOffset], oldSize); +// +// } else { +// memcpy(&_data[newOffset], &_data[oldOffset], oldSize); +// } +// +// if (searchPhdr) { +// log("moveSectionToEndAndResize [-] let's search for the corresponding phdr"); +// auto *header = (Elf64_Ehdr *) &_data[0]; +// bool found = false; +// for (int k = 0; k < header->e_phnum; k++) { +// auto phdr = &((Elf64_Phdr *) &_data[header->e_phoff])[k]; +// log("moveSectionToEndAndResize [-] found phdr p_offset<%lx> p_type<%lx> p_vaddr<%lx>", +// phdr->p_offset, phdr->p_type, phdr->p_vaddr); +// if (phdr->p_offset == oldOffset) { +// log("Found phdr for dynamic section!"); +// phdr->p_paddr = newOffset + (phdr->p_paddr - phdr->p_offset); +// phdr->p_vaddr = newOffset + (phdr->p_vaddr - phdr->p_offset); +// phdr->p_offset = newOffset; +// log("moveSectionToEndAndResize [-] successful moved to phdr p_offset<%lx> p_type<%lx> p_vaddr<%lx>", +// phdr->p_offset, phdr->p_type, phdr->p_vaddr); +// +// found = true; +// break; +// } +// } +// if (!found) { +// log("!!WARNING!! Could not find corresponding dynamic phdr..."); +// } +// } +// +// log("moveSectionToEndAndResize [-] done"); +// +// return newOffset; +// } else { +// +// } +// +// return 0; +// } +// \ No newline at end of file diff --git a/src/platforms/linux/parser/Elf32Parser.cpp b/src/platforms/linux/parser/Elf32Parser.cpp new file mode 100644 index 0000000..7dd692c --- /dev/null +++ b/src/platforms/linux/parser/Elf32Parser.cpp @@ -0,0 +1,142 @@ +// +// Created by Sascha Roth on 11.11.19. +// + +#include "Elf32Parser.h" +#include "IElfParser.h" +#include "tools/LoggingCallback.h" + +namespace ChickenHook { + + + bool Elf32Parser::iterateShdr(const std::function &callback) { + log("generateSymbolHooks [-] parsing headers..."); + auto *header = (Elf32_Ehdr *) &_data[0]; + + log("generateSymbolHooks [-] search for symbols"); + for (int k = 0; k < header->e_shnum; k++) { + auto shdr = &((Elf32_Shdr *) &_data[header->e_shoff])[k]; + + if (!callback(shdr)) { + return false; + } + } + return true; + } + + bool Elf32Parser::iterateSymbolTable(const std::vector &types, + const std::function function) { + + char *dynStrTab = nullptr; + auto *dynstr = getSectionByName(".dynstr"); + if (dynstr == nullptr) { + log("!! warning !! Could not find dynstr section!"); + } else { + dynStrTab = reinterpret_cast(&_data[dynstr->sh_offset]); + } + + char *strTab = nullptr; + auto *strtab = getSectionByName(".strtab"); + if (strtab == nullptr) { + log("!! warning !! Could not find strtab section!"); + } else { + strTab = reinterpret_cast(&_data[strtab->sh_offset]); + } + + return iterateShdr([this, &function, &types, &strTab, &dynStrTab](Elf32_Shdr *shdr) { + char *symbolName = nullptr; + for (int type : types) { + if (shdr->sh_type == type) { // shdr->sh_type == SHT_DYNSYM || + char *tab = nullptr; + if (type == SHT_SYMTAB) { + tab = strTab; + } else if (type == SHT_DYNSYM) { + tab = dynStrTab; + } + if (tab == nullptr) { + return true;// can happen, this is no error! + } + for (size_t entry = 0; + (entry + 1) * sizeof(Elf32_Sym) <= shdr->sh_size; entry++) { + Elf32_Sym *sym = (Elf32_Sym *) (&_data[shdr->sh_offset] + + entry * sizeof(Elf32_Sym)); + symbolName = tab + sym->st_name; + if (tab != nullptr && + sym->st_name != 0 && + sym->st_value != 0 && + sym->st_info == + 0x12) { // only symbols that are implemented in our binary + //log("Found symbol: <%s> st_value<%lx> st_info<%lx> st_other<%lx>", + // symbolName, sym->st_value, sym->st_info, sym->st_other); + + if (!function(shdr->sh_type, symbolName, sym->st_value, sym->st_info)) { + return false; + } + } + } + } + } + return true; + }); + } + + bool Elf32Parser::iterateNeeded(const std::function function) { + + auto *dynamic = getSectionByName(std::string(".dynamic")); + if (dynamic == nullptr) { + log("Could not find dynamic section!"); + return false; + } + auto *dynstr = getSectionByName(".dynstr"); + if (dynstr == nullptr) { + log("Could not find dynstr section!"); + return false; + } + char *strTab = reinterpret_cast(&_data[dynstr->sh_offset]); + + /// strtab2 + char *rpath = nullptr; + log("Searching for libraries in dynamic section"); + + auto *dyn = (Elf32_Dyn *) (&_data[(dynamic->sh_offset)]); + for (; dyn->d_tag != DT_NULL; dyn++) { + if (dyn->d_tag == DT_NEEDED) { + if (dyn->d_un.d_val != 0) { + rpath = strTab + dyn->d_un.d_val; + if (rpath != nullptr) { + if (!function(rpath)) { + return false; + } + } + + } + } + } + return true; + } + + Elf32Parser::Elf32Parser(std::vector &data) : IElfParser(data) {} + + template + K *Elf32Parser::getSectionByName(const std::string &name) { + auto *header = (Elf32_Ehdr *) &_data[0]; + //shdrs[shstrtabIndex].sh_offset + for (int k = 0; k < header->e_shnum; k++) { + auto shdr = &((Elf32_Shdr *) &_data[header->e_shoff])[k]; + uint32_t off = (((Elf32_Shdr *) &_data[header->e_shoff]))[header->e_shstrndx].sh_offset; + char *data = reinterpret_cast(&_data[off]); + std::string sectionName(data + shdr->sh_name); + //log("Found section <%s> off:<%lx> info<%lx> addr<%lx>", sectionName.c_str(), + // shdr->sh_offset, shdr->sh_info, shdr->sh_addr); + //log("shdr %d %p %d %s", off, data, shdr->sh_name, sectionName.c_str()); + if (sectionName == name) { + //Elf32_Dyn *dynamic = reinterpret_cast(&_data[shdr.sh_offset]); + + return (K *) shdr; + } + } + return nullptr; + } + +} diff --git a/src/platforms/linux/parser/Elf32Parser.h b/src/platforms/linux/parser/Elf32Parser.h new file mode 100644 index 0000000..f49bb7e --- /dev/null +++ b/src/platforms/linux/parser/Elf32Parser.h @@ -0,0 +1,32 @@ +// +// Created by sascharoth on 11.11.19. +// + +#pragma once + + +#include +#include "IElfParser.h" + +namespace ChickenHook { + + class Elf32Parser : public IElfParser { + + + public: + Elf32Parser(std::vector &data); + + + bool iterateNeeded(const std::function function) override; + + bool iterateShdr(const std::function& callback); + + + template + K *getSectionByName(const std::string &name); + + bool iterateSymbolTable(const std::vector &types, + const std::function function) override; + }; + +} \ No newline at end of file diff --git a/src/platforms/linux/parser/Elf64Parser.cpp b/src/platforms/linux/parser/Elf64Parser.cpp new file mode 100644 index 0000000..9dc6705 --- /dev/null +++ b/src/platforms/linux/parser/Elf64Parser.cpp @@ -0,0 +1,142 @@ +// +// Created by Sascha Roth on 11.11.19. +// + +#include "Elf64Parser.h" +#include "IElfParser.h" +#include "tools/LoggingCallback.h" + +namespace ChickenHook { + + + bool Elf64Parser::iterateShdr(const std::function &callback) { + log("generateSymbolHooks [-] parsing headers..."); + auto *header = (Elf64_Ehdr *) &_data[0]; + + log("generateSymbolHooks [-] search for symbols"); + for (int k = 0; k < header->e_shnum; k++) { + auto shdr = &((Elf64_Shdr *) &_data[header->e_shoff])[k]; + + if (!callback(shdr)) { + return false; + } + } + return true; + } + + bool Elf64Parser::iterateSymbolTable(const std::vector &types, + const std::function function) { + + char *dynStrTab = nullptr; + auto *dynstr = getSectionByName(".dynstr"); + if (dynstr == nullptr) { + log("!! warning !! Could not find dynstr section!"); + } else { + dynStrTab = reinterpret_cast(&_data[dynstr->sh_offset]); + } + + char *strTab = nullptr; + auto *strtab = getSectionByName(".strtab"); + if (strtab == nullptr) { + log("!! warning !! Could not find strtab section!"); + } else { + strTab = reinterpret_cast(&_data[strtab->sh_offset]); + } + + return iterateShdr([this, &function, &types, &strTab, &dynStrTab](Elf64_Shdr *shdr) { + char *symbolName = nullptr; + for (int type : types) { + if (shdr->sh_type == type) { // shdr->sh_type == SHT_DYNSYM || + char *tab = nullptr; + if (type == SHT_SYMTAB) { + tab = strTab; + } else if (type == SHT_DYNSYM) { + tab = dynStrTab; + } + if (tab == nullptr) { + return true;// can happen, this is no error! + } + for (size_t entry = 0; + (entry + 1) * sizeof(Elf64_Sym) <= shdr->sh_size; entry++) { + Elf64_Sym *sym = (Elf64_Sym *) (&_data[shdr->sh_offset] + + entry * sizeof(Elf64_Sym)); + symbolName = tab + sym->st_name; + if (tab != nullptr && + sym->st_name != 0 && + sym->st_value != 0 && + sym->st_info == + 0x12) { // only symbols that are implemented in our binary + //log("Found symbol: <%s> st_value<%lx> st_info<%lx> st_other<%lx>", + // symbolName, sym->st_value, sym->st_info, sym->st_other); + + if (!function(shdr->sh_type, symbolName, sym->st_value, sym->st_info)) { + return false; + } + } + } + } + } + return true; + }); + } + + bool Elf64Parser::iterateNeeded(const std::function function) { + + auto *dynamic = getSectionByName(std::string(".dynamic")); + if (dynamic == nullptr) { + log("Could not find dynamic section!"); + return false; + } + auto *dynstr = getSectionByName(".dynstr"); + if (dynstr == nullptr) { + log("Could not find dynstr section!"); + return false; + } + char *strTab = reinterpret_cast(&_data[dynstr->sh_offset]); + + /// strtab2 + char *rpath = nullptr; + log("Searching for libraries in dynamic section"); + + auto *dyn = (Elf64_Dyn *) (&_data[(dynamic->sh_offset)]); + for (; dyn->d_tag != DT_NULL; dyn++) { + if (dyn->d_tag == DT_NEEDED) { + if (dyn->d_un.d_val != 0) { + rpath = strTab + dyn->d_un.d_val; + if (rpath != nullptr) { + if (!function(rpath)) { + return false; + } + } + + } + } + } + return true; + } + + Elf64Parser::Elf64Parser(std::vector &data) : IElfParser(data) {} + + template + K *Elf64Parser::getSectionByName(const std::string &name) { + auto *header = (Elf64_Ehdr *) &_data[0]; + //shdrs[shstrtabIndex].sh_offset + for (int k = 0; k < header->e_shnum; k++) { + auto shdr = &((Elf64_Shdr *) &_data[header->e_shoff])[k]; + uint64_t off = (((Elf64_Shdr *) &_data[header->e_shoff]))[header->e_shstrndx].sh_offset; + char *data = reinterpret_cast(&_data[off]); + std::string sectionName(data + shdr->sh_name); + //log("Found section <%s> off:<%lx> info<%lx> addr<%lx>", sectionName.c_str(), + // shdr->sh_offset, shdr->sh_info, shdr->sh_addr); + //log("shdr %d %p %d %s", off, data, shdr->sh_name, sectionName.c_str()); + if (sectionName == name) { + //Elf64_Dyn *dynamic = reinterpret_cast(&_data[shdr.sh_offset]); + + return (K *) shdr; + } + } + return nullptr; + } + +} diff --git a/src/platforms/linux/parser/Elf64Parser.h b/src/platforms/linux/parser/Elf64Parser.h new file mode 100644 index 0000000..278fbd1 --- /dev/null +++ b/src/platforms/linux/parser/Elf64Parser.h @@ -0,0 +1,32 @@ +// +// Created by sascharoth on 11.11.19. +// + +#pragma once + + +#include +#include "IElfParser.h" + +namespace ChickenHook { + + class Elf64Parser : public IElfParser { + + + public: + Elf64Parser(std::vector &data); + + + bool iterateNeeded(const std::function function) override; + + bool iterateShdr(const std::function& callback); + + + template + K *getSectionByName(const std::string &name); + + bool iterateSymbolTable(const std::vector &types, + const std::function function) override; + }; + +} \ No newline at end of file diff --git a/src/platforms/linux/parser/IElfParser.cpp b/src/platforms/linux/parser/IElfParser.cpp new file mode 100644 index 0000000..fd161f8 --- /dev/null +++ b/src/platforms/linux/parser/IElfParser.cpp @@ -0,0 +1,10 @@ +// +// Created by Sascha Roth on 11.11.19. +// + +#include "IElfParser.h" +#include + +ChickenHook::IElfParser::IElfParser(std::vector &data) : _data(data) { +} + diff --git a/src/platforms/linux/parser/IElfParser.h b/src/platforms/linux/parser/IElfParser.h new file mode 100644 index 0000000..c6b5670 --- /dev/null +++ b/src/platforms/linux/parser/IElfParser.h @@ -0,0 +1,28 @@ +// +// Created by Sascha Roth on 11.11.19. +// + +#pragma once + +#include +#include + +namespace ChickenHook { + + class IElfParser { + + public: + IElfParser(std::vector &data); + + //virtual bool iterateSectionHeaders(const std::function) = 0; + virtual bool iterateSymbolTable(const std::vector &types, + const std::function function) = 0; + + virtual bool iterateNeeded(const std::function) = 0; + + + protected: + std::vector &_data; + }; + +} \ No newline at end of file diff --git a/src/tools/HexDump.cpp b/src/tools/HexDump.cpp new file mode 100644 index 0000000..f037646 --- /dev/null +++ b/src/tools/HexDump.cpp @@ -0,0 +1,5 @@ +// +// Created by Sascha Roth on 03.11.19. +// + +#include "HexDump.h" diff --git a/src/tools/HexDump.h b/src/tools/HexDump.h new file mode 100644 index 0000000..17891cf --- /dev/null +++ b/src/tools/HexDump.h @@ -0,0 +1,53 @@ +// +// Created by Sascha Roth on 03.11.19. +// + +#pragma once + +#include +#include +#include + +class HexDump { + +public: + template + static inline void hex_dump(const void* aData, std::size_t aLength, std::basic_ostream& aStream, std::size_t aWidth = 16) + { + const char* const start = static_cast(aData); + const char* const end = start + aLength; + const char* line = start; + while (line != end) + { + aStream.width(4); + aStream.fill('0'); + aStream << std::hex << line - start << " : "; + std::size_t lineLength = std::min(aWidth, static_cast(end - line)); + for (std::size_t pass = 1; pass <= 2; ++pass) + { + for (const char* next = line; next != end && next != line + aWidth; ++next) + { + char ch = *next; + switch(pass) + { + case 1: + aStream << (ch < 32 ? '.' : ch); + break; + case 2: + if (next != line) + aStream << " "; + aStream.width(2); + aStream.fill('0'); + aStream << std::hex << std::uppercase << static_cast(static_cast(ch)); + break; + } + } + if (pass == 1 && lineLength != aWidth) + aStream << std::string(aWidth - lineLength, ' '); + aStream << " "; + } + aStream << std::endl; + line = line + lineLength; + } + } +}; diff --git a/src/tools/LoggingCallback.cpp b/src/tools/LoggingCallback.cpp new file mode 100644 index 0000000..7d17d4d --- /dev/null +++ b/src/tools/LoggingCallback.cpp @@ -0,0 +1,74 @@ +// +// Created by Sascha Roth on 05.11.19. +// + +#include "LoggingCallback.h" + +namespace ChickenHook { + + // static function pointer to logging callback + void (*logFunction)(const std::string &logtext); + + /* + * Calculate number of characters that is required to apply pargs to format string. + * + * \return The number of characters that would be required by any printf function to format the string, not counting + * the terminating null character. If an encoding error occurs, a negative number is returned. + */ + int _vscprintf(const char *format, va_list pargs) { + va_list argcopy; + va_copy(argcopy, pargs); + int retval = vsnprintf(NULL, 0, format, argcopy); + va_end(argcopy); + return retval; + } + + /* + * convert CFormatString and parameters into formatted std::string. + */ + int vaListToString(const char *CFormatString, va_list argptr, std::string &result) { + // calculate the required buffer length of without actually writing + int len = _vscprintf(CFormatString, argptr); + if (len < 0) { + return len; + } + + // write into an allocated buffer (add 1 for null termination) and create a string from that result + char *buffer = new char[len + 1]; + len = vsnprintf(buffer, len + 1, CFormatString, argptr); + result = std::string(buffer); + delete[] buffer; + return len; + } + + /** + * Use this to log into the provided logging callback + */ + void log(const char *CFormatString, ...) { + + if (CFormatString == nullptr) { + return; + } + + if (logFunction == NULL) { + return; + } + + va_list argptr; + va_start(argptr, CFormatString); + std::string res; + int len = vaListToString(CFormatString, argptr, res); + if (len > 0) { + (*logFunction)(res); + } + va_end(argptr); + + } + + /* + * Set the logging callback + */ + void setLogFunction(void (*logCallback)(const std::string&)) { + logFunction = logCallback; + } +} \ No newline at end of file diff --git a/src/tools/LoggingCallback.h b/src/tools/LoggingCallback.h new file mode 100644 index 0000000..2c05e39 --- /dev/null +++ b/src/tools/LoggingCallback.h @@ -0,0 +1,38 @@ +// +// Created by Sascha Roth on 05.11.19. +// + +#pragma once +#include +#include +#include +#include +#include + +namespace ChickenHook { + + + /* + * Calculate number of characters that is required to apply pargs to format string. + * + * \return The number of characters that would be required by any printf function to format the string, not counting + * the terminating null character. If an encoding error occurs, a negative number is returned. + */ + int _vscprintf(const char *format, va_list pargs); + + /* + * convert CFormatString and parameters into formatted std::string. + */ + int vaListToString(const char *CFormatString, va_list argptr, std::string &result); + + /** + * Use this to log into the provided logging callback + */ + void log(const char *CFormatString, ...); + + /* + * Set the logging callback + */ + void setLogFunction(void (*logCallback)(const std::string &)); + +} \ No newline at end of file