goyejin
驱动牛犊
驱动牛犊
  • 注册日期2007-03-05
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望100点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
阅读:3250回复:10

关于HOOK系统API时的递归调用(或叫重入)问题的解决办法

楼主#
更多 发布于:2008-09-10 16:56
原贴:http://bbs.driverdevelop.com/htm_data/39/0303/36274.html

关于重入的问题很容易解决的,用一个TLS变量就可以了。由于只在调用线程的范围内改变TLS变量的值,所以改变当前线程的TLS变量不会改变其它线程中该TLS变量的值,ZwQueryDirectoryFile就可以根据该TLS变量的值来判断是否之前已经进入了一个ZwQueryDirectroyFile调用而且未返回。
而且TlsGetValue、TlsSetValue我跟踪过,其只是简单地利用段寄存器来区分对不同线程中该TLS变量的存取,并没有调用任何API,所以可以完全不用担心调用TlsGetValue、TlsSetValue会产生其它重入问题。
looksail
荣誉会员
荣誉会员
  • 注册日期2005-05-22
  • 最后登录2014-03-15
  • 粉丝2
  • 关注0
  • 积分1016分
  • 威望991点
  • 贡献值0点
  • 好评度239点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2008-09-18 00:58
看起来好复杂啊,越简单才越不会出问题
提问归提问,还是只能靠自己
znsoft
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2023-10-25
  • 粉丝300
  • 关注6
  • 积分910分
  • 威望14796点
  • 贡献值7点
  • 好评度2410点
  • 原创分5分
  • 专家分100分
  • 社区居民
  • 最爱沙发
  • 社区明星
板凳#
发布于:2008-09-10 20:51
我在某个开发包中看过某牛实现的tls驱动实现方案. 有一定的技巧.
http://www.zndev.com 免费源码交换网 ----------------------------- 软件创造价值,驱动提供力量! 淡泊以明志,宁静以致远。 ---------------------------------- 勤用搜索,多查资料,先搜再问。
goyejin
驱动牛犊
驱动牛犊
  • 注册日期2007-03-05
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望100点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
地板#
发布于:2008-09-10 17:38
其实TLS是次要的,关键是TLS的思想。
在驱动中是完全有可能去组织一个数据结构来实践(代替)TLS的。。。
goyejin
驱动牛犊
驱动牛犊
  • 注册日期2007-03-05
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望100点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2008-09-10 17:33
goyejin
驱动牛犊
驱动牛犊
  • 注册日期2007-03-05
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望100点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2008-09-10 17:26
引用第1楼dreamsity于2008-09-10 17:05发表的  :
驱动中可以使用TLS吗?
DWORD
APIENTRY
TlsAlloc(
    VOID
.......

TlsAlloc和TlsFree只在程序开始和结束(或其它适合的位置)去调用的;

在HOOK的函数里只用到TlsGetValue和TlsSetValue。。。
dreamsity
驱动小牛
驱动小牛
  • 注册日期2006-09-01
  • 最后登录2013-07-04
  • 粉丝0
  • 关注0
  • 积分40分
  • 威望821点
  • 贡献值1点
  • 好评度68点
  • 原创分1分
  • 专家分0分
6楼#
发布于:2008-09-10 17:23
不过这个的确是一个思路,IRP_MJ_CREATE是必须同步完成的,
也就是说有可能通过TLS来避免IRP_MJ_CREATE重入。
虽然内核内本身没有TLS的支持,但是否可以通过ROOKIT的技术增加一个TLS接口?
这样做是很有商业价值的,呵呵。值得研究!
一切都是时间问题!
goyejin
驱动牛犊
驱动牛犊
  • 注册日期2007-03-05
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望100点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2008-09-10 17:17
驱动下应该是可以使用的,最多就自己直接存取线程TED里的TLS数组。。。当然最好是有其它更安全稳定的方法去在驱动里存取TLS变量。。。
goyejin
驱动牛犊
驱动牛犊
  • 注册日期2007-03-05
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望100点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2008-09-10 17:13
引用第1楼dreamsity于2008-09-10 17:05发表的  :
驱动中可以使用TLS吗?
我知道IoSetTopOfIrp是用的TLS,但不知道怎么在驱动中分配自己的TLS。


我的是在Rang 3下的,Rang 0下的有待其它高手研究。。。
goyejin
驱动牛犊
驱动牛犊
  • 注册日期2007-03-05
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望100点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2008-09-10 17:11
我一般采用“阻塞”的概念,一个TLS变量的值为0表示无阻塞状态,大于0表示阻塞状态。下面是示例

// 程序开始
DWORD g_tls_isBlock = ::TlsAlloc();

// 程序结束
::TlsFree(g_tls_isBlock);

// 定义阻塞支持
#define BLOCKCOUNT()    ((LONG)::TlsGetValue(g_tls_isBlock))
#defien ISBLOCK()    (BLOCKCOUNT() > 0)
#define BLOCK()    (::TlsSetValue(g_tls_isBlock, (LPVOID)(BLOCKCOUNT() + 1))
#define UNBLOCK()    (::TlsSetValue(g_tls_isBlock, (LPVOID)(BLOCKCOUNT() - 1))


// 使用示例
void MyAPI()
{
    if (ISBLOCK())
    {
        return;
    }

    ...

    BLOCK();
    MyApi2();
    UNBLOCK();
}


void MyApi2()
{
    ...
    MyAPI();
    ...
}
dreamsity
驱动小牛
驱动小牛
  • 注册日期2006-09-01
  • 最后登录2013-07-04
  • 粉丝0
  • 关注0
  • 积分40分
  • 威望821点
  • 贡献值1点
  • 好评度68点
  • 原创分1分
  • 专家分0分
10楼#
发布于:2008-09-10 17:05
驱动中可以使用TLS吗?
DWORD
APIENTRY
TlsAlloc(
    VOID
    )

/*++

Routine Description:

    A TLS index may be allocated using TlsAlloc.  Win32 garuntees a
    minimum number of TLS indexes are available in each process.  The
    constant TLS_MINIMUM_AVAILABLE defines the minimum number of
    available indexes.  This minimum is at least 64 for all Win32
    systems.

Arguments:

    None.

Return Value:

    Not-0xffffffff - Returns a TLS index that may be used in a
        subsequent call to TlsFree, TlsSetValue, or TlsGetValue.  The
        storage associated with the index is initialized to NULL.

    0xffffffff - The operation failed. Extended error status is available
        using GetLastError.


--*/

{
    PPEB Peb;
    PTEB Teb;
    DWORD Index;

    Peb = NtCurrentPeb();
    Teb = NtCurrentTeb();

    RtlAcquirePebLock();
    try {

        Index = RtlFindClearBitsAndSet((PRTL_BITMAP)Peb->TlsBitmap,1,0);
        if ( Index == 0xffffffff ) {
            Index = RtlFindClearBitsAndSet((PRTL_BITMAP)Peb->TlsExpansionBitmap,1,0);
            if ( Index == 0xffffffff ) {
                BaseSetLastNTError(STATUS_NO_MEMORY);
                }
            else {
                if ( !Teb->TlsExpansionSlots ) {
                    Teb->TlsExpansionSlots = RtlAllocateHeap(
                                                RtlProcessHeap(),
                                                MAKE_TAG( TMP_TAG ) | HEAP_ZERO_MEMORY,
                                                TLS_EXPANSION_SLOTS * sizeof(PVOID)
                                                );
                    if ( !Teb->TlsExpansionSlots ) {
                        RtlClearBits((PRTL_BITMAP)Peb->TlsExpansionBitmap,Index,1);
                        Index = 0xffffffff;
                        BaseSetLastNTError(STATUS_NO_MEMORY);
                        return Index;
                        }
                    }
                Teb->TlsExpansionSlots[Index] = NULL;
                Index += TLS_MINIMUM_AVAILABLE;
                }
            }
        else {
            Teb->TlsSlots[Index] = NULL;
            }
        }
    finally {
        RtlReleasePebLock();
        }
#if DBG
    Index |= TLS_MASK;
#endif
    return Index;
}
这个函数是一个纯AP的函数吧!
一切都是时间问题!
游客

返回顶部