如何在驱动程序(SYS)中得到当前进程的完整路径和进程名?

  首先利用 PsGetCurrentProcess IoGetCurrentProcess 函数得到当前进程的句柄,这个句柄是指向 _EPROCESS 结构的指针, _EPROCESS 的结构如下:

typedef struct _EPROCESS


    {


    KPROCESS                     Pcb;


    NTSTATUS                     ExitStatus;


    KEVENT                       LockEvent;


    DWORD                        LockCount;


    QWORD                        CreateTime;


    QWORD                        ExitTime;


    PVOID                        LockOwner;


    DWORD                        UniqueProcessId;


    QWORD                        ActiveProcessLinks;


    DWORD                        QuotaPeakPoolUsage [2]; // NP, P


    DWORD                        QuotaPoolUsage     [2]; // NP, P


    DWORD                        PagefileUsage;


    DWORD                        CommitCharge;


    DWORD                        PeakPagefileUsage;


    DWORD                        PeakVirtualSize;


    QWORD                        VirtualSize;


    DWORD                        Vm [12];


    DWORD                        LastProtoPteFault;


    DWORD                        DebugPort;


    DWORD                        ExceptionPort;


    DWORD                        ObjectTable;


    DWORD                        Token;


    DWORD                        WorkingSetLock [8];


    DWORD                        WorkingSetPage;


    BOOLEAN                      ProcessOutswapEnabled;


    BOOLEAN                      ProcessOutswapped;


    BOOLEAN                      AddressSpaceInitialized;


    BOOLEAN                      AddressSpaceDeleted;


    DWORD                        AddressCreationLock [9];


    DWORD                        ForkInProgress;


    DWORD                        VmOperation;


    DWORD                        VmOperationEvent;


    DWORD                        PageDirectoryPte;


    QWORD                        LastFaultCount;


    PVOID                        VadRoot;


    DWORD                        VadHint;


    DWORD                        CloneRoot;


    DWORD                        NumberOfPrivatePages;


    DWORD                        NumberOfLockedPages;


    WORD                         w184;


    BOOLEAN                      ExitProcessCalled;


    BOOLEAN                      CreateProcessReported;


    HANDLE                       SectionHandle;


    struct _PEB                 *Peb;             // offset 0x1B0


    PVOID                        SectionBaseAddress;


    PVOID                        QuotaBlock;


    NTSTATUS                     LastThreadExitStatus;


    PROCESS_WS_WATCH_INFORMATION WorkingSetWatch;


    DWORD                        InheritedFromUniqueProcessId;


    ACCESS_MASK                  GrantedAccess;


    DWORD                        DefaultHardErrorProcessing;


    DWORD                        LdtInformation;


    DWORD                        VadFreeHint;


    DWORD                        VdmObjects;


    KMUTANT                      ProcessMutant;


    BYTE                         ImageFileName [16];              // offset 0x1FC


    DWORD                        VmTrimFaultValue [2];


    PVOID                        Win32Process;


    DWORD                        d1F8;


    DWORD                        d1FC;


    }


        EPROCESS,


     * PEPROCESS,


**PPEPROCESS;



从上面这个结构可以看出,进程名称就是ImageFileName,只要用_EPROCESS的基地址加上偏移地址0x1FC就可以得到进程名称的地址,代码如下:



char *ProcessName = (char*)PsGetCurrentProcess() + 0x1FC;


KdPrint((“Current Process Name: %s/n”, ProcessName));



要得到完整路径还需要利用_EPROCESS结构中的_PEB结构指针来得到ProcessParameters的地址。ProcessParameters保存着进程的完整路径。可以通过DDK附带的WinDbg工具打开一个可执行程序,然后用!peb命令来显示_PEB的结构信息。如下所示:

 


———————————————————————————————————————


> !peb


Debugger extension library [F:/WINNT/system32/ntsdexts] loaded


PEB at 7FFDF000


    InheritedAddressSpace:    No


    ReadImageFileExecOptions: No


    BeingDebugged:            Yes


    ImageBaseAddress:         00400000


    Ldr.Initialized: Yes


    Ldr.InInitializationOrderModuleList: 131f88 . 132998


    Ldr.InLoadOrderModuleList: 131ee0 . 132988


    Ldr.InMemoryOrderModuleList: 131ee8 . 132990


        00400000 D:/NtSysInfo.exe


        77F80000 F:/WINNT/System32/ntdll.dll


        77E60000 F:/WINNT/system32/KERNEL32.dll


        77DF0000 F:/WINNT/system32/USER32.dll


        77F40000 F:/WINNT/system32/GDI32.DLL


        76AF0000 F:/WINNT/system32/comdlg32.dll


        70BD0000 F:/WINNT/system32/SHLWAPI.DLL


        77D90000 F:/WINNT/system32/ADVAPI32.dll


        77D20000 F:/WINNT/system32/RPCRT4.DLL


        71700000 F:/WINNT/system32/COMCTL32.DLL


        77560000 F:/WINNT/system32/SHELL32.DLL


        78000000 F:/WINNT/system32/MSVCRT.DLL


        777C0000 F:/WINNT/System32/WINSPOOL.DRV


    SubSystemData:     0


    ProcessHeap:       130000


    ProcessParameters: 20000


        WindowTitle:  'D:/NtSysInfo.exe'


        ImageFile:    'D:/NtSysInfo.exe'


        CommandLine:  '"D:/NtSysInfo.exe" '


        DllPath:      'D:/;.;F:/WINNT/System32;F:/WINNT/system;F:/WINNT;F:/WINNT/system32;F:/WINNT;F:/WINNT/System32/Wbem;J:/WINDOWS;J:/WINDOWS/COMMAND;E:/WINDOWS/SYSTEM/WBEM;J:/WINDOWS;J:/WINDOWS/COMMAND;E:/WINDOWS/SYSTEM/WBEM;J:/WINDOWS;J:/WINDOWS/


COMMAND'



        Environment:  0x10000


 

WinDbg输出的PEB结构信息可以看出ProcessParameters的地址为0x20000ImageFile字段就是进程的完整路径。那么PorcessParamters的地址又保存在_PEB结构的什么地方呢?_PEB结构的基地址为0x7ffdf000,通过WinDbg的“db 0x7ffdf000 命令显示0x7ffdf000地址的信息可以发现ProcessParameters的地址保存在_PEB结构的0x10偏移量处,内容为0x20000


继续用“db 0x20000”命令显示ProcessParameters地址的内容,偏移量为0x3C处保存完整路径的地址,0x3C处的内容如果是:0x20670,利用“db 0x20670”即可显示出完整路径。完整路径用UNICODE格式保存。


我们利用程序模拟上面的步骤则可以得到当前进程的完整路径,代码如下:

PCWSTR GetCurrentProcessFileName()

{

       DWORD dwAddress = (DWORD)PsGetCurrentProcess();

       if(dwAddress == 0 || dwAddress == 0xFFFFFFFF)

              return NULL;

       dwAddress += 0x1B0;

       if((dwAddress = *(DWORD*)dwAddress) == 0) return 0;

       dwAddress += 0x10;

       if((dwAddress = *(DWORD*)dwAddress) == 0) return 0;

       dwAddress += 0x3C;

       if((dwAddress = *(DWORD*)dwAddress) == 0) return 0;

       KdPrint((“Current Process Full Path Name: %ws/n”,  (PCWSTR)dwAddress));

       return (PCWSTR)dwAddress;

} 


Windows NTWindows 2000_EPROCESS结构略有不同,所以偏移地址也不相同,故此上面的程序不能正常运行于Windows NT。要想在Windows NT下获得进程名和完整路径可以用类似的方法得出正确的偏移地址,进而编写出正确的程序。


如果想得到关于如何在Windows 9x的驱动程序(VXD)中得到当前进程的进程名和完整路径或者其他更多知识,可以访问费尔安全实验室的网站:http://www.xfilt.com

### 频繁读取标准输出的性能瓶颈分析 在 Python 的多线程或多进程环境中,频繁读取标准输出(`stdout`)可能会成为性能瓶颈。这是因为 `stdout` 是一个全局共享资源,在多线程或多进程中对其进行操作可能导致锁争用或其他同步开销。 #### 原因剖析 CPython 中的全局解释器锁(GIL, Global Interpreter Lock)会限制多线程环境下的真正并行执行[^2]。即使是在多进程模式下,虽然绕过了 GIL 的限制,但如果多个进程或线程同时尝试向同一个文件描述符(如 `stdout` 或日志文件)写入,则可能引发竞争条件或不必要的序列化操作,从而降低整体性能。 --- ### 解决方案 以下是几种针对该问题的有效解决方案: #### 1. 减少对 `stdout` 的调用频率 可以通过批量处理数据后再一次性打印的方式减少对 `stdout` 的访问次数。例如,将多次小规模的数据拼接成较大字符串再统一输出: ```python import sys def optimized_stdout(data_list): combined_output = "".join([str(item) for item in data_list]) # 合并数据 sys.stdout.write(combined_output + "\n") # 统一输出 ``` 这种方式减少了每次单独调用 `print()` 所带来的额外开销[^5]。 #### 2. 利用缓冲机制 启用更大的缓冲区可以显著改善 I/O 效率。默认情况下,Python 的 `sys.stdout` 已经启用了缓冲功能,但对于某些场景仍需手动调整缓冲策略。例如,使用 `-u` 参数禁用缓冲或将输出重定向至带缓存的日志工具中。 对于自定义流对象的情况,可设置较大的缓冲大小以适应高吞吐量需求: ```python class BufferedOutput: def __init__(self, buffer_size=1024 * 1024): # 设置缓冲区大小为 1MB self.buffer = [] self.buffer_size = buffer_size def write(self, message): self.buffer.append(message) if sum(len(m) for m in self.buffer) >= self.buffer_size: # 达到阈值则刷新 self.flush() def flush(self): full_message = ''.join(self.buffer) print(full_message, end="") self.buffer.clear() output_buffer = BufferedOutput() for i in range(1000000): output_buffer.write(f"{i}\n") output_buffer.flush() # 确保最后的内容被写出 ``` 此方法通过延迟实际写入动作降低了单次 I/O 开销[^3]。 #### 3. 替代多线程方式——采用多进程模型 由于 GIL 对于多线程的影响,推荐改用多进程架构来规避这一局限性。借助 `multiprocessing` 模块创建独立的工作单元,并让每个子进程负责自己的局部状态管理以及最终结果汇总工作。这样不仅实现了更高效的 CPU 并发利用,还避免了跨线程间通信所带来的复杂度增加风险。 需要注意的是,在这种设计思路下仍然要小心控制好各子进程之间的交互行为以免引入新的瓶颈点比如网络传输或者磁盘 IO 成为了新制约因素[^1]。 #### 4. 异步编程优化 当面对大量短时间任务时,异步框架如 `asyncio` 提供了一种轻量化调度机制允许我们无需显式启动额外 OS 层面线程即可完成类似效果的任务切换逻辑运行路径规划等工作流程安排;与此同时它也支持非阻塞型文件句柄操作进一步提升了响应速度与灵活性。 下面给出基于协程版本的一个简单例子展示如何高效地模拟并发请求过程而不必担心传统意义上那种因为等待某个耗时较长的操作结束前无法继续其他事情发生所造成的效率低下现象出现: ```python import asyncio async def async_task(task_id): await asyncio.sleep(0.1) # Simulate some delay return f"Task {task_id} completed" async def main(): tasks = [async_task(i) for i in range(10)] results = await asyncio.gather(*tasks) print("\n".join(results)) if __name__ == "__main__": asyncio.run(main()) ``` 上述代码片段展示了如何利用事件循环驱动多个小型作业快速交替推进直至全部完成为止的过程说明[^4]。 --- ### 结论 综上所述,解决 Python 多线程/多进程环境下频繁读取标准输出导致的性能问题是完全可行的。具体措施包括但不限于减少直接调用频次、增强内部缓冲能力、选用更适合当前应用场景的技术路线等手段相结合综合考量实施最佳实践方案达到预期目标。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值