好友
阅读权限30
听众
最后登录1970-1-1
|
本帖最后由 JoyChou 于 2014-3-16 19:40 编辑
一、如何遍历驱动
在内核中,可以通过大概下面几种方法获取,
0x1. 遍历驱动对象(Driver_Object)的DriverSection域
0x2. 遍历KPCR结构体的PsLoadedModuleList域
0x3. ZwQuerySystemInformation的11号功能
0x4. 内存暴力搜索
在应用层中,可以通过psapi的EnumDeviceDrivers API来获取,其关键是调用ZwQuerySystemInformation。
二、Anti原理
平时在用OD调试的时候,肯定会用到很多OD的插件。可以发现,这些插件都是dll文件,然后被OD加载调用。那既然OD加载了这么多插件,为何不直接遍历所有进程模块,如果发现有可疑的模块(例如:stringOD模块),那就可以直接判断调试器正在运行。但是,OD的进程被SOD隐藏了,如果不借助ARK工具,在任务管理器里面是看不到的。图1是XueTr观察到的。
图1
但是可以遍历系统驱动模块,因为驱动模块是没有隐藏的,所以可以通过程序遍历得到。如图2所示。但是,要排除掉系统的dbghelp.dll的干扰。
图2
可见,只要将驱动路径向上2个目录,来到OllyDbg目录,判断是否存在dbghelp.dll,即可确定是否有调试器的存在。如图3所示。
图3
三、代码
[C++] 纯文本查看 复制代码 #include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <Psapi.h>
#include <shlwapi.h> //PathFileExists
#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "shlwapi.lib")
#define ARRAY_SIZE 1024
int main(int argc, char *argv[])
{
DWORD cbNeeded = 0;
LPVOID drivers[ARRAY_SIZE] = {0};
int cDrivers = 0, i = 0;
if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) &&
cbNeeded < sizeof(drivers))
{
char szDriver[ARRAY_SIZE] = {0};
char szPath[ARRAY_SIZE] = {0};
char szDbgHelp[ARRAY_SIZE] = {0};
char szSystemPath[ARRAY_SIZE] = {0};
cDrivers = cbNeeded / sizeof(LPVOID);
bool bDetect = FALSE;
//得到C:\Windows\system32\dbghelp.dll
GetSystemDirectory(szSystemPath, sizeof(szSystemPath));
strcat_s(szSystemPath, "\\dbghelp.dll");
//printf("There are %d drivers\n", cDrivers);
for (i = 0; i < cDrivers; i++)
{
// 驱动名
if (GetDeviceDriverBaseName(drivers[i], szDriver, sizeof(szDriver) / sizeof(LPVOID)))
{
printf("%d:%s\n", i+1, szDriver);
// 驱动完整路径
GetDeviceDriverFileName(drivers[i], szPath, sizeof(szPath));
//只判断非系统驱动
if (szPath[1] == '?')
{
int len = strlen(szPath);
//printf("%d:%s\n", i+1, szPath);
// 得到驱动上一级目录
do
{
len--;
} while (szPath[len] != '\\');
// 得到驱动上 上一级目录
do
{
len--;
} while (szPath[len] != '\\');
szPath[len + 1] = '\0'; // 字符串截断
// 去除驱动路径的前4个字符"\??\"
for (int j = 0; j < len; j++)
{
szPath[j] = szPath[j + 4];
}
sprintf_s(szDbgHelp, "%sdbghelp.dll", szPath);
// 判断文件是否存在
if (PathFileExists(szDbgHelp))
{
// 排除系统的dbghelp.dll
if (_strcmpi(szSystemPath, szDbgHelp) != 0)
{
bDetect = TRUE;
break;
}
else
{
bDetect = FALSE;
}
}
}
}
}
if (bDetect)
{
printf_s("Detect OD\n");
printf_s("Path: %s\n", szPath);
printf_s("SOD Name: %s\n", szDriver);
}
else
{
printf_s("Do not Detect OD\n");
}
getchar();
}
}
四、效果在XP和32位的win7下面,驱动是不需要签名的,载入OD即可加载驱动。
图4
五、反调试之策 可以通过断链隐藏SOD的驱动名,一般是fengyue0.sys
隐藏代码: [C++] 纯文本查看 复制代码 VOID HideDriver(PDRIVER_OBJECT pDriverObject)
{
PLDR_DATA_TABLE_ENTRY pLdrData = NULL;
PLIST_ENTRY pCur, pHead = NULL;
UNICODE_STRING uDriverName;
// 初始化要隐藏的驱动名
RtlInitUnicodeString(&uDriverName, L"fengyue0.sys");
pLdrData = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
// 得到当前sys模块,并设置为第一个(head)以及当前(cur)模块
pCur = pHead = pLdrData->InLoadOrderLinks.Flink;
__try
{
do
{
// 这句pLdrData = (PLDR_DATA_TABLE_ENTRY)pCur是等价的
// 因为pCur在LDR_DATA_TABLE_ENTRY结构体的第一个域(成员)
pLdrData = CONTAINING_RECORD(pCur, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
if (pLdrData->BaseDllName.Length > 0 &&
pLdrData->BaseDllName.Buffer != NULL)
{
if (RtlCompareUnicodeString(&uDriverName, &(pLdrData->BaseDllName), FALSE) == 0)
{
KdPrint(("驱动隐藏\n"));
// 断链
pLdrData->InLoadOrderLinks.Blink->Flink =
pLdrData->InLoadOrderLinks.Flink;
pLdrData->InLoadOrderLinks.Flink->Blink =
pLdrData->InLoadOrderLinks.Blink;
// 断掉的链指向自己
pLdrData->InLoadOrderLinks.Flink =
(PLIST_ENTRY)&pLdrData->InLoadOrderLinks.Flink;
pLdrData->InLoadOrderLinks.Blink =
(PLIST_ENTRY)&pLdrData->InLoadOrderLinks.Flink;
KdPrint(("PsLoadedModuleList success \r\n"));
break;
}
}
pCur = pCur->Flink;
} while (pCur != pHead);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("PsLoadedModuleList Error \r\n"));
}
驱动载入后,再次运行之前的anti程序,就找不到驱动名了,反调试已经没用了。如图5。
图5
六、总结 这种anti手法,局限性比较低,因为StrongOD的驱动没有进行隐藏。反调试手段很多,大家可以随意发挥,只要能检测到。
反调试之遍历驱动名.zip
(160.55 KB, 下载次数: 175)
|
免费评分
-
查看全部评分
本帖被以下淘专辑推荐:
- · 破解教程|主题: 126, 订阅: 214
- · 精品贴|主题: 59, 订阅: 22
- · 精品贴|主题: 96, 订阅: 17
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|