Skip to content
Permalink
Browse files

Improved native logging

  • Loading branch information
roussosalex committed Jan 4, 2020
1 parent 5a24b4a commit 6be06963e0f048c3de7c5e4161c56c730d6f92a5
@@ -0,0 +1,19 @@
#ifndef NFCD_ERROR_H
#define NFCD_ERROR_H

#include <errno.h>
#include <android/log.h>

#define LOG_TAG "NATIVENFC"

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__ )
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__ )
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__ )
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

// assert x, print to error log on error
#define LOG_ASSERT(x, ...) if (!(x)) { LOGE(__VA_ARGS__); }
// assert x, print to error log, return on error
#define LOG_ASSERT_X(x, ...) if (!(x)) { LOGE(__VA_ARGS__); return; }

#endif // NFCD_ERROR_H
@@ -1,5 +1,5 @@
#ifndef NFCD_CONFIG
#define NFCD_CONFIG
#ifndef NFCD_CONFIG_H
#define NFCD_CONFIG_H

#include <vector>

@@ -99,4 +99,4 @@ class Config {
std::vector<Option> mOptions;
};

#endif //NFCD_CONFIG
#endif //NFCD_CONFIG_H
@@ -1,8 +1,13 @@
#ifndef NFCD_SYMBOL_H
#define NFCD_SYMBOL_H

#include <link.h>
#include <string>
#include <sys/mman.h>
#include <unordered_map>

#include <nfcd/error.h>

class SymbolTable {
public:
static void create(const char *file) {
@@ -16,8 +21,10 @@ class SymbolTable {
unsigned long getSize(std::string name) {
auto it = mSymbols.find(name);

if (it == mSymbols.end())
if (it == mSymbols.end()) {
LOGE("Symbol %s missing from SymbolTable", name.c_str());
return 0;
}

return it->second;
}
@@ -27,14 +34,16 @@ class SymbolTable {
FILE *phy = fopen(file, "rb");
fseek(phy, 0, SEEK_END);
long phy_size = ftell(phy);

mBase = mmap(nullptr, (size_t)phy_size, PROT_READ, MAP_PRIVATE, fileno(phy), 0);
fclose(phy);
LOG_ASSERT_X(mBase != MAP_FAILED, "Loading library via mmap failed with %d", errno);

parse();
LOG_ASSERT(parse(), "Symbol table missing from library");
munmap(mBase, (size_t)phy_size);
}

int parse() {
bool parse() {
char *base = (char*)mBase;
ElfW(Ehdr) *header = (ElfW(Ehdr) *) base;

@@ -72,7 +81,7 @@ class SymbolTable {
// not found -> should never happen
if (tbl_string_off == 0 || tbl_string_sz == 0 || tbl_symbol_off == 0
|| tbl_symbol_sz == 0)
return 1;
return false;

ElfW(Sym) *symbol = (ElfW(Sym) *)(base + tbl_symbol_off);
ElfW(Sym) *end = (ElfW(Sym) *)(base + tbl_symbol_off + tbl_symbol_sz);
@@ -84,11 +93,13 @@ class SymbolTable {
}
}

return 0;
return true;
}

void *mBase;
std::unordered_map<std::string, unsigned long> mSymbols;

static SymbolTable *mInstance;
};
};

#endif //NFCD_SYMBOL_H
@@ -3,19 +3,13 @@

#include <cstdint>
#include <functional>
#include <android/log.h>
#include <type_traits>

#include <nfcd/error.h>

// maximum trampoline size
#define TR_MAX_SIZE 52

#define LOG_TAG "NATIVENFC"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__ )
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__ )
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__ )
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOGEX(...) do { LOGE(__VA_ARGS__); return; } while(0)

class Hook {
public:
Hook(void *handle, const char *symbol, void *redirect);
@@ -38,13 +32,13 @@ class Hook {
}

private:
void constructTrampoline();
bool constructTrampoline();

void swapTrampoline(bool install);
bool swapTrampoline(bool install);

void hookCacheflush();
bool hookCacheflush();

void unprotect();
bool unprotect();

// symbol address, hook address
void *mSymbol = nullptr, *mHook = nullptr;
@@ -1,6 +1,7 @@
#include <dlfcn.h>
#include <unistd.h>

#include <nfcd/error.h>
#include <nfcd/libnfc-external.h>
#include <nfcd/helper/Config.h>
#include <nfcd/helper/Symbol.h>
@@ -21,10 +22,8 @@ tNFA_STATUS hook_NFA_EnablePolling(tNFA_TECHNOLOGY_MASK poll_mask);

inline const char *libnfc_path() {
#ifdef __aarch64__
LOGI("ARM64 detected!");
return "/system/lib64/libnfc-nci.so";
#elif __arm__
LOGI("ARM detected!");
return "/system/lib/libnfc-nci.so";
#endif
}
@@ -9,6 +9,7 @@
Hook::Hook(void *handle, const char *symbol, void *redirect) {
// find symbol
mSymbol = dlsym(handle, symbol);
LOG_ASSERT_X(mSymbol, "Missing symbol: %s", symbol);

// if redirect enabled
if (redirect) {
@@ -17,27 +18,27 @@ Hook::Hook(void *handle, const char *symbol, void *redirect) {
// get symbol alignment
mAlignment = SymbolTable::instance()->getSize(symbol);
// construct trampoline for this architecture
constructTrampoline();
LOG_ASSERT_X(constructTrampoline(), "Trampoline construction failed");
// unprotect the region
unprotect();
LOG_ASSERT_X(unprotect(), "Unprotecting failed");
// install the trampoline
swapTrampoline(true);
LOG_ASSERT_X(swapTrampoline(true), "Trampoline installation failed");
}
}

void Hook::precall() {
// uninstall trampoline while hook is running to avoid recursion
if (mHook)
swapTrampoline(false);
LOG_ASSERT(swapTrampoline(false), "Precall uninstall failed");
}

void Hook::postcall() {
// install trampoline again when hook is finished
if (mHook)
swapTrampoline(true);
LOG_ASSERT(swapTrampoline(true), "Postcall install failed");
}

void Hook::constructTrampoline() {
bool Hook::constructTrampoline() {
unsigned long symbol = (unsigned long) mSymbol;
unsigned long hook = (unsigned long) mHook;

@@ -46,11 +47,10 @@ void Hook::constructTrampoline() {

#ifdef __arm__
if (symbol_is_thumb && hook_is_thumb) {
LOGI("THUMB");
LOGI("Constructing THUMB trampoline");
mIsThumb = true;

unsigned char trampoline[20];

trampoline[1] = 0xb4;
trampoline[0] = 0x60; // push {r5,r6}
trampoline[3] = 0xa5;
@@ -75,27 +75,27 @@ void Hook::constructTrampoline() {
mTrampolineSize = sizeof(trampoline);
std::memcpy(mTrampoline, trampoline, mTrampolineSize);
} else if (!symbol_is_thumb && !hook_is_thumb) {
LOGI("ARM");
LOGI("Constructing ARM trampoline");
mIsThumb = false;

unsigned int trampoline[3];

trampoline[0] = 0xe59ff000; // LDR pc, [pc, #0]
trampoline[1] = hook;
trampoline[2] = hook;

// store trampoline
mTrampolineSize = sizeof(trampoline);
std::memcpy(mTrampoline, trampoline, mTrampolineSize);
} else
LOGE("addr %p and hook %p don't match!", mSymbol, mHook);
} else {
LOGE("Alignment mismatch of symbol %p and hook %p", mSymbol, mHook);
return false;
}
#else
if (!symbol_is_thumb && !hook_is_thumb) {
LOGI("ARM64");
LOGI("Constructing ARM64 trampoline");
mIsThumb = false;

unsigned int trampoline[4];

trampoline[0] = 0x58000050; // ldr x16, #8 -> x16 is IP0, load hook address
trampoline[1] = 0xD61F0200; // br x16 -> branch to register without modifying any regs

@@ -106,24 +106,30 @@ void Hook::constructTrampoline() {
// store trampoline
mTrampolineSize = sizeof(trampoline);
std::memcpy(mTrampoline, trampoline, mTrampolineSize);
} else
LOGE("addr %p and hook %p don't match!", mSymbol, mHook);
} else {
LOGE("Alignment mismatch of symbol %p and hook %p", mSymbol, mHook);
return false;
}
#endif
return true;
}

void Hook::swapTrampoline(bool install) {
bool Hook::swapTrampoline(bool install) {
void *symbol = mSymbol;

// prevent writing trampoline in potentially bigger symbol
if (mAlignment < mTrampolineSize)
LOGE("trampoline size larger than symbol alignment");
// prevent writing trampoline in potentially smaller symbol
if (mAlignment < mTrampolineSize) {
LOGE("Trampoline size %lu larger than approximate symbol size %lu", mTrampolineSize, mAlignment);
return false;
}
else if (mAlignment == 0)
LOGW("symbol has no alignment, overwrite possible");
LOGW("Symbol has no approximate size, possible overwrite");

// adjust symbol to thumb boundary:
// symbol points to first instruction, but in thumb mode (operand - instruction - operand)
// a operand precedes the first instruction. In order to overwrite the operand,
// subtract a byte from symbol so it points to the first operand.
/* adjust symbol to thumb boundary:
* symbol points to first instruction, but in thumb mode (operand - instruction - operand)
* a operand precedes the first instruction. In order to overwrite the operand,
* subtract a byte from symbol so it points to the first operand.
*/
if (mIsThumb)
symbol = (void *)((unsigned long) symbol - 1);

@@ -134,10 +140,10 @@ void Hook::swapTrampoline(bool install) {
// install/restore trampoline bytes
std::memcpy(symbol, install ? mTrampoline : mStored, mTrampolineSize);
// flush cache in symbol
hookCacheflush();
return hookCacheflush();
}

void Hook::hookCacheflush() {
bool Hook::hookCacheflush() {
unsigned long begin = (unsigned long) mSymbol;
unsigned long end = begin + mTrampolineSize;

@@ -156,15 +162,19 @@ void Hook::hookCacheflush() {
#else
arm64_cacheflush(begin, mTrampolineSize);
#endif
return true;
}

void Hook::unprotect() {
bool Hook::unprotect() {
int RWX = PROT_READ | PROT_WRITE | PROT_EXEC;
unsigned long page_size = sysconf(_SC_PAGESIZE);

unsigned long first_page = ~(page_size - 1) & (unsigned long) mSymbol;
unsigned long last_page = ~(page_size - 1) & ((unsigned long) mSymbol + mTrampolineSize);

if (mprotect((void *) first_page, page_size + (last_page - first_page), RWX) != 0)
LOGE("Error unprotecting pages");
if (mprotect((void *) first_page, page_size + (last_page - first_page), RWX) != 0) {
LOGE("Error unprotecting %p - %p: %d", (void*)first_page, (void*)last_page, errno);
return false;
}
return true;
}
@@ -102,12 +102,11 @@ tNFA_STATUS hook_NFA_EnablePolling(tNFA_TECHNOLOGY_MASK poll_mask) {
static void hookNative() {
// check if NCI library exists and is readable + is loaded
const char *lib_path = libnfc_path();
if (access(lib_path, R_OK) != 0)
LOGEX("Could not find libnfc-nci");
LOGI("Library expected at %s", lib_path);
LOG_ASSERT_X(access(lib_path, R_OK) == 0, "Library not accessible");

void *handle = dlopen(lib_path, RTLD_NOLOAD);
if (!handle)
LOGEX("Could not obtain handle of libnfc-nci");
LOG_ASSERT_X(handle, "Could not obtain library handle");

// create symbol mapping
SymbolTable::create(lib_path);
@@ -126,4 +125,4 @@ static void hookNative() {
hNFA_StartRfDiscovery = new Hook(handle, "NFA_StartRfDiscovery", nullptr);
hNFA_EnablePolling = new Hook(handle, "NFA_EnablePolling", nullptr);
#endif
}
}

0 comments on commit 6be0696

Please sign in to comment.
You can’t perform that action at this time.