update
This commit is contained in:
@@ -69,29 +69,42 @@ auto DoCFTrackX64(HANDLE hProcess,
|
|||||||
for (size_t i = stackArrays.size() - 1; i > 0; i--) {
|
for (size_t i = stackArrays.size() - 1; i > 0; i--) {
|
||||||
auto ripAddr = stackArrays[i].first;
|
auto ripAddr = stackArrays[i].first;
|
||||||
auto retAddr = stackArrays[i].second;
|
auto retAddr = stackArrays[i].second;
|
||||||
//printf("stack walk: %p\n", ripAddr);
|
|
||||||
|
|
||||||
if (retAddr == 0) {
|
if (retAddr == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto rawAddress = ripAddr - 0x16;
|
auto rawAddress = ripAddr - 0x20;
|
||||||
StackTracker stackTrack(hProcess, rawAddress, 0x30, false);
|
StackTracker stackTrack(hProcess, rawAddress, 0x28, false);
|
||||||
if (stackTrack.TryFindValidDisasm(rawAddress, 0x30) == false) {
|
if (stackTrack.TryFindValidDisasm(rawAddress, 0x28) == false) {
|
||||||
printf("\nSleepMask Encryption Memory Detected: %p\n\t", rawAddress);
|
printf("\nSleepMask Encryption Memory Detected: %p\n\t",
|
||||||
|
rawAddress);
|
||||||
PrintProcessInfoFromHandle(hProcess);
|
PrintProcessInfoFromHandle(hProcess);
|
||||||
|
stackTrack.PrintAsm();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto [successTrack, nextJmpAddress] = stackTrack.CalcNextJmpAddress();
|
auto [successTrack, nextJmpAddress] = stackTrack.CalcNextJmpAddress();
|
||||||
|
|
||||||
if (successTrack == false &&
|
if (successTrack == false) {
|
||||||
stackTrack.feature != _features::kCallRip &&
|
// very perfer lazy method
|
||||||
stackTrack.feature != _features::kCallReg &&
|
static const std::string WaitonAddressGate = "52 10 47 AE";
|
||||||
stackTrack.feature != _features::kSyscall) {
|
if (Tools::FindPatternInMemory(
|
||||||
printf("\nNon-integrity Stack Detect: %p\n\t", rawAddress);
|
(uint64_t)stackTrack.SuccessReadedBuffer.data(),
|
||||||
PrintProcessInfoFromHandle(hProcess);
|
stackTrack.SuccessReadedBuffer.size(),
|
||||||
|
WaitonAddressGate) != 0) {
|
||||||
|
printf("skip waitonaddress, golang detect\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (stackTrack.feature != _features::kCallRip &&
|
||||||
|
stackTrack.feature != _features::kCallReg &&
|
||||||
|
stackTrack.feature != _features::kSyscall) {
|
||||||
|
printf("\nNon-integrity Stack Detect: %p ripAddr: %p \n\t",
|
||||||
|
rawAddress, ripAddr);
|
||||||
|
PrintProcessInfoFromHandle(hProcess);
|
||||||
|
stackTrack.PrintAsm();
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -101,7 +114,7 @@ auto DoX64StackDetect(HANDLE hProcess, HANDLE hThread) -> void {
|
|||||||
context.ContextFlags = CONTEXT_ALL;
|
context.ContextFlags = CONTEXT_ALL;
|
||||||
std::vector<std::pair<uint64_t, uint64_t>> stackArrays;
|
std::vector<std::pair<uint64_t, uint64_t>> stackArrays;
|
||||||
SymInitialize(hProcess, nullptr, TRUE);
|
SymInitialize(hProcess, nullptr, TRUE);
|
||||||
//printf("scan tid: %d \n", GetThreadId(hThread));
|
printf("scan tid: %d \n", GetThreadId(hThread));
|
||||||
do {
|
do {
|
||||||
if (GetThreadContext(hThread, &context) == false) {
|
if (GetThreadContext(hThread, &context) == false) {
|
||||||
break;
|
break;
|
||||||
@@ -126,26 +139,30 @@ auto DoX64StackDetect(HANDLE hProcess, HANDLE hThread) -> void {
|
|||||||
}
|
}
|
||||||
if (SimpleCheckIn2020(hProcess, StackFarmeEx.AddrPC.Offset)) {
|
if (SimpleCheckIn2020(hProcess, StackFarmeEx.AddrPC.Offset)) {
|
||||||
detect = true;
|
detect = true;
|
||||||
//break;
|
// break;
|
||||||
}
|
}
|
||||||
|
|
||||||
stackArrays.push_back(
|
stackArrays.push_back(
|
||||||
{StackFarmeEx.AddrPC.Offset, StackFarmeEx.AddrReturn.Offset});
|
{StackFarmeEx.AddrPC.Offset, StackFarmeEx.AddrReturn.Offset});
|
||||||
}
|
}
|
||||||
//if (detect) {
|
// if (detect) {
|
||||||
// break;
|
// break;
|
||||||
//}
|
// }
|
||||||
DoCFTrackX64(hProcess, stackArrays);
|
DoCFTrackX64(hProcess, stackArrays);
|
||||||
} while (false);
|
} while (false);
|
||||||
SymCleanup(hProcess);
|
SymCleanup(hProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主扫描函数
|
// 主扫描函数
|
||||||
auto DoLittleHackerMemeDetect(DWORD pidFilter = 0, bool scanAll = false) -> void {
|
auto DoLittleHackerMemeDetect(DWORD pidFilter = 0, bool scanAll = false)
|
||||||
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); // 所有线程
|
-> void {
|
||||||
|
HANDLE hThreadSnap =
|
||||||
|
CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); // 所有线程
|
||||||
THREADENTRY32 te32 = {};
|
THREADENTRY32 te32 = {};
|
||||||
te32.dwSize = sizeof(THREADENTRY32);
|
te32.dwSize = sizeof(THREADENTRY32);
|
||||||
|
|
||||||
if (hThreadSnap == INVALID_HANDLE_VALUE || !Thread32First(hThreadSnap, &te32))
|
if (hThreadSnap == INVALID_HANDLE_VALUE ||
|
||||||
|
!Thread32First(hThreadSnap, &te32))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -158,7 +175,8 @@ auto DoLittleHackerMemeDetect(DWORD pidFilter = 0, bool scanAll = false) -> void
|
|||||||
if (!scanAll && pidFilter != 0 && te32.th32OwnerProcessID != pidFilter)
|
if (!scanAll && pidFilter != 0 && te32.th32OwnerProcessID != pidFilter)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!scanAll && pidFilter == 0 && te32.th32OwnerProcessID != GetCurrentProcessId())
|
if (!scanAll && pidFilter == 0 &&
|
||||||
|
te32.th32OwnerProcessID != GetCurrentProcessId())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto handleDeleter = [](HANDLE h) {
|
auto handleDeleter = [](HANDLE h) {
|
||||||
@@ -172,12 +190,11 @@ auto DoLittleHackerMemeDetect(DWORD pidFilter = 0, bool scanAll = false) -> void
|
|||||||
OpenProcess(PROCESS_ALL_ACCESS, FALSE, te32.th32OwnerProcessID),
|
OpenProcess(PROCESS_ALL_ACCESS, FALSE, te32.th32OwnerProcessID),
|
||||||
handleDeleter);
|
handleDeleter);
|
||||||
|
|
||||||
if (!hProcess || hProcess.get() == INVALID_HANDLE_VALUE ||
|
if (!hProcess || hProcess.get() == INVALID_HANDLE_VALUE || !hThread ||
|
||||||
!hThread || hThread.get() == INVALID_HANDLE_VALUE)
|
hThread.get() == INVALID_HANDLE_VALUE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!Tools::Is64BitPorcess(hProcess.get()))
|
if (!Tools::Is64BitPorcess(hProcess.get())) continue;
|
||||||
continue;
|
|
||||||
DoX64StackDetect(hProcess.get(), hThread.get());
|
DoX64StackDetect(hProcess.get(), hThread.get());
|
||||||
|
|
||||||
} while (Thread32Next(hThreadSnap, &te32));
|
} while (Thread32Next(hThreadSnap, &te32));
|
||||||
@@ -194,12 +211,10 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
if (arg == "-all") {
|
if (arg == "-all") {
|
||||||
scanAll = true;
|
scanAll = true;
|
||||||
}
|
} else if (arg == "-pid" && i + 1 < argc) {
|
||||||
else if (arg == "-pid" && i + 1 < argc) {
|
|
||||||
scanAll = false;
|
scanAll = false;
|
||||||
targetPid = static_cast<DWORD>(std::stoul(argv[++i]));
|
targetPid = static_cast<DWORD>(std::stoul(argv[++i]));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
std::cerr << "[!] Unknown argument ,go scan all: " << arg << "\n";
|
std::cerr << "[!] Unknown argument ,go scan all: " << arg << "\n";
|
||||||
scanAll = true;
|
scanAll = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "stack_tracker.h"
|
#include "stack_tracker.h"
|
||||||
|
|
||||||
auto StackTracker::rpm(uintptr_t address, size_t readSize)
|
auto StackTracker::rpm(uintptr_t address, size_t readSize)
|
||||||
-> std::vector<char> {
|
-> std::vector<char> {
|
||||||
size_t NumOfRead = 0;
|
size_t NumOfRead = 0;
|
||||||
@@ -12,8 +13,7 @@ auto StackTracker::rpm(uintptr_t address, size_t readSize)
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
auto StackTracker::LookslikeValidEntry(cs_insn* insn, size_t count) -> bool {
|
auto StackTracker::LookslikeValidEntry(cs_insn* insn, size_t count) -> bool {
|
||||||
if (insn == nullptr || count == 0)
|
if (insn == nullptr || count == 0) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
int threshold_score = 2;
|
int threshold_score = 2;
|
||||||
int score = 0;
|
int score = 0;
|
||||||
@@ -25,39 +25,36 @@ auto StackTracker::LookslikeValidEntry(cs_insn* insn, size_t count) -> bool {
|
|||||||
const cs_insn& inst = insn[i];
|
const cs_insn& inst = insn[i];
|
||||||
|
|
||||||
switch (inst.id) {
|
switch (inst.id) {
|
||||||
case X86_INS_PUSH:
|
case X86_INS_PUSH:
|
||||||
if (strcmp(inst.mnemonic, "push") == 0)
|
if (strcmp(inst.mnemonic, "push") == 0) score++;
|
||||||
|
break;
|
||||||
|
case X86_INS_MOV:
|
||||||
|
if (strstr(inst.op_str, "rbp") != nullptr ||
|
||||||
|
strstr(inst.op_str, "rsp") != nullptr)
|
||||||
|
score++;
|
||||||
|
break;
|
||||||
|
case X86_INS_SUB:
|
||||||
|
case X86_INS_ADD:
|
||||||
|
if (strstr(inst.op_str, "rsp") != nullptr) score++;
|
||||||
|
break;
|
||||||
|
case X86_INS_CALL:
|
||||||
|
score += 1;
|
||||||
|
break;
|
||||||
|
case X86_INS_LEA:
|
||||||
|
if (strstr(inst.op_str, "rip") != nullptr) score++;
|
||||||
|
break;
|
||||||
|
case X86_INS_TEST:
|
||||||
|
case X86_INS_CMP:
|
||||||
|
case X86_INS_JE:
|
||||||
|
case X86_INS_JNE:
|
||||||
|
case X86_INS_JMP:
|
||||||
score++;
|
score++;
|
||||||
break;
|
break;
|
||||||
case X86_INS_MOV:
|
case X86_INS_NOP:
|
||||||
if (strstr(inst.op_str, "rbp") != nullptr || strstr(inst.op_str, "rsp") != nullptr)
|
break; // 忽略
|
||||||
score++;
|
default:
|
||||||
break;
|
if (score == 0) score -= 1; // 杂指令降低一点分数
|
||||||
case X86_INS_SUB:
|
break;
|
||||||
case X86_INS_ADD:
|
|
||||||
if (strstr(inst.op_str, "rsp") != nullptr)
|
|
||||||
score++;
|
|
||||||
break;
|
|
||||||
case X86_INS_CALL:
|
|
||||||
score += 1;
|
|
||||||
break;
|
|
||||||
case X86_INS_LEA:
|
|
||||||
if (strstr(inst.op_str, "rip") != nullptr)
|
|
||||||
score++;
|
|
||||||
break;
|
|
||||||
case X86_INS_TEST:
|
|
||||||
case X86_INS_CMP:
|
|
||||||
case X86_INS_JE:
|
|
||||||
case X86_INS_JNE:
|
|
||||||
case X86_INS_JMP:
|
|
||||||
score++;
|
|
||||||
break;
|
|
||||||
case X86_INS_NOP:
|
|
||||||
break; // 忽略
|
|
||||||
default:
|
|
||||||
if (score == 0)
|
|
||||||
score -= 1; //杂指令降低一点分数
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (score >= threshold_score) {
|
if (score >= threshold_score) {
|
||||||
@@ -66,24 +63,31 @@ auto StackTracker::LookslikeValidEntry(cs_insn* insn, size_t count) -> bool {
|
|||||||
}
|
}
|
||||||
return score >= threshold_score;
|
return score >= threshold_score;
|
||||||
}
|
}
|
||||||
auto StackTracker::TryFindValidDisasm(uint64_t baseAddr, size_t maxOffset) -> bool {
|
auto StackTracker::TryFindValidDisasm(uint64_t baseAddr, size_t maxOffset)
|
||||||
|
-> bool {
|
||||||
for (size_t i = 0; i < maxOffset; ++i) {
|
for (size_t i = 0; i < maxOffset; ++i) {
|
||||||
auto buf = this->rpm(baseAddr + i, this->trackSize);
|
auto buf = this->rpm(baseAddr + i, this->trackSize);
|
||||||
if (buf.size() != this->trackSize) continue;
|
if (buf.size() != this->trackSize) continue;
|
||||||
cs_insn* testInsn = nullptr;
|
cs_insn* testInsn = nullptr;
|
||||||
auto cnt = cs_disasm(this->capstoneHandle,
|
this->disasmCount = cs_disasm(this->capstoneHandle,
|
||||||
reinterpret_cast<const uint8_t*>(buf.data()),
|
reinterpret_cast<const uint8_t*>(buf.data()),
|
||||||
this->trackSize, baseAddr + i, 0, &testInsn);
|
this->trackSize, baseAddr + i, 0, &testInsn);
|
||||||
if (cnt > 0 && LookslikeValidEntry(testInsn, cnt)) {
|
// this->PrintAsm(testInsn);
|
||||||
|
if (this->disasmCount > 0) {
|
||||||
|
this->insn = testInsn;
|
||||||
|
}
|
||||||
|
if (this->disasmCount > 0 && LookslikeValidEntry(testInsn, this->disasmCount)) {
|
||||||
this->baseAddr += i;
|
this->baseAddr += i;
|
||||||
if (this->insn != nullptr) {
|
if (this->insn != nullptr) {
|
||||||
cs_free(this->insn, this->disasmCount);
|
cs_free(this->insn, this->disasmCount);
|
||||||
}
|
}
|
||||||
this->insn = testInsn;
|
for (size_t j = 0; j < this->disasmCount; ++j) {
|
||||||
this->disasmCount = cnt;
|
// this->PrintAsm(&this->insn[j]);
|
||||||
for (size_t j = 0; j < cnt; ++j) {
|
|
||||||
this->insList.push_back(std::make_shared<cs_insn>(this->insn[j]));
|
this->insList.push_back(
|
||||||
|
std::make_shared<cs_insn>(this->insn[j]));
|
||||||
}
|
}
|
||||||
|
this->SuccessReadedBuffer = buf;
|
||||||
this->readSuccess = true;
|
this->readSuccess = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -104,10 +108,14 @@ StackTracker::StackTracker(HANDLE hProcess, uint64_t StartAddress,
|
|||||||
cs_option(capstoneHandle, CS_OPT_SKIPDATA, CS_OPT_ON);
|
cs_option(capstoneHandle, CS_OPT_SKIPDATA, CS_OPT_ON);
|
||||||
/*
|
/*
|
||||||
do {
|
do {
|
||||||
|
// 1.读取
|
||||||
auto bufferArrays = this->rpm(StartAddress, trackSize);
|
auto bufferArrays = this->rpm(StartAddress, trackSize);
|
||||||
if (bufferArrays.size() != trackSize) {
|
if (bufferArrays.size() != trackSize) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// 2. 反过来
|
||||||
|
std::reverse(bufferArrays.begin(), bufferArrays.end());
|
||||||
|
// 3. 这里就是向上的了.指令是对的上的
|
||||||
disasmCount =
|
disasmCount =
|
||||||
cs_disasm(capstoneHandle,
|
cs_disasm(capstoneHandle,
|
||||||
reinterpret_cast<const uint8_t*>(bufferArrays.data()),
|
reinterpret_cast<const uint8_t*>(bufferArrays.data()),
|
||||||
@@ -115,8 +123,10 @@ StackTracker::StackTracker(HANDLE hProcess, uint64_t StartAddress,
|
|||||||
if (disasmCount == 0) {
|
if (disasmCount == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (size_t index = 0; index < disasmCount; index++) {
|
// 4. 再反过来
|
||||||
|
for (size_t index = disasmCount; index > 0; index--) {
|
||||||
const auto code = insn[index];
|
const auto code = insn[index];
|
||||||
|
this->PrintAsm(&code);
|
||||||
this->insList.push_back(std::make_shared<cs_insn>(code));
|
this->insList.push_back(std::make_shared<cs_insn>(code));
|
||||||
}
|
}
|
||||||
this->readSuccess = true;
|
this->readSuccess = true;
|
||||||
@@ -135,7 +145,7 @@ auto StackTracker::getNextIns() -> std::shared_ptr<cs_insn> {
|
|||||||
}
|
}
|
||||||
StackTracker::~StackTracker() {
|
StackTracker::~StackTracker() {
|
||||||
if (insn) {
|
if (insn) {
|
||||||
cs_free(insn, disasmCount);
|
//cs_free(insn, disasmCount);
|
||||||
cs_close(&capstoneHandle);
|
cs_close(&capstoneHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,16 +178,26 @@ auto StackTracker::matchCode(
|
|||||||
inline auto StackTracker::is_call(cs_insn* ins) -> bool {
|
inline auto StackTracker::is_call(cs_insn* ins) -> bool {
|
||||||
return ins->id == X86_INS_CALL;
|
return ins->id == X86_INS_CALL;
|
||||||
}
|
}
|
||||||
|
auto StackTracker::PrintAsm() -> void {
|
||||||
|
for (size_t j = 0; j < this->disasmCount; ++j) {
|
||||||
|
for (int x = 0; x < this->insn[j].size; x++) {
|
||||||
|
printf("%02X ", this->insn[j].bytes[x]);
|
||||||
|
}
|
||||||
|
printf("0x%llx :\t\t%s\t%s\t\n", this->insn[j].address,
|
||||||
|
this->insn[j].mnemonic, this->insn[j].op_str);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
auto StackTracker::CalcNextJmpAddress() -> std::pair<bool, uint64_t> {
|
auto StackTracker::CalcNextJmpAddress() -> std::pair<bool, uint64_t> {
|
||||||
if (this->readSuccess == false) {
|
if (this->readSuccess == false) {
|
||||||
return {false , 0};
|
return {false, 0};
|
||||||
}
|
}
|
||||||
this->feature = _features::kNonCallOnly;
|
this->feature = _features::kNonCallOnly;
|
||||||
|
|
||||||
uint64_t callAddress = 0;
|
uint64_t callAddress = 0;
|
||||||
auto isMatchCall = matchCode(
|
auto isMatchCall = matchCode(
|
||||||
[&](cs_insn* instruction) {
|
[&](cs_insn* instruction) {
|
||||||
|
|
||||||
if (instruction->id != X86_INS_CALL) {
|
if (instruction->id != X86_INS_CALL) {
|
||||||
if (instruction->id == X86_INS_SYSCALL) {
|
if (instruction->id == X86_INS_SYSCALL) {
|
||||||
this->feature = _features::kSyscall;
|
this->feature = _features::kSyscall;
|
||||||
@@ -192,35 +212,39 @@ auto StackTracker::CalcNextJmpAddress() -> std::pair<bool, uint64_t> {
|
|||||||
callAddress =
|
callAddress =
|
||||||
instruction->address + instruction->size + operand.imm;
|
instruction->address + instruction->size + operand.imm;
|
||||||
return true;
|
return true;
|
||||||
}
|
} else if (operand.type == X86_OP_MEM) {
|
||||||
else if (operand.type == X86_OP_MEM) {
|
|
||||||
const x86_op_mem& mem = operand.mem;
|
const x86_op_mem& mem = operand.mem;
|
||||||
// 我们只处理可以静态计算的 RIP 相对寻址
|
// 我们只处理可以静态计算的 RIP 相对寻址
|
||||||
if (mem.base == X86_REG_RIP) {
|
if (mem.base == X86_REG_RIP) {
|
||||||
uint64_t pointerAddress = instruction->address + instruction->size + mem.disp;
|
uint64_t pointerAddress =
|
||||||
|
instruction->address + instruction->size + mem.disp;
|
||||||
size_t pointerSize = this->isWow64 ? 4 : 8;
|
size_t pointerSize = this->isWow64 ? 4 : 8;
|
||||||
std::vector<char> pointerBuffer = this->rpm(pointerAddress, pointerSize);
|
std::vector<char> pointerBuffer =
|
||||||
|
this->rpm(pointerAddress, pointerSize);
|
||||||
if (pointerBuffer.empty()) {
|
if (pointerBuffer.empty()) {
|
||||||
std::cerr << "Failed to read pointer at 0x" << std::hex << pointerAddress << std::endl;
|
std::cerr << "Failed to read pointer at 0x" << std::hex
|
||||||
|
<< pointerAddress << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (pointerSize == 8) {
|
if (pointerSize == 8) {
|
||||||
callAddress = *reinterpret_cast<uint64_t*>(pointerBuffer.data());
|
callAddress =
|
||||||
}
|
*reinterpret_cast<uint64_t*>(pointerBuffer.data());
|
||||||
else { // 32位
|
} else { // 32位
|
||||||
callAddress = *reinterpret_cast<uint32_t*>(pointerBuffer.data());
|
callAddress =
|
||||||
|
*reinterpret_cast<uint32_t*>(pointerBuffer.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
//std::cout << "Found RIP-relative call at 0x" << std::hex << instruction->address
|
// std::cout << "Found RIP-relative call at 0x" << std::hex
|
||||||
// << ". Pointer at 0x" << pointerAddress
|
// << instruction->address
|
||||||
// << ". Final Target: 0x" << callAddress << std::endl;
|
// << ". Pointer at 0x" << pointerAddress
|
||||||
|
// << ". Final Target: 0x" << callAddress << std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//std::cout << "Skipping non-RIP-relative memory call at 0x" << std::hex << instruction->address << std::endl;
|
// std::cout << "Skipping non-RIP-relative memory call at 0x" <<
|
||||||
|
// std::hex << instruction->address << std::endl;
|
||||||
this->feature = _features::kCallRip;
|
this->feature = _features::kCallRip;
|
||||||
return false;
|
return false;
|
||||||
}
|
} else if (operand.type == X86_OP_REG) {
|
||||||
else if (operand.type == X86_OP_REG) {
|
|
||||||
this->feature = _features::kCallReg;
|
this->feature = _features::kCallReg;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "head.h"
|
#include "head.h"
|
||||||
enum class _features {
|
enum class _features { kNone, kNonCallOnly, kCallRip, kCallReg, kSyscall };
|
||||||
kNone,
|
|
||||||
kNonCallOnly,
|
|
||||||
kCallRip,
|
|
||||||
kCallReg,
|
|
||||||
kSyscall
|
|
||||||
};
|
|
||||||
class StackTracker {
|
class StackTracker {
|
||||||
private:
|
private:
|
||||||
bool readSuccess;
|
bool readSuccess;
|
||||||
bool isWow64;
|
bool isWow64;
|
||||||
HANDLE targetProcess;
|
HANDLE targetProcess;
|
||||||
std::vector<std::shared_ptr<cs_insn>> insList;
|
std::vector<std::shared_ptr<cs_insn>> insList;
|
||||||
cs_insn* insn = nullptr;
|
|
||||||
size_t disasmCount = 0;
|
|
||||||
csh capstoneHandle;
|
csh capstoneHandle;
|
||||||
uint64_t ins_ip, ins_ip_address, baseAddr, trackSize;
|
uint64_t ins_ip, ins_ip_address, baseAddr, trackSize;
|
||||||
auto getNextIns() -> std::shared_ptr<cs_insn>;
|
auto getNextIns() -> std::shared_ptr<cs_insn>;
|
||||||
auto LookslikeValidEntry(cs_insn* insn, size_t count) -> bool;
|
auto LookslikeValidEntry(cs_insn* insn, size_t count) -> bool;
|
||||||
inline auto is_call(cs_insn* ins) -> bool;
|
inline auto is_call(cs_insn* ins) -> bool;
|
||||||
|
|
||||||
template <typename T, typename B>
|
template <typename T, typename B>
|
||||||
auto matchCode(T match_fn, B process_fn,
|
auto matchCode(T match_fn, B process_fn,
|
||||||
std::optional<uint32_t> num_operands,
|
std::optional<uint32_t> num_operands,
|
||||||
@@ -27,13 +20,15 @@ class StackTracker {
|
|||||||
-> bool;
|
-> bool;
|
||||||
auto rpm(uintptr_t address, size_t readSize) -> std::vector<char>;
|
auto rpm(uintptr_t address, size_t readSize) -> std::vector<char>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
cs_insn* insn = nullptr;
|
||||||
|
size_t disasmCount = 0;
|
||||||
|
std::vector<char> SuccessReadedBuffer;
|
||||||
_features feature;
|
_features feature;
|
||||||
StackTracker(HANDLE hProcess, uint64_t StartAddress, size_t trackSize,
|
StackTracker(HANDLE hProcess, uint64_t StartAddress, size_t trackSize,
|
||||||
bool isX32);
|
bool isX32);
|
||||||
~StackTracker();
|
~StackTracker();
|
||||||
|
auto PrintAsm() -> void;
|
||||||
auto CalcNextJmpAddress() -> std::pair<bool, uint64_t>;
|
auto CalcNextJmpAddress() -> std::pair<bool, uint64_t>;
|
||||||
auto TryFindValidDisasm(uint64_t baseAddr, size_t maxOffset) -> bool;
|
auto TryFindValidDisasm(uint64_t baseAddr, size_t maxOffset) -> bool;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,37 @@
|
|||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
// 71 A3 52 10 47 AE A0
|
||||||
|
#define INRANGE(x, a, b) (x >= a && x <= b)
|
||||||
|
#define getBits(x) \
|
||||||
|
(INRANGE((x & (~0x20)), 'A', 'F') ? ((x & (~0x20)) - 'A' + 0xa) \
|
||||||
|
: (INRANGE(x, '0', '9') ? x - '0' : 0))
|
||||||
|
#define getByte(x) (getBits(x[0]) << 4 | getBits(x[1]))
|
||||||
namespace Tools {
|
namespace Tools {
|
||||||
|
auto FindPatternInMemory(uint64_t StartAddress, size_t MemorySize,
|
||||||
|
std::string pattern) -> uint64_t {
|
||||||
|
const char* pat = pattern.c_str();
|
||||||
|
uint64_t firstMatch = 0;
|
||||||
|
uint64_t rangeStart = StartAddress;
|
||||||
|
uint64_t rangeEnd = rangeStart + MemorySize;
|
||||||
|
for (uint64_t pCur = rangeStart; pCur < rangeEnd; pCur++) {
|
||||||
|
if (!*pat) return firstMatch;
|
||||||
|
|
||||||
|
if (*(PBYTE)pat == '\?' || *(BYTE*)pCur == getByte(pat)) {
|
||||||
|
if (!firstMatch) firstMatch = pCur;
|
||||||
|
|
||||||
|
if (!pat[2]) return firstMatch;
|
||||||
|
|
||||||
|
if (*(PWORD)pat == '\?\?' || *(PBYTE)pat != '\?')
|
||||||
|
pat += 3;
|
||||||
|
|
||||||
|
else
|
||||||
|
pat += 2; // one ?
|
||||||
|
} else {
|
||||||
|
pat = pattern.c_str();
|
||||||
|
firstMatch = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
auto Is64BitPorcess(HANDLE hProcess) -> bool {
|
auto Is64BitPorcess(HANDLE hProcess) -> bool {
|
||||||
BOOL bIsWow64 = false;
|
BOOL bIsWow64 = false;
|
||||||
IsWow64Process(hProcess, &bIsWow64);
|
IsWow64Process(hProcess, &bIsWow64);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "head.h"
|
#include "head.h"
|
||||||
namespace Tools {
|
namespace Tools {
|
||||||
auto EnableDebugPrivilege(bool bEnable) -> bool;
|
auto EnableDebugPrivilege(bool bEnable) -> bool;
|
||||||
auto Is64BitPorcess(HANDLE hProcess) -> bool;
|
auto Is64BitPorcess(HANDLE hProcess) -> bool;
|
||||||
};
|
auto FindPatternInMemory(uint64_t StartAddress, size_t MemorySize,
|
||||||
|
std::string pattern) -> uint64_t;
|
||||||
|
}; // namespace Tools
|
||||||
|
|||||||
Reference in New Issue
Block a user