首页
论坛
专栏
课程

[原创]突破Windows XP 4G内存限制续

scdeny
2
2011-11-14 14:12 220852
上次经过一段时间的研究后,发现了通过修改ntkrnlpa.exe可以突破Windows XP 4G内存限制,完全使用4G以上物理内存(http://bbs.pediy.com/showthread.php?t=137830),但是在测试过程中发现使用USB存储设备时会出现蓝屏等问题,后来因为太忙,也没能继续研究。最近难得短暂清闲,功夫不负有心人,花了一个多星期终于找到问题所在了,下面谈谈在探索过程中的一些心得。
1.首先替换usb相关驱动
既然一插U盘就蓝屏,而使用USB鼠标、摄像头等都没有问题,那么首先怀疑是usbstor.sys的问题。Windows 2003可以支持4G以上物理内存,那么我们将Windows 2003的USB驱动替换到XP上来,首先替换usbstor.sys,现象依旧。那么全部替换usb相关驱动,包括usbstor.sys、usbport.sys、usbhub.sys、usbehci.sys等,XP可以正常启动,USB设备也能使用,但经反复测试,发现使用U盘时有时还是会蓝屏。
2.是谁造成了内存访问越界?
种种蓝屏迹象表明,很可能是因为内存读写越界造成的。破解4G限制后,虽然物理地址扩展到32位以上,但是虚拟地址依然是32位的啊,使用虚拟地址的程序不可能造成内存访问越界啊。那么有哪些代码用到了物理地址呢? 
首先想到的是内存分页管理,负责映射物理地址到虚拟地址空间,维护了一个物理内存的页帧数据库MmPfnDatabase,会不会是因为物理地址空间扩大后,这个页帧数据库并没有扩大,而导致映射4G以上物理内存时发生错误呢?
一番折腾,在MiInitMachineDependent函数中找到了如下代码
MmFreePagesByColor[0] = (PMMCOLOR_TABLES)&MmPfnDatabase[MmHighestPossiblePhysicalPage + 1];

看来XP对这个数据库空间还是有考虑的,验证一下
lkd> dd MmPfnDatabase
8088b0c8  818c6000 0000ff00 00000006 0000003f
lkd> dd MmHighestPossiblePhysicalPage
8088b120  00137fff 00137fff 000f7379 00000040

MMPFN结构体大小为1C字节
lkd> dt _MMPFN
nt!_MMPFN
   +0x000 u1               : __unnamed
   +0x004 PteAddress       : Ptr32 _MMPTE
   +0x008 u2               : __unnamed
   +0x00c u3               : __unnamed
   +0x010 OriginalPte      : _MMPTE
   +0x018 u4               : __unnamed
lkd> ?818c6000+(137fff+1)*1c
Evaluate expression: -2085724160 = 83ae6000
lkd> dd MmFreePagesByColor
80886388  83ae6000 83ae6300 c0883000 f77fffff

MmPfnDatabase确实是预留了足够大的空间,既然MmPfnDatabase空间足够大,那就不存在页面映射错误,还会是谁会直接操作物理地址呢?
3.谁动了我的物理地址?
感谢Geoff Chappell的一篇文章
《Licensed Memory in 32-Bit Windows Vista》
其中提到了微软官方关于Windows XP sp2以后版本无法显示全部物理内存的答复:
《The RAM reported by the System Properties dialog box and the System Information tool is less than you expect in Windows Vista or in Windows XP Service Pack 2 or later version》,
从这里又链接到完整版的介绍:
《Changes to Functionality in Microsoft Windows XP Service Pack 2
Part 3: Memory Protection Technologies》

其中讲到了
The largest driver PAE compatibility issue involves direct memory access (DMA) transfers and map register allocation. Many devices that support DMA, usually 32-bit adapters, are not capable of performing 64-bit physical addressing

大意是说: PAE兼容的最大问题是驱动程序进行的直接内存访问(DMA)传输和映射寄存器分配。很多设备都支持DMA,但DMA往往为32位的,不能执行64位物理寻址。
那么我们遇到的问题很可能就是DMA的问题了,因为在DMA传输过程中,DMA不经过页表映射,直接访问物理地址。经过我们的4G内存限制破解后,物理地址范围扩大到了4G以上,PAE最大可以寻址64G(36位物理地址),如果驱动在请求DMA向4G以上物理地址传输数据时,DMA就会将36位地址截断为32位地址,从而将数据传输到错误的内存地址,导致蓝屏,难道我们只有祈求驱动分配4G以下物理内存了吗?DMA硬件都只能接受32位地址,在碰到36位地址时就无能为力了吗?当然不能!
4.双缓冲DMA传输
 The Windows 2000 Server family and later provide double-buffering for the DMA transaction by providing a 32-bit address that is indicated by a map register. The device can perform the DMA transaction to the 32-bit address and the kernel copies the memory to the 64-bit address that is provided to the driver.

Windows 2000 Server family及其以后的版本通过映射寄存器为DMA传输提供了双缓冲机制,也就是说,为每次请求DMA传输的缓冲区再分配一块位于32位物理地址空间的内存,让DMA将数据传输到这块低地址空间,内核再将这些数据复制到驱动提供的64位地址。所以尽管存在DMA硬件限制,32位Windows 2003依然能够正常使用4G以上内存。
5.难道是USB驱动不支持双缓冲映射?在向DMA写入物理地址时将36位物理地址截断了?那么逆向usb驱动,感谢tiamo对USB体系的分析
http://bbs3.driverdevelop.com/read.php?tid=86767&skinco=wind
不然真是无从着手,USB数据传输时的调用堆栈如下:
b82540e0 f805a042 81fc29dc 81840c80 817e88f4 usbehci!EHCI_SubmitTransfer+0x53
b8254128 f805a74a 81fc2028 81840b08 804e3ec4 USBPORT!USBPORT_DmaEndpointActive+0x1f0
b8254154 f805cb7c 81fc2028 00000000 804e3ec4 USBPORT!USBPORT_DmaEndpointWorker+0x140
b825417c f805e4c3 81fc2028 00000003 00000001 USBPORT!USBPORT_CoreEndpointWorker+0x6d2
b82541f0 806f2a98 81fc2028 00000000 413e504d USBPORT!USBPORT_MapTransfer+0x76f
b825421c 8052e551 821c7788 81fc205c 00000001 hal!HalAllocateAdapterChannel+0x126
b8254234 f805e6df 821c7788 81fc2028 00000001 nt!IoAllocateAdapterChannel+0x2a
b8254278 f805f4d9 81fc2028 817adad0 804e3ec4 USBPORT!USBPORT_FlushMapTransferList+0x1b1

USBPORT.SYS通过调用nt!IoAllocateAdapterChannel请求DMA通道,并执行回调函数USBPORT_MapTransfer,原型如下:
signed int __stdcall USBPORT_MapTransfer(PDEVICE_OBJECT DeviceObject, PIRP CurrentIrp, PVOID MapRegisterBase, PTRANSFER pTransfer)

MapRegisterBase即为映射寄存器基址,其实映射寄存器并非为硬件寄存器,而是指向一块内存映射区域,MapRegisterBase指向了一个TRANSLATION_ENTRY结构体的列表,
TRANSLATION_ENTRY结构体如下
typedef struct _TRANSLATION_ENTRY {
    PVOID VirtualAddress;
    ULONG PhysicalAddress;
    ULONG Index;
} TRANSLATION_ENTRY, *PTRANSLATION_ENTRY;

这个结构体中的VirtualAddress 和PhysicalAddress指向了系统预先分配好的4G以下物理内存,用来作为双缓冲的备份缓冲区。在调用IoAllocateAdapterChannel时指定要申请的映射寄存器的数量,在USBPORT_MapTransfer中就可以通过MapRegisterBase指针使用申请数量的TRANSLATION_ENTRY结构体列表。
USBPORT_MapTransfer会调用hal!IoMapTransfer,hal!IoMapTransfer大致执行路径如下:
__int64 __stdcall IoMapTransfer(PADAPTER_OBJECT AdapterObject, PMDL Mdl, PVOID MapRegisterBase, PVOID CurrentVa, PULONG Length, BOOLEAN WriteToDevice)
if ( MapRegisterBase )
{
    result = HalpMapTransfer(AdapterObject, Mdl, MapRegisterBase, CurrentVa, Length, WriteToDevice);
}
else
{
计算缓冲区Mdl中的连续物理内存块,返回64位物理基址
}
  return result;
}

通过IoMapTransfer得到要传递给DMA的物理地址,如果MapRegisterBase 为0,就直接计算缓冲区Mdl中的连续物理内存块,返回64位物理基址,这个地址来自于Mdl,不能保证它是否位于4G以下物理地址。如果MapRegisterBase不为0,则调用hal! HalpMapTransfer。
在HalpMapTransfer中,
PHYSICAL_ADDRESS
HalpMapTransfer(
    IN PADAPTER_OBJECT AdapterObject,
    IN PMDL Mdl,
    IN PVOID MapRegisterBase,
    IN PVOID CurrentVa,
    IN OUT PULONG Length,
    IN BOOLEAN WriteToDevice
)
{
if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER
                && transferLength < *Length) {

        logicalAddress = translationEntry->PhysicalAddress + pageOffset;
        translationEntry->Index = COPY_BUFFER;
        index = 0;
        transferLength = *Length;
        useBuffer = TRUE;
    }
if (useBuffer  &&  WriteToDevice) {
        HalpCopyBufferMap(
            Mdl,
            translationEntry + index,
            CurrentVa,
            *Length,
            WriteToDevice
            );
    }
}

如果MapRegisterBase不为0,且满足一定条件,就设置useBuffer为TRUE,useBuffer就是启用双缓冲的标志,如果useBuffer为TURE,并且是从内存写入到设备(WriteToDevice),那么就将数据复制到映射缓存(因为读取过程不涉及到DMA操作,所有不需要映射缓存参与)。看来,影响是否使用双缓冲的关键参数为MapRegisterBase ,只有MapRegisterBase 不为0,HalpMapTransfer才会启用双缓冲机制,调用HalpCopyBufferMap将64位物理地址缓冲区拷贝到映射寄存器指向的位于4G以下地址空间的缓冲存。
VMWare里调试一下,断点下在USBPORT_MapTransfer,MapRegisterBase还真为0,既然MapRegisterBase来自于nt!IoAllocateAdapterChannel,那么继续到这个函数中去寻找答案,在nt!IoAllocateAdapterChannel中发现如下代码:
if ( NumberOfMapRegisters && AdapterObject->NeedsMapRegisters )
{
MasterAdapter = AdapterObject->MasterAdapter;
MapRegisterBase = (int)((char *)MasterAdapter->MapRegisterBase + 12 * MapRegisterId);
}
else
{
AdapterObject->MapRegisterBase = 0;
AdapterObject->NumberOfMapRegisters = 0;
}

从条件语句看,只要NumberOfMapRegisters为0或者AdapterObject->NeedsMapRegisters为0二者之一满足条件,AdapterObject->MapRegisterBase = 0都会执行。NumberOfMapRegisters为申请的映射寄存器数量,这个值肯定不为0,那么只有AdapterObject->NeedsMapRegisters为0了。AdapterObject结构体为ADAPTER_OBJECT,是USBPORT.SYS在系统启动的时候在USBPORT!USBPORT_StartDevice函数中调用nt!IoGetDmaAdapter获取的,nt!IoGetDmaAdapte最终调用了hal! HalGetAdapter,原型如下:
PADAPTER_OBJECT HalGetAdapter(PDEVICE_DESCRIPTION DeviceDescription, PULONG NumberOfMapRegisters)

DeviceDescription为总线驱动程序发送的一些生成ADAPTER_OBJECT的参数,NumberOfMapRegisters是个指针,用来返回驱动能使用的最大的映射寄存器数量。
在HalGetAdapter函数中发现了如下代码:
if ( ScatterGather && (LessThan16Mb || InterfaceType == Eisa || InterfaceType == PCIBus) )
{
    MapRegistersNeed = 0;
}

ScatterGather为分散\聚集模式,一般都为TRUE,LessThan16Mb一般为FALSE,现在基本没有16M以下内存的机器了吧,关键是InterfaceType,如果是Eisa或者PCIBus任意一种,MapRegistersNeed都会设为0,那么双缓冲模式就不会被启动。现在我们的机器一般都是使用PCI总线,而USB总线是挂在PCI总线下的,所以就不会启用双缓冲了。那Windows 2003里对应的代码是怎样的呢?
if ( bScatterGather
    && (!HalpPhysicalMemoryMayAppearAbove4GB || DevDesc->Dma64BitAddresses)
    && (LessThan16Mb || InterfaceType == Eisa || InterfaceType == PCIBus) )
{
    MapRegistersNeed = 0;
}

原来Windows 2003多加了一个判断HalpPhysicalMemoryMayAppearAbove4GB和DevDesc->Dma64BitAddresses,按照2003的逻辑,如果我们的机器物理地址空间大于4GB了,并且DMA硬件不支持64位地址,那么就会直接开启双缓冲,而不管总线是什么类型,或者其他的什么条件。XP上这段程序是建立在只有32位物理地址的前提下,PCI 总线和Eisa总线的DMA都支持到32位的,所以不需要双缓冲机制。
既然关键点找到了,那就patch吧jz改成jmp。此外还要注意Windows 2003在多个地方判断了HalpPhysicalMemoryMayAppearAbove4GB这个标志,涉及到修改的地方主要在HalInitSystem里面。由于XP原来主要工作于32位物理地址空间,现在地址空间变大,启用了双缓冲模式,所有相应参数要改大:
HalpMapBufferSize为映射缓存大小,原来为0x10000,改为0x30000
SizeOfBitMap为映射寄存器使用位图大小,原来为0x10,改为0x30
HalInitSystem调用了HalpAllocPhysicalMemory申请映射缓存,物理内存少于4G时,申请参数为
HalpAllocPhysicalMemory(LoaderBlock, 0x1000000u, 0x10u, 1);
即在物理地址0x1000000u以下的空间申请0x10u页,最后一个参数表示是否64k对齐。而当物理内存大于4G时,Windows 2003申请参数为
HalpAllocPhysicalMemory(LoaderBlock, 0xFFFFFFFFu, 0x30u, 1);
即在4G以下物理地址空间申请0x30u页,64k对齐。汇编代码改动结果如下:
 push    1
 push    10h
 push    1000000h
 push    ebx
 mov     DefaultSizeOfBitMap, 40h
 mov     esi, 10000h
 call    _HalpAllocPhysicalMemory@16

 改为
 push    1
 push    30h
 push    FFFFFFFFh
 push    ebx
 mov     DefaultSizeOfBitMap, 4000h
 mov     esi, 30000h
 call    _HalpAllocPhysicalMemory@16

这就搞定了,对了,改完hal.dll一定要重新计算校验和,不然会启动失败。
搞到最后,原来还是hal.dll的问题,还白费力气,研究了半天usb驱动。既然是hal.dll的问题,为什么硬盘、网卡等等这些使用DMA的设备就没有引发系统蓝屏呢?难道说这些驱动在一开始发起请求的时候就总是申请4G以下物理内存来进行DMA操作?或者是其他设备的DMA硬件已经都支持36位以上寻址了?还有待去考证。
总算搞完了,希望这次补丁能够更加稳定些,还有问题的话不知道什么时候再能去解决了。在此感谢我敬爱的领导兼导师,感谢他把我领进ROOTKIT的大门,感谢他的包容和理解,感谢他对我年轻气盛的容忍和悉心开导。不玩了,好好工作,努力干活。

[防守篇]2018看雪.TSRC CTF 挑战赛(团队赛)11月1日征题开启!

上传的附件:
最新回复 (174)
waysun 2011-11-14 14:19
2

0

沙发,前排留名,要加精了嘿嘿
kwzlj 2011-11-14 14:20
3

0

沙发嘛,楼主牛啊,有4G内存的赶紧试一下。
b23526 2011-11-14 14:30
4

0

2G内存的无情撸过
levizhou 1 2011-11-14 14:34
5

0

有个问题不明白, 32位程序最典型的指针操作
mov eax, [0x0f0f0f0f] 指针是固定的32位
如何能寻址到4GB以后的内存呢?
scdeny 2 2011-11-14 14:43
6

0

[QUOTE=levizhou;1019599]有个问题不明白, 32位程序最典型的指针操作
mov eax, [0x0f0f0f0f] 指针是固定的32位
如何能寻址到4GB以后的内存呢?[/QUOTE]
你所说的32位地址是虚拟地址空间,操作系统通过分页机制将物理内存映射虚拟地址空间,现在通过PAE技术,CPU已经能够寻址36位的物理地址空间,但每个应用程序还是只能使用32位虚拟地址空间,建议你看看关于讲“分页机制”方面的书
快雪时晴 4 2011-11-14 15:33
7

0

大大有研究,看看这个
<求鉴定:《终于知道ramdisk 4g是如何使用4G以上内存了,慎用!》_辅助工具讨论区_反病毒区 卡饭论坛>
http://bbs.kafan.cn/thread-1127521-1-1.html
Fido 2011-11-14 15:54
8

0

这个太强大了啊.....

钻研精神值得钦佩啊....
Fido 2011-11-14 15:55
9

0

我昨天刚好把我的XP 虚拟了一个3.7G的虚拟磁盘用做页面文件...

用了2天了.挺爽的..没啥问题啊...速度确实飞一般的感觉啊..
cntrump 13 2011-11-14 15:59
10

0

2003 可以支持 4 G 以上内存,何解?
MengXP 2011-11-14 17:22
11

0

膜拜楼主~~~~~~~~~~~~~~~~
楼主是我的偶像~~~~
BianChengN 2011-11-14 17:23
12

0

牛,支持楼主
wusha 2011-11-14 17:53
13

0

膜拜,支持。
scdeny 2 2011-11-14 19:27
14

0

文中所说的第一个问题确实存在,不过我相信ramdisk作为一款成熟稳定地软件,会有更巧妙地方法解决。第二个问题没有谈的意义,作为已经加载进内核的驱动程序,随便改几个字节就能导致系统崩溃,正规厂商在写驱动时不敢这么放肆去写系统不允许访问的内存,如果你碰到恶意驱动那就只有认栽了。
ramdisk虚拟出来的磁盘本就是掉电即消失的内存,用来放放临时文件还可以,放重要文件一定要慎重
cnliuqh 2011-11-14 21:24
15

0

支持!大牛!!
KiDebug 4 2011-11-14 21:24
16

0

二话不说,一个字:顶!
lixupeng 2011-11-14 22:23
17

0

好深奥收下!
superdj 2011-11-14 22:48
18

0

刚看到,希望实用,感谢分享及原创精神~
靴子 2011-11-14 23:16
19

0

如果xp 4G内存可良好运行 为什么微软不直接支持呢?
butian 2011-11-14 23:33
20

0

大牛,沙发。。。
komany 2011-11-15 01:18
21

0

试了下你的这个,嘿嘿,蓝屏,我的是AMD x4 640 ,4G内存
苍穹天空 2011-11-15 04:31
22

0

牛,支持楼主
sniss 2011-11-15 08:17
23

0

顶顶楼主,膜拜,羡慕嫉妒恨
kangcin 2011-11-15 08:31
24

0

这个得顶一下 备留
havegone 2011-11-15 09:29
25

0

大牛啊。膜拜了
jerrynpc 2011-11-15 10:27
26

0

界面都做出来了,太狠了。

无法学习,只能膜拜。

下载了,就要顶啊
MengXP 2011-11-15 11:06
27

0

开机滚动条蓝屏?
monsterok 3 2011-11-15 12:28
28

0

楼主神文。。看不下去呀。。。
yuweiping 2011-11-15 13:49
29

0

我的笔记本用你上次那个蓝屏,今晚下载来用你这个看看蓝不蓝屏。我的笔记本内存4个G
speedboy 2011-11-15 19:11
30

0

下载试用!!
zbzb 2011-11-15 19:18
31

0

强贴留名啊。膜拜!好强的技术。
达文西 2011-11-15 19:33
32

0

搞个投票总结成功失败的百分比如何?
xPLK 3 2011-11-15 21:07
33

0

不错……
改天用虚拟机试试。
wnarutou 2011-11-15 21:16
34

0

强文,没看懂...
膜拜
film 2011-11-15 22:02
35

0

你导师更牛!
执着理解 2011-11-16 01:42
36

0

好长啊…学习……
gongseoul 2011-11-16 03:20
37

0

看了合眼福了,接下来改系统内核了!
luliyuan 2011-11-16 09:43
38

0

这个帖子的技术性 太强了  佩服中。。。。。。。。。。。。。
zzxxaa 2011-11-16 11:40
39

0

这么给力啊
异或空间 2011-11-16 12:14
40

0

领教了,多谢。
dayang 2011-11-16 16:24
41

0

有LZ这样的精神,我估计没有搞不下来的项目
brilight 2011-11-16 16:45
42

0

支持樓主~~
欢欢super 2011-11-16 23:55
43

0

破解后,我的USB3插口插上没有反应,设备管理器里显示USB3的驱动加载不了,,但USB2插口可以用
cutepan 2011-11-17 00:46
44

0

经过测试,使用使用移动硬盘会卡住死机了~~~
luochangwe 2011-11-17 01:13
45

0

支持!大牛!!
xie风腾 2011-11-17 09:43
46

0


学习了哟,多谢分享
scdeny 2 2011-11-17 11:35
47

0

从NT4的源代码就可以发现,物理地址使用64位长的LARGE_INTEGER表示:
typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
说明从NT架构一开始,微软就已经考虑到了Windows在64位物理地址的机器上运行,至于为什么从2000一直到Win7的32位终端版本都将物理地址空间限制到4G以下,微软官方的解释是为了提高驱动程序的兼容性。
奇怪的是Windows 2003 同样是32位版本却允许用到64G的物理地址空间,2003的内核跟XP的内核相差不大,并且Win7比2003新的多吧,却同样存在4G的限制,这肯定不能用技术原因来解释,那只有一个理由:
微软我偏不让你用!很多人怀疑是出于商业原因。。。
其实,XP、Win7跟2003一样,已经完全能够胜任在4G以上物理地址空间运行,只是被强行限制。
Win7的内存限制相对简单,只是通过一个检查License的函数MxMemoryLicense限制了内存的可用量。而在XP上,除了通过版本检查函数ExVerifySuite限制内存可用量外,微软还玩了一点小花招,比如说关闭DMA映射寄存器支持,这都只是一些开关而已,打开了这些开关,XP的内核完完全全可以在4G以上物理地址运行。
cntrump 13 2011-11-17 12:42
48

0

原来如此,64位系统,好用好用真好用。
wangshy 2 2011-11-17 13:52
49

0

945的板,BIOS 认出4G内存,2003下只认3G
大空翼 2011-11-17 19:59
50

0

刚加到4G内存...测试下
返回