本帖最后由 舒默哦 于 2021-4-3 15:30 编辑
应用层
NtQueryInformationProcess函数,微软给出的一些信息:
https://docs.microsoft.com/zh-cn/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess?redirectedfrom=MSDN
这个函数的功能是检索指定进程的信息(Retrieves information about the specified process.)。
[C] 纯文本查看 复制代码
__kernel_entry NTSTATUS NtQueryInformationProcess(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
PROCESSINFOCLASS 是一个枚举类型:
[C] 纯文本查看 复制代码
typedef enum _PROCESSINFOCLASS {
ProcessBasicInformation = 0,
ProcessDebugPort = 7,
ProcessWow64Information = 26,
ProcessImageFileName = 27,
ProcessBreakOnTermination = 29
} PROCESSINFOCLASS;
与调试相关的只有ProcessDebugPort,微软列出了CheckRemoteDebuggerPresent()和 IsDebuggerPresent()与NtQueryInformationProcess相关。
CheckRemoteDebuggerPresent最终会调用NtQueryInformationProcess:
IsDebuggerPresent()并不会调用NtQueryInformationProcess,而是直接在PEB中取值返回。
[C] 纯文本查看 复制代码
int main()
{
IsDebuggerPresent();
cout << "正常退出" << endl;
system("pause");
}
在函数入口之前,NtQueryInformationProcess会被调用多次,rdx分别为 0x24、0x17 ,在打印函数之后会被调用一次,rdx为0x0。
中间没有调用NtQueryInformationProcess,表明在window10 64位系统中IsDebuggerPresent()的操作与NtQueryInformationProcess函数没有直接关系。
内核
在逆向工程核心原理这本书中,NtQueryInformationProcess用于反调试的协议号有三个0x7、0x1E、0x1F,在微软提供的PROCESSINFOCLASS枚举类型中没有0x1E、0x1F,那作者怎么知道的呢?我也参考了一些帖子,好像没有分析内核中的NtQueryInformationProcess。作者肯定分析了内核中的NtQueryInformationProcess,并且还测试了其他的协议号,得出的结论是0x7、0x1E、0x1F三个协议号可以用于反调试。NtQueryInformationProcess这个函数非常长,
在IDA中按下F5后,代码也有2000多行,其中有很多协议号,照葫芦画瓢,接下来直接定位分析0x7、0x1E、0x1F这三个协议号。
内核中NtQueryInformationProcess开头部分:
0x7
ProcessInformationClass为0x7时:
在CheckRemoteDebuggerPresent函数中,没有直接利用返回值,而是通过返回和0作比较,利用setne指令取反,得到的布尔值传回给输出参数。
0x1E
ProcessInformationClass为0x1E:
跟进DbgkOpenProcessDebugPort函数:
跟进ObOpenObjectByPointer最中会调用ObpCreateHandle创建一个句柄:
小结:没有调试时,输出参数是0,返回值为:0xffffffffc0000353(0xC0000353错误码STATUS_PORT_NOT_SET表示的是端口号未设置)。
调试时,输出参数是一个句柄,返回值为0。
[C] 纯文本查看 复制代码
参考代码:
#include <winternl.h>
typedef NTSTATUS(__stdcall* NTQUERYINFORMATIONPROCESS)(
HANDLE ProcessHandle,
DWORD ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG_PTR ReturnLength
);
NTQUERYINFORMATIONPROCESS ntQueryInformationProcess;
int main()
{
ULONG_PTR debugPort = 0;
HMODULE hModule = LoadLibrary("ntdll.dll");
ntQueryInformationProcess =
(NTQUERYINFORMATIONPROCESS)GetProcAddress(hModule, "NtQueryInformationProcess");
//注意第四个参数的大小为8,在上面内核代码有个比较如果不为8,直接返回0xc0000004的错误。
ULONG_PTR rets = ntQueryInformationProcess(GetCurrentProcess(), 0x1E, &debugPort, sizeof(debugPort), NULL);
printf("debugPort:%d ntQueryInformationProcess返回值:%llx\n", debugPort, rets);
cout << "正常退出" << endl;
system("pause");
}
如果第四个参数(ProcessInformationLength)不为8,执行流程如下:
最终返回:
0x1F
当ProcessInformationClass为0x1F时:
打开wrk找到ps.h查找_EPROCESS结构体,flags标志的第一位和第二位与调试有关,这儿检测的是第二位。
Don't inherit debug port(翻译:不继承调试端口)。所以没有调试时返回1,有调试则返回0。
|