+ -
当前位置:首页 → 问答吧 → 如何理解如下代码中的地址表达式(代码不长)

如何理解如下代码中的地址表达式(代码不长)

时间:2011-03-13

来源:互联网

很久以前学习过16位汇编语言,对32位汇编只是稍微有些了解.最近调试一段VC写的代码中遇到如下一个函数的汇编代码,但是我不知道怎么去理解里面的地址表达试,代码不长,那位兄弟有空就请帮忙解释一下,谢谢了

原始的VC函数如下

C/C++ code

DWORD WINAPI RemoteThread(void*p)
{
    DWORD d=(DWORD)::GetProcAddress(::GetModuleHandle(0),"RemoteThread");
    return d;
}



在VC调试器的反汇编窗口中的代码如下:

C/C++ code

DWORD WINAPI RemoteThread(void*p)
{
    DWORD d=(DWORD)::GetProcAddress(::GetModuleHandle(0),"RemoteThread");
00418570  push        offset string "RemoteThread" (48B6D8h) 
00418575  push        0    
00418577  call        dword ptr [__imp__GetModuleHandleW@4 (44E308h)] 
0041857D  push        eax  
0041857E  call        dword ptr [__imp__GetProcAddress@8 (44E304h)] 
    return d;
}
00418584  ret         4    



我把代码复制到别的地方后反汇编代码如下:

Assembly code


00BBB680  push        48B6D8h 
00BBB685  push        0    
00BBB687  call        dword ptr ds:[44E308h] ;这个地址式如何去确定其线性地址?
00BBB68D  push        eax  
00BBB68E  call        dword ptr ds:[44E304h] 
00BBB694  ret         4    





这个函数我打算用来创建远线程的,最终会在其它进程里执行。

先不管以上代码是否会正常工作,我的问题是:
如这行代码怎么看
call dword ptr ds:[44E308h]

我如何去计算其线性地址?
记得以前16位汇编里,应该是ds*16+44E308h吧(当然16位里不能这么大的数)。后来我一直以为32位里就是直接取44E308h这个值,因为我一直以为ds的值应该为0,所以不必去管32位CPU到底用什么方法取得线性地址。但是现在我发现在调试的时候我的段寄存器竟然不是0,而是如下的值:
EAX = 00BBB680 
EBX = 00418570 
ECX = 00000000 
EDX = 00001000 
ESI = 00418970 
EDI = 00BBBA80 
EIP = 00413391 
ESP = 0012F4F0 
EBP = 0012F514 
EFL = 00000202 

CS = 001B 
DS = 0023 
ES = 0023 
SS = 0023 
FS = 003B 
GS = 0000 

那么我觉得自己以前的知识彻底的错了,真是郁闷啊,我也不知道以前是从哪里获得的认识:32位段寄存器为0.

以上都是废话,只是想说明下我为什么需要汇编知识,大家可以直接跳过,还是来继续我问的问题:

当DS = 0023h时指令call dword ptr ds:[44E308h]里的线性地址是多少,是怎么计算的?

另我使用的操作系统是Windows 2003企业版,CPU是AMD 4核,内存8G

作者: liuhua1982   发布时间: 2011-03-13

ds的值是段选择子,对应着全局描述符表或局部描述符表中的一个段描述符,段描述符中有段基址,修改ds时从新的段选择子对应的段描述符中取得段基址,放在ds的缓存寄存器中
call dword ptr ds:[44E308h]从ds的缓存寄存器中获得段基址,加上段偏移即得线性地址
windows中ds,ss,cs,es的段基址为0

作者: Lactoferrin   发布时间: 2011-03-13

32位windows中ds,ss,cs,es的段基址被设置为0
x64中ds,ss,cs,es的段基址直接被忽略掉

作者: Lactoferrin   发布时间: 2011-03-13

原来段寄存器里只是存储着"全局描述符表或局部描述符表"中的一条记录的..(地址?索引?当然这个问题我自己再去找资料,以前课本早不到了,如果谁有资料欢迎给个网页地址)。
既然windows中ds,ss,cs,es的段基址为0那么我以前理解的段积存器为0其实也是歪打正着了,难怪以前在VC中嵌入一些小段的汇编代码也没出什么问题。
感谢Lactoferrin

作者: liuhua1982   发布时间: 2011-03-13

段选择子中有描述符表的索引,intel的开发人员手册里有说明

作者: Lactoferrin   发布时间: 2011-03-13