首先来看两段IDA中的代码
上面的图是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相同的
************************************************
************************************************
测试的时候写了一个小程序,效果如下:
输入指定函数名称和反汇编长度:
通过DebugView可以看到反汇编的结果<指令类型+指令长度>:
与livekd对比一下,没有异常:
下面简单说一下使用方法,应用层就不在这里讨论了,只看一下驱动方面:
#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