前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、反调试
PEB相关
BegingDebugged标记位可以使用FS寄存器访问到,也可以使用API函数IsDebuggerpressent()检查,如果其值为1则证明本进程处于被调式状态
#include <stdio.h>
#include <Windows.h>
bool PEB_BegingDebugged()
{
bool BegingDebugged = false;
_asm
{
MOV EAX, DWORD PTR FS : [0X30] ;
MOV AL, BYTE PTR DS : [EAX + 0X02] ;
MOV BegingDebugged, AL;
}
return BegingDebugged;
}
int main()
{
bool Ret = PEB_BegingDebugged();
if (Ret == false)
{
printf("啥事没有");
}
else
{
printf("有危险,快跑!!!");
}
system("pause");
return 0;
}
NtQueryinformationProcess相关
**NtQueryinformationProcess是一个可以同时在R0及R3运行的函数,它的主要作用是查看进程相关的各种信息
根据想要查看的信息类型不同,我们给它的第二个参数Process Information Class传递的值也不同,根据Process Information Class的类别可知,此函数可以查看大概60余种进程相关的信息
ProcessDebugPort可以获取目标进程的调试端口,如果目标进程未出与调试状态,此端口为0,否则为0xFFFFFFFF**
#include <Windows.h>
#include <stdio.h>
#include <winternl.h>
#pragma comment(lib,"ntdll.lib")
bool NQIP_ProessDebugPort()
{
//ProcessDebugPort可以获取目标进程的调试端口,如果目标进程未出与调试状态,此端口为0,否则为0xFFFFFFFF
int nDebugPort = 0;
NtQueryInformationProcess(
GetCurrentProcess(),
ProcessDebugPort,
&nDebugPort,
sizeof(nDebugPort),
NULL);
return nDebugPort == 0xFFFFFFFF ? true : false;
}
int main()
{
bool Ret = NQIP_ProessDebugPort();
if (Ret == true)
{
printf("有危险\n");
}
else
{
printf("啦啦啦啦");
}
system("pause");
return 0;
}
*ProcessDebugObjectHandle可以获取目标进程的调试对象句柄,如果未处于调试状态则获取的值为NULL
#include <Windows.h>
#include <stdio.h>
#include <winternl.h>
#pragma comment(lib,"ntdll.lib")
bool NQIP_ProcessDebugObjectHandle()
{
HANDLE hPorcessDebugObjecthandle = 0;
//ProcessDebugObjectHandle可以获取目标进程的调试对象句柄,如果未处于调试状态则获取值为NULL
NtQueryInformationProcess(
GetCurrentProcess(), //目标进程句柄
(PROCESSINFOCLASS)0x1E, //查询信息类型
&hPorcessDebugObjecthandle, //输出查询信息
sizeof(hPorcessDebugObjecthandle), //输出查询类型大小
NULL //实际返回大小
);
return (hPorcessDebugObjecthandle == 0) ? true:false;
}
int main()
{
bool Ret = NQIP_ProcessDebugObjectHandle();
if (Ret == true)
{
printf("啦啦啦啦啦啦啦");
}
else
{
printf("有危险,快跑!!!!");
}
system("pause");
return 0;
processDebugFlag可以获取目标进程的调试标记,如果处于调试状态其值为0,否则为1
#include <Windows.h>
#include <stdio.h>
#include <winternl.h>
#pragma comment(lib,"ntdll.lib")
bool NQLP_ProcessDebugFla()
{
//processDebugFlag可以获取目标进程的调试标记,如果处于调试状态其值为0,否则为1
BOOL bProcessDebugFlag = 0;
NtQueryInformationProcess(
GetCurrentProcess(), //目标进程句柄
(PROCESSINFOCLASS)0x1F, //查询信息类型
&bProcessDebugFlag, //输出查询信息
sizeof(bProcessDebugFlag), //查询类型大小
NULL //实际返回类型大小
);
return bProcessDebugFlag ? true : false;
}
int main()
{
bool Ret = NQLP_ProcessDebugFla();
if (Ret == true)
{
printf("啥事没有~啦啦啦啦啦");
}
else
{
printf("正在被调试,赶紧跑!!!");
}
system("pause");
return 0;
}
ProcessBasicInformation 可以获取指定进程的父进程PID,我们可以将其与Explorer.exe的PID进行对比,如果不匹配则证明此进程不是被双击运行的
#include <Windows.h>
#include <stdio.h>
#include <winternl.h>
#pragma comment(lib,"ntdll.lib")
bool NQLP_CheckParentProcess()
{
//ProcessBasicInformation 可以获取指定进程的父进程PID,我们可以将其与Explorer.exe的PID进行对比,如果不匹配则证明此进程不是被双击运行的
struct PROCESS_BASE_INFORMATION {
ULONG ExitStatus; //进程返回码
PPEB PebBaseAddress; //PEB地址
ULONG AffinityMask; //CPU亲和性掩码
LONG BasePriority; //基本优先级
ULONG uNIQUEpROCEId; //本进程ID
ULONG InheritedFromUniqueProcessId;//父进程PID
}stcProcInfo;
NtQueryInformationProcess(
GetCurrentProcess(),
ProcessBasicInformation, &stcProcInfo,
sizeof(stcProcInfo), NULL);
DWORD ExPlorerPID = 0;
DWORD CurrentPID = stcProcInfo.InheritedFromUniqueProcessId;
GetWindowThreadProcessId(FindWindow(L"Progman",NULL),&ExPlorerPID);
return ExPlorerPID == CurrentPID ? false : true;
}
int main()
{
bool Ret = NQLP_CheckParentProcess();
if (Ret == true)
{
printf("有危险,快跑!!!");
}
else
{
printf("啦啦啦啦啦~啥事没有!!!!");
}
system("pause");
return 0;
}
NtQuerySysteminformation()函数获取当前系统是否开启调试模式
#include <Windows.h>
#include <stdio.h>
#include <winternl.h>
#pragma comment(lib,"ntdll.lib")
//
typedef enum THREAD_INFO_CLASS {
ThreadHideFromDebugger = 17
};
typedef NTSTATUS(NTAPI* ZW_SET_INFORMATION_THREAD)(
IN HANDLE ThreadHandle,
IN THREAD_INFO_CLASS ThreadInformaitonClass,
IN PVOID ThreadInformation,
IN ULONG ThreadInformationLength);
void ZSIT_DetachDebug()
{
ZW_SET_INFORMATION_THREAD Func;
Func = (ZW_SET_INFORMATION_THREAD)GetProcAddress(
LoadLibrary(L"ntdll.dll"), "ZwSetInformationThread");
Func(GetCurrentThread(), ThreadHideFromDebugger, NULL, NULL);
}
int main()
{
ZSIT_DetachDebug();
system("pause");
return 0;
}
破解函数反调试的最有效的方法就是找到具体的函数调用的地点,并分析其条件跳转,然后做暴力破解,亦或是通过HOOK的方式过滤其返回消息。想要在调试的过程种做好以上工作,最好熟记各个功能号(第二个参数传的值)的作用: 0x07 获取调试端口(processDebugPort) 0x1E获取调试句柄(processDebugObjectHandle) 0x1F获取调试标记(ProcessDebugFlags)
总结
静态反调试 1. PEB->BeingDebugged是1(偏移为PEB+0X2的位置) 2. PEB->NtGlobalFlag 是0x70(PEB+0X68) 3. PEB->.ProcessHeap ForceFlags 不为2,(PEB + 0X90 + 0X40) 4. NtQueryInformationProcess相关 5. ProcessDebugPort : 调试端口 6. ProcessDebuggObjectHandle : 调试对象的句柄 7. ProcessDebugFlag:调试标记动态反调试:
1.
2. 攻击调试器,让调试器和被调试进程分离
3. 0xCC检查
4. 时间检查
5. 通过异常 因为有调试器的时候,UEG就会失败,那么就可以将一些关键代码隐藏在UEH中。
6. 加壳
7. 虚拟机技术
8. 代码膨胀与混淆