【原创】为你的驱动挂上外挂 - 嵌入反汇编引擎


thisIs 当前离线

标 题:  【原创】为你的驱动挂上外挂 - 嵌入反汇编引擎
作 者: thisIs
时 间: 2011-09-25,22:11:03
链 接: http://bbs.pediy.com/showthread.php?t=140587



首先来看两段IDA中的代码
名称:  xp_ntopenprocess.jpg查看次数: 2847文件大小:  90.4 KB

名称:  win7_psopenprocess.jpg查看次数: 2839文件大小:  126.0 KB

上面的图是win xp下 NtOpenProcess 中的代码片段
下面的图是win 7下 PsOpenProcess 中的代码片段,win 7中 NtOpenProcess 成了包装函数,由PsOpenProcess真正完成打开进程的操作

两个系统中打开某一进程时的指令执行路径上都会经过ObOpenObjectByPointer函数,
该函数在这里传进进程的EPROCESS结构,返回相应的进程句柄,该句柄最终返回给我们

可见如果在这里inline hook了ObOpenObjectByPointer函数,并通过比对EPROCESS来过滤自身的话,
就能防止被其他进程打开访问自己的进程

那么我们如果想修复这个inline hook的话,首先想到的方法就是定位到hook的指令处,
然后通过取得真实的ObOpenObjectByPointer函数地址来进行修复

但是,这条指令位于函数比较深层的位置,在函数头500+以后的偏移地址,如果用通常的搜索特征码的方式进行定位难度比较大,
而且也不容易做到多系统兼容:xp下的ObOpenObjectByPointer前后的指令与win7下ObOpenObjectByPointer前后的指令长度并不相符,
当然你可以选择针对不同的系统,使用多套特征码进行搜寻定位,但这与反汇编引擎比起来通用性,安全性都不在一个级别

前段时间一直在想找个比较小巧的反汇编引擎,我的要求比较简单,能测出指令长度和指令类型就行,
不过找了几个都不理想<也可能自己愚笨,没搞懂怎么使用>

以前在RING3层的时候一直在使用OD的反汇编引擎,不过把OD的上百KB的引擎嵌入我区区几十KB的驱动有点喧宾夺主了,
于是自己花了点时间精简了一下OD的反汇编引擎,效果上还算比较理想

精简之后去掉了所有字串相关操作,也就是将不会有字串形式的参考信息;
指令表那里去掉了C_NOW,C_MMX,C_FLT这样至少我用不着的指令,如果大家需要的话可以自己添加上;
定义了一组指令类型,基本包含了所有的常见指令,当然大家也是可以自己进行添加的.
需要注意的只有这里:
代码:
typedef struct _CmdData {
  ULONG          mask;
  ULONG          code;
  UCHAR          len;
  UCHAR          bits;
  UCHAR          arg1,arg2,arg3;
  UCHAR          type;     //指令类型
}CmdData, *PCmdData;
原版的OD引擎将指令类型定义为了UCHAR,限制了指令的细分数量,大家可以根据需要自己调整一下,
因为自己这样已经够用了,也就没有扩展


另外主函数和返回结构也进行了消减:
代码:
typedef struct _Disasm {
  ULONG  cmdtype;   //指令类型
  ULONG  error;         //错误信息
  ULONG  warnings;  //警告信息
}Disasm,*PDisasm;

ULONG DisasmCode(PUCHAR Src,ULONG SrcSize,PDisasm pDisasm);

Src:要反汇编的指令地址
SrcSize:指令长度
pDisasm:返回结构
使用上是与原版的OD相同的


************************************************
************************************************
测试的时候写了一个小程序,效果如下:
输入指定函数名称和反汇编长度:
名称:  RING3.jpg查看次数: 2817文件大小:  18.0 KB

通过DebugView可以看到反汇编的结果<指令类型+指令长度>:
名称:  debugview.jpg查看次数: 2829文件大小:  166.3 KB

与livekd对比一下,没有异常:
名称:  windbg.jpg查看次数: 2830文件大小:  237.4 KB


下面简单说一下使用方法,应用层就不在这里讨论了,只看一下驱动方面:
代码:
#ifndef DISASMMAIN_H
#define DISASMMAIN_H
#endif

#include <ntddk.h>
#include "disasm.h"

//与RING3层通讯结构
typedef struct _myStruct{
  ULONG  Length;      //反汇编长度
  PWCHAR pFuncName[100];  //要反汇编的函数名称
}myStruct,*PMyStruct;


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath);

__drv_dispatchType(IRP_MJ_DEVICE_CONTROL)
DRIVER_DISPATCH DispatchDeviceIoControl;
NTSTATUS DispatchDeviceIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp);

__drv_dispatchType_other
DRIVER_DISPATCH DispatchCompletion;
NTSTATUS DispatchCompletion(PDEVICE_OBJECT pDeviceObject, PIRP pIrp);

DRIVER_UNLOAD Unload;
VOID Unload(PDRIVER_OBJECT pDriverObject);
头文件只引用disasm.h即可


代码:
#include "disAsmMain.h"

#pragma alloc_text (INIT,DriverEntry)
#pragma alloc_text (PAGE,DispatchDeviceIoControl)
#pragma alloc_text (PAGE,Unload)
#pragma alloc_text (PAGE,DispatchCompletion)

#define DEVICE_NAME L"\\Device\\disAsm"
#define DEVICE_SYMBOLICLINK_NAME L"\\DosDevices\\disAsmSymLink"

#define IOCTL_DISASM_SPECIAL_FUNCTION (CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,FILE_ANY_ACCESS,METHOD_BUFFERED))


NTSTATUS
DispatchDeviceIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
  ULONG                ulIoControlCode;     //控制代码
  PVOID                pvBuf = NULL;
  PIO_STACK_LOCATION   pIrpStatck = NULL;
  NTSTATUS             status = STATUS_UNSUCCESSFUL;

  PMyStruct       pFuncInfo;
  PVOID         pFuncAddress = NULL;
  UNICODE_STRING     destString;
  ULONG  DecodedLength = 0;
  ULONG  dw;
  Disasm  dis;

  pIrpStatck      = IoGetCurrentIrpStackLocation(pIrp);
  ulIoControlCode = pIrpStatck->Parameters.DeviceIoControl.IoControlCode;
  pvBuf           = pIrp->AssociatedIrp.SystemBuffer; 
  pIrp->IoStatus.Status = status;
  pIrp->IoStatus.Information = 0;

  pFuncInfo = (PMyStruct)pvBuf;
  KdPrint(("目标函数:%S",(PWCHAR)pFuncInfo->pFuncName));

  switch ( ulIoControlCode )
  {
  case IOCTL_DISASM_SPECIAL_FUNCTION:

    if ( pFuncInfo->Length == 0 ) break;
    RtlInitUnicodeString(&destString,(PWCHAR)pFuncInfo->pFuncName);

    pFuncAddress = MmGetSystemRoutineAddress(&destString);
    if (pFuncAddress == NULL)
    {
      KdPrint(("未发现指定函数"));
      break;
    }

    while ( DecodedLength < pFuncInfo->Length )
    {
      dw = DisasmCode((PUCHAR)((ULONG)pFuncAddress+DecodedLength),pFuncInfo->Length - DecodedLength,&dis);
      DecodedLength = DecodedLength + dw;

      switch ( dis.cmdtype )
      {
      case C_NOP: KdPrint(("C_NOP  %d",dw)); break;
      case C_TST: KdPrint(("C_TST  %d",dw)); break;
      case C_CMP: KdPrint(("C_CMP  %d",dw)); break;
      case C_CMPS: KdPrint(("C_CMPS  %d",dw)); break;
      case C_CMPSB: KdPrint(("C_CMPSB  %d",dw)); break;
      case C_CMPSW: KdPrint(("C_CMPSW  %d",dw)); break;
      case C_CMPSD: KdPrint(("C_CMPSD  %d",dw)); break;

      case C_MOV: KdPrint(("C_MOV  %d",dw)); break;
      case C_MOVS: KdPrint(("C_MOVS  %d",dw)); break;
      case C_MOVSX: KdPrint(("C_MOVSX  %d",dw)); break;
      case C_MOVSB: KdPrint(("C_MOVSB  %d",dw)); break;
      case C_MOVSW: KdPrint(("C_MOVSW  %d",dw)); break;
      case C_MOVSD: KdPrint(("C_MOVSD  %d",dw)); break;
      case C_MOVZX: KdPrint(("C_MOVZX  %d",dw)); break;

      case C_JMP: KdPrint(("C_JMP  %d",dw)); break;
      case C_JMC: KdPrint(("C_JMC  %d",dw)); break;
      case C_CAL: KdPrint(("C_CAL  %d",dw)); break;
      case C_RET: KdPrint(("C_RET  %d",dw)); break;

      case C_XOR: KdPrint(("C_XOR  %d",dw)); break;
      case C_AND: KdPrint(("C_AND  %d",dw)); break;
      case C_OR: KdPrint(("C_OR  %d",dw)); break;
      case C_NOT: KdPrint(("C_NOT  %d",dw)); break;

      case C_PSH: KdPrint(("C_PSH  %d",dw)); break;
      case C_POP: KdPrint(("C_POP  %d",dw)); break;
      case C_PSHA: KdPrint(("C_PSHA  %d",dw)); break;
      case C_POPA: KdPrint(("C_POPA  %d",dw)); break;
      case C_PSHF: KdPrint(("C_PSHF  %d",dw)); break;
      case C_POPF: KdPrint(("C_POPF  %d",dw)); break;

      case C_ADD: KdPrint(("C_ADD  %d",dw)); break;
      case C_ADC: KdPrint(("C_ADC  %d",dw)); break;
      case C_SBB: KdPrint(("C_SBB  %d",dw)); break;
      case C_SUB: KdPrint(("C_SUB  %d",dw)); break;
      case C_INC: KdPrint(("C_INC  %d",dw)); break;
      case C_DEC: KdPrint(("C_DEC  %d",dw)); break;
      case C_MUL: KdPrint(("C_MUL  %d",dw)); break;
      case C_IMUL: KdPrint(("C_IMUL  %d",dw)); break;
      case C_DIV: KdPrint(("C_DIV  %d",dw)); break;
      case C_IDIV: KdPrint(("C_IDIV  %d",dw)); break;

      case C_NEG: KdPrint(("C_NEG  %d",dw)); break;
      case C_LEA: KdPrint(("C_LEA  %d",dw)); break;
      case C_XCHG: KdPrint(("C_XCHG  %d",dw)); break;
      
      case C_SHR: KdPrint(("C_SHR  %d",dw)); break;
      case C_SHL: KdPrint(("C_SHL  %d",dw)); break;
      case C_ROL: KdPrint(("C_ROL  %d",dw)); break;
      case C_ROR: KdPrint(("C_ROR  %d",dw)); break;
      case C_RCL: KdPrint(("C_RCL  %d",dw)); break;
      case C_RCR: KdPrint(("C_RCR  %d",dw)); break;
      case C_SAR: KdPrint(("C_SAR  %d",dw)); break;
      case C_SAL: KdPrint(("C_SAK  %d",dw)); break;

      case C_CLI: KdPrint(("C_CLI  %d",dw)); break;
      case C_STI: KdPrint(("C_STI  %d",dw)); break;
      case C_ENTER: KdPrint(("C_ENTER  %d",dw)); break;
      case C_LEAVE: KdPrint(("C_LEAVE  %d",dw)); break;
      case C_INT: KdPrint(("C_INT  %d",dw)); break;
      case C_INT3: KdPrint(("C_INT3  %d",dw)); break;
      case C_SYSENTER: KdPrint(("C_SYSENTER  %d",dw)); break;
      case C_SYSEXIT: KdPrint(("C_SYSEXIT  %d",dw)); break;

      default:
         KdPrint(("C_UNKNOW  %d",dw)); break;
      }
    }

    pIrp->IoStatus.Information = 0;
    pIrp->IoStatus.Status = status = STATUS_SUCCESS;

    KdPrint(("打完收工"));

    break;
    
  default:
    KdPrint(("接收到非法命令\n"));
    pIrp->IoStatus.Information = 0;
    pIrp->IoStatus.Status = status = STATUS_INVALID_DEVICE_REQUEST;

    break;
  }

  IoCompleteRequest(pIrp,IO_NO_INCREMENT);
  return status;
}


VOID
Unload(PDRIVER_OBJECT pDriverObject)
{
  UNICODE_STRING    SymLinkName;

  RtlInitUnicodeString(&SymLinkName,DEVICE_SYMBOLICLINK_NAME);
  IoDeleteSymbolicLink(&SymLinkName);
  IoDeleteDevice(pDriverObject->DeviceObject);
}

NTSTATUS
DispatchCompletion(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
  pIrp->IoStatus.Status = STATUS_SUCCESS;
  pIrp->IoStatus.Information = 0;
  IoCompleteRequest(pIrp,IO_NO_INCREMENT);

  return STATUS_SUCCESS;
}


DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
  PDEVICE_OBJECT     pMyDeviceObject = NULL;
  UNICODE_STRING     SymLinkName;
  UNICODE_STRING     MyDeviceName;
  NTSTATUS           status = STATUS_SUCCESS;
  ULONG              i;

  for(i=0; i<IRP_MJ_MAXIMUM_FUNCTION; i++)
    pDriverObject->MajorFunction[i] = DispatchCompletion;

  pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceIoControl;
  pDriverObject->DriverUnload = Unload;

  //创建设备对象
  RtlInitUnicodeString(&MyDeviceName,DEVICE_NAME);
  status = IoCreateDevice(pDriverObject,0,&MyDeviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&pMyDeviceObject);
  if (!NT_SUCCESS(status)){
    KdPrint(("创建设备对象失败\n"));
    return status;
  }

  //创建符号链接
  RtlInitUnicodeString(&SymLinkName,DEVICE_SYMBOLICLINK_NAME);
  status = IoCreateSymbolicLink(&SymLinkName,&MyDeviceName);
  if (!NT_SUCCESS(status)){
    IoDeleteDevice(pMyDeviceObject);
    KdPrint(("创建符号链接失败\n"));
    return status;
  }

  pMyDeviceObject->Flags |= DO_BUFFERED_IO;
  pMyDeviceObject->Flags  = pMyDeviceObject->Flags & ~ DO_DEVICE_INITIALIZING;

  return status;
}
解析指令时dw将返回被解析的字节长度,正常情况下也就是一条指令的长度,
DecodedLength用来累加已被解析的长度

这只是最简单的一个小应用,如何让它在驱动中发挥更大的作用全在你的想象力~~
想想前面的搜索调用ObOpenObjectByPointer的指令地址,使用反汇编引擎可以很容易得实现


精简之后checked编译这个驱动大小为17KB,还是能接受的

由于水平所限,难免出现BUG,如果各位朋友在使用过程中发现了什么问题,请一定要告诉我啊~
我的QQ:2575439022


下面附上精简的OD反汇编引擎源文件,另外我也写了一份delphi版本的精简引擎,方便喜欢用delphi的朋友,一并上传了.

C精简版              : DisAsm_Mini_C.rar
DELPHI精简版     : DisAsm_Mini_delphi.rar

C原版                                                       : DisAsm_C.rar
DELPHI原版修改版<适用UNICODE编码>      : DisAsm_delphi.rar
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值