Created
February 28, 2023 16:18
-
-
Save archercreat/4a4803a8d4f6d3c5a07818790a37e484 to your computer and use it in GitHub Desktop.
VMProtect virtual machine tracer using Intel pin.
This file contains hidden or 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
#include "pin.h" | |
#include <iostream> | |
static uint64_t last_address = 0ull; | |
static uint32_t last_opcode = 0ul; | |
static constexpr auto vm_section = ".vmp1"; | |
std::string to_hex(uint64_t value) | |
{ | |
std::stringstream ss; | |
ss << "0x" << std::hex << value; | |
return ss.str(); | |
} | |
bool in_main_module(uint64_t address) | |
{ | |
PIN_LockClient(); | |
bool exe = false; | |
if (auto img = IMG_FindByAddress(address); IMG_Valid(img)) | |
{ | |
exe = IMG_IsMainExecutable(img); | |
} | |
PIN_UnlockClient(); | |
return exe; | |
} | |
bool in_vm_section(uint64_t address) | |
{ | |
PIN_LockClient(); | |
bool vm = false; | |
if (auto rtn = RTN_FindByAddress(address); RTN_Valid(rtn)) | |
{ | |
if (auto sec = RTN_Sec(rtn); SEC_Valid(sec)) | |
{ | |
vm = SEC_Name(sec).find(vm_section) != std::string::npos; | |
} | |
} | |
PIN_UnlockClient(); | |
return vm; | |
} | |
void handle_call(uint64_t rip, uint32_t opcode) | |
{ | |
// If we found external call. | |
// | |
PIN_LockClient(); | |
if (in_vm_section(last_address) && !in_main_module(rip)) | |
{ | |
if (auto rtn = RTN_FindByAddress(rip); RTN_Valid(rtn)) | |
{ | |
std::printf("\t0x%llx %s\n", last_address, RTN_Name(rtn).c_str()); | |
} | |
else | |
{ | |
std::printf("\t0x%llx 0x%llx\n", last_address, rip); | |
} | |
} | |
else if (in_vm_section(last_address) && last_opcode == XED_ICLASS_CALL_NEAR) | |
{ | |
std::printf("\t0x%llx 0x%llx\n", last_address, rip); | |
} | |
last_address = rip; | |
last_opcode = opcode; | |
PIN_UnlockClient(); | |
} | |
void handle_popfq(void* rsp) | |
{ | |
uint64_t top{}; | |
if (PIN_SafeCopy(&top, rsp, sizeof(top)) == sizeof(top)) | |
{ | |
// Discard trap flag bit. | |
// | |
top &= ~0x100; | |
PIN_SafeCopy(rsp, &top, sizeof(top)); | |
} | |
} | |
void instruction_cb(INS ins, void*) | |
{ | |
const auto rip = INS_Address(ins); | |
const auto op = INS_Opcode(ins); | |
if (op == XED_ICLASS_PUSH && INS_OperandIsImmediate(ins, 0) && in_vm_section(rip)) | |
{ | |
INS_InsertCall( | |
ins, IPOINT_BEFORE, (AFUNPTR)+[](uint64_t rip) { std::printf("vm:\n\tentry: 0x%llx\n", rip); }, | |
IARG_INST_PTR, | |
IARG_END | |
); | |
} | |
if (op == XED_ICLASS_POPFQ) | |
{ | |
INS_InsertCall( | |
ins, IPOINT_BEFORE, (AFUNPTR)handle_popfq, | |
IARG_REG_VALUE, REG_RSP, | |
IARG_END | |
); | |
} | |
else if (op == XED_ICLASS_CPUID) | |
{ | |
INS_InsertCall( | |
ins, IPOINT_BEFORE, | |
(AFUNPTR)+[](uint64_t rip) { if (in_vm_section(rip)) std::printf("\t0x%llx cpuid\n", rip); }, | |
IARG_INST_PTR, | |
IARG_END | |
); | |
} | |
else if (op == XED_ICLASS_RDTSC) | |
{ | |
INS_InsertCall( | |
ins, IPOINT_BEFORE, | |
(AFUNPTR)+[](uint64_t rip) { if (in_vm_section(rip)) std::printf("\t0x%llx rdtsc\n", rip); }, | |
IARG_INST_PTR, | |
IARG_END | |
); | |
} | |
INS_InsertCall( | |
ins, IPOINT_BEFORE, (AFUNPTR)handle_call, | |
IARG_INST_PTR, | |
IARG_UINT32, op, | |
IARG_END | |
); | |
} | |
void image_load_cb(IMG img, void*) | |
{ | |
std::printf("Loaded: 0x%llx %s\n", IMG_LowAddress(img), IMG_Name(img).c_str()); | |
} | |
void syscall_cb(uint32_t tid, CONTEXT* context, SYSCALL_STANDARD std, void*) | |
{ | |
auto rip = PIN_GetContextReg(context, REG_INST_PTR); | |
auto eax = PIN_GetSyscallNumber(context, std); | |
auto arg0 = PIN_GetSyscallArgument(context, std, 0); | |
auto arg1 = PIN_GetSyscallArgument(context, std, 1); | |
auto arg2 = PIN_GetSyscallArgument(context, std, 2); | |
auto arg3 = PIN_GetSyscallArgument(context, std, 3); | |
if (in_main_module(rip)) | |
{ | |
std::printf("0x%llx %lld(0x%llx, 0x%llx, 0x%llx, 0x%llx)\n", rip, eax, arg0, arg1, arg2, arg3); | |
} | |
} | |
void fini(int32_t code, void*) | |
{ | |
} | |
int main(int argc, char* argv[]) | |
{ | |
// Initialize symbol processing. | |
// | |
PIN_InitSymbols(); | |
// Initialize pin. | |
// | |
if (PIN_Init(argc, argv)) | |
{ | |
return -1; | |
} | |
PIN_AddSyscallEntryFunction(syscall_cb, nullptr); | |
PIN_AddFiniFunction(fini, nullptr); | |
INS_AddInstrumentFunction(instruction_cb, nullptr); | |
IMG_AddInstrumentFunction(image_load_cb, nullptr); | |
PIN_StartProgram(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment