EnumProcessModules 失败

zzz822163 2008-11-11 06:20:46
我通过PsSetCreateProcessNotifyRoutine将进程句柄传回EXE文件中,根据句柄使用EnumProcessModules ,但是失败了,仅完成部分的 ReadProcessMemoty 或 WriteProcessMemory 请求。
我换成GetProcessImageFileName可以得到\Device\HardDiskVolume1\XXX这样的东东,用户态下也不知怎样转换,而且他只在XP及以上才有用.
我的目的就是为了获得进程的全路径,我知道在驱动中可以通过PsLookupProcessByProcessId得到命令行参数,但也不知道怎么计算偏移量,请大家指点一下吧.
...全文
550 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
WinEggDrop 2008-11-14
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 zzz822163 的回复:]
引用 16 楼 WinEggDrop 的回复:

C/C++ code
BOOL GetProcessCmdLine(DWORD dwId,LPWSTR wBuf,DWORD dwBufLen)
{
LONG status;
HANDLE hProcess;
PROCESS_BASIC_INFORMATION pbi;
PEB Peb;
PROCESS_PARAMETERS ProcParam;
DWORD dwDummy;
DWORD dwSize;
LPV…
[/Quote]

status等于0就是成功呀.
zzz822163 2008-11-14
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 WinEggDrop 的回复:]

C/C++ code
BOOL GetProcessCmdLine(DWORD dwId,LPWSTR wBuf,DWORD dwBufLen)
{
LONG status;
HANDLE hProcess;
PROCESS_BASIC_INFORMATION pbi;
PEB Peb;
PROCESS_PARAMETERS ProcParam;
DWORD dwDummy;
DWORD dwSize;
LPVOID lpAddress;
BOOL bRet = FALSE;

// Get process handle
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,dwId);
if (!hProcess)
return FALSE;

// Retrieve information
status = NtQueryInformationProcess(hProcess,
ProcessBasicInformation,
(PVOID)&pbi,
sizeof(PROCESS_BASIC_INFORMATION),
NULL
);


if (status)
goto cleanup;
[/Quote]
我知道有这么个方法,但是我NtQueryInformationProcess查询后得到的status 总是0
WinEggDrop 2008-11-13
  • 打赏
  • 举报
回复
[Quote=引用楼主 zzz822163 的帖子:]
我通过PsSetCreateProcessNotifyRoutine将进程句柄传回EXE文件中,根据句柄使用EnumProcessModules ,但是失败了,仅完成部分的 ReadProcessMemoty 或 WriteProcessMemory 请求。
我换成GetProcessImageFileName可以得到\Device\HardDiskVolume1\XXX这样的东东,用户态下也不知怎样转换,而且他只在XP及以上才有用.
我的目的就是为了获得进程的全路径,我知道在驱动中可以通过PsLookupProcessByProcessId得到命令行参数,但也不知道…
[/Quote]

拿到句柄的话,使用NtQueryObject得到这个object的内存需求,然后NtQueryInformationFile()得到它的全路径.至于EnumProcesModules失败,这并不奇怪,XP/2003中有不少进程就算可以打开进程句柄,EnumProcessModules()也是会失败的(有几个svchost.exe进程就会这样),要想成功,要使用特别的方法打开进程句柄才可以,而且打开后是用ReadProcessMemory()才能得到路径信息等.
WinEggDrop 2008-11-13
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 zzz822163 的回复:]
C/C++ code
DWORD g_GetCmdLine(DWORD dwPID,TCHAR* pCmdLine,DWORD dwBufLen)
{


#define BUFFER_LEN 1024 //reading buffer for the commandline

HANDLE hProc = OpenProcess(PROCESS_VM_READ,FALSE,dwPID);
if(hProc == NULL)
{
return GetLastError();
}

DWORD dwRet = -1;
DWORD dwAddr = *(DWORD*)((DWORD)GetCommandLine + 1);//第2个字节开始才是我…
[/Quote]

你这读命令行参数是这样写的吗?进程中的命令行参数都是PEB中的,你这是在进程中乱读.

#include <windows.h>
#include <stdio.h>

#define ProcessBasicInformation 0

typedef struct
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct
{
ULONG AllocationSize;
ULONG ActualSize;
ULONG Flags;
ULONG Unknown1;
UNICODE_STRING Unknown2;
HANDLE InputHandle;
HANDLE OutputHandle;
HANDLE ErrorHandle;
UNICODE_STRING CurrentDirectory;
HANDLE CurrentDirectoryHandle;
UNICODE_STRING SearchPaths;
UNICODE_STRING ApplicationName;
UNICODE_STRING CommandLine;
PVOID EnvironmentBlock;
ULONG Unknown[9];
UNICODE_STRING Unknown3;
UNICODE_STRING Unknown4;
UNICODE_STRING Unknown5;
UNICODE_STRING Unknown6;
} PROCESS_PARAMETERS, *PPROCESS_PARAMETERS;

typedef struct
{
ULONG AllocationSize;
ULONG Unknown1;
HINSTANCE ProcessHinstance;
PVOID ListDlls;
PPROCESS_PARAMETERS ProcessParameters;
ULONG Unknown2;
HANDLE Heap;
} PEB, *PPEB;

typedef struct
{
DWORD ExitStatus;
PPEB PebBaseAddress;
DWORD AffinityMask;
DWORD BasePriority;
ULONG UniqueProcessId;
ULONG InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION;


// ntdll!NtQueryInformationProcess (NT specific!)
//
// The function copies the process information of the
// specified type into a buffer
//
// NTSYSAPI
// NTSTATUS
// NTAPI
// NtQueryInformationProcess(
// IN HANDLE ProcessHandle, // handle to process
// IN PROCESSINFOCLASS InformationClass, // information type
// OUT PVOID ProcessInformation, // pointer to buffer
// IN ULONG ProcessInformationLength, // buffer size in bytes
// OUT PULONG ReturnLength OPTIONAL // pointer to a 32-bit
// // variable that receives
// // the number of bytes
// // written to the buffer
// );
typedef LONG (WINAPI *PROCNTQSIP)(HANDLE,UINT,PVOID,ULONG,PULONG);


PROCNTQSIP NtQueryInformationProcess;

BOOL GetProcessCmdLine(DWORD dwId,LPWSTR wBuf,DWORD dwBufLen);

void main(int argc, char* argv[])
{
if (argc<2)
{
printf("Usage:\n\ncmdline.exe ProcId\n");
return;
}

NtQueryInformationProcess = (PROCNTQSIP)GetProcAddress(
GetModuleHandle("ntdll"),
"NtQueryInformationProcess"
);

if (!NtQueryInformationProcess)
return;

DWORD dwId;
sscanf(argv[1],"%lu",&dwId);

WCHAR wstr[255];

if (GetProcessCmdLine(dwId,wstr,sizeof(wstr)))
wprintf(L"Command line for process %lu is:\n%s\n",dwId,wstr);
else
wprintf(L"Could not get command line!");

}

BOOL GetProcessCmdLine(DWORD dwId,LPWSTR wBuf,DWORD dwBufLen)
{
LONG status;
HANDLE hProcess;
PROCESS_BASIC_INFORMATION pbi;
PEB Peb;
PROCESS_PARAMETERS ProcParam;
DWORD dwDummy;
DWORD dwSize;
LPVOID lpAddress;
BOOL bRet = FALSE;

// Get process handle
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,dwId);
if (!hProcess)
return FALSE;

// Retrieve information
status = NtQueryInformationProcess(hProcess,
ProcessBasicInformation,
(PVOID)&pbi,
sizeof(PROCESS_BASIC_INFORMATION),
NULL
);


if (status)
goto cleanup;

if (!ReadProcessMemory(hProcess,
pbi.PebBaseAddress,
&Peb,
sizeof(PEB),
&dwDummy
)
)
goto cleanup;

if (!ReadProcessMemory( hProcess,
Peb.ProcessParameters,
&ProcParam,
sizeof(PROCESS_PARAMETERS),
&dwDummy
)
)
goto cleanup;

lpAddress = ProcParam.CommandLine.Buffer;
dwSize = ProcParam.CommandLine.Length;

if (dwBufLen<dwSize)
goto cleanup;

if (!ReadProcessMemory( hProcess,
lpAddress,
wBuf,
dwSize,
&dwDummy
)
)
goto cleanup;


bRet = TRUE;

cleanup:

CloseHandle (hProcess);


return bRet;
}

zzz822163 2008-11-13
  • 打赏
  • 举报
回复
你给的例子我也看过了,但他没有求出全路径来,我也不会弄,而且在驱动层做一不小心就蓝屏了....
http://www.xfocus.net/articles/200503/788.html安全稳定的实现进线程监控
我参照的是这个,把他监视线程的代码删掉了,但他一点也不稳定,我在另一个帖子说过,运行一段时间后就让我其他所有程序都起不来了
palmax 2008-11-13
  • 打赏
  • 举报
回复
没有GUI的进程是不等待的。
但是Sleep这个方法确实不科学。
不知道你怎么调试的,有可能ReadProcessMemory成功了,但是tcBuf里确实没东西。

你的驱动和exe通信的时机是怎样我不清楚。
我做过系统所有进程枚举,都可以得到CommandLine,不过枚举的话肯定是进程已经创建好了。

为什么不在驱动层做呢?
这里有个例子:
http://www.xfocus.net/articles/200303/495.html
zzz822163 2008-11-13
  • 打赏
  • 举报
回复
但是我加了个循环for(int k=0;k<10;k++)啊,我把他放到前面还是不行,
DWORD startTime = GetTickCount();
printf("%d\n",startTime);
WaitForInputIdle((HANDLE)hProc, INFINITE);
startTime = GetTickCount();
printf("%d\n",startTime);
上面的代码加到了try的前面,输出的两个时间是完全一样的,他没有等待

palmax 2008-11-13
  • 打赏
  • 举报
回复
我已经说了让你先等待,再读,你偏要先读再等待。
zzz822163 2008-11-13
  • 打赏
  • 举报
回复

DWORD g_GetCmdLine(DWORD dwPID,TCHAR* pCmdLine,DWORD dwBufLen)
{


#define BUFFER_LEN 1024 //reading buffer for the commandline

HANDLE hProc = OpenProcess(PROCESS_VM_READ,FALSE,dwPID);
if(hProc == NULL)
{
return GetLastError();
}

DWORD dwRet = -1;
DWORD dwAddr = *(DWORD*)((DWORD)GetCommandLine + 1);//第2个字节开始才是我们要读的地址
TCHAR tcBuf[BUFFER_LEN] = {0};
DWORD dwRead = 0;

//判断平台
DWORD dwVer = GetVersion();
try
{
if(dwVer < 0x80000000) // Windows NT/2000/XP
{
for(int k=0;k<10;k++)
{
if(ReadProcessMemory(hProc,(LPVOID)dwAddr,&dwAddr,4,&dwRead))
{
if(ReadProcessMemory(hProc,(LPVOID)dwAddr,tcBuf,BUFFER_LEN,&dwRead))
{
_tcsncpy(pCmdLine,tcBuf,dwBufLen); //最好检查一下dwRead和dwBufLen的大小,使用较小的那个
dwRet = 0;
break;
}
else
printf("ReadProcessMemory12222222221,zzzz\n");
}
else
{
Sleep(100);
//WaitForInputIdle((HANDLE)dwPID, INFINITE);
printf("ReadProcessMemory111111,zzzz\n");
}
}
}
else // Windows 95/98/Me and Win32s
{
while(true) //使用while是为了出错时方便跳出循环
{
if(!ReadProcessMemory(hProc,(LPVOID)dwAddr,&dwAddr,4,&dwRead)) break;
if(!ReadProcessMemory(hProc,(LPVOID)dwAddr,&dwAddr,4,&dwRead)) break;

if(!ReadProcessMemory(hProc,(LPVOID)(dwAddr + 0xC0),tcBuf,BUFFER_LEN,&dwRead)) break;
if(*tcBuf == 0)
{
if(!ReadProcessMemory(hProc,(LPVOID)(dwAddr + 0x40),&dwAddr,4,&dwRead)) break;
if(!ReadProcessMemory(hProc,(LPVOID)(dwAddr + 0x8),&dwAddr,4,&dwRead)) break;
if(!ReadProcessMemory(hProc,(LPVOID)dwAddr,tcBuf,BUFFER_LEN,&dwRead)) break;
}

_tcsncpy(pCmdLine,tcBuf,dwBufLen); //最好检查一下dwRead和dwBufLen的大小,使用较小的那个
dwRet = 0;
break;
}
}
}
catch(...)
{
dwRet = ERROR_INVALID_ACCESS; //exception
}
CloseHandle(hProc);

return dwRet;
}

用WaitForInputIdle我一次都没成功过,用Sleep的话还有80%的成功率
palmax 2008-11-13
  • 打赏
  • 举报
回复
提升了就不要再恢复了,感觉恢复没有意义。

那个方法主要是靠GetCommandLine来完成,命令行字符缓冲区留大一些,比如1024,因为命令行是exe全路径+exe参数列表

PsSetCreateProcessNotifyRoutine如果是在进程创建的第一时间就通知你,读不到也是有可能的,不要用Sleep,因为你不知道Sleep多久,
应该用 WaitForInputIdle(hProcess, INFINITE)等待进程初始化完成,其中hProcess是那个被你监视到的新创建的进程的句柄,在这个函数之后再调用读取命令行的方法。
zzz822163 2008-11-13
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 palmax 的回复:]
参考这个:
http://www.vckbase.com/document/viewdoc/?id=1685

读取前将自己进程提升至 SE_DEBUG_NAME
[/Quote]
我用这个方法读到命令行了,但也是Sleep一下再重试才成功的,我怀疑可能最开始系统还没来得及填充内容吧?
将自己进程提升至 SE_DEBUG_NAME需要再恢复过来吗?
还有命令行中是./update/game.exe这样的相对路径,居然不是全路径!!!
palmax 2008-11-12
  • 打赏
  • 举报
回复
参考这个:
http://www.vckbase.com/document/viewdoc/?id=1685

读取前将自己进程提升至 SE_DEBUG_NAME
cnzdgs 2008-11-12
  • 打赏
  • 举报
回复
这个错误可以Sleep一下再重试。
zzz822163 2008-11-12
  • 打赏
  • 举报
回复
我看了,是299,就是仅完成部分的 ReadProcessMemoty 或 WriteProcessMemory 请求。
cnzdgs 2008-11-12
  • 打赏
  • 举报
回复
失败的时候用GetLastError取错误码看看。
zzz822163 2008-11-12
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 cnzdgs 的回复:]
用ZwOpenSymbolicLinkObject、ZwQuerySymbolicLinkObject可以把\DosDevices\C:这样的名称转换成\Device\HardDiskVolume1这样的设备名,可以用循环来取每个盘符对应的设备来与其对应。
或者把进程ID给应用程序,在应用程序中打开进程,获取路径。
[/Quote]
用这个方法是可以,但他只在XP及以上才有用

我现在在EnumProcessModules失败 之后,再sleep一下,然后就成功了,不知道是为什么?
cnzdgs 2008-11-11
  • 打赏
  • 举报
回复
用ZwOpenSymbolicLinkObject、ZwQuerySymbolicLinkObject可以把\DosDevices\C:这样的名称转换成\Device\HardDiskVolume1这样的设备名,可以用循环来取每个盘符对应的设备来与其对应。
或者把进程ID给应用程序,在应用程序中打开进程,获取路径。
ilovedrv 2008-11-11
  • 打赏
  • 举报
回复
看看这篇帖子,或许有帮助

http://topic.csdn.net/t/20030902/21/2216601.html

2,640

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 硬件/系统
社区管理员
  • 硬件/系统社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧