Skip to content

Commit

Permalink
fix: RevokeMsgHook group msg for NT 4194
Browse files Browse the repository at this point in the history
  • Loading branch information
cinit committed Jul 14, 2023
1 parent 5a1001d commit 07ad7b3
Show file tree
Hide file tree
Showing 9 changed files with 626 additions and 170 deletions.
2 changes: 2 additions & 0 deletions app/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ add_library(qauxv SHARED
utils/MemoryUtils.cc
utils/ConfigManager.cc
utils/ElfScan.cc
utils/AobScanUtils.cc
utils/arch_utils.cc

ntkernel/NtRecallMsgHook.cc

Expand Down
373 changes: 234 additions & 139 deletions app/src/main/cpp/ntkernel/NtRecallMsgHook.cc

Large diffs are not rendered by default.

87 changes: 87 additions & 0 deletions app/src/main/cpp/utils/AobScanUtils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
// Created by sulfate on 2023-07-14.
//

#include "AobScanUtils.h"

#include <fmt/format.h>

#include "ElfScan.h"

namespace utils {

using Validator = AobScanTarget::Validator;

static std::string bytes2hex(std::span<const uint8_t> bytes) {
std::string result;
result.reserve(bytes.size() * 2);
for (uint8_t byte: bytes) {
result += fmt::format("{:02x}", byte);
}
return result;
}

bool SearchForAllAobScanTargets(std::vector<AobScanTarget*> targets,
const void* imageBase, bool isLoadedImage,
std::vector<std::string>& errors) {
bool hasFailed = false;
for (auto* target: targets) {
std::string_view name = target->name;
std::span<const uint8_t> sequence = target->sequence;
int step = target->step;
bool execMemOnly = target->execMemOnly;
int64_t offsetForResult = target->offsetForResult;
auto validator = target->resultValidator;
auto rawResultSet = FindByteSequenceImpl(imageBase, isLoadedImage, sequence, execMemOnly, step);
if (rawResultSet.empty()) {
errors.emplace_back(fmt::format("AobScanUtils: failed to find target '{}' with sequence {}", name, bytes2hex(sequence)));
hasFailed = true;
continue;
}
if (rawResultSet.size() > 1) {
std::string msg = fmt::format("AobScanUtils: found {} targets '{}' with sequence {}", rawResultSet.size(), name, bytes2hex(sequence));
for (auto result: rawResultSet) {
msg += fmt::format("offset: 0x{:x}, ", result);
}
errors.emplace_back(std::move(msg));
hasFailed = true;
continue;
}
uint64_t result = uint64_t(int64_t(rawResultSet[0]) + offsetForResult);
if (validator.has_value()) {
// TODO: 2023-07-14 if the image is a mmaped file, the offset in file is not provided, currently we just set it to 0
if (!validator.value()(imageBase, isLoadedImage, result, 0)) {
errors.emplace_back(fmt::format("AobScanUtils: validator failed for target '{}' with sequence {} for result 0x{:x}",
name, bytes2hex(sequence), result));
hasFailed = true;
continue;
}
}
target->results.emplace_back(result);
}
return !hasFailed;
}

const Validator CommonAobScanValidator::kArm64StpX29X30SpImm = [](const void* base, bool isLoaded,
uint64_t rva, uint64_t optOffsetInFile) -> bool {
if (!isLoaded) {
// TODO: 2023-07-14 if the image is a mmaped file, the offset in file is not provided, currently we just set it to 0
// currently we only support loaded image
return false;
}
if (base == nullptr) {
return false;
}
const uint8_t* va = reinterpret_cast<const uint8_t*>(base) + rva;
const uint32_t* p = reinterpret_cast<const uint32_t*>(va);
uint32_t inst = *p;
// expect fd 7b ba a9 stp x29,x30,[sp, #???]!
if ((inst & ((0b11111111u << 24) | (0b11000000u << 16u) | (0b01111111u << 8u) | 0xFF))
== ((0b10101001u << 24u) | (0b10000000u << 16u) | (0x7b << 8u) | 0xfd)) {
return true;
} else {
return false;
}
};

}
114 changes: 114 additions & 0 deletions app/src/main/cpp/utils/AobScanUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//
// Created by sulfate on 2023-07-14.
//

#ifndef QAUXV_AOBSCANUTILS_H
#define QAUXV_AOBSCANUTILS_H

#include <cstdint>
#include <vector>
#include <array>
#include <string>
#include <string_view>
#include <span>
#include <optional>
#include <functional>

namespace utils {

class AobScanTarget {
public:
/**
* A validator for the result of AOB scan. Note that the offsetForResult is applied before the validator.
* @param base the base address of the ELF image
* @param isLoaded true if the image is loaded in memory by a linker, false if it's a mmap-ed file
* @param rva the relative virtual address of the result, this is real result of the AOB scan
* @param optOffsetInFile the offset in the file, if the image is loaded in memory, this value is 0
*/
using Validator = std::function<bool(const void* base, bool isLoaded, uint64_t rva, uint64_t optOffsetInFile)>;

std::string name; // for debugging purpose only
std::vector<uint8_t> sequence;
int step = 0;
bool execMemOnly = false;
int64_t offsetForResult = 0;
std::optional<Validator> resultValidator;

std::vector<uint64_t> results;

AobScanTarget() = default;

AobScanTarget(std::string name, std::vector<uint8_t> sequence, int step, bool execMemOnly, int64_t offsetForResult,
std::optional<Validator> resultValidator)
: name(std::move(name)), sequence(std::move(sequence)), step(step), execMemOnly(execMemOnly),
offsetForResult(offsetForResult), resultValidator(std::move(resultValidator)) {}

inline AobScanTarget& WithName(std::string newName) {
this->name = std::move(newName);
return *this;
}

inline AobScanTarget& WithSequence(std::vector<uint8_t> newSequence) {
this->sequence = std::move(newSequence);
return *this;
}

inline AobScanTarget& WithStep(int newStep) {
this->step = newStep;
return *this;
}

inline AobScanTarget& WithExecMemOnly(bool newExecMemOnly) {
this->execMemOnly = newExecMemOnly;
return *this;
}

inline AobScanTarget& WithOffsetForResult(int64_t newOffsetForResult) {
this->offsetForResult = newOffsetForResult;
return *this;
}

inline AobScanTarget& WithResultValidator(std::optional<Validator> newResultValidator) {
this->resultValidator = std::move(newResultValidator);
return *this;
}

inline AobScanTarget& WithResultValidator(Validator newResultValidator) {
this->resultValidator = std::move(newResultValidator);
return *this;
}

inline uint64_t GetResultOffset() const noexcept {
if (results.size() != 1) {
return 0;
}
return results[0];
}

inline bool HasResult() const noexcept {
return results.size() == 1;
}
};

class CommonAobScanValidator {
public:
/**
* Require the result to be arm64 instruction "stp x29, x30, [sp, #imm]" or "stp x29, x30, [sp, #imm]!"
* This is used to find the function prologue.
*/
static const AobScanTarget::Validator kArm64StpX29X30SpImm;
};

/**
* Search for all AOB scan targets in the given image.
* @param targets an array of AOB scan targets
* @param imageBase the base address of the ELF image
* @param isLoadedImage true if the image is loaded in memory by a linker, false if it's a mmap-ed file
* @param errors a vector of error messages
* @return true if and only if every AOB scan target has one result
*/
bool SearchForAllAobScanTargets(std::vector<AobScanTarget*> targets, const void* imageBase, bool isLoadedImage, std::vector<std::string>& errors);

}

#endif //QAUXV_AOBSCANUTILS_H
2 changes: 2 additions & 0 deletions app/src/main/cpp/utils/ElfScan.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ std::vector<uint64_t> FindByteSequenceForImageFile(const void* baseAddress, std:

std::vector<uint64_t> FindByteSequenceForLoadedImage(const void* baseAddress, std::span<const uint8_t> sequence, bool execMemOnly, int step);

std::vector<uint64_t> FindByteSequenceImpl(const void* baseAddress, bool isLoaded, std::span<const uint8_t> sequence, bool execMemOnly, int step);

}

#endif //QAUXV_ELFSCAN_H
30 changes: 30 additions & 0 deletions app/src/main/cpp/utils/arch_utils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// Created by sulfate on 2023-07-14.
//

#include "arch_utils.h"

#include <cstdlib>

#ifdef __aarch64__

extern "C" __attribute__((naked, visibility("default"))) void* call_func_with_x8(const void* func, void* x8, void* x0, void* x1, void* x2, void* x3) {
__asm volatile (
"mov x16, x0\n"
"mov x8, x1\n"
"mov x0, x2\n"
"mov x1, x3\n"
"mov x2, x4\n"
"mov x3, x5\n"
"br x16\n"
);
}

#else // not __aarch64__

extern "C" void* call_func_with_x8(const void* func, void* x8, void* x0, void* x1, void* x2, void* x3) {
// not implemented
abort();
}

#endif // __aarch64__
10 changes: 10 additions & 0 deletions app/src/main/cpp/utils/arch_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//
// Created by sulfate on 2023-07-14.
//

#ifndef QAUXV_ARCH_UTILS_H
#define QAUXV_ARCH_UTILS_H

extern "C" void* call_func_with_x8(const void* func, void* x8, void* x0, void* x1, void* x2, void* x3);

#endif //QAUXV_ARCH_UTILS_H
Loading

0 comments on commit 07ad7b3

Please sign in to comment.