[Tutorial with Source] GetPidsByProcessName menu

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 15 of 18
  1. #1
    Ellesar1's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    78
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    [Tutorial with Source] GetPidsByProcessName

    Hello,

    First of all: this tutorial describes the very earliest phase of programming an own bot/hack/tool/whatever. Most of you do already know this info or don't have to know it due to the libraries which are out there in the net. Although, it would be nice if you could fly over the code and post suggestions for improvements that I could make. (may it be coding style or bad performance or something else...)

    Since I'm also pretty new to memory editing, I want to build things by hand instead of taking a library. I want to understand what the single steps are which are processed in the background. Therefore, I've started to write some little program from scratch.

    The first action you have to do to begin with reading / writing memory, is to get a process handle via the OpenProcess() function from psapi.dll. OpenProcess requires the process' ID.

    You can't get this ID that easy, since there could be multiple WoW's running and therefore you can't simply enter "WoW.exe" into some magic function and get the process ids from them.

    The solution is to enumerate over all active processes regardless of them being wow processes or not, and to get their process names. Then, it's a simple string comparison with "WoW.exe" and you are done.

    Note that you need to add the "SeDebugPrivilege" to the own processes ProcessToken to access some processes, including the WoW process. This requires the process to be elevated to administrator rights in Windows Vista and up. The privilege has to be set as soon as you access the process with OpenProcess(); The second function takes care of setting the flag.
    To elevate the process, just go to the Linker => Manifest settings in the project properties and choose requireAdministrator in the UAC dropdown field.


    The attachment contains my implementation of the mentioned functions, which automates this process of getting the process ID.

    sample usage:
    Code:
    #include <windows.h>
    #include <psapi.h>
    #include <stdio.h>
    #include <tchar.h>
    #include <vector>
    #include "process.h"
    #include <exception>
    
    
    int main () {
    	try {
    		Process::SetDebugPrivileges();
    		std::vector<DWORD> processPIDs = Process::GetPidsByProcessName(std::basic_string<TCHAR>(TEXT("Wow.exe")));
    		_tprintf(TEXT("Found %d WoW processes.\n"), processPIDs.size());
    	} catch (std::exception& e) {
    		_tprintf(TEXT("ERROR: %s\n"), e.what());
    	} catch (...) {
    		_tprintf(TEXT("UNKNOWN EXCEPTION\n"));
    	}
    	getchar();
    	return 0;
    }
    source:
    process.h
    Code:
    #ifndef process_h_included
    #define process_h_included
    #include <tchar.h>
    #include <vector>
    #include <string>
    
    class Process {
    public:
    	static void SetDebugPrivileges ();
    	static std::vector<DWORD> GetPidsByProcessName (const std::basic_string<TCHAR> &processName);
    };
    #endif
    process.cpp
    Code:
    #include <windows.h>
    #include <tchar.h>
    #include <vector>
    #include <exception>
    #include "process.h"
    #include <Tlhelp32.h>
    #include <string>
    #include <memory.h>
    
    void Process::SetDebugPrivileges () {
    	// Get own process token
    	HANDLE hToken_unsafe;
    	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken_unsafe)) {
    		throw std::runtime_error("setDebugPrivileges: OpenProcessToken failed");
    	}
    	const std::tr1::shared_ptr<void> hToken (hToken_unsafe, CloseHandle);	
    	TOKEN_PRIVILEGES tPrivileges;
    	if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tPrivileges.Privileges[0].Luid)) {
    		throw std::runtime_error("setDebugPrivileges: LookupPrivilegeValue failed");
    	}
    	// Set SeDebugPrivilege flag
    	tPrivileges.PrivilegeCount = 1;
    	tPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    	if (!AdjustTokenPrivileges(hToken.get(), FALSE, &tPrivileges, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL)) {
    		throw std::runtime_error("setDebugPrivileges: AdjustTokenPrivileges failed");
    	}
    	if (GetLastError() != ERROR_SUCCESS) {
    		throw std::runtime_error("setDebugPrivileges: AdjustTokenPrivileges didn't adjust all specified privileges");
    	}
    };
    
    std::vector<DWORD> Process::GetPidsByProcessName (const std::basic_string<TCHAR> &processName) {
    	// Make snapshot of process list
    	const std::tr1::shared_ptr<void> hProcessSnapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL), CloseHandle);
    	if (hProcessSnapshot.get() == INVALID_HANDLE_VALUE) {
    		throw std::runtime_error("Process::GetPidsByProcessName: CreateToolhelp32Snapshot failed");
    	}
    	// Go through the list and search for processes with a matching process name
    	std::vector<DWORD> result;
    	PROCESSENTRY32 pEntry;
    	pEntry.dwSize = sizeof(PROCESSENTRY32);
    	for (BOOL success = Process32First(hProcessSnapshot.get(), &pEntry);
    		success && GetLastError() != ERROR_NO_MORE_FILES;
    		success = Process32Next(hProcessSnapshot.get(), &pEntry))
    	{
    		if (processName == pEntry.szExeFile) {
    			result.push_back(pEntry.th32ProcessID);
    		}
    	}
    	return result;
    };
    Enjoy!
    Last edited by Ellesar1; 10-13-2009 at 03:22 PM.

    [Tutorial with Source] GetPidsByProcessName
  2. #2
    furang's Avatar Member
    Reputation
    19
    Join Date
    Jul 2009
    Posts
    84
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you use your tool for only one Wow.exe process, then there's easier way.
    FindWindow() to get Wow window handle, GetWindowThreadProcessId() to get wow's pID (additionally you can get mainthread ID), OpenProcess to get wow process handle.
    i did it 4 lulz

  3. #3
    Cypher's Avatar Kynox's Sister's Pimp
    Reputation
    1356
    Join Date
    Apr 2006
    Posts
    5,368
    Thanks G/R
    0/4
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Your code is awful (riddled with potential bugs and crashes, poorly designed, etc), however the concept is there... I guess...

  4. #4
    flo8464's Avatar Active Member
    Reputation
    30
    Join Date
    Apr 2009
    Posts
    434
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just in case someone likes to see a different attempt to get that job done, here is the code I use in my lib:

    Code:
    std::vector<DWORD> Process::getListByProcessName(const std::wstring& processName)
    {
    	HANDLE procSnapshot;
    	procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    	if(procSnapshot == INVALID_HANDLE_VALUE)
    		throw std::exception("Process::getListByProcessName() Error : CreateToolhelp32Snapshot() failed");
    
    	std::vector<DWORD> procList;
    	PROCESSENTRY32 procEntry = { sizeof(procEntry) };
    	for(int moreProcessEntries = Process32First(procSnapshot, &procEntry); moreProcessEntries; moreProcessEntries = Process32Next(procSnapshot, &procEntry)) 
    	{
    		std::wstring currentProcess(procEntry.szExeFile);
    		std::transform(currentProcess.begin(), currentProcess.end(), currentProcess.begin(), tolower);
    
    		if(currentProcess == processName)
    			procList.push_back(procEntry.th32ProcessID);
    	}
    
    	CloseHandle(procSnapshot);
    	return procList;
    }
    or: nopaste.info - free nopaste script and service
    Last edited by flo8464; 10-10-2009 at 07:00 PM.

  5. #5
    Ellesar1's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    78
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for your feedback! Very important to fix my coding errors etc. in the beginning rather than later.

    Your code is awful (riddled with potential bugs and crashes, poorly designed, etc), however the concept is there... I guess...
    I think that you mean the error handling with "crashes", the fact that a process could go away in the middle of my function and respawn as a WoW.exe with the same PID with "bugs" and the ugly non-descriptive bool return type and the fact that you can't get pids without debug rights with "poorly designed".

    Just in case someone likes to see a different attempt to get that job done, here is the code I use in my lib
    I think that the idea of taking a snapshot and operating on it is cleaner than having the risk of processes spawning and going away during the code. Think that I will go for it too.

    I only see four small things you could add:
    - the user inputted process name is not converted to lowercase. however, the process names are.
    - Process32First returns a BOOL, not an int
    - since PROCESSENTRY32.szExeFile is an array of TCHAR and not of WCHAR, you should use std::string instead of std::wstring to not making it crash on non-unicode systems.
    - CloseHandle uses SEH and can throw exceptions if running under a debugger. However, outside of the debugger, you should be fine.

    Thanks for your feedback. Will update my code.
    Last edited by Ellesar1; 10-11-2009 at 09:02 AM.

  6. #6
    flo8464's Avatar Active Member
    Reputation
    30
    Join Date
    Apr 2009
    Posts
    434
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    - the user inputted process name is not converted to lowercase. however, the process names are.
    Yeah, you are right. Right now I am the only one using it and I consider myself smart enough to use my own code correctly, but good suggestion.

    - Process32First returns a BOOL, not an int
    BOOL is a typedef to int. I personally don't like all the Windows-typedefs and as long as they are just typedefs to basic datatypes (and no structures) I rarely use them.

    - since PROCESSENTRY32.szExeFile is an array of TCHAR and not of WCHAR, you should use std::string instead of std::wstring to not making it crash on non-unicode systems.
    Everything in my lib uses widestrings only.

    - CloseHandle uses SEH and can throw exceptions if running under a debugger. However, outside of the debugger, you should be fine.
    Didn't think about that. Thanks.

  7. #7
    Ellesar1's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    78
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    just looked again at the closehandle thing on MSDN

    If the application is running under a debugger, the function will throw an exception if it receives either a handle value that is not valid or a pseudo-handle value.
    since the handle stays inside the function and we ensure manually that it is valid and not a pseudo-handle value (wtf is this?), we don't need to check for this SEH exception. however, the normal exception should be caught:
    If the function fails, the return value is zero. To get extended error information, call GetLastError.
    since we don't have influence of this one.



    I've updated the first post with the new code. Please look at it even if you are familiar with memory editing so that I can improve with an easy sample which doesn't take much time to change. Note that it is not necessary to have debug privileges, since openprocess is not called anymore to list them.

  8. #8
    flo8464's Avatar Active Member
    Reputation
    30
    Join Date
    Apr 2009
    Posts
    434
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah, looks good. I also fixed my code, should be free of flaws now..

    Code:
    std::vector<DWORD> Process::getListByProcessName(const std::wstring& processName)
    {
    	std::wstring processName_lowerCase = processName;
    	std::transform(processName_lowerCase.begin(), processName_lowerCase.end(), processName_lowerCase.begin(), towlower);
    
    	HANDLE procSnapshot;
    	procSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    	if(procSnapshot == INVALID_HANDLE_VALUE)
    		throw std::exception("Process::getListByProcessName() Error : CreateToolhelp32Snapshot() failed");
    
    	std::vector<DWORD> procList;
    	PROCESSENTRY32 procEntry = { sizeof(procEntry) };
    	for(int moreProcessEntries = Process32FirstW(procSnapshot, &procEntry); moreProcessEntries; moreProcessEntries = Process32NextW(procSnapshot, &procEntry)) 
    	{
    		std::wstring currentProcess(procEntry.szExeFile);
    		std::transform(currentProcess.begin(), currentProcess.end(), currentProcess.begin(), towlower);
    
    		if(currentProcess == processName_lowerCase)
    			procList.push_back(procEntry.th32ProcessID);
    	}
    
    	if(!CloseHandle(procSnapshot))
    		throw std::exception("Process::getListByProcessName() Error : CloseHandle() failed");
    
    	return procList;
    }
    Last edited by flo8464; 10-11-2009 at 11:43 AM.

  9. #9
    Cypher's Avatar Kynox's Sister's Pimp
    Reputation
    1356
    Join Date
    Apr 2006
    Posts
    5,368
    Thanks G/R
    0/4
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Ellesar1 View Post
    Thanks for your feedback! Very important to fix my coding errors etc. in the beginning rather than later.


    I think that you mean the error handling with "crashes", the fact that a process could go away in the middle of my function and respawn as a WoW.exe with the same PID with "bugs" and the ugly non-descriptive bool return type and the fact that you can't get pids without debug rights with "poorly designed".
    No.

    * You're using pointers rather than references in a totally unnecessary manner.
    * You're leaking resources all over the place due to a lack of RAII. (Example: You call OpenProcessToken, then if LookupPrivilegeValue fails you throw an exception without cleaning up the handle.)
    * You're using global data unnecessarily. This can cause threading issues and is simply bad style.
    * Your code is a messy mix of C and C++. You use C++ containers but then use C-style strings. C++ style strings are there for a reason.
    * Lots of your code lacks const-correctness.
    etc

  10. #10
    Ellesar1's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    78
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    First of all, +rep for your post, Cypher, and thanks for taking some time to look over my code.

    * Your code is a messy mix of C and C++. You use C++ containers but then use C-style strings. C++ style strings are there for a reason.
    I've googled about the differences of them and just have to say that you are perfectly right. Taking an std::string isn't really more unefficient than using direct TCHAR[] although it's more "high-level" and you don't feel the inner representation that much. They are just the new way to handle strings.
    => Changed the argument to a std::string (which should be converted to std::basic_string<TCHAR> via all the typedefs and therefore to a std::wstring on unicode systems (?) )

    * You're using pointers rather than references in a totally unnecessary manner.
    also read about this and have to agree with you again. Call by reference is better than call by pointer, since you don't have to check for NULL at runtime and it is easier to use. The bad side of it (and the only one where I think that call by pointer should be used) is that they you cannot use them for pointer arithmetic. for example, the following will not work. (yes i know that it's not the best example).
    Code:
    char x[] = "Cypher rocks!";
    char *c = x;
    while (*c++) {
       // do something
    }
    * You're using global data unnecessarily. This can cause threading issues and is simply bad style.
    I think that you want to point to this "execute only once" bool out there which doesn't prevent two threads to execute the method at the same time and causing it to set the flag multiple times in some potential cases. Although it doesn't do something bad in this case (well, you set it two times, but that's just some minimal amount of time wasted by one of them), I see your point.
    => Since it is not the point of the (minimal) "library" to decide whether or not to set a flag (maybe, some other command from the user has reset the flag and you actually WANT to set it again), I've removed it.
    There's one question left. How do you make some proper version of such a once function?

    * Lots of your code lacks const-correctness.
    and another concept I didn't know before as I understand it, you should mark everything with const that has not to be modified.
    i've found the following:
    • the argument of GetPidsByProcessName. however, since it is now an std::string and therefore passed by value (which is not inefficient at all, the way how strings are stored), I can ignore it.
    • HANDLE hProcessSnapshot, since it is not changed somewhere
    • HANDLE hToken: does NOT work, since it is set via reference. is there a way to const it afterwards?

    (somehow, the LIST board code has stopped working)

    * You're leaking resources all over the place due to a lack of RAII. (Example: You call OpenProcessToken, then if LookupPrivilegeValue fails you throw an exception without cleaning up the handle.)
    didn't heard about that either. (why aren't these concepts teached in normal tutorials... cypher you should write a c++ beginner book which takes care of such concepts :-))
    will use the shared_ptr's with custom deleter to accomplish this goal as soon as service pack 1 for VS08 is downloaded and installed and I have it defined in the <memory> header file.

    thanks again for your hints. will update code tomorrow

  11. #11
    flo8464's Avatar Active Member
    Reputation
    30
    Join Date
    Apr 2009
    Posts
    434
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A good reason to use std::string over pointers to character-arrays is that you can't stop a user from being retarded.

    What if the user gives you a pointer pointing to somewhere out of the applications memory space? Your function will crash. What if your function gets fed by a non-zero-terminated C-string ?

    Problems which can't appear if you use std::strings.

    => Changed the argument to a std::string (which should be converted to std::basic_string<TCHAR> via all the typedefs and therefore to a std::wstring on unicode systems (?) )
    The C++-Lib doesn't know TCHAR. Just typedef it yourself?

  12. #12
    Ellesar1's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    78
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    TCHAR should be converted to char or to WCHAR depending on if the system understands unicode or not. since i put a

    Code:
    #include <tchar.h>
    inside it, c++ will know it

    (that's what I've heard about tchar. don't know if it is correct)

  13. #13
    flo8464's Avatar Active Member
    Reputation
    30
    Join Date
    Apr 2009
    Posts
    434
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yes, but

    std::string is typedef-ed to std::basic_string<char>

    and

    std::wstring is typedef-ed to std::basic_string<wchar_t>

    Best solution would be the following:

    typedef std::basic_string<TCHAR> tstring

  14. #14
    Cypher's Avatar Kynox's Sister's Pimp
    Reputation
    1356
    Join Date
    Apr 2006
    Posts
    5,368
    Thanks G/R
    0/4
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    1. You can still do pointer arithmetic in most cases, however you shouldn't need to in most cases so your point is moot:
    void Foo(const std::string& Arg1, const std::vector<DWORD>& Arg2)
    {
    char const * const pBlah = Arg1.c_str(); // pointer to my string
    DWORD const * const pBlah2 = &Arg2[0]; // Pointer to my buffer
    }

    You don't need to use the method you presented to loop over a string, C++ strings provide iterators and the subscript operator for a reason.

    2. Don't take strings by value. Take them by reference-to-const. See the code I posted above for an example. Doing this is in most cases 'faster' that taking the string by value, but it is never slower. So you only stand to gain from doing it.

    3. In order to do a proper 'execute-once' function I'd use boost's threading library. It offers such a function which uses the correct atomic operations in order to set/get the value.

    4. You don't want a shared_ptr with a custom deleter. Check out the "EnsureCleanup" class from 'Windows via C/C++'.
    http://www.wintellect.com/Downloads/...1,%202007).zip

  15. #15
    Ellesar1's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    78
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    damn it. downloaded the service pack for the wrong language version..... -.- have to wait the whole evening until the correct one is installed and i can merge my code with the newly gained knowledge.

    @1: i know that my example is not the best but could not imagine a better one. maybe there is really absolutely never a reason for call by pointer. thanks for the hint about iterators! just knew that you can access the std::string's character also over the array index

    @4: what's the exact difference between the "shared_ptr with a custom deleter" and the "ensurecleanup"? for me it looks like being similar: it takes the HANDLE and a custom deleter and calls the deleter as soon as it is not referenced anymore.

    @2: it makes sense that it cannot be slower since the address of the string doesn't need to be calculated in an expensive way => will update my code with this.

    @3: okay, so it seems to work with semaphores as the only way to accomplish it. since i have removed the "once"-part of the function, i'll just keep that in mind.



    @flo:
    - hmm: char is typedeffed to TCHAR, string is typedeffed to basic_string<char> => and therefore to basic_string<TCHAR>. am i wrong? EDIT yes was wrong. tchar is typedeffed to char.
    Last edited by Ellesar1; 10-13-2009 at 01:55 PM.

Page 1 of 2 12 LastLast

Similar Threads

  1. Coloa Fishbot - Simple fishbot with source
    By grosfilsdepute in forum World of Warcraft Bots and Programs
    Replies: 5
    Last Post: 10-20-2009, 08:48 AM
  2. Replies: 6
    Last Post: 02-09-2009, 02:44 AM
  3. AC Web Ultimate Repack for 2.3.0 Tutorial! With Pictures For Newbies
    By Skozzan in forum WoW EMU Guides & Tutorials
    Replies: 140
    Last Post: 02-04-2008, 11:48 AM
  4. Auto-Queue/Anti-AFK HonorBot With Source Code (c++)
    By Flying Piggy in forum World of Warcraft Bots and Programs
    Replies: 12
    Last Post: 09-12-2007, 11:13 AM
  5. All-Jumps {(Jumping Script)} With Source!
    By iHack in forum World of Warcraft Bots and Programs
    Replies: 55
    Last Post: 08-01-2007, 03:27 AM
All times are GMT -5. The time now is 02:25 PM. Powered by vBulletin® Version 4.2.3
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2024 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search