最近拿到一个使用XTrap的游戏,据说此物乃NP和HS之外的第三大反外挂系统,so拿来瞧了瞧。
Ring3层包括几个dll和一个进程。看里面貌似使用了pipe相关的函数,运行时也起了一个进程。所以XTrap的架构应该和NP很类似,但是实现上就要弱很多了。
1、 现在还没发现有ring3全局注入的dll。
2、 大量工作放到了作为和游戏接口的dll里面。通过dll方式提供游戏使用这点不同于NP的lib库,而更类似HS。这种方式一大弱点就是那个dll容易被模拟,并且比较难发现。
3、驱动相对来说应该是三个系统里面最弱的了,原因下面会讲到。花了5天时间逆出了整个驱动的源码,好像没有那么多硬编码的东西,呵呵。不过倒是发现了一些编程的BUG什么的。基本的功能点只有三个:HOOK SSDT实现的跨进程访问控制、通过对IoAccessMap的设置关闭对鼠标键盘端口访问权限、通过挂接Int 1中断获得调试信息。
大概的流程如下:
1、 DriverEntry:通过PsGetVersion判断系统版本,并根据不同的版本保存要Hook的在SSDT Shadow表中服务的ID。而SSDT表中的则是由后面IoControl里面Ring3传下来的。目前来看已经支持Vista了。通过 KeQuerySystemTime拿了一下系统时间并保存下来,不过后面就没有再使用了,估计以后为了反调试会做时间检查什么的东西吧。申请了 0x2000长度的内存,这是用于后面设置IoAccessMap的。然后就是例行的IoCreateDevice和 IoCreateSymbolicLink,设置Dispatch例程。XTrap的IRP_MJ_DEVICE_CONTROL、 IRP_MJ_CREATE、IRP_MJ_CLOSE、IRP_MJ_CLEANUP是在同一个例程中处理的。最后有一个莫名其妙的调用 KfLowerIrql( KeRaiseIrqlToDpcLevel());偶的水平实在是还难以理解高丽棒子为啥要这样做,嘿嘿。
2、 剩下的就是通过DeviceIoControl来控制的了,我这个版本的XTrap一共有17个ControlCode。Dispatch例程的代码如下
NTSTATUS
XDvaDispatchAll( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION pIrpStack;
PVOID pSystemBuffer;
PVOID pOutBuffer;
ULONG ulMajorFunction;
NTSTATUS ntStatus;
pIrpStack = IoGetCurrentIrpStackLocation( Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
pSystemBuffer = Irp->AssociatedIrp.SystemBuffer;
ulMajorFunction = pIrpStack->MajorFunction;
switch( ulMajorFunction)
{
case IRP_MJ_DEVICE_CONTROL:
if( (pIrpStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == 0x3)
{
pOutBuffer = Irp->UserBuffer;
}
else
{
pOutBuffer = pSystemBuffer;
}
return DoDeviceIoControl( Irp, pIrpStack->FileObject, 1, pSystemBuffer,
pIrpStack->Parameters.DeviceIoControl.InputBufferLength,
pOutBuffer, pIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
pIrpStack->Parameters.DeviceIoControl.IoControlCode,
&Irp->IoStatus, DeviceObject);
case IRP_MJ_CLOSE:
HookSSDT( g_HookInfo.NtOpenProcessInfo.Id, (ULONG)g_pNtOpenProcess, (ULONG)NewNtOpenProcess);
HookSSDT( g_HookInfo.NtDeviceIoControlFileInfo.Id, (ULONG)g_pNtDeviceIoControlFile, (ULONG)NewNtDeviceIoControlFile);
HookSSDT( g_HookInfo.NtWriteVirtualMemoryInfo.Id, (ULONG)g_pNtWriteVirtualMemory, (ULONG)NewNtWriteVirtualMemory);
HookSSDT( g_HookInfo.NtOpenSectionInfo.Id, (ULONG)g_pNtOpenSection, (ULONG)NewNtOpenSection);
HookSSDT( g_HookInfo.NtProtectVirtualMemoryInfo.Id, (ULONG)g_pNtProtectVirtualMemory, (ULONG)NewNtProtectVirtualMemory);
HookSSDT( g_HookInfo.NtTerminateProcessInfo.Id, (ULONG)g_pNtTerminateProcess, (ULONG)NewNtTerminateProcess);
HookSSDT2( g_dwNtGdiGetPixelId, (ULONG)g_pNtGdiGetPixel, (ULONG)NewNtGdiGetPixel);
HookSSDT2( g_dwNtUserSendInputId, (ULONG)g_pNtUserSendInput, (ULONG)NewNtUserSendInput);
HookSSDT2( g_dwNtUserCallNextHookExId, (ULONG)g_pNtUserCallNextHookEx, (ULONG)NewNtUserCallNextHookEx);
HookSSDT2( g_dwNtUserPostMessageId, (ULONG)g_pNtUserPostMessage, (ULONG)NewNtUserPostMessage);
HookSSDT2( g_dwNtUserTranslateMessageId, (ULONG)g_pNtUserTranslateMessage, (ULONG)NewNtUserTranslateMessage);
if( g_byIsSuccess)
{
g_byIsSuccess = FALSE;
}
if( g_byIsReboot)
{
_asm cli;
WRITE_PORT_UCHAR( (PUCHAR)0x64, (UCHAR)0xFE);
_asm hlt;
}
else
{
ntStatus = STATUS_SUCCESS;
}
break;
case IRP_MJ_CREATE:
if( g_arrSomeCode[0] == 0)
{
memcpy( g_arrSomeCode, MyInt1, 5*sizeof( ULONG));
}
ntStatus = STATUS_SUCCESS;
break;
case IRP_MJ_CLEANUP:
ntStatus = STATUS_SUCCESS;
break;
default:
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
}
IofCompleteRequest( Irp, IO_NO_INCREMENT);
return ntStatus;
}
IRP_MJ_DEVICE_CONTROL的处理是在另外一个函数里面,由于太复杂,影响blog的美观,就不写出来了,哈哈。这里面可以看到,XTrap采用了和NP一样的办法重起电脑,就是往64端口写0xFE。挺白痴的是居然通过WRITE_PORT_UCHAR,难道以为只有他会 Hook~
IRP_MJ_CREATE里面把自己的Int 1 函数的代码复制了一段出来,这个会用于后面再覆盖回去,是用于对付Inline hook的伎俩。
其他就没什么好说的了。
3、 关于SSDT的Hook
SSDT中Hook的函数有以下几个:NtOpenProcess、NtDeviceIoControlFile、 NtWriteVirtualMemory、NtOpenSection、NtProtectVirtualMemory、 NtTerminateProcess
Shadow Table中Hook的函数有下面几个:NtGdiGetPixel、NtUserSendInput、NtUserCallNextHookEx、NtUserPostMessage、NtUserTranslateMessage。
所有函数Hook的目的都很清楚,没有什么古怪的地方,呵呵。不过相当部分的钩子都只是简单的pass过去,并没有任何实质性的处理。可以看出来XTrap仍然是一个非常不完善的系统,这些部分应该都是留到以后进行功能扩充的。
关于Shadow Table的处理有一些特别的地方。Shadow Table的地址获取采用了硬编码+验证的方式。这一点偶个人觉得还是在KeAddSystemServiceTable中去取比较好,至少说在出现新的系统的时候很大可能并不用修改代码。另外,取到Shadow Table地址之后,除了将KSERVICE_TABLE_DESCRIPTOR地址保存之外,还将Shadow Table的Base保存到了KeServiceDescriptorTable第二项的Base中,以后在Hook或者其他操作的时候就直接到 KeAddSystemServiceTable地址+0x10去取了。这一点我也觉得有些奇怪,保存到全局变量什么的不就好了,为什么要去修改系统本身的东西,虽然目前那个位置并没有什么用。大约是为了反调试。
4、 关于Int 1的处理
这里貌似也没什么好说的,记录了一下断点被触发的次数、dr0到dr4的内容什么的,然后IoControl里面Ring3会取走这些信息。不过有个很搞笑的BUG,Hook中断的函数里面的cli没有对应的sti。
5、 关于IoAccessMap的处理
这里没什么好说的,是由Ring3触发,Ring0实现。贴一段DeviceIoContrl里面的代码就明白了。
case 0x85000044:
ntStatus = STATUS_INVALID_PARAMETER;
if( !pSystemBuffer || ulInputBufferLength != 4)
{
break;
}
PsLookupProcessByProcessId( *((ULONG*)pSystemBuffer), pSystemBuffer);
((PUCHAR)g_pIoAccessMap)[0x0C] |= 0xFF;
((PUCHAR)g_pIoAccessMap)[0x0D] |= 0xFF;
Ke386IoSetAccessProcess( pSystemBuffer, 1);
Ke386SetIoAccessMap( 1, g_pIoAccessMap);
ntStatus = STATUS_SUCCESS;
break;
现在模拟键盘的所谓硬件模式,大部分人都是使用了网上一些开源工具,例如WinIo,基本原理就是通过IoAccessMap打开ring0的端口读写权限(啰嗦一句,上次看到某人拿来的一个sys,貌似将整个机器的io都打开了,实在是无比暴力……。寒一个)。所以对应办法就是也通过改写 IoAccessMap关闭掉权限。
这也是我现在比较推荐使用的方法,对使用WinIo的按键精灵什么的外挂,都有药到病除的疗效。而且,影响范围比较小,只关闭了有限的端口。对于某些特殊情况下的程序,也可以发现之后再单独处理。不过对于自己写驱动读写端口的一类外挂来说,任何办法都没用了。 In~~~out~~~~in~~~~out~~~~~in~~~~~~out~~~~~~
6、 下面选一些函数贴出来吧
ULONG __stdcall
NewNtGdiGetPixel( PVOID hDC, LONG XPos, LONG YPos)
{
BOOLEAN blIsBlock = TRUE;
if ( g_dwCurrentProcessId == (ULONG)PsGetCurrentProcessId())
{
blIsBlock = FALSE;
}
//这里奇怪,不知道为什么这么搞
if ( XPos == 0)
{
if( YPos != 0)
{
if( YPos == 0x5A)
{
blIsBlock = FALSE;
}
}
else
{
blIsBlock = FALSE;
}
}
if( g_byIsSuccess == TRUE && blIsBlock == TRUE)
return 0;
return g_pNtGdiGetPixel( hDC, XPos, YPos);
}
ULONG
__stdcall NewNtUserSendInput(
ULONG nInputs,
LPINPUT pInput,
ULONG cbSize)
{
if( (g_byIsSuccess != TRUE) || (g_byAllowUserSendInput == TRUE))
{
return g_pNtUserSendInput( nInputs, pInput, cbSize);
}
else
{
return 1;
}
}
NTSTATUS
__stdcall NewNtOpenProcess (
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId
)
{
if( g_dwCurrentProcessId != 0)
{
if( (ULONG)ClientId->UniqueProcess == g_dwCurrentProcessId)
{
if( DesiredAccess != 0x478)
{
DesiredAccess &= 0xFFFFFFCF;//清掉PROCESS_VM_READ和PROCESS_VM_WRITE
}
}
}
if( g_dwProtectPid2 != 0)
{
if( g_dwProtectPid2 == (ULONG)ClientId->UniqueProcess)
{
DesiredAccess &= 0x0FFFFFFFE; //清掉PROCESS_TERMINATE
}
}
if( g_dwCurrentProcessId == (ULONG)ClientId->UniqueProcess)
{
g_dwIsSomeoneOpenMe = 1;
}
return g_pNtOpenProcess( ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
}
NTSTATUS
__stdcall NewNtWriteVirtualMemory(
HANDLE ProcessHandle,
PVOID BaseAddress,
CONST VOID *Buffer,
SIZE_T BufferSize,
PSIZE_T NumberOfBytesWritten
)
{
BOOLEAN blIsNeedSkip = FALSE;
PROCESS_BASIC_INFORMATION stProcessInfo;
HANDLE Handle;
HANDLE hCurrentPid;
RtlZeroMemory( &stProcessInfo, sizeof(stProcessInfo));
if( STATUS_SUCCESS ==
ZwDuplicateObject( (HANDLE)0xFFFFFFFF,
ProcessHandle,
(HANDLE)0xFFFFFFFF,
&Handle,
0x400,
0,
0)
)
{
ZwQueryInformationProcess( Handle, 0, &stProcessInfo, 0x18, 0);
ZwClose( Handle);
}
if( g_dwCurrentProcessId == (ULONG)stProcessInfo.UniqueProcessId)
{
blIsNeedSkip = TRUE;
}
hCurrentPid = PsGetCurrentProcessId();
if( (ULONG)hCurrentPid == g_dwSafePid1 ||
(ULONG)hCurrentPid == g_dwSafePid2 ||
(ULONG)hCurrentPid == g_dwSafePid3)
{
blIsNeedSkip = FALSE;
}
if( (ULONG)hCurrentPid == g_dwCurrentProcessId)
{
if( (g_dwFromUser2 | 0xFFFFF0F) == 0xFFFFF1F)
{
blIsNeedSkip = FALSE;
}
}
if ( !g_byIsSuccess || !blIsNeedSkip)
{
return g_pNtWriteVirtualMemory( ProcessHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesWritten);
}
return 0;
}
ULONG __stdcall NewNtUserTranslateMessage(PMSG lpMsg, ULONG dwhkl)
{
CHAR ucScanCode, ucScanCode2;
UCHAR blNeedSkip = FALSE;
if( lpMsg->message == 0x100 || lpMsg->message == 0x101)
{//WM_KEYDOWN,WM_KEYUP
ucScanCode2 = IsNeedSkipKeyMsg( lpMsg->wParam);
if( ucScanCode2)
{
ucScanCode = (lpMsg->lParam & 0x00FF0000) >> 16;
if( ucScanCode == ucScanCode2)
{
blNeedSkip = TRUE;
}
}
}
if( !g_byIsSuccess || !blNeedSkip)
{
return g_pNtUserTranslateMessage( lpMsg, dwhkl);
}
return 1;
}

转XTrap驱动分析相关推荐

  1. linux串口驱动分析

    linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...

  2. 【转】android电池(四):电池 电量计(MAX17040)驱动分析篇

    关键词:android 电池  电量计  MAX17040 任务初始化宏 power_supply 平台信息: 内核:linux2.6/linux3.0 系统:android/android4.0  ...

  3. Android10.0 Binder通信原理(五)-Binder驱动分析

    摘要:本节主要来讲解Android10.0 Binder的驱动层分析 阅读本文大约需要花费35分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设计 ...

  4. linux 串口驱动 atmel_set_mctrl何时调用,linux uart serial使用驱动分析

    uart tty serial 驱动分析 内核版本3.14.23 以atmel为例: 起点: static int __init atmel_serial_init(void) { int ret; ...

  5. linux 网卡驱动分析,LINUX_网卡驱动分析

    LINUX_网卡驱动分析 (36页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.9 积分 Linux DM9000网卡驱动程序完全分析说明仁 本文分 ...

  6. Linux PCI网卡驱动分析

    http://www.uplinux.com/shizi/wenxian/4429.html Linux网卡驱动分析 学习应该是一个先把问题简单化,在把问题复杂化的过程.一开始就着手处理复杂的问题,难 ...

  7. Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇

    Core层中有两个重要函数 mmc_alloc_host 用于构造host,前面已经学习过,这里不再阐述:另一个就是 mmc_add_host,用于注册host 前面探测函数s3cmci_probe, ...

  8. wince串口驱动分析(转)

    wince串口驱动分析 串行通讯接口主要是指UART(通用串行)和IRDA两种.通常的串行连接电气连接上有3wire和9wire两种.3wire的接线方式下定义了发送.接收和地三根连接.其用途就如名称 ...

  9. framebuffer驱动详解4——framebuffer驱动分析2(probe函数讲解)

    以下内容源于朱有鹏<物联网大讲堂>课程的学习,如有侵权,请告知删除. 主要在填充fbdev这个结构体. 二.framebuffer驱动分析2 1.probe函数分析 (1)struct s ...

最新文章

  1. 一天之内用SDN能做出什么
  2. 0607am抽象类接口析构方法tostring小知识点
  3. Javaweb权限管理设计思路
  4. 【数据库】Kingbase金仓数据库工程维护简明手册
  5. python反转列表_python列表反转
  6. Make!Sense 动手好伴侣,带你轻松做实验
  7. bat tomcat程序在后台执行_jenkins 中利用 cmd 命令启动 tomcat,进程被杀
  8. TCA9548A iic地址扩展器件 树莓派JAVA版教程
  9. java的resultset的next_java中resultset获取的是两个数据库,它的next()方法是怎么的
  10. 2021-2022年度第三届全国大学生算法设计与编程挑战赛(冬季赛)-正式赛 部分题解
  11. iOS安全攻防(七)使用iOSOpenDev开发SpringBoard的Tweat
  12. python while函数_Python:无法在while循环中调用函数
  13. coding.net及git的使用方式
  14. MySQL创建数据库、数据表 | 零基础自学SQL课程系列Day3
  15. 「视频」PISCES要先派机器人去外太空,帮人类建立另一个家园?
  16. GNSS说第(七)讲---自适应动态导航定位(六)---导航解算中的误差探测、诊断与修复
  17. 腿抖在饮食上需要注意什么?
  18. 云主机如何保证信息安全?
  19. K8S最新版本集群部署超详细(k8s版本1.5.1)docker 版本19.03.1以及基本操作和服务介绍。
  20. CdTe量子点修饰CLV3信号多肽/偶联穿膜肽/Angiopep-2多肽修饰Ag2S量子点的制备

热门文章

  1. 【C#】Winform监听USB串口设备拔插
  2. 顶易中国整理邮件发送详解
  3. C++QT实现压缩文件、文件夹和解压缩操作
  4. python模拟登录网站_用python实现模拟登录人人网
  5. linux下Android Monitor启动失败问题
  6. 用python进行主成分分析(PCA)
  7. 主成分分析PCA简介及其python实现
  8. 【Webpack】1105- 深入学习 Webpack Loader 知识
  9. BUUCTF-web [极客大挑战 2019]PHP1
  10. 计算机专用软件 up,Advanced PC Cleanup(垃圾清理工具) V1.0.0 英文安装版