Skip to content

Instantly share code, notes, and snippets.

@SeeFlowerX
Forked from romainthomas/qbdi_android.cpp
Created November 22, 2021 01:52
Show Gist options
  • Save SeeFlowerX/cd559e8be10e167b393002dfa66ca979 to your computer and use it in GitHub Desktop.
Save SeeFlowerX/cd559e8be10e167b393002dfa66ca979 to your computer and use it in GitHub Desktop.
QBDI API example
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <jni.h>
#include <set>
#include "LIEF/ELF.hpp"
#include <android/log.h>
#include <dlfcn.h>
#include "QBDI.h"
#include "callback.hpp"
#define FAKE_RET_ADDR 42
static JavaVM* jvm = nullptr;
static JNIEnv* env = nullptr;
static const char* TARGET_LIB = "libnative-lib.so";
static constexpr size_t STACK_SIZE = 0x100000; // 1MB
static uintptr_t base_address = 0;
static auto console = spdlog::stdout_color_mt("console");
using namespace QBDI;
using namespace LIEF::ELF;
extern "C" {
JNIEXPORT void InitializeSignalChain() {}
JNIEXPORT void ClaimSignalChain() {}
JNIEXPORT void UnclaimSignalChain() {}
JNIEXPORT void InvokeUserSignalHandler() {}
JNIEXPORT void EnsureFrontOfChain() {}
JNIEXPORT void AddSpecialSignalHandlerFn() {}
JNIEXPORT void RemoveSpecialSignalHandlerFn() {}
}
int main(int argc, char** argv) {
// Create JVM
// ===========
JavaVMOption opt[2];
opt[0].optionString = "-Djava.library.path=/data/local/tmp";
opt[1].optionString = "-verbose:jni"; // may want to remove this, it's noisy
JavaVMInitArgs args;
args.version = JNI_VERSION_1_6;
args.options = opt;
args.nOptions = 2;
args.ignoreUnrecognized = JNI_FALSE;
void* handler = dlopen("/system/lib/libart.so", RTLD_NOW);
// ...
console->info("JVM created!");
void* hdl = dlopen(TARGET_LIB, RTLD_NOW);
if (hdl == nullptr) {
std::cerr << dlerror() << std::endl;
return EXIT_FAILURE;
}
using jni_function_t = jstring(*)(JNIEnv*, jobject, jstring);
auto&& jni_function = reinterpret_cast<jni_function_t>(dlsym(hdl, "Java_kr_repo_h2spice_crypto500_MainActivity_a"));
if (jni_function == nullptr) {
console->error("{}", dlerror());
return EXIT_FAILURE;
}
context_t ctx;
std::vector<MemoryMap> maps = getCurrentProcessMaps();
auto&& it_range = std::find_if(std::begin(maps), std::end(maps),
[] (MemoryMap mm) {
return mm.name.find(TARGET_LIB) != std::string::npos;
});
if (it_range != std::end(maps)) {
ctx.range = &(it_range->range);
base_address = ctx.range->start;
}
std::unique_ptr<Binary> bin = Parser::parse(TARGET_LIB);
if (not bin) {
console->error("Error while parsing {}", TARGET_LIB);
return EXIT_FAILURE;
}
ctx.bin = bin.get();
uint8_t *fakestack = nullptr;
console->info("Initializing VM ...");
std::unique_ptr<VM> vm{new VM()};
const char* INPUT = "g1UlZafiuGdCgpTkWYjaZg3kE6qCd7kF3kV+nMKcGHc=";
jstring jINPUT = env->NewStringUTF(INPUT);
jstring real_output = jni_function(env, nullptr, jINPUT);
console->info("Input: {}", INPUT);
console->info("Real Output: {}", env->GetStringUTFChars(real_output, nullptr));
console->info("Setup callback");
vm->addCodeCB(PREINST, inst_cbk, nullptr);
vm->recordMemoryAccess(MEMORY_READ_WRITE);
vm->addCodeCB(POSTINST, inst_cbk, nullptr);
// Get a pointer to the GPR state of the vm
GPRState* state = vm->getGPRState();
// Setup initial GPR state, this fakestack will produce a ret NULL at the end of the execution
allocateVirtualStack(state, STACK_SIZE, &fakestack);
console->info("Simulate call in QBDI");
simulateCall(state, FAKE_RET_ADDR, {
reinterpret_cast<rword>(env),
/* jobject */ reinterpret_cast<rword>(nullptr),
/* Base64 Input */ reinterpret_cast<rword>(jINPUT),
});
console->info("Instument module: {}", TARGET_LIB);
vm->addInstrumentedModule(TARGET_LIB);
// Run the DBI execution
console->info("Run '{}' through QBDI", "Java_kr_repo_h2spice_crypto500_MainActivity_a");
vm->run(reinterpret_cast<rword>(jni_function), static_cast<rword>(FAKE_RET_ADDR));
rword ret = QBDI_GPR_GET(state, REG_RETURN);
const char* dbi_output = env->GetStringUTFChars((jstring)ret, nullptr);
console->info("DBI output {}", dbi_output);
alignedFree(fakestack);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment