这个方法其实很不科学,硬编码偏移带来的兼容性问题以及16字节截断的问题(Win7过后是15字节)就不用说了,关键是这个 EPROCESS.ImageFileName 其实并不靠谱。
咱们可以做个实验,随便打开一个程序,比如记事本notepad.exe。然后看看ImageFileName:
似乎没什么问题。接下来关闭这个notepad.exe,再将可执行程序改个名,比如改成xxx.exe:
再次双击运行,再看看ImageFileName:
发现问题了吧?在内核中 EPROCESS.ImageFileName 只不过是个参考信息,准确的路径在 EPROCESS.SeAuditProcessCreationInfo.ImageFileName 这个地方:
不过硬编码偏移始终不是一个好方法,正确的方法是召唤 ZwQueryProcessInformation(其实原理就是EPROCESS.SeAuditProcessCreationInfo.ImageFileName)。下面贴一段我自己常用的进程名获取函数(其实从某个主动防御的代码中逆向出来的):
- PUNICODE_STRING GetProcNameByEproc(IN PEPROCESS pEproc)
- /*++
-
- Routine Description:
-
- 获取指定进程的完整进程名
-
-
- Arguments:
-
- pEproc - 指定进程的EPROCESS地址
-
-
- Return Value:
-
- 成功则返回进程名,失败返回NULL
-
-
- Comments:
-
- 该函数返回的进程名,由调用则负责释放(ExFreePool)。
-
-
- --*/
- {
- NTSTATUS NtStatus;
- HANDLE hProc = NULL;
- PBYTE pBuf = NULL;
- ULONG ulSize = 32;
-
- PAGED_CODE();
-
- //
- // 1. pEproc --> handle
- //
- NtStatus = ObOpenObjectByPointer( pEproc,
- OBJ_KERNEL_HANDLE,
- NULL,
- 0,
- NULL,
- KernelMode,
- &hProc
- );
-
- if (!NT_SUCCESS(NtStatus))
- return NULL;
-
- //
- // 2. ZwQueryInformationProcess
- //
- while ( TRUE )
- {
- pBuf = ExAllocatePoolWithTag(NonPagedPool, ulSize, ALLOC_TAG);
- if ( !pBuf ) {
- ZwClose(hProc);
- return NULL;
- }
-
- NtStatus = ZwQueryInformationProcess( hProc,
- ProcessImageFileName,
- pBuf,
- ulSize,
- &ulSize);
- if ( NtStatus != STATUS_INFO_LENGTH_MISMATCH )
- break;
-
- ExFreePool(pBuf);
- }
-
- ZwClose(hProc);
-
- if ( !NT_SUCCESS(NtStatus) ) {
- ExFreePool(pBuf);
- return NULL;
- }
-
- //
- // 3. over
- //
- return (PUNICODE_STRING)pBuf;
- }
进程名使用完毕后记得 ExFreePool。
其实非要用硬编码的话,除了 EPROCESS.ImageFileNameEPROCESS 和 PROCESS.SeAuditProcessCreationInfo.ImageFileName 还有其它地方也可以获得进程名,例如 PEB 里的ldr。具体可以参考我以前写的《彻底改掉进程名》。