-
// test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
PROCESS_INFORMATION _agentProcInfo;
BOOL StartAgent(void)
{
STARTUPINFO startup_info;
DWORD32 ret;
WCHAR exe[MAX_PATH] = L"notepad.exe";
//launch agent
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
ZeroMemory(&_agentProcInfo, sizeof(_agentProcInfo));
startup_info.cb = sizeof(startup_info);
startup_info.lpDesktop = const_cast(TEXT("Winsta0\\default"));
ret = CreateProcess(NULL, exe, NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS, NULL, NULL,
&startup_info, &_agentProcInfo);
return ret;
}
enum TerminationStatus {
TERMINATION_STATUS_NORMAL_TERMINATION, // zero exit status
TERMINATION_STATUS_ABNORMAL_TERMINATION, // non-zero exit status
TERMINATION_STATUS_PROCESS_WAS_KILLED, // e.g. SIGKILL or task manager kill
TERMINATION_STATUS_PROCESS_CRASHED, // e.g. Segmentation fault
TERMINATION_STATUS_STILL_RUNNING, // child hasn't exited yet
TERMINATION_STATUS_MAX_ENUM
};
// Exit codes with special meanings on Windows.
const DWORD kNormalTerminationExitCode = 0;
const DWORD kDebuggerInactiveExitCode = 0xC0000354;
const DWORD kKeyboardInterruptExitCode = 0xC000013A;
const DWORD kDebuggerTerminatedExitCode = 0x40010004;
// This exit code is used by the Windows task manager when it kills a
// process. It's value is obviously not that unique, and it's
// surprising to me that the task manager uses this value, but it
// seems to be common practice on Windows to test for it as an
// indication that the task manager has killed something if the
// process goes away.
const DWORD kProcessKilledExitCode = 1;
void Check()
{
TerminationStatus status;
DWORD tmp_exit_code;
CloseHandle(_agentProcInfo.hProcess );
//CloseHandle(_agentProcInfo.hProcess );
/*
我最近调试程序才发觉,CloseHandle这个函数的一个怪异的行为。我突然想到可以利用这个行为来欺骗或者对抗调试器。
这个怪异的行为是这样的,调用CloseHandle释放一个无效句柄,如果进程在调试器之外,那么函数返回FALSE,而GetLastError得到ERROR_INVALID_HANDLE;但是如果进程在调试器内,那么系统将抛出异常C0000008H。
一、首先说如何得到一个无效句柄呢?
方法一:一个句柄释放多次次
这个方法看似没问题,但实际有很大的隐患。因为新创建的内核对象是总是寻找句柄表的空白记录,因此有可能存在已经释放过的句柄又被利用,而这时再次释放会很不安全。
方法二:硬编码一个足够大的句柄值
用procexp.exe看一下就会发现进程里的句柄值很少大于1000h,因此赌一下也是可以的
方法三:释放一个不可关闭的句柄
这个我认为是最安全的一种方法,首先自己随便调用一个CreateXXX得到一个句柄h1,再调用SetHandleInformation将句柄h1设为不可关闭的,最后调用CloseHandle释放它就行了
*/
if (!GetExitCodeProcess(_agentProcInfo.hProcess, &tmp_exit_code))
{
printf("Error");
}
switch (tmp_exit_code)
{
case kNormalTerminationExitCode:
status = TERMINATION_STATUS_NORMAL_TERMINATION;
break;
case kDebuggerInactiveExitCode: // STATUS_DEBUGGER_INACTIVE.
case kKeyboardInterruptExitCode: // Control-C/end session.
case kDebuggerTerminatedExitCode: // Debugger terminated process.
case kProcessKilledExitCode: // Task manager kill.
status = TERMINATION_STATUS_PROCESS_WAS_KILLED;
break;
default:
// All other exit codes indicate crashes.
status = TERMINATION_STATUS_PROCESS_CRASHED;
break;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
StartAgent();
Check();
return 0;
}
-
阅读(1945) | 评论(0) | 转发(0) |