Windows-如何获得一个CPU指令的长度?

Windows-如何获得一个CPU指令的长度?

清晨说ぺ晚安 发布于 2017-04-15 字数 156 浏览 1167 回复 1

在Hook技术中,有一种是内联hook。需要在hook之前获取要hook位置指令的长度。对于现在有X86,X64,还有IA64等几种CPU指令集,能有一个统一的完整的解决方案吗?

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

虐人心 2017-08-09 1 楼

给你发个使用通过逆向反汇编引擎出来的一个C代码,我正在用这个,很好用。
你去网上下载lDasm.h、lDasm.cpp,代码行数超过限制,无法给你贴代码。

调用处代码:

PUCHAR pOpcode=NULL;
ULONG ulLength=SizeOfCode(cPtr,&pOpcode);

其中cPtr为PUCHAR类型的指向指令的开始地址。实际使用时,把cPtr指向函数地址,往下遍历到要Inline HOOK的地址就行。每遍历一条指令cPtr+=ulLength。

给你发一段我HOOK CALL指令的代码(替换CALL后面的地址),其实和Inline HOOK差不多,只是更隐蔽一些。汇编中的CALL调用有两种形式,一种为“call+相对偏移”、一种为“call+dword ptr[]”。

BOOL CallAddrHook(PVOID pStartAddr,PVOID pNewAddr,ULONG Size,BOOL bHook,ULONG ulDriverStart,
OUT ULONG *pNeedCallAddr,OUT PVOID ulMemAddr,OUT ULONG *pOrigAddr,OUT ULONG *pHookedAddr)
{
PUCHAR cPtr=NULL,pOpcode=NULL;
ULONG ulLength=0,ulTmp=0;
KIRQL oldIrql;
for (cPtr=pStartAddr;(ULONG)cPtr<(ULONG)pStartAddr+Size;cPtr+=ulLength)
{
ulLength=SizeOfCode(cPtr,&pOpcode);
//计算当前指令长度
if (!ulLength)
break;
if (ulLength==5 && *cPtr==0xE8) //call+相对偏移 形式
{
KdPrint(("指令长度为5且为call+相对偏移 形式!"));
if (bHook)
{
RtlCopyMemory(g_OrigCallAddr,cPtr+1,4); //保存原始Call地址
ulTmp=(ULONG)pNewAddr-(ULONG)cPtr-5; //我们的Call地址相对偏移
*pHookedAddr=ulTmp; //保存相对偏移地址,以便即时Patch
*pNeedCallAddr=*(PULONG)(cPtr+1)+ ulDriverStart;
*pOrigAddr=(ULONG)(cPtr+1); //保存被Hook的地方,以便即时Patch
KdPrint(("被CALL HOOK的原绝对地址为:0x%08X",*pNeedCallAddr));
}
//使用自旋锁
KeAcquireSpinLock(&cb_spinlock,&cb_oldirql);
//提升中断请求级
oldIrql = KeRaiseIrqlToDpcLevel();
WPOFF();
if (bHook)
*(PULONG)(cPtr+1)=ulTmp;
else //unHook
*(PULONG)(cPtr+1)=*(PULONG)g_OrigCallAddr;
WPON();
//恢复先前中断请求级
KeLowerIrql(oldIrql);
//释放自旋锁
KeReleaseSpinLock(&cb_spinlock, cb_oldirql);
return TRUE;
}
else if (ulLength==6 && *cPtr==0xFF && *(cPtr+1)==0x15) //call+dword ptr[] 形式
{
KdPrint(("指令长度为6且为call+dword ptr[] 形式!"));
if (bHook)
{
RtlCopyMemory(g_OrigCallAddr,cPtr+2,4); //保存原始Call地址
//这种形式需要通过内存地址间接call
ulMemAddr=ExAllocatePoolWithTag(NonPagedPool,4,'CMEM');
*(PULONG)ulMemAddr=(ULONG)pNewAddr;
*pHookedAddr=(ULONG)ulMemAddr; //保存相对偏移地址,以便即时Patch
*pNeedCallAddr= *((PULONG)*(PULONG)(cPtr+2));
*pOrigAddr=(ULONG)(cPtr+2); //保存被Hook的地方,以便即时Patch
KdPrint(("被CALL HOOK的原绝对地址为:0x%08X",*pNeedCallAddr));
}
//使用自旋锁
KeAcquireSpinLock(&cb_spinlock,&cb_oldirql);
//提升中断请求级
oldIrql = KeRaiseIrqlToDpcLevel();
WPOFF();
if (bHook)
*(PULONG)(cPtr+2)=(ULONG)ulMemAddr;
else
*(PULONG)(cPtr+2)=*(PULONG)g_OrigCallAddr;
WPON();
//恢复先前中断请求级
KeLowerIrql(oldIrql);
//释放自旋锁
KeReleaseSpinLock(&cb_spinlock, cb_oldirql);
return TRUE;
}
}
return FALSE;
}