near call and far call in Assembly

2023年12月16日

以下是x64dbg调试某一程序的界面。

00E33FCB | E8 10D3D3FF              | call <v2game.sub_B712E0>         
00E33FD0 | C645 FC 32               | mov byte ptr ss:[ebp-4],32       
00E33FD4 | 8D8D 4CF8FFFF            | lea ecx,dword ptr ss:[ebp-7B4]   
00E33FDA | E8 F14AD4FF              | call <v2game.sub_B78AD0>         
00E33FDF | 8D95 30F8FFFF            | lea edx,dword ptr ss:[ebp-7D0]   
00E33FE5 | 52                       | push edx                         
00E33FE6 | 8B85 A4FEFFFF            | mov eax,dword ptr ss:[ebp-15C]   
00E33FEC | 8B10                     | mov edx,dword ptr ds:[eax]       
00E33FEE | 8B8D A4FEFFFF            | mov ecx,dword ptr ss:[ebp-15C]   
00E33FF4 | 8B82 90000000            | mov eax,dword ptr ds:[edx+90]    
00E33FFA | FFD0                     | call eax                         
00E33FFC | 8985 28E9FFFF            | mov dword ptr ss:[ebp-16D8],eax  
00E34002 | 8B8D 28E9FFFF            | mov ecx,dword ptr ss:[ebp-16D8]  
00E34008 | 898D 24E9FFFF            | mov dword ptr ss:[ebp-16DC],ecx  
00E3400E | C645 FC 34               | mov byte ptr ss:[ebp-4],34       
00E34012 | 8B85 24E9FFFF            | mov eax,dword ptr ss:[ebp-16DC]  
00E34018 | 8D4D A4                  | lea ecx,dword ptr ss:[ebp-5C]    
00E3401B | E8 C0D2D3FF              | call <v2game.sub_B712E0>        
00E34020 | C645 FC 32               | mov byte ptr ss:[ebp-4],32

第一行(00E33FCB)是call sub_B712E0,倒数第二行(00E3401B)也是call sub_B712E0。但它们的二进制代码不一样,为什么?

原来,在x86指令集里,call(E8)命令是相对的,也叫做near call。[1]

v2game.sub_B712E0的目标地址为00E33FD0+FFD3D310=00E34020+FFD3D2C0=100B712E0。注意要采用little endian。[2]

最后,在32位系统中,地址是4字节,所以最开头的1被舍弃,所以v2game.sub_B712E0所在的地址为00B712E0。

call能不能调用一个绝对地址?

一个方法是转换为上面一样的相对地址,另一个方法是far call。

参考资料

  1. Ange. Better explanation of different x86 CALL variations. . 2013-05-03 [2023-12-16].
  2. Joachim Isaksson. X86 encode near call relative offset. . 2013-10-14 [2023-12-16].