之前问过几次,没什么人解答,后来还是自己抽空研究了一下,win32 runtime编译问题。
有不少人按照教程编译,无论是vs2010 vs2008 ,win32runtime编译,生成Inc文件后,加密出来的vmp程序都无法跑。
我之前也提问过,当时时间太仓促 ,没空研究一下。最近回头又碰到了一次,还是自己抽空看了一下。
实际上确实是编译优化的影响。 (当然按文章修改后,还是用vs2010编译 release 32 。其他的我没试过是否OK)
在loader.cc中 有连续的两个 tNtQueryInformationProcess
- if (NT_SUCCESS(reinterpret_cast<tNtQueryInformationProcess *>(syscall | sc_query_information_process)(process, ProcessDebugPort, &debug_object, sizeof(debug_object), NULL)) && debug_object != 0) {
- LoaderMessage(mtDebuggerFound);
- return LOADER_ERROR;
- }
- debug_object = 0;
- if (NT_SUCCESS(reinterpret_cast<tNtQueryInformationProcess *>(syscall | sc_query_information
_process)(process, ProcessDebugObjectHandle, &debug_object, sizeof(debug_object), reinterpret_cast<PULONG>(&debug_object)))
- || debug_object == 0) {
- LoaderMessage(mtDebuggerFound);
- return LOADER_ERROR;即使在vs2010/2008下,由于优化被编译成了
mov eax,fake_func_addr
mov [ebp+xxx] ,eax
....
call [ebp+xxx] 这样的形式。
这部分runtime地址在最后的代码中是需要重新填充真实的地址的。
在intel.cc
IntelFunction::ReadFromBuffer
中 有对这个call 进行替换。
vmp期望遇到
MOV EAX,0XFACE_ID
CALL EAX 这种形式
遇到编译的
call [ebp+xxx]识别错误就不再替换了。导致后续出错
else if (command->type() == cmCall) {
if (command->operand(0) == operand) {
command->Init(cmSyscall, command->operand(0));
/*
因为编译器优化的影响 call fake_syscall 。导致IntelFunction::ReadFromBuffer 识别这个 FACE_SYSCALL 有问题,IntelFunction::ReadFromBuffer 只能识别 reg =face_syscall|funcid + call reg 这种。编译器优化了连续两个这样的call 变成了 [mem]=face_syscall|funcid call [mem] 。没有识别出来。
*/
static int fuckingcall =0;
printf("found FACE_SYSCALL call %d at last syscall | \n",fuckingcall++);
command->CompileToNative();
command->include_option(roNoNative);
syscall_found = true;
}
if (operand.type != otRegistr || operand.registr == regEAX)
is_end = true;
}最终导致这两个地址上的call 地址没有被替换。
解决方案
1 调整代码逻辑,将两个连续的call ntquery 拆开。避免连续的两个 tNtQueryInformationProcess 被优化错误。(懒得折腾了,我才用的这种方式)

if (data.options() & LOADER_OPTION_CHECK_DEBUGGER) {
if(sc_query_information_process){
HANDLE debug_object = 0;
{
if (NT_SUCCESS(reinterpret_cast<tNtQueryInformationProcess *>(syscall | sc_query_information_process)(process, ProcessDebugObjectHandle, &debug_object, sizeof(debug_object), reinterpret_cast<PULONG>(&debug_object)))
|| debug_object == 0) {
LoaderMessage(mtDebuggerFound);
return LOADER_ERROR;
}
}
}
if (peb->BeingDebugged) {
LoaderMessage(mtDebuggerFound);
return LOADER_ERROR;
}
if (sc_query_information_process) {
// disable InstrumentationCallback
if (peb->OSMajorVersion > 6) {
// Windows 10
PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION info;
info.Version = 0;
info.Reserved = 0;
info.Callback = NULL;
if (tNtSetInformationProcess *set_information_process = reinterpret_cast<tNtSetInformationProcess *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_SET_INFORMATION_PROCESS_NAME), true)))
set_information_process(process, ProcessInstrumentationCallback, &info, sizeof(info));
}
HANDLE debug_object;
/*
syscall|sc_query_information_process
*/
{
if (NT_SUCCESS(reinterpret_cast<tNtQueryInformationProcess *>(syscall | sc_query_information_process)(process, ProcessDebugPort, &debug_object, sizeof(debug_object), NULL)) && debug_object != 0) {
LoaderMessage(mtDebuggerFound);
return LOADER_ERROR;
}
}
} else if (tNtQueryInformationProcess *query_information_process = reinterpret_cast<tNtQueryInformationProcess *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_QUERY_INFORMATION_PROCESS_NAME), true))) {
HANDLE debug_object;
if (NT_SUCCESS(query_information_process(process, ProcessDebugPort, &debug_object, sizeof(debug_object), NULL)) && debug_object != 0) {
LoaderMessage(mtDebuggerFound);
return LOADER_ERROR;
}
if (NT_SUCCESS(query_information_process(process, ProcessDebugObjectHandle, &debug_object, sizeof(debug_object), NULL))) {
LoaderMessage(mtDebuggerFound);
return LOADER_ERROR;
}
}
// disable debugger
if (sc_set_information_thread)
reinterpret_cast<tNtSetInformationThread *>(syscall | sc_set_information_thread)(thread, ThreadHideFromDebugger, NULL, 0);
else if (tNtSetInformationThread *set_information_thread = reinterpret_cast<tNtSetInformationThread *>(LoaderGetProcAddress(ntdll, reinterpret_cast<const char *>(FACE_NT_SET_INFORMATION_THREAD_NAME), true)))
set_information_thread(thread, ThreadHideFromDebugger, NULL, 0);
}
2 多搞一个asm obj,通过汇编硬编码成call eax的形式。避免换编译器出问题。最优。
最后于 4小时前
被IamHuskar编辑
,原因: