-
Notifications
You must be signed in to change notification settings - Fork 305
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: RevokeMsgHook group msg for NT 4194
- Loading branch information
Showing
9 changed files
with
626 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.