首页
社区
课程
招聘
CPU如何使用生成程序的虚拟地址
发表于: 2005-11-19 22:15 11204

CPU如何使用生成程序的虚拟地址

qduwg 活跃值
35
2005-11-19 22:15
11204

我终于可以发布我的问题了。不知为什么经常找不到服务器。唉!

看雪兄及所有大侠:
你好!

我现在在逐步看一些网站上的破解资料和X86CPU的一些资料,我有一

个关于内存管理的问题始终不明白:内存在保护模式下如何使用?我的

问题如下:

我们使用S-ICE和TRW等调试软件的时候,显示的指令地址是虚拟地址

,比如0167:00411120,而且该虚拟地址跟文件地址有一个确定的转

换公式:虚拟地址=文件地址+C00+0040000H。那些虚拟地址是调试

器自己加上的吧?文件内有地址信息吗?还是只有二进制程序码?地址

是经过推算出来的吧。

现在我不明白的是这个虚拟地址如何转换为物理地址的。通过了解CPU

内存管理的知识,转换过程如下:虚拟地址->线性地址->物理地址

。该过程的实现由全局描述符表和局部描述符表查表来完成。这些内存

访问工作都是基于程序已经加载到内存后的基础上的。也就是说程序代

码已经是现成的在内存里放着的了。没有人告诉我们程序代码怎么放进

内存去的。虚拟地址怎么确定出来的?

所以我的问题是,操作系统加载程序的时候,操作系统怎么知道应该把

即将加载的程序放在哪里呢?因为此刻并没有所谓段基址和偏移量一说

的。也就是没有所谓的虚拟地址供CPU用,他怎么个去访问内存呢?难

道在加载程序之前操作系统就确定了程序即将使用的各种段基址了吗?

如果这样的话,CPU可以用这些虚拟地址转换为物理地址,然后把程序

从硬盘调入内存中。否则,CPU根本不知道要把程序代码放在哪里。我

的意思是说无论CPU“读取”内存还是“写入”内存,都需要用虚拟地

址,然后经过一系列转换,才能找到真正的物理内存单元。我的想法对

吗?请各位指教!是不是从硬盘加载程序到内存的时候不经过CPU,而

是使用DMA通道呢?对DMA来说没有所谓虚拟地址一说了吧,只是把内

容写进内存即可。可是也有一个问题,CPU怎么知道程序代码放在虚拟

空间的什么地方呢?CS是什么地址呢?

另外,不同程序的不同虚拟地址是否会映射到同一个物理空间内呢,如

果那样,是否会发生冲突呢?一个程序可能修改了另一个程序的内容。

但教程说不会,我不明白其中道理。

我现在对内存访问的问题真是一头雾水,实在令我郁闷!希望得到高手

指教!在此道声感谢!


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (12)
雪    币: 2384
活跃值: (766)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
2
不太明白你的意思,或许下面的链接是你要的答案:
http://bbs.pediy.com/showthread.php?s=&threadid=18022
2005-11-19 22:49
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
3
物理地址是唯一的,虚拟地址可以都一样.内存里面的东西也是通过硬盘上的程序弄出来的,所以内存的东西可以看作临时的,就不用太多考虑了.找硬盘的东西的时候先用虚拟地址根据段、页等,找到具体在硬盘上什么磁道。

就是说虚拟地址的计算不依赖于物理地址。
2005-11-20 17:56
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
4
最初由 小虾 发布
不太明白你的意思,或许下面的链接是你要的答案:
http://bbs.pediy.com/showthread.php?s=&threadid=18022


楼主不是这个意思.

这个问题也困扰了我很久,或许看看<<Undocumented Windows 2000>>会有帮助.
2005-11-20 20:48
0
雪    币: 475
活跃值: (1130)
能力值: ( LV9,RANK:1410 )
在线值:
发帖
回帖
粉丝
5
最初由 prince 发布


楼主不是这个意思.

这个问题也困扰了我很久,或许看看<<Undocumented Windows 2000>>会有帮助.


我的意思不是上面的老兄所讲的,我的问题其实很简单:CPU在从硬盘读入到内存的时候,是否使用虚拟地址寻址,如果使用的话,怎么确定的代码段等各段的地址的?因为在PE头部有这个地址信息,可是在没有读进内存之前,CPU怎么知道的?难道读取的PE头部信息直接送CPU内部缓存,然后找出各段的起始地址,然后就可以根据这个信息继续读取剩余的代码到内存了。这样CPU就可以使用虚拟地址往内存写入数据了,跟读取数据的时候过程是一样的。我的猜测是这样的,不知是否正确?希望高手指点迷津!!感谢!

我的这个问题,其实在所有的讲解X86模式的参考书里面都没有讲到这个问题,我的问题是普遍问题,我猜好多人根本不懂,当然不懂也没有关系的,不妨碍破解等。但是我希望搞明白这个问题。我是喜欢钻研的人,喜欢深究!

感谢各位!
2005-11-20 21:08
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
加载程序是操作系统干的事吧
操作系统根据PE头信息建立段表项,页表项
加载一部分程序到内存中,另一部分在虚拟内存中(硬盘)
真正程序运行在cache中,cache中代码更少了
cpu只管根据虚拟地址访问,
如果需要的代码未加载,就会产生缺页中断,
中断处理程序把内存中一部分暂时不用的代码替换出去,把需要用到的为加载的代码替换近来,具体顺序是 cache <==> 内存 <==> 虚拟内存(硬盘)
由硬件转换成物理地址,
执行用户程序就是任务切换,可以通过TSS实现,也可以不用TSS实现,
只要有了加载信息,就和进程调度差不多了吧

个人理解,错误之处还请指出
2005-11-20 23:46
0
雪    币: 475
活跃值: (1130)
能力值: ( LV9,RANK:1410 )
在线值:
发帖
回帖
粉丝
7
加载程序是操作系统干的事吧
操作系统根据PE头信息建立段表项,页表项
加载一部分程序到内存中,另一部分在虚拟内存中(硬盘)
真正程序运行在cache中,cache中代码更少了
cpu只管根据虚拟地址访问,
如果需要的代码未加载,就会产生缺页中断,
中断处理程序把内存中一部分暂时不用的代码替换出去,把需要用到的为加载的代码替换近来,具体顺序是 cache <==> 内存 <==> 虚拟内存(硬盘)
由硬件转换成物理地址,
执行用户程序就是任务切换,可以通过TSS实现,也可以不用TSS实现,
只要有了加载信息,就和进程调度差不多了吧
----------------------------------------------------------
你回答的问题好像比较离题了,过于搪塞了。没有切中我问题的实质。
操作系统怎么根据PE头信息建立段表项,页表项,起码CPU要读取硬盘上的PE信息,然后写入内存吧?那么怎么写入内存呢?怎么形成内存地址呢?因为在CPU没有得到PE信息之前他把内容写到哪里去?
2005-11-27 20:28
0
雪    币: 217
活跃值: (99)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
读PE头是其中系统某进程的事,当它调用CreateProcess时是Kernel32.dll在该进程中创建临时空间并读取PE头.
再根据PE头的信息,向ring0级的ntoskrnl申请一个4G的段,
再用类似WriteProcessMemory的方法从磁盘上的PE文件映象到新建进程空间的内存中.
然后处理各个表,最后开始创建线程从入口开始执行.
2005-11-27 22:01
0
雪    币: 254
活跃值: (126)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
9
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
;Written by Four-F (four-f@mail.ru)
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                    GetPhysicalAddress                                             
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

GetPhysicalAddress proc dwAddress:DWORD

; Converts virtual address in dwAddress to corresponding physical address

        mov eax, dwAddress
        mov ecx, eax

        shr eax, 22                                                             ; (Address >> 22) => Page Directory Index, PDI
        shl eax, 2                                                              ; * sizeof PDE = PDE offset

        mov eax, [0C0300000h][eax]                                              ; [Page Directory Base + PDE offset]

        .if ( eax & (mask pde4kValid) )                                         ; .if ( eax & 01y )
                ; PDE is valid
                .if !( eax & (mask pde4kLargePage) )                            ; .if ( eax & 010000000y )
                        ; small page (4kB)
                        mov eax, ecx
                        ; (Address >> 12) * sizeof PTE => PTE offset
                        shr eax, 10
                        and eax, 1111111111111111111100y
                        add eax, 0C0000000h                                     ; add Page Table Array Base
                        mov eax, [eax]                                          ; fetch PTE

                        .if eax & (mask pteValid)                               ; .if ( eax & 01y )
                                ; PTE is valid
                                and eax, mask ptePageFrameNumber                ; mask PFN   (and eax, 11111111111111111111000000000000y)

                                ; We actually don't need these two lines
                                ; because of module base is always page aligned
                                and ecx, 00000000000000000000111111111111y      ; Byte Index
                                add eax, ecx                                    ; add byte offset to physical address
                        .else
                                xor eax, eax                                    ; error
                        .endif
                .else
                        ; large page (4mB)
                        and eax, mask pde4mPageFrameNumber                      ; mask PFN   (and eax, 11111111110000000000000000000000y)
                        and ecx, 00000000001111111111111111111111y              ; Byte Index
                        add eax, ecx                                            ; add byte offset to physical address
                .endif
        .else
                xor eax, eax                                                    ; error
        .endif

        ret

GetPhysicalAddress endp
2005-11-28 09:09
0
雪    币: 250
活跃值: (103)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
10
这和操作系统的存储管理机制有关。微软的做法是让软件中涉及的内存(块)等物理概念越来越远离人们的视线,取而代之的都是虚拟的东西。
2006-4-6 13:38
0
雪    币: 210
活跃值: (42)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
这是操作系统的事,去看看操作系统原理就知道怎么回事了。内存管理方面
2006-4-12 19:14
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
先去看看PE格式吧
里面有几个参数
是PE加载器要用到的
虚拟地址上的都是软件方面的东西
你问得大多和操作系统有关
2006-4-12 22:25
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
斑竹写的问题好象在操作系统中有讲到吧
在计算机运行中,硬盘上有文件分区表,内存中也有类似的表, 在表中写着内存的分区情况和那些区是空闲的,那些是占用的
从硬盘上读入文件时,系统首先访问硬盘分区表,找到这个文件的文件分区表,看看有多少段,每个段在硬盘的位置,然后开始掉入内存分区表中标示为空闲的内存段
2006-6-3 16:39
0
游客
登录 | 注册 方可回帖
返回
//