drv experiment : FOLLOW_JMP parse
来源:互联网 发布:麒麟臂数据 编辑:程序博客网 时间:2024/06/10 23:35
在nt!*API中, 有些入口地址处附近有5个字节的JMP代码.
用FOLLOW_JMP宏可以算出JMP到的绝对地址.
#define FOLLOW_JMP( JMPADDR ) ((ULONG)(JMPADDR) + 5 + *(ULONG*)((ULONG)(JMPADDR) + 1))
这个宏不好理解, 且是硬编码, 用函数实现了一个FOLLOW_JMP, 通用一些.
根据给定的内核API地址, 给定JMP命令前面的字节数量, 分析从JMP命令得到JMP到的绝对地址.
工程下载: prjGetJmpCmdAddr_2013_0619.rar
/// @file \prjGetJmpCmdAddr\main.cpp/// @brief FOLLOW_JMP 宏不太好理解, 换成函数来分析FOLLOW_JMP的实现/**#define FOLLOW_JMP( JMPADDR ) \((ULONG)(JMPADDR) + 5 + *(ULONG*)((ULONG)(JMPADDR) + 1))FOLLOW_JMP 适用于 nt!FsRtlIsPagingFile*/#include <Ntddk.h> /** nt!FsRtlIsPagingFile: 804ed978 8bff mov edi,edi 804ed97a 55 push ebp 804ed97b 8bec mov ebp,esp 804ed97d 5d pop ebp 804ed97e e907dd0100 jmp nt!MmIsFileObjectAPagingFile (8050b68a) nt!MmIsFileObjectAPagingFile: 8050b68a 8bff mov edi,edi *//// nt!FsRtlIsPagingFile API入口附近, JMP命令前面有6个字节#define BYTES_CNT_BEFORE_JMP_ON_FS_RTL_IS_PAGING_FILE 6/// JMP 命令是5个字节#define BYTES_CNT_JMP_CMD 5/// JMP命令字#define ASM_CMD_JMP 0xE9BOOLEAN fnGetApiJmpAddr(wchar_t * pcApiName, ULONG uAddrBeforeJmpCmd, ULONG * pJmpAddr);PVOID GetKernelApiAddress(wchar_t * pcApiName);/// @fn fnGetAddrJmpTo/// @brief 查找JMP命令要跳到的绝对地址/// @param ULONG ulAddrJmpCmd, JMP命令地址/// @return ULONG/// @retval 0, ulApiAddr地址后面不是JMP指令或者失败/// @retval 非0, 得到了ulApiAddr之后JMP指令要跳到的地址ULONG fnGetAddrJmpTo(ULONG ulAddrJmpCmd);extern "C"NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath){ ULONG pJmpAddr = 0; KdPrint((">> DriverEntry\r\n")); if (fnGetApiJmpAddr( L"FsRtlIsPagingFile", BYTES_CNT_BEFORE_JMP_ON_FS_RTL_IS_PAGING_FILE, &pJmpAddr)) { DbgPrint("pJmpAddr = 0x%X\r\n", pJmpAddr); } else DbgPrint("Test_GetApiJmpAddr failed\r\n"); KdPrint(("<< DriverEntry\r\n")); return STATUS_SUCCESS;}BOOLEAN fnGetApiJmpAddr(wchar_t * pcApiName, ULONG uAddrBeforeJmpCmd, ULONG * pJmpAddr){ ULONG ulApiAddr = 0; ///< API地址 ULONG ulAddrJmpCmd = 0; ///< JMP命令地址 if ((NULL == pcApiName) || (NULL == pJmpAddr)) return FALSE; ulApiAddr = (ULONG) GetKernelApiAddress(pcApiName); if (!MmIsAddressValid((PVOID)(ulApiAddr))) { return FALSE; } ulAddrJmpCmd = ulApiAddr + uAddrBeforeJmpCmd; /** kd> dv /V ulApiAddr f7a4cc60 @ebp-0x04 ulApiAddr = 0x804ed978 kd> dv /V ulAddrBeforeJmpCmd f7a4cc5c @ebp-0x08 ulAddrBeforeJmpCmd = 0x804ed97e kd> uf nt!FsRtlIsPagingFile nt!FsRtlIsPagingFile: 804ed978 8bff mov edi,edi 804ed97a 55 push ebp 804ed97b 8bec mov ebp,esp 804ed97d 5d pop ebp 804ed97e e907dd0100 jmp nt!MmIsFileObjectAPagingFile (8050b68a) nt!MmIsFileObjectAPagingFile: 8050b68a 8bff mov edi,edi */ /// 实验可知: ulApiAddr + uAddrBeforeJmpCmd 是JMP命令的地址 if (MmIsAddressValid((PVOID)(ulAddrJmpCmd))) { /// *pJmpAddr is 8050b68a ~ *pJmpAddr = fnGetAddrJmpTo(ulAddrJmpCmd); return TRUE; } return FALSE;}ULONG fnGetAddrJmpTo(ULONG ulAddrJmpCmd){ BOOLEAN bRc = FALSE; UCHAR ucCmdByte = 0; ///< JMP命令的命令字 ULONG ulAddrJmpCmdContent = 0; ///< JMP命令的内容所在的地址 ULONG ulAddrOffset = 0; ///< JMP命令要跳到的相对地址 ULONG ulAddrFollowJmp = 0; ///< JMP命令要跳到的绝对地址 __try { ucCmdByte = *(UCHAR *)(ulAddrJmpCmd); if (ASM_CMD_JMP == ucCmdByte) { ulAddrJmpCmdContent = (ULONG)(ulAddrJmpCmd) + 1; ulAddrOffset = *(ULONG*)(ulAddrJmpCmdContent); ulAddrFollowJmp = ulAddrJmpCmd + BYTES_CNT_JMP_CMD + ulAddrOffset; bRc = TRUE; ///< 全部执行成功, 没有异常发生 } } __finally { } return bRc ? ulAddrFollowJmp : 0;}PVOID GetKernelApiAddress(wchar_t * pcApiName){ UNICODE_STRING str; if (NULL == pcApiName) return NULL; RtlInitUnicodeString(&str, pcApiName); /// MmGetSystemRoutineAddress /// If the function name can be resolved, /// the routine returns a pointer to the function. /// Otherwise, the routine returns NULL. return MmGetSystemRoutineAddress(&str);}
- drv experiment : FOLLOW_JMP parse
- experiment : thread on drv
- experiment : 字符串分解 on drv
- experiment: parse crash info on vs2008
- drv experiment : 从内核API代码定位函数地址或结构指针地址
- experiment
- Experiment
- experiment
- Drv总结
- 6.1.1Drv/Serial(Character Device Drv)
- 6.1.4.Drv/PWM(Character Device Drv)
- parse
- parse
- parse
- $parse
- IPCAM?还是DRV?
- xorg-x11-drv-vmware
- GD25Q32C FLASH DRV
- pthread线程
- Android 从一次apk迁移窥看Android JellyBean(4.1)的变化
- Linux常用命令
- SVN安装配置与使用
- java类加载器以及ClassNotFoundException异常
- drv experiment : FOLLOW_JMP parse
- Xms Xmx PermSize MaxPermSize 区别
- IOS 改变导航栏返回按钮的标题
- 使用Publish/Subscribe 设计模式达到对象间数据同步
- WPF学习系列 MVVM设计模式 一
- Struts2中Action result各种转发类型
- ajax入门详解
- 2013 不知不觉,写了这么多文章。。。
- epoll为什么这么快,epoll的实现原理