Gloomy对Windows内核的分析(内核反汇编技术)
内核反汇编技术
===============================
Windows NT主要是由C写成的,所以总的来说进程本身的反汇编不是很复杂。通常对局部变
量和参数的使用是通过地址和用EBP形成的stack frame来进行的。例如:
PAGE:801932D4 mov eax, large fs:0
PAGE:801932DA push ebp
PAGE:801932DB mov ebp, esp ; 堆栈中的frame
PAGE:801932DD push 0FFFFFFFFh
PAGE:801932DF push offset $T13371
PAGE:801932E4 push offset __except_handler3
PAGE:801932E9 push eax
PAGE:801932EA xor eax, eax
PAGE:801932EC mov large fs:0, esp
PAGE:801932F3 sub esp, 64h ; 局部变量在堆栈中的位置
PAGE:801932F6 mov [ebp+Flag], al ; 使用局部变量
有时,编译器会生成更为优化的代码,直接使用ESP来引用堆栈。
.text:80124320 sub esp, 8
.text:80124323 test byte ptr ds:_NtGlobalFlag+2, 8
.text:8012432A push ebx
.text:8012432B push esi
.text:8012432C push edi
.text:8012432D push ebp
.text:8012432E jnz loc_FFFFF000_80124443
.text:80124334 mov esi, [esp+18h+arg_0] ; 引用第一个参数
IDA PRO这个特别的反汇编器可以跟踪堆栈的创建,所以建立了下面例子中的相应的常量。在
调用函数时,参数以相反的顺序放在堆栈中。调用函数自己要负责清理堆栈(编译器就是这
样为C函数生成代码的)。
PAGE:80193288 push [ebp+ExceptPort]
PAGE:8019328B push [ebp+DebugPort]
PAGE:8019328E push [ebp+SectionHandle]
PAGE:80193291 push [ebp+bInheritHandle]
PAGE:80193294 push edx ; ffffffff
PAGE:80193295 push [ebp+ObjectAttributes] ;(参数3)
PAGE:80193298 push [ebp+Access] ; (参数2)
PAGE:8019329B push ecx ; Handle (参数1)
PAGE:8019329C call _PspCreateProcess@32
; PspCreateProcess (Handle,Access,
; ObjectAttributes,-1,bIbjeritHandle.SectionHandle,DebugPort,ExceptPort);
PAGE:801932A1
PAGE:801932A1 NtCreateProcessExit: ; CODE XREF: _NtCreateProcess@32+71 j
PAGE:801932A1 ; _NtCreateProcess@32+80 j
PAGE:801932A1 mov ecx, [ebp+var_10]
PAGE:801932A4 pop edi
PAGE:801932A5 mov large fs:0, ecx
PAGE:801932AC pop esi
PAGE:801932AD pop ebx
PAGE:801932AE mov esp, ebp
PAGE:801932B0 pop ebp
PAGE:801932B1 retn 20h ; 清理堆栈(返回后ESP加上0x20)
为了提高速度,有时在OS内核中会使用fastcall的函数,参数通过堆栈传递。例如:
PAGE:8018CC9D mov ecx, [ebp+pObject] ; 第一个参数(下一个参数在edx中)
PAGE:8018CCA0 call @ObfDereferenceObject@4 ; fastcall函数
在这个例子中使用了内核中内部的非导出函数。在下一个例子中,我们使用HAL.DLL中的未公
开的导出的fastcall函数:
.text:801335E2 mov ecx, eax ; OldIrql
.text:801335E4 call ds:__imp_@KfLowerIrql@4
fastcall函数在其名字中都有字符‘f’。
Microsoft提供了符号信息,这些符号信息可以用来调试程序。这些信息可以确定内部函数(
非导出的)和全局变量的真实名称。这就简化了辨别函数和变量名称的工作,而且除此之外
,通过后缀@N可以确定函数参数的数量。
调试信息是以NT 4.0的.DBG文件和Windows 2K的.PDB文件的形式提供的。SoftICE和IDA都通
晓PDB和DBG文件(IDA使用插件来加载ntoskrnl.pdb)。
内核中的函数、变量和结构体的名称本身都能表达一些信息。前缀通常有两种意思,描述函
数的特征或是用于子系统的数据。例如:Mm - 子系统内存,Cc - 缓存,Ob - 对象管理器,
Ps - 进程管理,Se - 内存管理器,Ke - 内核其它的结构体,Ex - 执行体系统。如果函数
是初始化用的(或其可能会转入此类函数),则在前缀的第一个字母后加一个字符‘i’。例
如Ki、Mi。使用Fastcall的函数在前缀后加‘f’。系统调用使用前缀Nt。这些函数不是内核
导出的函数,它们的地址记录在service table里。调用服务要通过软中断0x2e。内核导出了
Zw函数,这些函数是对中断的封装。
.text:8011A49C _ZwCreateFile@44 proc near ; CODE XREF: _FsRtlpOpenDev@8+4D p
.text:8011A49C arg_0 = byte ptr 4
.text:8011A49C mov eax, 17h
.text:8011A4A1 lea edx, [esp+arg_0]
.text:8011A4A5 int 2Eh ; 中断处理程序调用NtCreateFile
.text:8011A4A7 retn 2Ch
.text:8011A4A7 _ZwCreateFile@44 endp
我不知道字符Zw是什么意思(好像只有内核的设计者知道)。可能是Zero Wheel(或是零环
)的意思,因为Zw函数是从内核模式调用的(在DDK中描述了一些)。从用户模式下,系统服
务是通过NTDLL(实现于用户模式)调用的,NTDLL导出了NtXXX的封装函数ZwXXX。
内核中的名字主要要遵循一种描述规则。当然,名字本身承载着意义。名字的内容通常是行
为及其对象,即对对象进行某种行为。如:ObCreateObject。
许多的操作系统函数都仅仅是对内核内部函数的封装。例如,NtCreateSection调用了MmCre
ateSection,用的参数也都相同。现在,如果统计一下的话,许多Nt函数的原型都是Window
s NT内核研究者所熟知的,许多内部函数的原型也就可以不用通过逆向工程而获得。有了C语
言函数的原型再学习其结构和思想就轻松多了。
理论上讲,取得关于内核的信息的更简单的方法不是反汇编内核的映象,而是其它的代码。
例如,使用WinDbg的kernel-mode extensions的代码。WinDbg的扩展中有额外的命令,扩展
的调试命令集。其中有明显使用内核内部结构的命令,或是能减轻分析内核内部结构工作的
命令。例如命令!ca、!tokenfields、!processfields等等。反汇编kdextx86.dll和kdex2x8
6.dll的代码可以得到某些结构的信息。
内核调试扩展是个.DLL。导出扩展的命令所用的名字与在WinDbg调试器中遇到的名字是相同
的。例如,processfields。扩展的DLL导出了函数WinDbgExtensionDllInit,这个函数是在
加载扩展后从WinDbg调试器中调用的。函数的原型如下:
VOID WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
USHORT MajorVersion,
USHORT MinorVersion)
第一个参数是指向在.DLL中使用的API的指针。WINDBG_EXTENSION_APIS结构体包含以下成员
,这些成员定义了访问扩展函数集:
lpOutputRoutine - 在控制台输出字符串
lpGetExpressionRoutine - 计算表达式的值
lpGetSymbolRoutine - 取得符号在内存中的地址
lpDisasmRoutine - 反汇编内存
lpCheckControlCRoutine - 检查是否按下CTRL-C (未实现)
lpReadProcessMemoryRoutine - 读进程内存,带有对GPF的保护。
lpWriteProcessMemoryRoutine - 写内存
lpGetThreadContextRoutine - 取得进程寄存器的值
lpSetThreadContextRoutine - 设置寄存器
lpIoctlRoutine - 未实现
lpStackTraceRoutine - 跟踪堆栈
这样.DLL导出了对应于扩展命令的函数,并可以用于与调试器的有限而熟悉的函数集的协同
工作。进一步给出实现扩展命令的函数的原型。
#define DECLARE_API32(s) /
CPPMOD VOID /
s( /
HANDLE hCurrentProcess, /
HANDLE hCurrentThread, /
ULONG dwCurrentPc, /
ULONG dwProcessor, /
PCSTR args /
)
有趣的是参数args,它指向WinDbg中命令的字符串。借助反汇编可以取得足够的信息以研究
扩展命令的工作逻辑。在首要的研究中可以选出直接操纵内核结构体和能辨别结构体成员的
命令。例如,命令!ca的代码说明了内核结构体control area和segment。这个命令的逻辑并
不复杂:辨别命令行,从内核内存中读取所要的结构体,输出域中的内容。
但是,扩展命令经常并不会列出内核结构体的所有内容。并且,从名字中并不总是能明确的
推断出域的含义,但是反汇编这条命令可以简化对内核内部函数的分析工作。在任何情况下
都会有机会对信息做对比,从各种各样的线索中取得信息。
---------------------------------------------------------------------------
(c)Gloomy aka Peter Kosyh, Melancholy Coding'2001
http://gloomy.cjb.net
mailto:gl00my@mail.ru
董岩 译
http://greatdong.blog.edu.cn
Gloomy对Windows内核的分析(内核反汇编技术)相关推荐
- linux内核源代码分析----内核基础设施之klist
概述 klist是list的线程安全版本,他提供了整个链表的自旋锁,查找链表节点,对链表节点的插入和删除操作都要获得这个自旋锁.klist的节点数据结构是klist_node,klist_node引入 ...
- windows 内核情景分析
原文很长:先转部分过来,有时间看一下: 一 windows 内核情景分析---说明 说明 本文结合<Windows内核情景分析>(毛德操著).<软件调试>(张银奎著).< ...
- [转贴]Gloomy对Windows内核的分析(研究CreateProcess)
(转载)Gloomy对Windows内核的分析(研究CreateProcess) 我给出一个反汇编Win32 API函数CreateProcess的例子,来 ...
- Gloomy对Windows内核的分析(对象管理器)
Gloomy对Windows内核的分析(对象管理器) 目录 Inside WINDOWS NT Object Manager 00."对象化的" Windows NT 01.Win ...
- Gloomy对Windows内核的分析
/Files/ddlzq/Gloomy对Windows内核的分析.pdf 转载于:https://www.cnblogs.com/ddlzq/archive/2010/09/03/1817244.ht ...
- 基于windows PE文件的恶意代码分析;使用SystemInternal工具与内核调试器研究windows用户空间与内核空间...
基于windows PE文件的恶意代码分析:使用SystemInternal工具与内核调试器研究windows用户空间与内核空间 ******************** 既然本篇的主角是PE文件,那 ...
- Windows内核系统调用分析
系统调用 进程 --> 调用OS API:OS进程管理 --> 调配进程. 仅从用户进程角度,OS就像是一个被动响应的运行时库.Windows提供了一个系统调用界面作为外层,即Win32A ...
- windows内核情景分析---进程线程1
本篇主要讲述进程的启动过程.线程的调度与切换.进程挂靠 一.进程的启动过程: BOOL CreateProcess ( LPCTSTR lpApplicationName, ...
- Windows内核情景分析-概述
现在的Windows 现在的windows内核包含了两大部分,一部分是本来意面上的操作系统内核,另一部分则是移到了内核中的视窗服务,前者对应ntoskrnl.exe后者win32k.sys:后者部分为 ...
最新文章
- 资源 | 2018年值得关注的200场机器学习会议(建议收藏)
- 那些年我们一起追过的Shell Script
- Linux:终端自定义title
- STM32 基础系列教程 33 - Lwip_tcp_client
- 剑指offer: 不用加减乘除做加法
- 桐花万里python路-基础篇-01-历史及进制
- Boost:字符串裁剪Trim的测试程序
- [CF/AT/Luogu]各大网站网赛 爆肝部部长工作报告文件Ⅱ
- 我在暴躁同事小张的胁迫下学会了Go的交叉编译和条件编译
- 2020 年,你必须知道发展最快和衰落最快的软件技能
- php 输出数组第一个元素,怎么在php中利用reset() 函数输出数组中的第一个元素
- 9.GitLab 汉化
- vue+jsplumb 实现连线绘图
- mysql gtid dump_MySQL之mysqldump备份的--set-gtid-purged参数
- 供应链管理 MOOC学习笔记(全)
- 知识图谱文献综述(第一章 知识表示与建模)
- 什么是二维条码与及特点
- matlab一维矩形积分,玩转matlab之一维 gauss 数值积分公式及matlab源代码
- 毕业设计 基于深度学习的人脸性别年龄识别 - 图像识别 opencv
- 分支类1 7-3 根据输入的空气污染指数,输出相应的信息。 (5 分)
热门文章
- Windows WEB服务器配置安全规范
- Redis6-过期淘汰、经典数据类型的实现
- 单一原则,开放-封闭原则,依赖反转,里氏族替换原则
- VB.NET学习笔记:ADO.NET操作ACCESS数据库——OleDbDataAdapter的Update方法更新数据库的秘密(行状态RowState和行版本 DataRowVersion)
- 记一次内网渗透测试实训总结
- access数据库连接_从MS Access连接到不同的数据库
- C++:OTSU确定标线点云分割阈值
- Qt5 CMake配置
- C语言与Windows API编程!有无同路人?
- 迷茫中的java入門者