获取所有进程的映像路径以及命令VC源代码

来源:互联网 发布:时时彩开奖视频源码 编辑:程序博客网 时间:2024/05/16 08:00
  1. http://code1.okbase.net/codefile/CommandLine.cpp_201211112590_1.htm
    /*****************************************************************************************
  2. 在网上,我们似乎很难找到关于获取其他进程命令行的方案或源代码,呵呵~,反正我找了很久还是找不着~~~。废话就不说了,开始进入正题。
  3. 我们知道,如果获取本进程命令行的话,可以通过调用 GetCommandLine 获得, GetCommandLine 返回的是LPTSTR类型的数据,该返回值便是本进程命令行的内存首地址。那么,我们可以让远程执行 GetCommandLine 这个函数,然后获取远程进程中这个函数的返回值,再通过 ReadProcessMemory 把远程进程的命令行读出来就得到我们想要的了。
  4. 具体实现步骤如下:
  5. 1、通过 GetProcAddress 取得 GetCommandLineA 的地址。
  6. 2、用 CreateRemoteThread 启动远程线程,使远程进程执行 GetCommandLineA 。
  7. 3、用 WaitForSingleObject 等待远程线程结束。
  8. 4、用 GetExitCodeThread 取得远程线程退出代码,其实就是远程进程中 GetCommandLineA 函数的返回值,这是远程进程命令行的首地址。
  9. 5、通过 GetProcAddress 取得 lstrlenA 的地址。
  10. 6、用 CreateRemoteThread 启动远程线程,使远程进程执行 lstrlenA 。
  11. 7、用 WaitForSingleObject 等待远程线程结束。
  12. 8、用 GetExitCodeThread 取得远程线程退出代码,其实就是远程进程中 lstrlenA 函数的返回值,这是远程进程命令行的文本长度。
  13. 9、使用 ReadProcessMemory 把远程进程的命令行读取出来。
  14. 10、收工!
  15. ·若要转载,请保持该文章的完整性。
  16. ******************************************************************************************/
  17. //////////////////////////////////////////////////////////////////////////////////////////
  18. //功能:获取所有进程的映像路径以及命令行参数
  19. //作者:梁增健(lzj85@163.com)
  20. //MyQQ:184186651
  21. //日期:2007.06.11
  22. //////////////////////////////////////////////////////////////////////////////////////////
  23. #include <windows.h>
  24. #include <tlhelp32.h>
  25. #include <iostream.h>
  26. //定义命令行信息结构体
  27. typedef struct tagCOMMANDLINEINFO {
  28. DWORD dwDestCommand_addr;//目标进程命令行的起始地址
  29. DWORD iDestCommandLength;//目标进程命令行的长度
  30. } COMMANDLINEINFO;
  31. //函数声明
  32. BOOLUpgradeProcessPrivilege(HANDLE,LPCTSTR);
  33. BOOLGetProcessCommandLineInfo(HANDLE,COMMANDLINEINFO*);
  34. //主函数
  35. intmain(int argc,char*argv[ ],char*envp[ ] )
  36. {
  37. UpgradeProcessPrivilege(GetCurrentProcess(),SE_DEBUG_NAME);//提升本进程的权限
  38. HANDLE hSnapshot, hProcess;
  39. hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,NULL);//创建进程快照
  40. PROCESSENTRY32 pe;
  41. ZeroMemory(&pe,sizeof(PROCESSENTRY32));
  42. pe.dwSize=sizeof(PROCESSENTRY32);
  43. BOOL bFirstProcess=TRUE, bSucceed=FALSE;
  44. do
  45. {
  46. if(bFirstProcess)
  47. bFirstProcess = !(bSucceed=Process32First(hSnapshot,&pe));//获取第一个进程的信息
  48. else
  49. bSucceed = Process32Next(hSnapshot, &pe); //获取下一个进程的信息
  50. if(bSucceed)
  51. {
  52. hProcess = OpenProcess (PROCESS_ALL_ACCESS,FALSE, pe.th32ProcessID);//打开进程
  53. if(hProcess!=0)
  54. {
  55. char*strDestCommand;
  56. COMMANDLINEINFO cli;
  57. ZeroMemory(&cli,sizeof(COMMANDLINEINFO));
  58. if(GetProcessCommandLineInfo(hProcess,&cli))//获取进程的命令行信息
  59. {
  60. try
  61. {
  62. strDestCommand = new char[cli.iDestCommandLength+1];
  63. ZeroMemory(strDestCommand, cli.iDestCommandLength+1);
  64. //读取目标进程的命令行文本
  65. ReadProcessMemory ( hProcess,
  66. (constvoid*)cli.dwDestCommand_addr,
  67. strDestCommand,
  68. cli.iDestCommandLength,
  69. NULL);
  70. cout<<"程序名:"<<pe.szExeFile<<"\n命令行:"<<strDestCommand<<"\n"<<endl;
  71. delete []strDestCommand;
  72. }
  73. catch(...)
  74. {
  75. cout<<"发生异常!\n"<<endl;
  76. }
  77. }
  78. else
  79. {
  80. cout<<"程序名:"<<pe.szExeFile<<"\n"<<endl;
  81. }
  82. CloseHandle(hProcess);//关闭进程句柄
  83. }
  84. }
  85. }while(bSucceed);
  86. CloseHandle(hSnapshot);//关闭快照句柄
  87. return0;
  88. }
  89. /****************************************************************************************/
  90. /*****************************************子程序*****************************************/
  91. /****************************************************************************************/
  92. //////////////////////////////////////////////////////////////////////////////////////////
  93. //名称:UpgradeProcessPrivilege
  94. //功能:提升进程权限
  95. //作者:梁增健(lzj85@163.com)
  96. //MyQQ:184186651
  97. //日期:2007.06.11
  98. //////////////////////////////////////////////////////////////////////////////////////////
  99. BOOLUpgradeProcessPrivilege(HANDLE hProcess,
  100. LPCTSTR lpPrivilegeName=SE_DEBUG_NAME)
  101. {
  102. HANDLE hToken=NULL;
  103. if(OpenProcessToken(hProcess,TOKEN_ALL_ACCESS,&hToken))
  104. {
  105. LUIDLuid;
  106. if(LookupPrivilegeValue(NULL, lpPrivilegeName, &Luid))
  107. {
  108. TOKEN_PRIVILEGES tp;
  109. tp.PrivilegeCount=1;
  110. tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
  111. tp.Privileges[0].Luid=Luid;
  112. return(AdjustTokenPrivileges(hToken,FALSE,&tp,0,NULL,NULL) );
  113. }
  114. }
  115. returnFALSE;
  116. }
  117. //////////////////////////////////////////////////////////////////////////////////////////
  118. //名称:GetProcessCommandLineInfo
  119. //功能:获取进程命令行信息
  120. //作者:梁增健(lzj85@163.com)
  121. //MyQQ:184186651
  122. //日期:2007.06.11
  123. //////////////////////////////////////////////////////////////////////////////////////////
  124. BOOLGetProcessCommandLineInfo(HANDLE hProcess,COMMANDLINEINFO*CommandLineInfo)
  125. {
  126. if(IsBadReadPtr(CommandLineInfo,sizeof(COMMANDLINEINFO)))//判断指针是否有效
  127. returnFALSE;
  128. FARPROCGetCommandLineA_addr, lstrlenA_addr;
  129. HANDLE hThread;
  130. //获取 GetCommandLineA 的地址
  131. GetCommandLineA_addr=GetProcAddress(GetModuleHandle("Kernel32.dll"),"GetCommandLineA");
  132. if(GetCommandLineA_addr==0)
  133. returnFALSE;
  134. //启动远程线程,使远程进程执行 GetCommandLineA 函数
  135. hThread = CreateRemoteThread(hProcess, NULL, 0,
  136. (LPTHREAD_START_ROUTINE)GetCommandLineA_addr,NULL,0,NULL);
  137. if(hThread==0)
  138. returnFALSE;
  139. WaitForSingleObject (hThread,INFINITE);//等待远程线程结束
  140. //作者:梁增健 Email:lzj85@163.com MyQQ:184186651
  141. //获取远程 GetCommandLineA 的返回值,若正常返回,则该值为远程进程命令行的首地址
  142. GetExitCodeThread (hThread,&(CommandLineInfo->dwDestCommand_addr));
  143. CloseHandle (hThread);
  144. if(CommandLineInfo->dwDestCommand_addr==0)
  145. returnFALSE;
  146. //获取 lstrlenA 的地址
  147. lstrlenA_addr = GetProcAddress( GetModuleHandle ("Kernel32.dll"),"lstrlenA");
  148. if(GetCommandLineA_addr==0)
  149. returnFALSE;
  150. //启动远程线程,使远程进程执行 lstrlenA 函数
  151. hThread = CreateRemoteThread(hProcess, NULL, 0,(LPTHREAD_START_ROUTINE)lstrlenA_addr,
  152. (void*)CommandLineInfo->dwDestCommand_addr,0,NULL);
  153. if(hThread==0)
  154. returnFALSE;
  155. WaitForSingleObject (hThread,INFINITE);
  156. //获取远程 lstrlenA 的返回值,若正常返回,则该值为远程进程命令行文本的长度
  157. GetExitCodeThread (hThread,&(CommandLineInfo->iDestCommandLength));
  158. CloseHandle (hThread);
  159. returnTRUE;
  160. }
  161. /*************************************************************************************/
  162. /****************************************子程序***************************************/
  163. /*************************************************************************************/

    开发环境: VC6 Windows XP

    测试环境: WindowsXP

    我们都知道,在程序里获取命令行参数很简单,WinMain函数会以参数的形式传递给我们,或者可以调用API GetCommandLine 获取。但是GetCommandLine函数不接受参数,获取的只是自己程序的命令行参数。那么如果我们想获取别的应用程序的命令行参数应该怎么办呢?
    有的同学说,既然GetCommandLine只能获取本程序的命令行参数,我们可以在其它进程里插入一个Dll,在那个进程的地址空间调用GetCommandLine函数,然后传回来就可以了。这样好像有点儿不太友好。让我们想想还有没有别的办法。

    我们想,自己的命令行参数既然随时都可以获取到,那么在该进程里一定有一个地方存放它。那么在哪儿呢?看一下GetCommandLine函数的反汇编代码,我们发现,原来世界是如此的美好!

    以下是WinXP系统的GetCommandLine函数反汇编代码:

    1..text:7C812C8D GetCommandLineA proc near
    2..text:7C812C8D mov eax, dword_7C8835F4     //dword_7C8835F4 就是命令行参数字符串的地址
    3.//该指令机器码为 A1 F4 35 88 7C,从第2个字节开始的4个字节就是我们要的地址
    4..text:7C812C92 retn
    5..text:7C812C92 GetCommandLineA endp

    既然知道了放在哪儿了,我们自己去拿就可以了。因为GetCommandLine函数的地址在各个进程内都是一样的,所以可以直接用我们进程里的地址。 win2000/xp系统很简单,98下稍微麻烦一点儿,需要进行一些简单的计算。 以下是GetCommandLine函数在win98下的汇编代码:

    01..text:BFF8C907 GetCommandLineA proc near
    02..text:BFF8C907 mov eax, dword_BFFCADE4
    03..text:BFF8C90C mov ecx, [eax]
    04..text:BFF8C90E mov eax, [ecx+0C0h]
    05..text:BFF8C914 test eax, eax
    06..text:BFF8C916 jnz short locret_BFF8C91E
    07..text:BFF8C918 mov eax, [ecx+40h]
    08..text:BFF8C91B mov eax, [eax+8] //算到这儿,才是我们想要的地址
    09..text:BFF8C91E
    10..text:BFF8C91E locret_BFF8C91E: ; CODE XREF: GetCommandLineA+F.
    11..text:BFF8C91E retn

    这样,我们就可以调用OpenProcess函数打开其它进程,然后用ReadProcessMemory读取相应的数据即可。 示例代码:

    view source
    print?
    01.DWORD g_GetCmdLine(DWORD dwPID,TCHAR* pCmdLine,DWORD dwBufLen)
    02.{
    03.#define BUFFER_LEN    512        //reading buffer for the commandline
    04. 
    05.HANDLE hProc = OpenProcess(PROCESS_VM_READ,FALSE,dwPID);
    06.if(hProc == NULL)
    07.{
    08.return GetLastError();
    09.}
    10. 
    11.DWORD dwRet = -1;
    12.DWORD dwAddr = *(DWORD*)((DWORD)GetCommandLine + 1);//第2个字节开始才是我们要读的地址
    13.TCHAR tcBuf[BUFFER_LEN] = {0};
    14.DWORD dwRead = 0;
    15. 
    16.//判断平台
    17.DWORD dwVer = GetVersion();
    18.try
    19.{
    20.if(dwVer < 0x80000000)        // Windows NT/2000/XP
    21.{
    22.if(ReadProcessMemory(hProc,(LPVOID)dwAddr,&dwAddr,4,&dwRead))
    23.{
    24.if(ReadProcessMemory(hProc,(LPVOID)dwAddr,tcBuf,BUFFER_LEN,&dwRead))
    25.{
    26._tcsncpy(pCmdLine,tcBuf,dwBufLen);    //最好检查一下dwRead和dwBufLen的大小,使用较小的那个
    27.dwRet = 0;
    28.}
    29.}        
    30.}
    31.else                        // Windows 95/98/Me    and Win32s
    32.{
    33.while(true)                //使用while是为了出错时方便跳出循环
    34.{
    35.if(!ReadProcessMemory(hProc,(LPVOID)dwAddr,&dwAddr,4,&dwRead))break;
    36.if(!ReadProcessMemory(hProc,(LPVOID)dwAddr,&dwAddr,4,&dwRead))break;
    37. 
    38.if(!ReadProcessMemory(hProc,(LPVOID)(dwAddr + 0xC0),tcBuf,BUFFER_LEN,&dwRead)) break;
    39.if(*tcBuf == 0)
    40.{
    41.if(!ReadProcessMemory(hProc,(LPVOID)(dwAddr + 0x40),&dwAddr,4,&dwRead)) break;
    42.if(!ReadProcessMemory(hProc,(LPVOID)(dwAddr + 0x8),&dwAddr,4,&dwRead)) break;
    43.if(!ReadProcessMemory(hProc,(LPVOID)dwAddr,tcBuf,BUFFER_LEN,&dwRead)) break;
    44.}
    45. 
    46._tcsncpy(pCmdLine,tcBuf,dwBufLen);    //最好检查一下dwRead和dwBufLen的大小,使用较小的那个
    47.dwRet = 0;
    48.break;
    49.}
    50.}
    51.}
    52.catch(...)
    53.{
    54.dwRet = ERROR_INVALID_ACCESS;    //exception
    55.}
    56.CloseHandle(hProc);
    57. 
    58.return dwRet;
    59.}

    全文完


    1. #include "stdafx.h"
    2. #include <windows.h>
    3. #include <stdio.h>
    4. #include <conio.h>

    5. //UNICODE_STRING结构定义
    6. typedef struct
    7. {
    8.         USHORT Length;
    9.         USHORT MaximumLength;
    10.         PWSTR Buffer;
    11. }UNICODE_STRING, *PUNICODE_STRING;


    12. //进程参数结构定义,必有和NativeAPI规范相符和
    13. typedef struct
    14. {
    15.         ULONG AllocationSize;
    16.         ULONG ActualSize;
    17.         ULONG Flags;
    18.         ULONG Unknown1;
    19.         UNICODE_STRING Unknown2;
    20.         HANDLE InputHandle;
    21.         HANDLE OutputHandle;
    22.         HANDLE ErrorHandle;
    23.         UNICODE_STRING CurrentDirectory;
    24.         HANDLE CurrentDirectoryHandle;
    25.         UNICODE_STRING SearchPaths;
    26.         UNICODE_STRING ApplicationName;
    27.         UNICODE_STRING CommandLine;
    28.         PVOID EnvironmentBlock;
    29.         ULONG Unknown[9];
    30.         UNICODE_STRING Unknown3;
    31.         UNICODE_STRING Unknown4;
    32.         UNICODE_STRING Unknown5;
    33.         UNICODE_STRING Unknown6;
    34. }PROCESS_PARAMETERS, *PPROCESS_PARAMETERS;

    35. //PEB: Process Environment Block, 进程环境变量块
    36. typedef struct
    37. {
    38.         ULONG AllocationSize;
    39.         ULONG Unknown1;
    40.         HINSTANCE ProcessHinstance;
    41.         PVOID ListDlls;
    42.         PPROCESS_PARAMETERS ProcessParameters;
    43.         ULONG Unknown2;
    44.         HANDLE Heap;
    45. }PEB,*PPEB;

    46. //进程基本信息结构定义
    47. typedef struct
    48. {
    49.         DWORD ExitStatus;
    50.         PPEB PebBaseAddress;
    51.         DWORD AffinityMask;
    52.         DWORD BasePriority;
    53.         ULONG UniqueProcessId;
    54.         ULONG InheritedFromUniqueProcessId;
    55. }PROCESS_BASIC_INFORMATION;

    56. //函数指针定义,类型为WINDOWS Native API, 用于获取NtQueryInformationProcess的地址
    57. typedef LONG(WINAPI *PROCNTQSIP)(HANDLE,UINT,PVOID,ULONG,PULONG);

    58. //函数指针声明
    59. PROCNTQSIP NtQueryInformationProcess;

    60. //获取进程的命令行参数
    61. //dwId:输入参数,进程ID
    62. //wBuf:输出参数,用于存储命令行参数的缓冲区指针
    63. //dwBufLen:输入参数,缓冲区的大小
    64. //返回值:TRUE,成功FALSE,失败
    65. BOOL GetProcessCmdLine(DWORD dwId,LPWSTR wBuf,DWORD dwBufLen);

    66. //提升权限的函数
    67. void EnableDebugPriv(void);

    68. //主函数,程序入口
    69. void main(int argc,char* argv[])
    70. {
    71.         //命令行参数合法性判断
    72.         if(argc!=2)
    73.         {
    74.                 printf("usage:\n\t%s <PID>\n",argv[0]);
    75.                 return;
    76.         }
    77.         //提升权限,否则无法读取其它进程信息
    78.         EnableDebugPriv();
    79.         //获取WINDOWS Native API NtQueryInformationProcess的入口地址
    80.         NtQueryInformationProcess=(PROCNTQSIP)GetProcAddress(GetModuleHandle("ntdll"),"NtQueryInformationProcess");
    81.         //获取的函数入口的合法性检查
    82.         if(!NtQueryInformationProcess)
    83.         {
    84.                 return;
    85.         }
    86.         //从命令行获取目标进程的PID
    87.         DWORD dwId;
    88.         sscanf(argv[1],"%lu",&dwId);
    89.         //定义缓冲区,用于获得目标进程的命令行参数
    90.         WCHAR wstr[2048];
    91.         //清空缓冲区
    92.         ZeroMemory(wstr,sizeof(wstr));
    93.         //获取目标进程的命令行参数
    94.         if(GetProcessCmdLine(dwId,wstr,sizeof(wstr)))
    95.         {
    96.                 //获取成功,打印结果
    97.                 wprintf(L"commandline for process %lu is:\n %s\n",dwId,wstr);
    98.         }
    99.         else
    100.         {
    101.                 //获取失败,打印提示信息
    102.                 wprintf(L"Could not Get Command Line!");
    103.         }
    104. }
    105. //获取进程的命令行参数
    106. BOOL GetProcessCmdLine(DWORD dwId,LPWSTR wBuf,DWORD dwBufLen)
    107. {
    108.         LONG status;
    109.         HANDLE hProcess;
    110.         PROCESS_BASIC_INFORMATION pbi;
    111.         PEB Peb;
    112.         PROCESS_PARAMETERS ProcParam;
    113.         DWORD dwDummy;
    114.         DWORD dwSize;
    115.         LPVOID IpAddress;
    116.         BOOL bRet=FALSE;

    117.         //打开进程,获取查询和毒虚拟内存的权限
    118.         hProcess=OpenProcess(PROCESS_QUERY_INFORMATION| PROCESS_VM_READ,FALSE,dwId);
    119.         if(!hProcess)
    120.         {
    121.                 return FALSE;
    122.         }

    123.         //查询进程的基本信息,获取PEB
    124.         status=NtQueryInformationProcess(hProcess,0,(PVOID)&pbi,sizeof(PROCESS_BASIC_INFORMATION),NULL);
    125.         if(status)
    126.         {
    127.                 goto EndGet;
    128.         }
    129.         //读取进程的PEB指针
    130.         if(!ReadProcessMemory(hProcess,pbi.PebBaseAddress,&Peb,sizeof(PEB),&dwDummy))
    131.         {
    132.                 goto EndGet;
    133.         }
    134.         //获取目标进程空间存储的命令行参数字符串的指针
    135.         if(!ReadProcessMemory(hProcess,Peb.ProcessParameters,&ProcParam,sizeof(PROCESS_PARAMETERS),&dwDummy))
    136.         {
    137.                 goto EndGet;
    138.         }
    139.         IpAddress=ProcParam.CommandLine.Buffer;
    140.         dwSize=ProcParam.CommandLine.Length;
    141.         if(dwBufLen<dwSize)
    142.         {
    143.                 goto EndGet;
    144.         }
    145.         //读取目标进程的命令行参数到本进程的缓冲区
    146.         if(!ReadProcessMemory(hProcess,IpAddress,wBuf,dwSize,&dwDummy))
    147.         {
    148.                 goto EndGet;
    149.         }
    150.         bRet=TRUE;

    151. EndGet:
    152.         //关闭目标进程的句柄
    153.         CloseHandle(hProcess);
    154.         return bRet;
    155. }
    156. //提升本进程权限
    157. void EnableDebugPriv(void)
    158. {
    159.         HANDLE hToken;
    160.         LUID sedebugnameValue;
    161.         TOKEN_PRIVILEGES tkp;

    162.         //打开本进程,获得调整权限的权限
    163.         if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
    164.         {
    165.         return;
    166.         }
    167.         //查询EBUG权限的值
    168.         if(!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&sedebugnameValue))
    169.         {
    170.         CloseHandle(hToken);
    171.         return;
    172.         }
    173.         tkp.PrivilegeCount=1;
    174.         tkp.Privileges[0].Luid=sedebugnameValue;
    175.         tkp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
    176.         //调整本进程的权限,使之具有可以高度其它进程的权限
    177.         AdjustTokenPrivileges(hToken,FALSE,&tkp,sizeof tkp,NULL,NULL);
    178.         //关闭本进程句柄 
    179.         CloseHandle(hToken);
    180. }


0 0
原创粉丝点击