分享
 
 
 

《Undocumented Windows 2000 Secrets》翻译 --- 第六章(7)

王朝system·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

第六章 在用户模式下调用内核API函数

翻译:Kendiv( fcczj@263.net )

更新:Sunday, May 15, 2005

声明:转载请注明出处,并保证文章的完整性,本人保留译文的所有权利。

访问未导出的符号

为什么我们要允许应用程序执行本该内核驱动程序完成的操作?我们能将应用程序的能力增强到内核驱动程序也无法达到的程度吗?我们可以调用既没有文档化也没有导出的内部函数吗?这听起来有些危险,不过,就像我接下来要展示的那样,如果小心的进行控制,它将不会像看起来那样“可怕”。

查找内部符号

前面所讲的内核调用接口将查找导出符号的地址的工作委托给了Spy device,该Spy device可全面访问位于高一半的线形地址空间(upper half of the linear address space)中的内核模块的PE映像。不过,如果要调用的函数或者要访问的全局变量并没有导出,那么Spy device将没有机会找到它们的地址。在编写本章以及检查内核调试器输出的某些反汇编代码时,我总是想:“他们不导出这个漂亮的函数真是可惜!”这是因为内核调试器向我展示了确切的函数名,这让我非常恼火,但我的应用程序将完全忽略它们。当然,我可以使用我的内核调用接口跳到这些函数的无格式二进制入口点(the plain binary entry point of the function),但这不是一种很好的编程风格。以后发布的Service Pack很可能将这些入口点移动到其他位置。

我相信如果调试器可以做到这一点,我的程序也应该可以做到。在第一章中给出的一个示例DLL将我引上了正确的道路。只要操作系统的的符号文件正确安装了,w2k_img.dll就可以查找由Windows 2000内核模块定义的任意符号的地址。因此,我进一步扩展了w2k_call.dll,增加了一个新的API函数,该函数可先查找一个内部符号对应的线性地址,然后调用w2kCall()执行它。当然,针对全局变量也提供了类似的函数。

列表6-32给出了所有扩展后的调用接口函数。并且,为了方便,还为每种主要函数类型提供了单独的函数,这些单独的函数对应列表6-20到6-22中的函数。w2kXCall()将完成主要的工作,它调用w2k_img.dll中的API函数imgTableResolve()以获取指定符号的线性地址,如果成功,该地址将被列入随后的w2kCall()调用列表中。因为w2kCall()被设计为调用一个地址而不是一个符号,NULL指针将作为w2kCall()的pbSymbol参数传入。pEntryPoint参数将被设置为符号的地址pie->pAddress,该地址从对应的符号文件中获取。就像在第一章解释的那样,w2k_img.dll可以确定大多数内部函数所需的调用约定,因此,通过测试IMG_CONVENTION_FASTCALL结构中pie->dconvention的值可自动设置fFastcall参数。参数的字节数和指向参数的指针将向前传递,就像接收自调用者一样。可以从符号信息中获取参数的个数,不过这仅对__stdcall和__fastcall函数有效。__cdecl symbols don’t encode the argument stack size in their decoration.

BOOL WINAPI w2kXCall (PULARGE_INTEGER puliResult,

PBYTE pbSymbol,

DWORD dArgumentBytes,

PVOID pArguments)

{

PIMG_TABLE pit;

PIMG_ENTRY pie;

BOOL fOk = FALSE;

if (((pit = w2kSymbolsGlobal (NULL)) != NULL) &&

((pie = imgTableResolve (pit, pbSymbol)) != NULL) &&

(pie->pAddress != NULL))

{

fOk = w2kCall (puliResult, NULL, pie->pAddress,

pie->dConvention == IMG_CONVENTION_FASTCALL,

dArgumentBytes, pArguments);

}

else

{

if (puliResult != NULL) puliResult->QuadPart = 0;

}

return fOk;

}

// -----------------------------------------------------------------

BOOL WINAPI w2kXCallV (PULARGE_INTEGER puliResult,

PBYTE pbSymbol,

DWORD dArgumentBytes,

...)

{

return w2kXCall (puliResult, pbSymbol,

dArgumentBytes, &dArgumentBytes + 1);

}

// -----------------------------------------------------------------

NTSTATUS WINAPI w2kXCallNT (PBYTE pbSymbol,

DWORD dArgumentBytes,

...)

{

ULARGE_INTEGER uliResult;

return (w2kXCall (&uliResult, pbSymbol,

dArgumentBytes, &dArgumentBytes + 1)

? uliResult.LowPart

: STATUS_IO_DEVICE_ERROR);

}

// -----------------------------------------------------------------

BYTE WINAPI w2kXCall08 (BYTE bDefault,

PBYTE pbSymbol,

DWORD dArgumentBytes,

...)

{

ULARGE_INTEGER uliResult;

return (w2kXCall (&uliResult, pbSymbol,

dArgumentBytes, &dArgumentBytes + 1)

? (BYTE) uliResult.LowPart

: bDefault);

}

// -----------------------------------------------------------------

WORD WINAPI w2kXCall16 (WORD wDefault,

PBYTE pbSymbol,

DWORD dArgumentBytes,

...)

{

ULARGE_INTEGER uliResult;

return (w2kXCall (&uliResult, pbSymbol,

dArgumentBytes, &dArgumentBytes + 1)

? (WORD) uliResult.LowPart

: wDefault);

}

// -----------------------------------------------------------------

DWORD WINAPI w2kXCall32 (DWORD dDefault,

PBYTE pbSymbol,

DWORD dArgumentBytes,

...)

{

ULARGE_INTEGER uliResult;

return (w2kXCall (&uliResult, pbSymbol,

dArgumentBytes, &dArgumentBytes + 1)

? uliResult.LowPart

: dDefault);

}

// -----------------------------------------------------------------

QWORD WINAPI w2kXCall64 (QWORD qDefault,

PBYTE pbSymbol,

DWORD dArgumentBytes,

...)

{

ULARGE_INTEGER uliResult;

return (w2kXCall (&uliResult, pbSymbol,

dArgumentBytes, &dArgumentBytes + 1)

? uliResult.QuadPart

: qDefault);

}

// -----------------------------------------------------------------

PVOID WINAPI w2kXCallP (PVOID pDefault,

PBYTE pbSymbol,

DWORD dArgumentBytes,

...)

{

ULARGE_INTEGER uliResult;

return (w2kXCall (&uliResult, pbSymbol,

dArgumentBytes, &dArgumentBytes + 1)

? (PVOID) uliResult.LowPart

: pDefault);

}

列表6-32. 扩展的调用接口

注意在列表6-32中的w2kXCall()在开始工作之前会首先调用w2kSymbolsGlobal()。列表6-33给出了w2kSymbolsGlobal()函数,以及其他一些帮助函数,w2kSymbolsGlobal()的目的是在第一次调用w2kXCall()之前加载ntoskrnl.exe的符号文件。符号表存储在名为gpit的全局变量中,该变量的类型为PIMG_TABLE,在随后调用的函数中可以使用该表。在辅助函数的帮助下,w2kSymbolsLoad()可通过*pdstatus参数返回列表6-2中的某一个状态代码。为了避免由于不匹配的符号信息而跳到无效的地址处,w2kSymbolsLoad()函数将使用w2kPeCheck()函数小心的将符号文件的时间戳、校验和(checksum)与目标模块的内存映像的相应域进行比较,如果它们不匹配,则丢弃相应的符号表。

PIMG_TABLE WINAPI w2kSymbolsLoad (PBYTE pbModule,

PDWORD pdStatus)

{

PVOID pBase;

DWORD dStatus = W2K_SYMBOLS_UNDEFINED;

PIMG_TABLE pit = NULL;

if ((pBase = imgModuleBaseA (pbModule)) == NULL)

{

dStatus = W2K_SYMBOLS_MODULE_ERROR;

}

else

{

if ((pit = imgTableLoadA (pbModule, pBase)) == NULL)

{

dStatus = W2K_SYMBOLS_LOAD_ERROR;

}

else

{

if (!w2kPeCheck (pbModule, pit->dTimeStamp,

pit->dCheckSum))

{

dStatus = W2K_SYMBOLS_VERSION_ERROR;

pit = imgMemoryDestroy (pit);

}

else

{

dStatus = W2K_SYMBOLS_OK;

}

}

}

if (pdStatus != NULL) *pdStatus = dStatus;

return pit;

}

// -----------------------------------------------------------------

PIMG_TABLE WINAPI w2kSymbolsGlobal (PDWORD pdStatus)

{

DWORD dStatus = W2K_SYMBOLS_UNDEFINED;

PIMG_TABLE pit = NULL;

w2kSpyLock ();

if ((gdStatus == W2K_SYMBOLS_OK) && (gpit == NULL))

{

gpit = w2kSymbolsLoad (NULL, &gdStatus);

}

dStatus = gdStatus;

pit = gpit;

w2kSpyUnlock ();

if (pdStatus != NULL) *pdStatus = dStatus;

return pit;

}

// -----------------------------------------------------------------

DWORD WINAPI w2kSymbolsStatus (VOID)

{

DWORD dStatus = W2K_SYMBOLS_UNDEFINED;

w2kSymbolsGlobal (&dStatus);

return dStatus;

}

// -----------------------------------------------------------------

VOID WINAPI w2kSymbolsReset (VOID)

{

w2kSpyLock ();

gpit = imgMemoryDestroy (gpit);

gdStatus = W2K_SYMBOLS_OK;

w2kSpyUnlock ();

return;

}

列表6-33. 符号表管理函数

列表6-33底部的w2kSymbolsStatus()和w2kSymbolsReset()函数可按需加载/卸载符号表。如果符号表不存在,w2kSymbolsStatus()将尝试加载它并返回其状态代码。如果w2k_call.dll已经尝试加载符号表但没有成功的话,那么w2kSymbolsStatus()将返回一个最后错误代码(见表6-2),除非调用w2kSymbolsReset()重置符号表。w2kSymbolsReset()将释放符号表占用的内存块(如果有的话),并在下一次请求之前强制重新加载整个符号表,这也包括ntoskrnl.exe的符号表。

表6-2. w2kSymbolsLoad()状态代码

状态代码

描 述

W2K_SYMBOLS_OK

模块的符号表已加载

W2K_SYMBOLS_MODULE_ERROR

模块没有常住内存

W2K_SYMBOLS_LOAD_ERROR

无法加载模块的符号文件

W2K_SYMBOLS_VERSION_ERROR

符号文件与内存中的模块映像不匹配

W2K_SYMBOLS_UNDEFINED

符号表的状态未定义

列表6-34中的w2kXCopy*()函数集构成了扩展的复制接口,它们分别对应于列表6-23中的相应函数。w2kXCopy()简单的使用值为负数的dArgumentBytes参数调用w2kXCall(),剩余的复制函数只是一组外包函数,用于提供更简洁的参数列表。

BOOL WINAPI w2kXCopy (PULARGE_INTEGER puliResult,

PBYTE pbSymbol,

DWORD dBytes)

{

return w2kXCall (puliResult, pbSymbol,

0xFFFFFFFF - dBytes, NULL);

}

// -----------------------------------------------------------------

BYTE WINAPI w2kXCopy08 (BYTE bDefault,

PBYTE pbSymbol)

{

ULARGE_INTEGER uliResult;

return (w2kXCopy (&uliResult, pbSymbol, 1)

? (BYTE) uliResult.LowPart

: bDefault);

}

// -----------------------------------------------------------------

WORD WINAPI w2kXCopy16 (WORD wDefault,

PBYTE pbSymbol)

{

ULARGE_INTEGER uliResult;

return (w2kXCopy (&uliResult, pbSymbol, 2)

? (WORD) uliResult.LowPart

: wDefault);

}

// -----------------------------------------------------------------

DWORD WINAPI w2kXCopy32 (DWORD dDefault,

PBYTE pbSymbol)

{

ULARGE_INTEGER uliResult;

return (w2kXCopy (&uliResult, pbSymbol, 4)

? uliResult.LowPart

: dDefault);

}

// -----------------------------------------------------------------

QWORD WINAPI w2kXCopy64 (QWORD qDefault,

PBYTE pbSymbol)

{

ULARGE_INTEGER uliResult;

return (w2kXCopy (&uliResult, pbSymbol, 8)

? uliResult.QuadPart

: qDefault);

}

// -----------------------------------------------------------------

PVOID WINAPI w2kXCopyP (PVOID pDefault,

PBYTE pbSymbol)

{

ULARGE_INTEGER uliResult;

return (w2kXCopy (&uliResult, pbSymbol, 4)

? (PVOID) uliResult.LowPart

: pDefault);

}

// -----------------------------------------------------------------

PVOID WINAPI w2kXCopyEP (PVOID pDefault,

PBYTE pbSymbol)

{

ULARGE_INTEGER uliResult;

return (w2kXCopy (&uliResult, pbSymbol, 0)

? (PVOID) uliResult.LowPart

: pDefault);

}

列表6-34. 扩展的复制函数

实现内核函数的Thunk

实现内部(指未导出的)内核函数的Thunk的方式与实现已导出的API函数的Thunk的方式相同,目前只有ntoskrnl.exe中的未导出函数可以被调用。这一限制是由于当前的w2k_call.dll中的符号表管理器只加载了ntoskrnl.exe的符号表,并不是调用接口自身的限制。仅加载ntoskrnl.exe的符号表只是为了让事情更简单的些,因为该模块中包含了大多数我们感兴趣的符号(当然,你可以扩展w2k_call.dll以加载多个符号表)。列表6-35包含两个用于Windows 2000对象管理的内部函数的Thunk,这两个Thunk可返回对象类型的相关信息。(对象类型将在第七章里详细讨论)。

列表6-36给出了三个非常重要的内部数据结构的Thunk,第七章的示例代码需要这些Thunk。注意,我对使用扩展的内核调用接口的Thunk的名称之前增加了两个下划线作为前缀。这表示仅在提供相应的符号文件的情况下,才能使用这些Thunk。如果你安装了Service Pack而没有更新相应的符号文件,则w2kSymbolsLoad()将拒绝加载符号文件(因为时间戳、校验和均不匹配),并且对有双划线前缀的Thunk的调用也将失败,这些Thunk将返回默认值。换句话说,有一个下划线前缀的Thunk仍然可以正常的工作(即使没有匹配的符号文件),因为这些Thunk是根据新模块的内存映像的导出表来解析符号的。不过,在更新系统后,如果被更新的模块不再导出我们所引用的API函数或者某些函数的参数列表发生了变化,那么它们仍可能失败,

NTSTATUS WINAPI

__ObQueryTypeInfo (POBJECT_TYPE ObjectType,

POBJECT_TYPE_INFO TypeInfo,

/* bytes */ DWORD TypeInfoLength,

/* init to 0 */ PDWORD ReturnLength)

{

return w2kXCallNT ("ObQueryTypeInfo",

16, ObjectType, TypeInfo, TypeInfoLength,

ReturnLength);

}

// -----------------------------------------------------------------

NTSTATUS WINAPI

__ObQueryTypeName (POBJECT Object,

POBJECT_NAME_INFORMATION NameString,

/* bytes */ DWORD NameStringLength,

PDWORD ReturnLength)

{

return w2kXCallNT ("ObQueryTypeName",

16, Object, NameString, NameStringLength,

ReturnLength);

}

列表6-35. ObQueryTypeInfo()和ObQueryTypeName()的Thunk示列

PERESOURCE WINAPI

__ObpRootDirectoryMutex (VOID)

{

return w2kXCopyP (NULL, "ObpRootDirectoryMutex");

}

// -----------------------------------------------------------------

POBJECT_DIRECTORY WINAPI

__ObpRootDirectoryObject (VOID)

{

return w2kXCopyP (NULL, "ObpRootDirectoryObject");

}

// -----------------------------------------------------------------

POBJECT_DIRECTORY WINAPI

__ObpTypeDirectoryObject (VOID)

{

return w2kXCopyP (NULL, "ObpTypeDirectoryObject");

}

列表6-36. 一些内部变量的Thunk示列

现在,已经足够了。不过你或许有一点失望,因为我没有给出使用w2k_call.dll的示例代码。不要担心,你会在下一章中得到这些示例代码

………………本章完……………

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有