zoukankan      html  css  js  c++  java
  • 于PsIsSystemThread无论是在线程系统线程标识获得



    我一直好奇一个进程的所有线程改变线程标志Terminated后。这个进程会自己主动结束吗?还是这个进程仅仅是被设置成了结束标志。而实际还在执行?
    想写个程序试验一下。但问题来了,怎么得到线程的标志呢?

    在PsIsSystemThread中得到线程的是否为系统线程的标志

    win xp 下的ntoskrnl.exe文件里的PsIsSystemThread的函数:
    ; Attributes: bp-based frame
    ; __stdcall PsIsSystemThread(x)
    public _PsIsSystemThread@4
    _PsIsSystemThread@4 proc near
    arg_0= dword ptr 8
    mov edi, edi ; IoIsSystemThread
    push ebp
    mov ebp, esp
    mov eax, [ebp+arg_0]
    mov eax, [eax+248h]
    shr eax, 4
    and al, 1
    pop ebp
    retn 4
    _PsIsSystemThread@4 endp
    F5一下下:
    char __stdcall PsIsSystemThread(int a1)
    {
    return (*(_DWORD *)(a1 + 0x248) >> 4) & 1;
    }
    比較以下来自官方的声明

    PsIsSystemThread routine

    The PsIsSystemThread routine checks whether a given thread is a system thread.

    Syntax

    BOOLEAN PsIsSystemThread(
      _In_  PETHREAD Thread
    );
    
    

    Parameters

    Thread [in]

    Pointer to the thread to be checked.

    Return value

    PsIsSystemThread returns TRUE if the specified thread is a system thread, FALSE otherwise.



    能够推測a1 + 0x248就是线程权限的标识。

    我们在xp系统上看一下:
    nt!_ETHREAD
    +0x000 Tcb : _KTHREAD
    +0x1c0 CreateTime : _LARGE_INTEGER
    +0x1c0 NestedFaultCount : Pos 0, 2 Bits
    +0x1c0 ApcNeeded : Pos 2, 1 Bit
    +0x1c8 ExitTime : _LARGE_INTEGER
    +0x1c8 LpcReplyChain : _LIST_ENTRY
    +0x1c8 KeyedWaitChain : _LIST_ENTRY
    +0x1d0 ExitStatus : Int4B
    +0x1d0 OfsChain : Ptr32 Void
    +0x1d4 PostBlockList : _LIST_ENTRY
    +0x1dc TerminationPort : Ptr32 _TERMINATION_PORT
    +0x1dc ReaperLink : Ptr32 _ETHREAD
    +0x1dc KeyedWaitValue : Ptr32 Void
    +0x1e0 ActiveTimerListLock : Uint4B
    +0x1e4 ActiveTimerListHead : _LIST_ENTRY
    +0x1ec Cid : _CLIENT_ID
    +0x1f4 LpcReplySemaphore : _KSEMAPHORE
    +0x1f4 KeyedWaitSemaphore : _KSEMAPHORE
    +0x208 LpcReplyMessage : Ptr32 Void
    +0x208 LpcWaitingOnPort : Ptr32 Void
    +0x20c ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION
    +0x210 IrpList : _LIST_ENTRY
    +0x218 TopLevelIrp : Uint4B
    +0x21c DeviceToVerify : Ptr32 _DEVICE_OBJECT
    +0x220 ThreadsProcess : Ptr32 _EPROCESS
    +0x224 StartAddress : Ptr32 Void
    +0x228 Win32StartAddress : Ptr32 Void
    +0x228 LpcReceivedMessageId : Uint4B
    +0x22c ThreadListEntry : _LIST_ENTRY
    +0x234 RundownProtect : _EX_RUNDOWN_REF
    +0x238 ThreadLock : _EX_PUSH_LOCK
    +0x23c LpcReplyMessageId : Uint4B
    +0x240 ReadClusterSize : Uint4B
    +0x244 GrantedAccess : Uint4B
    +0x248 CrossThreadFlags : Uint4B
    +0x248 Terminated : Pos 0, 1 Bit
    +0x248 DeadThread : Pos 1, 1 Bit
    +0x248 HideFromDebugger : Pos 2, 1 Bit
    +0x248 ActiveImpersonationInfo : Pos 3, 1 Bit
    +0x248 SystemThread : Pos 4, 1 Bit
    +0x248 HardErrorsAreDisabled : Pos 5, 1 Bit
    +0x248 BreakOnTermination : Pos 6, 1 Bit
    +0x248 SkipCreationMsg : Pos 7, 1 Bit
    +0x248 SkipTerminationMsg : Pos 8, 1 Bit
    +0x24c SameThreadPassiveFlags : Uint4B
    +0x24c ActiveExWorker : Pos 0, 1 Bit
    +0x24c ExWorkerCanWaitUser : Pos 1, 1 Bit
    +0x24c MemoryMaker : Pos 2, 1 Bit
    +0x250 SameThreadApcFlags : Uint4B
    +0x250 LpcReceivedMsgIdValid : Pos 0, 1 Bit
    +0x250 LpcExitThreadCalled : Pos 1, 1 Bit
    +0x250 AddressSpaceOwner : Pos 2, 1 Bit
    +0x254 ForwardClusterOnly : UChar
    +0x255 DisablePageFaultClustering : UChar
    果然,那么我们能够通过在PsIsSystemThread函数中查找特征码的方法来取得线程的标识。假设要保护进程。我们能够将进程的全部线程的线程标志都设置成SystemThread

    1. PsIsSystemThread是导出但未声明的函数,仅仅须要声明一下就能够使用了。
    声明:
    BOOLEAN PsIsSystemThread(
    _In_ PETHREAD Thread
    );


    蓝屏原因:
    机器上PsIsSystemThread函数的地址并非函数的真实地址,而是jmp指令,指令的目的地才地函数的真实地址。

    f8be2520 ff251826bef8 jmp dword ptr ds:[0F8BE2618h]
     
     


    问题来了,之中的一个:为什么得到的函数地址不是真实地址。是系统本身就是JMP样子的还是被机器上的安全软件给改动成JMP的?
    验证方法:
    回复快照,看最原始的系统中这个地方是不是也是JMP?

    在干净的系统上,uf函数总是能看到真正的地址:
    lkd> uf PsIsSystemThread
    nt!IoIsSystemThread:
    804ef8a2 8bff mov edi,edi
    804ef8a4 55 push ebp
    804ef8a5 8bec mov ebp,esp
    804ef8a7 8b4508 mov eax,dword ptr [ebp+8]
    804ef8aa 8b8048020000 mov eax,dword ptr [eax+248h]
    804ef8b0 c1e804 shr eax,4
    804ef8b3 2401 and al,1
    804ef8b5 5d pop ebp
    804ef8b6 c20400 ret 4


    而在程序中看到的都是JMP地址:
    BOOLEAN PsIsSystemThread(PETHREAD Thread);
    dprintf("PsIsSystemThread:0X%08X ", (PULONG)pPsIsSystemThread);
    看来系统本身就是JMP地址。



    通过x nt!PsIsSystemThread看看结果,得到函数真实地址。函数真实地址的地方是不是FF 25
    而函数的真实地址是804ef8a2
    lkd> uf PsIsSystemThread
    nt!IoIsSystemThread:
    804ef8a2 8bff mov edi,edi
    804ef8a4 55 push ebp
    804ef8a5 8bec mov ebp,esp
    804ef8a7 8b4508 mov eax,dword ptr [ebp+8]
    804ef8aa 8b8048020000 mov eax,dword ptr [eax+248h]
    804ef8b0 c1e804 shr eax,4
    804ef8b3 2401 and al,1
    804ef8b5 5d pop ebp
    804ef8b6 c20400 ret 4


    而程序得到的地址为JMP地址
    BOOLEAN PsIsSystemThread(PETHREAD Thread); 
    BOOLEAN IoIsSystemThread(PETHREAD Thread);
    dprintf("PsIsSystemThread:0X%08X ", (PULONG)pPsIsSystemThread);
    dprintf("IoIsSystemThread:0X%08X ", (PULONG)pIoIsSystemThread);

    这两个函数的地址分别为:
    PsIsSystemThread:0XF8C2055C
    IoIsSystemThread:0XF8C20550
    lkd> u 0xf8c2055c
    f8c2055c ff259c06c2f8 jmp dword ptr ds:[0F8C2069Ch]
    f8c20562 cc int 3
    f8c20563 cc int 3
    f8c20564 cc int 3
    f8c20565 cc int 3
    f8c20566 cc int 3
    f8c20567 cc int 3
    f8c20568 ff25a806c2f8 jmp dword ptr ds:[0F8C206A8h]
    lkd> u f8c20550
    f8c20550 ff259806c2f8 jmp dword ptr ds:[0F8C20698h]
    f8c20556 cc int 3
    f8c20557 cc int 3
    f8c20558 cc int 3
    f8c20559 cc int 3
    f8c2055a cc int 3
    f8c2055b cc int 3
    f8c2055c ff259c06c2f8 jmp dword ptr ds:[0F8C2069Ch]
    dword ptr ds:[0F8C2069Ch] = dword ptr ds:[0F8C20698h] = 804ef8a2

    http://bbs.pediy.com/showthread.php?

    t=93742

    这里的代码好像没有处理FF25
    所以看雪上楼主的这个程序会蓝屏。
    改后代码:
    ULONG GetCrossThreadFlagOffset()
    {
    ULONG Offset = 0;
    PUCHAR pPsIsSystemThread;
    PULONG pFuncAddr;
    PUCHAR pFeature;
    if(Offset == 0)
    {
    pPsIsSystemThread = (PUCHAR)PsIsSystemThread;
    }
    dprintf("PsIsSystemThread:0X%08X ", (PULONG)pPsIsSystemThread);
    //推断是不是FF 25
    if ((*pPsIsSystemThread) != 0xFF || *(pPsIsSystemThread+1) != 0X25)
    {
    dprintf("pProc is not ff 25. ");
    return Offset;
    }
    //ff25 9806c2f8 jmp dword ptr ds:[0F8C20698h]
    pFuncAddr = (*(PULONG)(pPsIsSystemThread+2));
    dprintf("pFuncAddr:0X%08X ", (PULONG)pFuncAddr);
    pFuncAddr = (PULONG)*pFuncAddr;
    dprintf("pFuncAddr:0X%08X ", (PULONG)pFuncAddr);
    pFeature = (PUCHAR)pFuncAddr;
    while( *pFeature!=0x8B || *(pFeature+1)!=0x80 )
    pFeature++;
    dprintf("Instruction found in address:0X%08X ",(PULONG)pFeature);
    Offset = *(PULONG)(pFeature+2);
    dprintf("Offset:0X%08X ",Offset);
    return Offset;
    }

    版权声明:本文博主原创文章。博客,未经同意不得转载。

  • 相关阅读:
    ThingsBoard 二次开发之源码分析 3-启动分析 2
    ThingsBoard 二次开发之源码分析 2-启动分析 1
    ThingsBoard 二次开发之源码分析 1- 基础知识
    ThingsBoard 2.5.3发布
    ThingsBoard 3.1 发布
    物联网 IoT 使用 Node-RED 的 5 大理由
    Thingsboard 简单教程:使用 ThingsBoard 查看物联网数据
    如何下载并安装应用商城应用
    如何优雅的在Markdown中使用图片
    Windows键盘无法调起
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/4877613.html
Copyright © 2011-2022 走看看