kernel detective 查看linux kernel版本ssdt为什么都被修改

PHP开发框架
开发工具/编程工具
服务器环境6803人阅读
黑苹果(14)
版权说明:本文章参考tonymacx86的这篇文章,
如果需要转载,请注明原文地址:
为了让OS X的各个组件在你的笔记本上更好的运行,你通常需要一个经过适当打了补丁的DSDT以及一系列SSDT。本文将为你之后正确地对OEM提供的DSDT/SSDT打补丁打下基础。
高级用户或许希望能够通过Clover实现在不提取DSDT/SSDT的情况下打补丁,参见这篇教程:。
如果你尝试使用来自另一台电脑的DSDT,那么你几乎总会以失败告终。你很难验证来自其他电脑的ACPI文件是否有效。如果你使用外来的ACPI文件,有时即使硬件配置上的细微差别(BIOS版本,内存大小,BIOS的设置以及其它硬件差异不如无线网卡)也会导致系统的不稳定和莫名其妙的问题。这些硬件配置差异会导致地址空间的差异,从而导致一台计算机的DSDT并不适合另一台计算机。即使同一型号的电脑,也经常会发生配置了不同的主板这种情况,从而导致ACPI文件的各不相同。
打补丁的过程分为以下几步:
获取原始文件
反编译原始文件
分析和过滤原始文件
保存(编译)和安装
获取原始ACPI文件
所有的BIOS都会为操作系统提供一套ACPI文件。所以,不管什么操作系统,你都可以获取这些文件以便后续打补丁。你可以在Linux,OS X,Windows甚至 Clover里取得这些文件。不管什么方式,你获取的这些文件都完全相同,不过因为软件不同,命名可能也不同。
本篇教程将使用三种方法获得ACPI文件:在OS X里使用patchmatic;在Clover里使用F4;使用Linux。
使用patchmatic
如果你已经安装了OS X,并且没有使用任何打过补丁的ACPI文件启动,你可以使用patchmatic来获得DSDT/SSDT原始文件。从此处下载patchmatic可执行文件(请务必阅读README文件因为下载地址在里面)。如果想要在终端中使用,你需要把可执行文件(在ZIP中)复制到 /usr/bin 中。
安装完patchmatic之后,你可以在终端中这样调用:
cd ~/Desktop
mkdir extract
cd extract
patchmatic -extract
patchmatic会把所有已经加载的ACPI文件释放到当前文件夹,如果你在bootloader中使用了任何选项从而影响了DSDT/SSDT,你将无法获得原始的ACPI文件,所以你需要确保没有使用这样的选项。比如说,如果你使用(Chameleon)DropSSDT=Yes,或者(Clover) DropOem=true,原生的SSDT会被忽略,这样你就没有办法在patchmatic获得它们了。对于Clover DSDT “Fixes”也是相同的道理——这些修复会修改原生的DSDT,所以你需要避免这些修复。有一些选项比如GeneratePStates/GenerateCStates=Yes, 或者是 Clover的 /ACPI/SSDT/Generate/CStates /ACPI/SSDT/Generate/PStates将会注入额外的SSDT,从而导致一些莫名其妙的问题,这些情况都应该被避免。
结合上述这些原因,使用Linux或Clover来获得ACPI文件更加简单。
注意:使用’patchmatic -extract’来确认你获得的DSDT/SSDT是否是你需要的文件是一个有效的方法。
使用Clover F4(推荐)
推荐使用Clover F4这种方法,不仅因为提取的方法很简单,而且还可以很方便地对ACPI的原始文件和打过补丁的文件进行比对(为了分析解决问题)。
在Clover的主页,你可以按F4然后Clover会把原生的ACPI文件放到EFI/Clover/ACPI/origin目录下。当你启动OS X之后你就可以对它们进行反编译或者打补丁操作。注意,有些BIOS需要同时按Fn+F4才能激活F4,所以如果你不确定,把F4盒Fn+F4都按一遍。这个过程并不会有任何反馈,因为要等待文件写入会有一个小小的延迟,如果这些文件被写入USB存储设备,那么这个延迟会更加明显。
有时,Clover F4会写入重复的SSDT。这些副本在反编译的时候会造成一些问题。如果你真的遇到这样的问题,你需要分析哪些文件是副本,最简单的方法就是看文件大小,相同的文件大小往往对应着相同的文件。
你可以通过在终端中输入以下命令来查看SSDT的字节大小。
ls -l SSDT*.aml
使用Linux获得文件
在Linux中,原生的ACPI文件直接存在于文件系统之中。你可以在/sys/firmware/acpi/tables 和 /sys/firmware/acpi/tables/dynamic目录中找到它们。你可以在终端中输入命令来获得所有文件。
你没有必要安装Linux,只要从USB启动即可:
在终端中输入
sudo cp -R /sys/firmware/acpi/tables DEST
你需要把这些文件复制到一个FAT32文件系统的USB设备。使用FAT32文件系统可以避免权限问题因为这个文件系统不支持文件权限。DEST的值是你的USB设备的挂载点,它由你的Linux版本和Linux的启动方式决定,你可以 通过在终端中输入mount来查看挂载点,或者在Linux文件管理器中把鼠标放在存储设备的图标上来查看。
反编译所需的工具
为了正确反编译你获得的文件,你需要iasl编译器,它需要在终端运行。
你需要一个较新版的iasl来正确地反编译。可以在这里下载适当的版本:。。推荐把iasl的可执行文件复制到/usr/bin,这样就能在终端中方便使用该工具。
举个例子,如果你把它下载到~/Downloads/iasl.zip,你可以在终端中通过以下方法进行解压和复制:
cd ~/Downloads
unzip iasl.zip
sudo cp iasl /usr/bin
从github编译最新版本的iasl
你可以从github编译最新版的iasl,假设你已经安装了Xcode:
mkdir ~/Projects && cd ~/Projects
git clone https://github.com/RehabMan/Intel-iasl.git iasl.git
cd iasl.git
最新的版本总是包含一些实验性的并且没有经过完全测试的代码。比如,新的代码中Intel添加了If/Else代码块因为Switch/Case有Bug。
建议使用修改之前的版本
git checkout b9c6c2b
注意:b9c6c2b这个版本在bitbucket已经提供下载。
然后编译工程:
现在你可以使用以下命令安装:
sudo make install
如果你已经安装了MaciASL,你也可以在MaciASL中使用新版的编译器(在/usr/bin这个目录下):
sudo cp /usr/bin/iasl /Applications/MaciASL.app/Contents/MacOS/iasl61
最新版的iasl总会在bitbucket提供下载,但对于那些总是喜欢使用最新版的人,需要自己编译项目。。。
反编译ACPI文件
虽然原生的ACPI文件可以通过MaciASL直接打开,但并不推荐这么做。直接使用MaciASL打开将会导致aml文件被单独反编译,如果aml文件之间有复杂的引用关系,将不能正确地进行反编译,你将会发现一堆难以修复的错误。
因此,最好将所有aml文件一起进行反编译。你需要把所有的DSDT/SSDT放在一个独立的文件夹中,不要把不相关的文件复制进来,并且确保所有文件以.aml结尾。
然后,在终端中输入以下命令进行反编译:
cd "to directory where you placed all SSDT/DSDT"
iasl -da -dl *.aml
注意:不要尝试使用-da选项反编译其它的ACPI文件,不会有任何效果。
注意:也请阅读下方的部分,考虑使用refs.txt,方法很简单,但可以有效排除许多常见的错误。
完成上述步骤之后,你只需要使用*.dsl文件来做接下来的工作,可以使用MaciALS来编辑它们。当然,要使用它们,你必须把它们保存为“ACPI Machine Language Binary”格式并且以.aml作为文件的后缀,然后将它们放在正确的位置以便被bootloader加载。你可以保留这些打过补丁的..dsl文件以便以后打更多的补丁。
注意:使用ACPI6.1可以更好地处理被iasl编译过的aml文件。ACPI6.1在编译器中添加了一个组件,使用它可以在生成的aml文件中添加外部引用信息。ACPI的解释器会忽略这些信息,但是这些信息对于反编译器正确地反编译一个独立的aml文件很有用。因此,你可能会发现被新的工具重新编译过的aml文件可以直接被MaciASL打开并且不包含任何错误。当然,我们直接提取的aml文件中由于不包含这些信息,所以此时我们仍然需要使用-da选项联合所有的aml文件进行反编译,正如上面所介绍的。
注意:针对Snow Leopard的ACPI文件:很不幸,10.6.8这个版本太老了以至于其阻止aml进行外部引用。如果你需要将ACPI文件应用在Snow Leopard中,你需要在将dsl编译到aml的时候使用-oe选项。这个选项不能在MaciASL中使用,因此你只能在终端中完成编译。
使用refs.txt来完成反编译
有时会存在一些未定义的外部符号。isal反编译器会尝试猜测参数的个数,但这种尝试经常出错。你可以通过使用一个记录着外部定义的文本文件来纠正这些错误。常见的未定义符号比如SGPO, ECRD, ECWT, 和 MMTB。下面的refs.txt包括一些常见和非常见的丢失符号(根据论坛上网友的反馈得来)来解决反编译器遇到的问题。
首先在DSDT/SSDT所在的目录下厂家refs.txt文件:
External(MDBG, MethodObj, 1)
External(_GPE.MMTB, MethodObj, 0)
External(_SB.PCI0.LPCB.H_EC.ECWT, MethodObj, 2)
External(_SB.PCI0.LPCB.H_EC.ECRD, MethodObj, 1)
External(_SB.PCI0.LPCB.H_EC.ECMD, MethodObj, 1)
External(_SB.PCI0.PEG0.PEGP.SGPO, MethodObj, 2)
External(_SB.PCI0.GFX0.DD02._BCM, MethodObj, 1)
External(_SB.PCI0.SAT0.SDSM, MethodObj, 4)
External(_GPE.VHOV, MethodObj, 3)
External(_SB.PCI0.XHC.RHUB.TPLD, MethodObj, 2)
注意:一个更友好的方式是在终端中使用pbpaste创建文件。你需要首先将上方的文档复制到剪贴板(别告诉我你不会),然后:
pbpaste&refs.txt
上述命令会在当前目录创建refs.txt文件,然后在反编译的过程中使用该文件:
iasl -da -dl -fe refs.txt *.aml
老版本的反编译器会把这些外部声明放在其它声明的前面。这不是一个好方法。大多数时候,你需要把它们移动到其它声明的后面。这种错误非常明显,因此当你看到来自refs.txt中的外部声明的错误时应当能够辨别。在ACPI6.1当中,这个bug已经被修复了。
筛选ACPI文件
对于一些老电脑(Sandy Bridge或者更早的)来说,与CPU相关的SSDT会造成一些问题,如果你遇到这样的问题,那么你不能把这样的SSDT放在ACPI/patched。
如果没有问题,我比较喜欢按照原始的顺序使用那些正确地打过补丁的SSDT。如果又一个SSDT没有经过任何修改,那么你不需要重新编译它,直接使用原始的aml文件即可。
注意:来自Clover或者Linux的动态子目录的SSDT不能被放在ACPI/patched下,因为这些SSDT只有在需要的时候才会被动态加载进来,可能不够完整。
当你成功地反编译所有文件之后,检查每一个SSDT文件从而确定这些SSDT的功能。如果一个SSDT与CPU相关并且你确定其会导致一些问题,那么就将它放在一边,不要把它放在bootloader的相关目录中。大多数时候,如果SSDT中存在包含在Scope _PR.CPUx中的object,那么它很有可能与CPU有关。
下面列出你可能会遇到的典型SSDT
与CPU相关:如上所述,包含一些会导致问题的未知因素。
SATA:无所谓是否使用,看你是不是强迫症。
PTID:大多数情况这个文件对于OS X来说没什么用,并且包含许多错误。少数情况下,它可能会提供读取风扇转速,温度或者其它系统状态的方法。
IAOE:如果这个SSDT存在,它经常作为DSDT中的in _PTS 和 _WAK的入口。如果没有它系统睡眠可能会出现问题。
GFX0:通常存在’Device GFX0’的SSDT与集成显卡有关。你需要在这个SSDT上打补丁来实现背光控制。一些老的笔记本经常会把GFX0定义在DSDT中。新的Haswell笔记本通常定义在SSDT中(即使也可以定义在DSDT中)。
PEGP:在双显卡的笔记本中PEGP通常与独立显卡有关。这样的SSDT通常不止一个,你需要把它们联合起来,这样打补丁才会有效。最常见的就是禁用独立显卡的补丁。
你最好记下哪些SSDT你打算忽略,哪些需要保留原始文件,哪些需要修改。
即使进行联合反编译,反编译出的代码仍然可能包含一些错误。导致这些错误的原因有很多,如果iasl的某些修改,iasl自身的不完善,以及笔记本之间的不同编译环境。比如,一个导致错误的常见原因(我自己的想法)是一些被引用的函数(比如MMTB和MDBG)实际上是存在于Windows系统本身的,而不在ACPI中;还有一种情况是代码中本身存在bug或者是代码被无意地写入(有时很难区分这一点)。
因此,当你已经知道了你需要哪些ACPI文件,你必须修正它们之中包含的错误。在我的github仓库中有许多修复常见错误的补丁,你可以使用MaciASL完成打补丁的操作。
MaciASL软件:
笔记本补丁:
注意:我没有在DSDT editor上测试我的补丁,因为它包含了太多的bug,而且iasl的版本也太老,因此就不要来问关于它的问题啦。
为了能够顺利完成下载和对MaciASL进行正确的设置,请务必提前阅读README文件。应对syntax/error的补丁的名字以”[syn]”开头,对一些比较老的DSDT来说常见的例子如”Fix _PLD Buffer/Package Error”, “Fix TNOT Error”, 和 “Fix FPED Parse Error”。为了确定你需要哪些补丁,你可以阅读iasl报出的错误信息以及引起错误的代码。你也可以尝试应用一些补丁,同时在MaciASL中观察补丁对文件进行了修改,如果你对某个错误不是很熟悉,可以通过这种方法多尝试几次来修正错误。
对于某些错误,你可以通过简单地删除造成错误的代码。但是这取决于这些代码是否有用。比如说,由’External’引起的错误可以直接删除来解决错误。如果你想,你甚至可以写一个补丁来自动完成这个工作。
如果你对ACPI比较熟悉并且有一点编程基础将会对这些工作很有好处。
目前你的目标是让这些dsl文件在编译的时候没有errors (warnings/remarks/optimizations 一般不会有影响)。一旦你得到一个编译无误的文件,你就可以继续对它进行打补丁来修复你遇到的问题。
常见的补丁
一般来说,只有当你需要修复特定的问题的时候才需要对DSDT打补丁,但是有一些补丁在很多场合下都需要使用并且几乎不大可能会导致问题,这些补丁也在github的仓库中:
“Fix _WAK Arg0 v2”
“HPET Fix”
“SMBUS Fix”
“IRQ Fix”
“RTC Fix”
“OS Check Fix”
“Fix Mutex with non-zero SyncLevel”
“Fix PNOT/PPNT” (只有当你忽略了与CPU有关的SSDT才需要使用)
“Add IMEI” (如果你的DSDT或者SSDT已经存在IMEI/HECI/MEI device,不需要使用该补丁)
注意:The OS Check Fix补丁跟你电脑出厂预装的系统或者现在正在使用的系统版本都没有关系。
注意:如果你使用了所有的SSDT不要使用”Fix PNOT/PPNT”这个补丁,只有在你去除了与CPU相关的SSDT情况下才能使用。
USB补丁可以修复“瞬间唤醒”问题,这个问题导致电脑在从睡眠到开始到唤醒的几秒钟内不能再次睡眠。
针对你的硬件适当打上补丁
“6-series USB”
“7-series/8-series USB”
USB3 Mutliplex补丁可以让你使用苹果原生的AppleUSBXHCI.kext而不是GenericUSBXCHI.kext。它基于Mieze公布的一些写信。大多数DSDT需要修改才能使用。比如ProBook就需要使用该补丁的一个修改版本。而Lenovo u310/u410可以直接使用:
“7-series USB3 Multiplex”
如果你正在Yosemite上使用GenericUSBXHCI.kext,确保你使用的是为Yosemite生成的GenericUSBXHCI.kext。要避免瞬间唤醒这种情况你可能还需要内核标识 -gux_defer_usb2。
如果在使用AppleUSBXHCI.kext的时候遇到瞬间唤醒的问题,一个可选的解决方案是使用”USB _PRW 0x6D (instant wake)”。你必须检查DSDT与 _PRW有关的函数的返回值来确定这个补丁是否适合你的DSDT。当然github仓库还提供了”USB _PRW 0x0D (instant wake)”(0x0d和0x6d对于XHC/EHC/HDEF来说都是从_PRW返回的常见值)。
如果你有一个Haswell CPU/8-series 芯片组,,并且AooleLPC.kext没有加载,你需要使用下面的补丁注入一个合适的ID从而允许驱动被加载:
“Haswell LPC”
如果你有一个Skylake CPU/100-series 芯片组,,并且AooleLPC.kext没有加载,你需要使用下面的补丁注入一个合适的ID从而允许驱动被加载:
“Skylake LPC”
注意:重命名一定要彻底。通常,重命名可以更好地适配OS X系统。比如把GFX0重命名为IGPU可以让IGPU power management正确工作。在这种情况下,所有与其有关的SSDT/DSDT都需要参与重命名。
注意:一定要避免重名现象发生。一种很常见的情况是往SSDT中添加一个_DSM函数,但同时OEM也在同一个路径中定义了一个_DSM函数。要避免这种情况,你可以使用”Remove _DSM methods”补丁作为你使用的第一个补丁,当然也可以选择”Rename _DSM methods to XDSM” 这个补丁,因为有时”Remove _DSM methods”会暴露出MaciASL的一个bug。
针对特定问题的补丁
电池状态:
背光控制:
禁用独立显卡:
当你在阅读一些针对特定笔记本的教程的时候,这些文章可能会直接将补丁的内容贴出来,你只需要把这些补丁的内容直接粘贴到MaciASL的窗口中,然后点击Apply即可。
如果你对编写补丁文件很感兴趣,请阅读MaciASL的补丁语法:
注意:在许情况下,对DSDT补丁需要与一些附加的kext结合从而使kext被系统正确加载。
保存与加载
为了使用打过补丁的DSDT/SSDT,你需要把它们保存在正确的位置从而可以让bootloader加载它们。对于不同的bootloader,保存的路径不同,命名要求也不同。首先你必须保存为”ACPI Machine Language Binary”格式。如果保存为AML extension可能会导致系统出现一些非常奇怪的问题。
Clover:文件首先应该被放置在Clover所在的分区(一般都是EFI分区),所以路径就是EFI/Clover/ACPI/patched。如果DSDT.aml文件存在,会自动替换OEM的DSDT。对于版本号低于3062的Clover,ACPI文件必须被命名为SSDT-x,x表示一个数字,最高到19.Clover允许数字不连续。版本号大于等于3062的Clover,会加载所有后缀为aml的文件,对于命名没有要求。记住SSDT的加载顺序很重要,因此按照原始的顺序命名SSDT很重要。
注意,针对Clover 3062+,由于SSDT加载方式的改变导致加载顺序变得随机,因此需要规定通过修改config.plist/ACPI/SortedOrder来指定加载顺序,下面的文件提供了一个很好的加载顺序模板:
Chameleon(或者 Chimera):文件需要放置在 系统盘的/Extra目录下。如果DSDT.aml文件存在,会自动替换OEM的DSDT。Chameleon不允许不连续的编号,所以需要命名为SSDT.aml, SSDT-1.aml, SSDT-2.aml, SSDT-3.aml等等。如果你命名为SSDT.aml, SSDT-1.aml, SSDT-4.aml, SSDT-5.aml,那么只有SSDT.aml, SSDT-1.aml会被加载因为后面的不再连续,所以被忽略。
最后,记住你不能只是把ACPI文件放在目录里而不忽略OEM的SSDT。最简单的办法就是使用DropSSDT=Yes (Chameleon) 或者 ACPI/SSDT/DropOem=true (Clover)来忽略所有的原生SSDT从而加载你修改过的SSDT。
MaciASL (RehabMan fork):
patchmatic:
iasl (RehabMan fork):
ACPI spec:
RehabMan github:
Clover laptop guide:
Clover config.plist files for laptops:
Clover thread:
Clover changes:
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:283891次
积分:7056
积分:7056
排名:第3090名
原创:425篇
转载:28篇
译文:14篇
评论:100条
(2)(3)(4)(34)(25)(16)(20)(24)(1)(1)(5)(13)(18)(10)(13)(4)(12)(1)(11)(11)(28)(17)(1)(24)(46)(37)(22)(40)(10)(4)(9)标 题:&内核读写只读内存方法总结[Delphi描述]
作 者: Anskya
时 间: ,16:24:39
链 接: /showthread.php?t=63791
以下代码均已Delphi描述...至于为什么...
首先我是一个Delphi&Coder...虽然我大部分时间使用的是ASM编译器和C编译器
但是我喜欢Delphi...好了不废话了...
已知的三种方法:如果各位有更好的意见欢迎大家提出
[1]使内存可读写
1.stl+cr0:
这个方法大家想必经常使用...
(参考I-32.3A文档)
由于cr0是一个32位寄存器...假设大家的CPU是32位的.没有64位测试环境
按照图这个结构我们可以了解到的信息
第16位:WP——Write&Protect,当设置为1时只提供读页权限
第0位:PE——Paging,当设置为1时提供分页
第1位:MP——Protection&Enable,当设置为1时进入保护模式
按照这个说明写出代码:
//1&关闭写保护
&&push&eax
&&mov&eax,&CR0
&&and&eax,&0FFFEFFFFh
&&mov&CR0,&eax
//2&打开写保护
&&push&eax
&&mov&eax,&CR0
&&or&eax,&NOT&0FFFEFFFFh
&&mov&CR0,&eax
也许大家看得有点模糊.其实这个代码就是修改第16位
NOT&0FFFEFFFFh&=&h
因为要设置第16位为1...所以结果也就是代码那种效果...
鄂~我也不知道说什么了.也就是位操作你也可以直接使用
//1&关闭写保护
&&push&&eax
&&mov&&&eax,&cr0
&&and&&&eax,&not&h
&&mov&&&cr0,&eax
&&pop&&&eax
//2&打开写保护
&&push&&eax
&&mov&&&eax,&cr0
&&or&&&&eax,&h
&&mov&&&cr0,&eax
&&pop&&&eax
一般使用的时候我们都会加上cli和sti,由于这两个指令只能控制当前CPU对于
多核系统是无法起到有效的互斥的...所以一般都是配合&自转锁&使用
关于自转锁的话题我们下面会详细的说的
2.通过内存描述表(MDL)中描述一块内存区域,MDL包含此内存区域的起始地址,
拥有者进程,字节数量以及标志.(据说是Bill提供的方法.难道和VirtualProtect一样?)
&&PMDL&=&^_MDL;
&&_MDL&=&packed&record
&&&&Next:&PMDL;
&&&&Size:&USHORT;
&&&&MdlFlags:&USHORT;
&&&&Process:&P
&&&&MappedSystemVa:&PVOID;
&&&&StartVa:&PVOID;
&&&&ByteCount:&ULONG;
&&&&ByteOffset:&ULONG;
&&MDL&=&_MDL;
&&MDL_MAPPED_TO_SYSTEM_VA&&&&&=&$0001;
&&MDL_PAGES_LOCKED&&&&&&&&&&&&=&$0002;
&&MDL_SOURCE_IS_NONPAGED_POOL&=&$0004;
&&MDL_ALLOCATED_FIXED_SIZE&&&&=&$0008;
&&MDL_PARTIAL&&&&&&&&&&&&&&&&&=&$0010;
&&MDL_PARTIAL_HAS_BEEN_MAPPED&=&$0020;
&&MDL_IO_PAGE_READ&&&&&&&&&&&&=&$0040;
&&MDL_WRITE_OPERATION&&&&&&&&&=&$0080;
&&MDL_PARENT_MAPPED_SYSTEM_VA&=&$0100;
&&MDL_LOCK_HELD&&&&&&&&&&&&&&&=&$0200;
&&MDL_PHYSICAL_VIEW&&&&&&&&&&&=&$0400;
&&MDL_IO_SPACE&&&&&&&&&&&&&&&&=&$0800;
&&MDL_NETWORK_HEADER&&&&&&&&&&=&$1000;
&&MDL_MAPPING_CAN_FAIL&&&&&&&&=&$2000;
&&MDL_ALLOCATED_MUST_SUCCEED&&=&$4000;
//&&读写只读内存(源于Gates大叔)
function&WriteReadOnlyMemoryGates(lpDest,&lpSource:&P&Length:&Integer):&
&&tempSpinLock:&KSPIN_LOCK;
&&oldirql:&KIRQL;
&&mdl:&PMDL;
&&writableAddress:&P
&&Result&:=&STATUS_UNSUCCESSFUL;
&&mdl&:=&MmCreateMdl(nil,&lpDest,&Length);
&&if&(mdl&&&&nil)&then
&&&&MmBuildMdlForNonPagedPool(mdl);
&&&&mdl^.MdlFlags&:=&mdl^.MdlFlags&or&MDL_MAPPED_TO_SYSTEM_VA;
&&&&writableAddress&:=&MmMapLockedPages(mdl,&KernelMode);
&&&&if&(writableAddress&&&&nil)&then
&&&&&&oldirql&:=&0;
&&&&&&KeInitializeSpinLock(@tempSpinLock);
&&&&&&fast_KfAcquireSpinLock(@tempSpinLock);
&&&&&&memcpy(writableAddress,&lpSource,&Length);
&&&&&&fast_KfReleaseSpinLock(@tempSpinLock,&oldirql);
&&&&&&MmUnmapLockedPages(writableAddress,&mdl);
&&&&&&Result&:=&STATUS_SUCCESS;
&&&&MmUnlockPages(mdl);
&&&&IoFreeMdl(mdl);
关键一步就是修改mdl的属性.让他可写....
下面来看看第三种方法
3.使用IoAllocateMdl来得到可写内存...
源于Mark早期写的代码...我这里直接翻译了...至于原理
大家参考一下DDK吧...我发现自己表达能力有限...
//&&写只读内存(源于Mark代码)
function&WriteReadOnlyMemoryMark(lpDest,&lpSource:&P&Length:&Integer):&
&&tempSpinLock:&KSPIN_LOCK;
&&oldirql:&KIRQL;
&&mdl:&PMDL;
&&writableAddress:&P
&&Result&:=&STATUS_UNSUCCESSFUL;
&&mdl&:=&IoAllocateMdl(lpDest,&Length,&False,&False,&nil);
&&if&(mdl&&&&nil)&then
&&&&MmBuildMdlForNonPagedPool(mdl);
&&&&MmProbeAndLockPages(mdl,&KernelMode,&IoWriteAccess);
&&&&writableAddress&:=&MmMapLockedPages(mdl,&KernelMode);
&&&&if&(writableAddress&&&&nil)&then
&&&&&&oldirql&:=&0;
&&&&&&KeInitializeSpinLock(@tempSpinLock);
&&&&&&fast_KfAcquireSpinLock(@tempSpinLock);
&&&&&&memcpy(writableAddress,&lpSource,&Length);
&&&&&&fast_KfReleaseSpinLock(@tempSpinLock,&oldirql);
&&&&&&MmUnmapLockedPages(writableAddress,&mdl);
&&&&&&Result&:=&STATUS_SUCCESS;
&&&&MmUnlockPages(mdl);
&&&&IoFreeMdl(mdl);
代码源于Mark早期编写的代码
相信看到这份代码和上面的第二种方法相信大家似乎都明白了什么...
是不是觉得两种方法都差不多区别就是在于
一个是直接修改MDL属性:MDL_MAPPED_TO_SYSTEM_VA
一个是MmProbeAndLockPages(mdl,&KernelMode,&IoWriteAccess);
来改写属性...其实这两种方法...嘿嘿~自己看看就明白了...
[2]改写内存!
平时我们修改内存单核下没有什么顾虑.stl|代码|cli
开关中断以后就可以自己操作了...
因为现在双核和多核越来越兴起了...
这么说吧.内存在没有完全修改完毕的时候...其他线程去读取的话...
就会造成读取错误的数据或者断码...
如果您是单核的话可以直接修改
1.stl+cli
&&&&&&cli&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//disable&WP&bit
&&&&&&push&&eax
&&&&&&mov&&&eax,&cr0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//move&CR0&register&
&&&&&&and&&&eax,&not&h&&&&&&&&&&&&&&&&&&&&&&&&&//disable&WP&bit
&&&&&&mov&&&cr0,&eax&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//write&register&back
&&&&&&pop&&&eax
&&&&//改写的代码
&&&&&&push&&eax&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//enable&WP&bit
&&&&&&mov&&&eax,&cr0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//move&CR0&register&
&&&&&&or&&&&eax,&h&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//enable&WP&bit
&&&&&&mov&&&cr0,&eax&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//write&register&
&&&&&&pop&&&eax
2.利用原子互斥操作
比如说我们需要SSDT,Shadow,etc&Hook
修改地址等操作的话...我们有一个简单的方法
使用...Interlocked系函数
修改地址推荐使用InterlockedExchange...
释放方法很简单
ZwOpenProcessNextHook&:=&TZwOpenProcess(InterlockedExchange(SystemServiceName
(GetImportFunAddr(@ZwOpenProcess)),&LONG(@ZwOpenProcessNextHook)));
提示一下这个函数使用的是fastcall调用方式,如果你使用的是Delphi的话建议你最好
注意一下使用方法...fastcall和Delphi的register的是有区别的
第一个参数:edx
第二个参数:ecx
第一个参数:eax
第二个参数:edx
第三个参数:ecx
提供以下InterlockedExchange的源代码
FORCEINLINE
InterlockedExchange(
&&&&IN&OUT&LONG&volatile&*Target,
&&&&IN&LONG&Value
&&&&__asm&{
&&&&&&&&mov&&&&&eax,&Value
&&&&&&&&mov&&&&&ecx,&Target
&&&&&&&&xchg&&&&[ecx],&eax
自转锁是内核中的一种同步机制...
关于自转锁的介绍请大家去看
&&Programming&the&Microsoft&Windows&Driver&Model&&这本书...
这本书刚开始看许多东西暂时还不太理解...
当线程获取自转锁的时候...会将当前线程提升到DISPATCH_LEVEL级别
这个时候内核将不会分配时间片给其他的CPU.这样就不会有其他线程
在你写操作的时候去访问你没有写完的地方了...放心大胆的写了...
怎么写?晕...这个问题这个问题...呵呵我可以不回答吗?memcpy总会用吧...
自转锁使用起来很简单...
(有个疑问.为什么获取和释放自转锁的函数在hal.dll函数中,初始化自转锁的函数
却在ntoskrnl.exe模块中...)
KeInitializeSpinLock(@TemSpinLockp);
KeAcquireSpinLock(@TemSpinLockp,&&oldirql);
你的操作代码
KeReleaseSpinLock(@TemSpinLockp,&oldirql);
如果有其他内核线程已经获取自转锁的时候你的线程是不会被分配到时间片的
所以你不用担心你会进去破坏代码(除非~除非~你提升到更高的级别...)
当你获取自转锁成功后..其他线程将进入自转状态..你可以理解为互斥
(EnterCriticalSection,LeaveCriticalSection)
[警告]请千万不要连续使用两次KeAcquireSpinLock!否则机器会(卡)死的很难看的
其他方法暂时不清楚.暂时由于自转锁的这种特殊效果.
所以大家能不用的时候尽量不要使用...使用的时候尽量减少自转时间.以达到更高的
小弟初学驱动编程.如果有不对的地方请各位大牛补充说明...这里拜过
&&如何写windows系统已保护的内存区域&&的作者.由于被转载了不知道多少次
当我看到这篇文章的时候...作者已经不知道是谁了...感谢这位无名英雄...谢谢
zhuwg,FlowerCode,农夫大哥,冷风(烤鸭),旋转&AV&群里的各位神牛们
希望感兴趣的Delphi&Fans可以PM我大家一起交流一下开发经验...*转载请注明来自看雪论坛@ &
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:37589次
排名:千里之外
转载:82篇
(1)(1)(4)(1)(1)(2)(17)(29)(25)(1)}

我要回帖

更多关于 kernel detective 1.5 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信