Qter 发表于 2020-1-28 18:52:16

VC 如何根据进程名称找程序的目录

你首先需要为VC下载一个Microsoft Platform SDK for Windows XP SP2,有了这个包以后,将psapi.h和psapi.lib拷贝到VC的include和lib目录,采用PSAPI编程:
1、用EnumProcesses函数列出当前所有进程
2、用OpenProcess打开进程
3、用GetProcessImageFileName函数就可以获取程序的完整目录

上面三个函数的资料在互联网上很完整,你可以用函数名作为关键字搜索一下就知道了。

下面举个例子:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")

void PrintProcessNameAndID( DWORD processID )
{
    TCHAR szProcessName = TEXT("<unknown>");
    TCHAR szProcessPath = TEXT("<unknown>");
    // 获取进程句柄

    HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
                                 PROCESS_VM_READ,
                                 FALSE, processID );

    // 获取进程名称和路径
    if (NULL != hProcess )
    {
      HMODULE hMod;
      DWORD cbNeeded;

      if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod),
             &cbNeeded) )
      {
            GetModuleBaseName( hProcess, hMod, szProcessName,
                               sizeof(szProcessName)/sizeof(TCHAR) );
      }
      GetProcessImageFileName(hProcess, szProcessPath, MAX_PATH);
    }

    // 打印进程名、进程号和路径地址.

    _tprintf( TEXT("%s(PID: %u) <%s>\n"), szProcessName, processID, szProcessPath );

    CloseHandle( hProcess );
}

void main( )
{
    // 获取进程列表.

    DWORD aProcesses, cbNeeded, cProcesses;
    unsigned int i;

    if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
      return;

    // 计算当前一共多少个活动进程
    cProcesses = cbNeeded / sizeof(DWORD);

    //打印进程信息
    for ( i = 0; i < cProcesses; i++ )
      if( aProcesses != 0 )
            PrintProcessNameAndID( aProcesses );
}

Qter 发表于 2020-1-28 20:52:14

VC_查找进程,关闭进程

// // FindProcess // 这个函数唯一的参数是你指定的进程名,如:你的目标进程 // 是 Notepad.exe,返回值是该进程的ID,失败返回0 // DWORD FindProcess(char *strProcessName) { DWORD aProcesses, cbNeeded, cbMNeeded; HMODULE hMods; HANDLE

//
// FindProcess
// 这个函数唯一的参数是你指定的进程名,如:你的目标进程
// 是 "Notepad.exe",返回值是该进程的ID,失败返回0
//

DWORD FindProcess(char *strProcessName)
{
    DWORD aProcesses, cbNeeded, cbMNeeded;
    HMODULE hMods;
    HANDLE hProcess;
    char szProcessName;

    if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) ) return 0;
    for(int i=0; i< (int) (cbNeeded / sizeof(DWORD)); i++)
    {
      //_tprintf(_T("%d\t"), aProcesses);
      hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses);
      EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbMNeeded);
      GetModuleFileNameEx( hProcess, hMods, szProcessName,sizeof(szProcessName));

      if(strstr(szProcessName, strProcessName))
      {
            //_tprintf(_T("%s;"), szProcessName);
            return(aProcesses);
      }
      //_tprintf(_T("\n"));
    }


    return 0;
}

//
// Function: ErrorForce
// 此函数中用上面的 FindProcess 函数获得你的目标进程的ID
// 用WIN API OpenPorcess 获得此进程的句柄,再以TerminateProcess
// 强制结束这个进程
//

VOID KillProcess()
{
    // When the all operation fail this function terminate the "winlogon" Process for force exit the system.
    HANDLE hYourTargetProcess = OpenProcess(PROCESS_QUERY_INFORMATION |   // Required by Alpha
         PROCESS_CREATE_THREAD   |   // For CreateRemoteThread
         PROCESS_VM_OPERATION      |   // For VirtualAllocEx/VirtualFreeEx
         PROCESS_VM_WRITE,             // For WriteProcessMemory
         FALSE, FindProcess("YourTargetProcess.exe"));

    if(hYourTargetProcess == NULL)
    {
      return;
    }

    TerminateProcess(hYourTargetProcess, 0);

    return;
}

//
// GetDebugPriv
// 在 Windows NT/2000/XP 中可能因权限不够导致以上函数失败
// 如以 System 权限运行的系统进程,服务进程
// 用本函数取得 debug 权限即可,Winlogon.exe 都可以终止哦 :)
//

BOOL GetDebugPriv()
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;

if ( ! OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
    {
return FALSE;
    }

if ( ! LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &sedebugnameValue ) )
{
CloseHandle( hToken );
return FALSE;
}

tkp.PrivilegeCount = 1;
tkp.Privileges.Luid = sedebugnameValue;
tkp.Privileges.Attributes = SE_PRIVILEGE_ENABLED;

if (!AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp, NULL, NULL ) )
    {
      CloseHandle( hToken );
      return FALSE;
    }

    return TRUE;
}

以上三个函数使用前先#include "Psapi.h"

然后SETTING->LINK 里添加Psapi.lib即可。。。。。



----------------------
在VC程序中创建进程,结束进程,按如下步骤进行即可:
  1.取得进程的句柄(利用FindWindow函数得到);
  2.获取进程ID号(用GetWindowThreadProcessId函数获取);
  3.打开进程,OpenProcess函数中的第一个参数设为PROCESS_TERMINATE,就可以获取处理该进程的句柄;
  4.利用TerminateProcess函数结束进程,将该函数的第二个参数设为4。
  代码如下:
  //结束进程
  int CStaticFunc::KillProcess(LPCSTR pszClassName, LPCSTR
  pszWindowTitle)
  {
  HANDLE hProcessHandle;
  ULONG nProcessID;
  HWND TheWindow;
  TheWindow = ::FindWindow( NULL, pszWindowTitle );
  ///方法一:
  ::GetWindowThreadProcessId( TheWindow, &nProcessID );
  hProcessHandle = ::OpenProcess( PROCESS_TERMINATE, FALSE,
  nProcessID );
  return ::TerminateProcess( hProcessHandle, 4 );
  ///方法二:
  return ::PostMessage(TheWindow, WM_CLOSE, NULL, NULL);
  }
  而启动进程则只需要CreateProcess函数就可完成,需要注意的是这个函数的几个输入参数,第一个参数是
  //创建新进程
  ///方法一:
  int CStaticFunc::CreateNewProcess(LPCSTR pszExeName)
  {
  PROCESS_INFORMATION piProcInfoGPS;
  STARTUPINFO siStartupInfo;
  SECURITY_ATTRIBUTES saProcess, saThread;
  ZeroMemory( &siStartupInfo, sizeof(siStartupInfo) );
  siStartupInfo.cb = sizeof(siStartupInfo);
  saProcess.nLength = sizeof(saProcess);
  saProcess.lpSecurityDescriptor = NULL;
  saProcess.bInheritHandle = true;
  saThread.nLength = sizeof(saThread);
  saThread.lpSecurityDescriptor = NULL;
  saThread.bInheritHandle = true;
  return ::CreateProcess( NULL, (LPTSTR)pszExeName, &saProcess,
  &saThread, false,
  CREATE_DEFAULT_ERROR_MODE, NULL, NULL,
  &siStartupInfo, &piProcInfoGPS );
  }
  ///方法二:
  WinExec(lpCmdLine, uCmdShow);

-----
1.使用ExitProcess()结束进程

   进程只是提供了一段地址空间和内核对象,其运行时通过在其地址空间内的主线程来体现的。当主线程的进入点函数返回时,进程也就随之结束。这种进程的终止方式是进程的正常退出,进程中的所有线程资源都能够得到正确的清除。除了这种进程的正常退出方式外,有时还需要在程序中通过代码来强制结束本进程或其他进程的运行。ExitProcess()函数的原型为:

void ExitProcess(UINT uExitCode);

   其参数uExitCode为进程设置了退出代码。该函数具有强制性,在执行完毕后进程即被结束,因此位于其后的任何代码将不能被执行。虽然ExitProcess()函数可以在结束进程的同时通知与其关联的动态链接库,但是由于它的这种执行的强制性,使得ExitProcess()函数在使用上将存在有安全隐患。例如,如果在程序调用ExitProcess()函数之前曾用new操作符申请过一段空间,那么将会由于ExitProcess()函数的强制性而无法通过delete操作符将其释放,从而造成内存泄露。有鉴于ExitProcess()函数的强制性和不安全性,在使用时一定要引起注意。

2.使用TerminateProcess()结束进程

   ExitProcess()只能强制执行本进程的退出,如果要在一个进程中强制结束其他进程就要用TerminateProcess()来实现。与ExitProcess()不同,TerminateProcess()函数执行后,被终止的进程是不会的到任何关于程序退出的通知的。也就是说,被终止的进程是无法在结束运行前进行退出前的收尾工作的。所以,通常只有在其他任何方法都无法迫使进程退出时才会考虑使用TerminateProcess()去强制结束进程。下面给出TerminateProcess()的函数原型:

BOOL TerminateProcess(HANDLE hProcess,UINT uExitCode);

   参数hProcess和uExitCode分别为进程句柄和退出代码。如果被结束的是本进程,可以通过GetCurrentProcess()获取到句柄。TerminateProcess()是异步执行的,在调用返回后并不能确定被终止进程是否已经真的退出,如果调用TerminateProcess()的进程对此细节关心,可以通过WaitForSingleObject()来等待进程的真正结束。





   在VC程序中如何结束系统正在运行的其他进程(该进程必须有窗口界面),其实很简单,按如下步骤进行即可:
    1.取得进程的句柄(利用FindWindow函数得到);
    2.获取进程ID号(用GetWindowThreadProcessId函数获取);
    3.打开进程,OpenProcess函数中的第一个参数设为PROCESS_TERMINATE,就可以获取处理该进程的句柄;
    4.利用TerminateProcess函数结束进程,将该函数的第二个参数设为4。

    代码如下:


//结束进程
int CStaticFunc::KillProcess(LPCSTR pszClassName, LPCSTR

pszWindowTitle)
{
    HANDLE hProcessHandle;
    ULONG nProcessID;
    HWND TheWindow;

    TheWindow = ::FindWindow( NULL, pszWindowTitle );
    ::GetWindowThreadProcessId( TheWindow, &nProcessID );
    hProcessHandle = ::OpenProcess( PROCESS_TERMINATE, FALSE, nProcessID );
    return ::TerminateProcess( hProcessHandle, 4 );
}


而启动进程则只需要CreateProcess函数就可完成
//启动新进程
int CStaticFunc::CreateNewProcess(LPCSTR pszExeName)
{
    PROCESS_INFORMATION piProcInfoGPS;
    STARTUPINFO siStartupInfo;
    SECURITY_ATTRIBUTES saProcess, saThread;
    ZeroMemory( &siStartupInfo, sizeof(siStartupInfo) );
    siStartupInfo.cb = sizeof(siStartupInfo);
    saProcess.nLength = sizeof(saProcess);
    saProcess.lpSecurityDescriptor = NULL;
    saProcess.bInheritHandle = true;
    saThread.nLength = sizeof(saThread);
    saThread.lpSecurityDescriptor = NULL;
    saThread.bInheritHandle = true;
    return ::CreateProcess( NULL, (LPTSTR)pszExeName, &saProcess, &saThread, false, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &siStartupInfo,&piProcInfoGPS );
}
--kaixuan's cnblogs

--------------------------
//kill进程from名字
BOOL KillProcessFromName(LPCSTR lpProcessName)
{
    HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(PROCESSENTRY32);
    if(!Process32First(hSnapShot,&pe))
    {
      return FALSE;
    }
    CString strProcessName = lpProcessName;
    strProcessName.MakeLower();
    while (Process32Next(hSnapShot,&pe))
    {
      CString scTmp = pe.szExeFile;
      scTmp.MakeLower();
      if(!scTmp.Compare(strProcessName))
      {
            DWORD dwProcessID = pe.th32ProcessID;
            HANDLE hProcess = ::OpenProcess(PROCESS_TERMINATE,FALSE,dwProcessID);
            ::TerminateProcess(hProcess,0);
            CloseHandle(hProcess);
            return TRUE;
      }
      scTmp.ReleaseBuffer();
    }
    strProcessName.ReleaseBuffer();
    return FALSE;
}
以杀死qq程序为例,我们可以通过下列方式:
KillProcessFromName("qq.exe");


Qter 发表于 2020-1-28 20:52:44

启动其它程序

1.WinExec

UINT WinExec(
LPCSTR lpCmdLine, // address of command line
UINT uCmdShow // window style for new application
);

使用方法如下:

WinExec(_T("D:\\Program Files\\zeecalls\\zeecalls.exe"),SW_SHOWMAXIMIZED);

这句话将会以最大化的方式打开zeecalls.exe,需要注意的是,在VC中,‘/’需要以‘//’来写。


2.ShellExecute   ---ShellExecuteEx
HINSTANCE ShellExecute(
HWND hwnd, //父窗口句柄
LPCTSTR lpOperation,//打开方式
LPCTSTR lpFile, //待打开的文件名
LPCTSTR lpParameters, LPCTSTR lpDirectory,//文件路径
INT nShowCmd );

同样,我们也可以通过这个函数来打开我们需要的文件:

ShellExecute(NULL,_T("open"),_T("zeecalls.exe"),NULL,_T("D:\\Program Files\\zeecalls\\"),SW_SHOWNORMAL);

这句话是以用正常的显示方式打开zeecalls.exe

3.CreateProcess
BOOL CreateProcess(

LPCTSTR lpApplicationName, //执行程序名

LPTSTR lpCommandLine, // 参数行

//下面两个参数描述了所创建的进程和线程的安全属性,如果为NULL则使用默认的安全属性
LPSECURITY_ATTRIBUTES lpProcessAttributes, // process security attributes
LPSECURITY_ATTRIBUTES lpThreadAttributes, // thread security attributes

BOOL bInheritHandles, // 继承标志
DWORD dwCreationFlags, // 创建标志
LPVOID lpEnvironment, // 环境变量
LPCTSTR lpCurrentDirectory, // 运行该进程的初始目录
LPSTARTUPINFO lpStartupInfo, // 用于在创建子进程时设置各种属性
LPPROCESS_INFORMATION lpProcessInformation //用于在进程创建后接受相关信息
);

在上面的参数中,使用了两个比较重要的数据结构:STARTUPINFO和PROCESS_INFORMATION。这两个结构的定义分别如下:

typedef struct _STARTUPINFO { // si
DWORD cb; //结构长度
LPTSTR lpReserved; //保留
LPTSTR lpDesktop; //保留
LPTSTR lpTitle; //如果为控制台进程则为显示的标题
DWORD dwX; //窗口横坐标
DWORD dwY; //窗口丛坐标
DWORD dwXSize; //窗口宽度
DWORD dwYSize; //窗口高度
DWORD dwXCountChars; //控制台窗口字符号宽度
DWORD dwYCountChars; //控制台窗口字符号高度
DWORD dwFillAttribute; //控制台窗口填充模式
DWORD dwFlags; //创建标记
WORD wShowWindow; //窗口显示标记,如同ShowWindow中的标记
        WORD cbReserved2; //保留参数
LPBYTE lpReserved2; //保留参数
HANDLE hStdInput; //标准输入句柄
HANDLE hStdOutput; //标准输出句柄
HANDLE hStdError; //标准错误句柄
} STARTUPINFO, *LPSTARTUPINFO;

typedef struct _PROCESS_INFORMATION { // pi
HANDLE hProcess; //进程句柄
HANDLE hThread; //进程的主线程句柄
DWORD dwProcessId; //进程的ID
DWORD dwThreadId; //进程的主线程ID
} PROCESS_INFORMATION;

作为例子,我们来看看如何使用CreateProcess来打开相同的文件:

PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si,0,sizeof(si));
si.cb=sizeof(si);
si.wShowWindow=SW_SHOW;
si.dwFlags=STARTF_USESHOWWINDOW;

bool fRet=CreateProcess("D:\\Program Files\\zeecalls\\zeecalls.exe",NULL,NULL,FALSE,NULL,NULL,NULL,NULL,&si,&pi);



用CreateProcess打开游戏,然后你的进程可以用WaitForSingleObject去等,这样在游戏没退出之前,你的进程是阻塞的。

Qter 发表于 2020-1-28 20:53:27

如何隐藏进程

在WINDOWS操作系统下,当我们无法结束或者不知道怎样结束一个程序的时候,或者是懒得去找“退出” 按钮的时候,通常会按“CTRL+ALT+DEL”呼出任务管理器,找到想结束的程序,点一下“结束任务”就了事 了,呵呵,虽然有点粗鲁,但大多数情况下都很有效,不是吗?设想一下,如果有这么一种软件,它所要做的工作就是对某个使用者在某台电脑上的活动作一定的限制, 而又不能被使用者通过“结束任务”这种方式轻易地解除限制,那该怎么做?无非有这么三种方法:1.屏蔽 “CTRL+ALT+DEL”这个热键的组合;2.让程序不出现在任务管理器的列表之中;3.让任务管理器无法杀掉 这个任务。对于第一种方法,这样未免也太残酷了,用惯了“结束任务”这种方法的人会很不习惯的;对于 第二种方法,在WINDOWS 9X下可以很轻易地使用注册服务进程的方法实现,但是对于WINDOWS NT 架构的操作系统没有这个方法了,进程很难藏身,虽然仍然可以实现隐藏,但实现机制较为复杂;对于第 三种方法,实现起来比较简单,我的作品:IPGate 网址过滤器 就是采用的这种方式防杀的,接下来我就 来介绍这种方法。任务管理器的“结束任务”实际上就是强制终止进程,它所使用的杀手锏是一个叫做TerminateProcess()的 Win32 API函数,我们来看看它的定义:BOOL TerminateProcess(HANDLE hProcess, // 将被结束进程的句柄UINT uExitCode // 指定进程的退出码);看到这里,是不是觉得不必往下看都知道接下来要做什么:Hook TerminateProcess()函数,每次 TerminateProcess()被调用的时候先判断企图结束的进程是否是我的进程,如果是的话就简单地返回一个 错误码就可以了。真的是这么简单吗?先提出一个问题,如何根据hProcess判断它是否是我的进程的句 柄?答案是:在我的进程当中先获得我的进程的句柄,然后通过进程间通讯机制传递给钩子函数,与 hProcess进行比较不就行了?错!因为句柄是一个进程相关的值,不同进程中得到的我的进程的句柄的值 在进程间进行比较是无意义的。 怎么办?我们来考察一下我的hProcess它是如何得到的。一个进程只有它的进程ID是独一无二的,操作 系统通过进程ID来标识一个进程,当某个程序要对这个进程进行访问的话,它首先得用OpenProcess这 个函数并传入要访问的进程ID来获得进程的句柄,来看看它的参数:HANDLE OpenProcess(DWORD dwDesiredAccess, // 希望获得的访问权限BOOL bInheritHandle, // 指明是否希望所获得的句柄可以继承DWORD dwProcessId // 要访问的进程ID);脉络渐渐显现:在调用TerminateProcess()之前,必先调用OpenProcess(),而OpenProcess()的参数表中 的dwProcessId是在系统范围内唯一确定的。得出结论:要Hook的函数不是TerminateProcess()而是 OpenProcess(),在每次调用OpenProcess()的时候,我们先检查dwProcessId是否为我的进程的ID(利用 进程间通讯机制),如果是的话就简单地返回一个错误码就可以了,任务管理器拿不到我的进程的句柄,它 如何结束我的进程呢?至此,疑团全部揭开了。由Hook TerminateProcess()到Hook OpenProcess()的这个过程,体现了一个逆 向思维的思想。其实我当初钻进了TerminateProcess()的死胡同里半天出也不来,但最终还是蹦出了灵感 的火花,注意力转移到了OpenProcess()上面,实现了进程防杀。喜悦之余,将这心得体会拿出来与大家 分享。
页: [1]
查看完整版本: VC 如何根据进程名称找程序的目录