前段时间对ntdll比较感兴趣,因为我现在只能在RING3徘徊,加上ntdll是最接近RING0的地方。
那IDA反它,发现了ZwXXX的API都是直接调用系统服务了,换句话说就是系统服务RING3的表现形式是ZwXXX的API。ZwXXXAPI里没有什么代码,就是
2000Srv的:
.text:77F8F9C8 ZwAccessCheckByTypeAndAuditAlarm: ; NtAccessCheckByTypeAndAuditAlarm
.text:77F8F9C8 mov eax, 4
.text:77F8F9CD lea edx, [esp+4]
.text:77F8F9D1 int 2Eh ; DOS 2+ internal - EXECUTE COMMAND
.text:77F8F9D1 ; DS:SI -> counted CR-terminated command string
.text:77F8F9D3 retn 40h
XP的:
.text:7C92D3CD mov eax, 4
.text:7C92D3D2 mov edx, 7FFE0300h
.text:7C92D3D7 call dword ptr [edx]
.text:7C92D3D9 retn 40h
很明显的区别就是XP已经把int进入RING0的方式改为sysenter了(在AMD上是syscall),另外7FFE0300这个地方放着KiFastSystemCall的地址,当然XP也有INT方式的函数:KiIntSystemCall,我想不直接调用KiFastSystemCall而是选择使用函数指针是因为XP不让经典的INT方式消失吧(我是这么想的),改7FFE0300的内容为KiIntSystemCall就等于使用INT方式了,那样会慢哦。
说了点和主题无关的东西。通过以上的分析,得到一个不可靠的结论:凡是Zw打头的API都是去掉系统服务的,然后开头代码都是mov eax,xx,根据这个不可靠的结论, 就可以通过遍厉ntdll.dll的导出函数,然后直接取得服务号就行,呵呵,自己都觉得很不可靠,下面是代码,遍厉导出函数的代码不是我写的,因为仅仅搞清楚了导入表
#include "windows.h"
#include "stdio.h"
BOOLEAN checkZwXXXByCode(DWORD funcEP)
{
unsigned char code;
code=*(char*)funcEP;
if(code==0xb8)
return TRUE;
else
return FALSE;
}
//开始想不加这个,结果输出了一些Rtl开头的API,他们都直接返回0x8004001
BOOLEAN checkZwXXXByName(char* apiName)
{
if(*(WORD*)apiName == 0x775A)
return TRUE;
return FALSE;
}
DWORD procAPIExportAddr(DWORD hModule)
{
char *ptr = (char *)hModule;
DWORD numEntries;
DWORD *ExportNamePointerTable;
DWORD ordinalBase;
WORD *ExportOrdinalTable;
DWORD *ExportAddrTable;
DWORD i,ii=0;
char *exportName;
DWORD funcEP;
DWORD ord;
if(!hModule)
return 0;
ptr += 0x3c; // offset 0x3c contains offset to PE header
ptr = (char *)(*(DWORD *)ptr) + hModule + 0x78; // offset 78h into PE header contains addr of export table
ptr = (char *)(*(DWORD *)ptr) + hModule; // ptr now points to export directory table
// offset 24 into the export directory table == number of entries in the Export Name Pointer Table
// table
numEntries = *(DWORD *)(ptr + 24);
//printf("NumEntries = %d/n", numEntries);
ExportNamePointerTable = (DWORD *)(*(DWORD *)(ptr + 32) + hModule);
// offset 32 into export directory contains offset to Export Name Pointer Table
ordinalBase = *((DWORD *)(ptr + 16));
//printf("OrdinalBase is %d/n", ordinalBase);
ExportOrdinalTable = (WORD *)((*(DWORD *)(ptr + 36)) + hModule);
// offset 36 into export directory contains offset to Ordinal Table
ExportAddrTable = (DWORD *)((*(DWORD *)(ptr + 28)) + hModule);
// offset 28 into export directory contains offset to Export Addr Table
for(i = 0; i < numEntries; i++)
{
exportName = (char *)(ExportNamePointerTable[i] + hModule);
ord= ExportOrdinalTable[i];
funcEP=ExportAddrTable[ord]+hModule;
if( checkZwXXXByName(exportName) && checkZwXXXByCode(funcEP) )
{
printf("[0x%x]%s/n",*(DWORD*)(funcEP+1),exportName); //获得功能号
ii++;
}
}
printf("Total=0x%x/n",ii); //统计个数
return 0;
}
main()
{
DWORD i=0,funcNum;
DWORD ntdllBase;
char* funcEP;
if(ntdllBase=LoadLibrary(".//ntdll.dll")) //这样是为了也能弄2000的,我的就XP,但是有2000的ntdll
procAPIExportAddr(ntdllBase);
}
最后发现XP下加了不少系统服务:)