GetProcessName in C++ - c++

I have a function with blow detail.
typedef part
typedef DWORD (WINAPI *GETMODULEFILENAMEEX)(HANDLE hProcess, HMODULE hModule, LPTSTR lpBaseName,DWORD nSize);
typedef BOOL (WINAPI *PFNTERMINATEPROCESS)(HANDLE hProcess,UINT uExitCode);
/// GetProcessName function
void GetProcessName(DWORD PID, PTSTR szProcessName, size_t cchSize)
{
HMODULE lib=LoadLibrary(TEXT("Psapi.dll"));
GetModuleFileNameEx=(GETMODULEFILENAMEEX)GetProcAddress
(lib,"GetModuleFileNameExW");
_tcscpy_s(szProcessName, cchSize, TEXT("---"));
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE,PID);
if (hProcess == NULL) {
_tcscpy_s(szProcessName, cchSize, TEXT("???"));
return;
}
if (GetModuleFileNameEx(hProcess,(HMODULE)0, szProcessName, cchSize)
== 0) {
if (!GetProcessImageFileName(hProcess, szProcessName, cchSize)) {
_tcscpy_s(szProcessName, cchSize, TEXT("???"));
}
}
CloseHandle(hProcess);
}
I want use this function in below function
BOOL WINAPI Hook_TerminateProcess(HANDLE hProcess,UINT uExitCode) {
BOOL nResult=false;
TCHAR szProcessName[MAX_PATH];
nResult = ((PFNTERMINATEPROCESS)(PROC) g_TerminateProcess)(hProcess,uExitCode);
GetProcessName(HandleToULong(hProcess),szProcessName,MAX_PATH); //my question here
MessageBox(0, szProcessName ,TEXT("My MessageBox Info"),MB_OK | MB_ICONERROR);
return(nResult);
}
When I call function GetProcessName, this must return process name but it ??? str always.
I call this function directly by PID, for example GetProcessName(2018,szProcessName,MAX_PATH);.
2018 for example is a pid and it work.
I don't know why HandleToULong(hProcess) doesn't work. My hProcess must be a handle
type certainly now how I fix this problem?

char name[MAX_PATH * 2 ] = "\0", *p;
GetModuleFileName(GetModuleHandle(NULL),name,MAX_PATH);
p = name + strlen(name) - 1;
while (isalnum(*p) || ('.' == *p) || ('_' == *p))
p--;
p++;
std::cout << p << std::endl;

You must call GetProcessId rather than HandleToULong. You need a process ID, not a handle-converted-to-an-unsigned-long

How can you terminate the process then expect the handle to still be valid? cause if any clean up is performed, all data is lost(you don't explicitly copy the handle, so this can happen)
your error seems to stem from where your retrieving hProcess, in which case you should check GetLastError to see why its failing

In Windows, a process ID is different from a process handle. You are taking the process handle in Hook_TerminateProcess and passing it into GetProcessName as a process ID. This will never work.
You should refactor GetProcessName to take a handle and then have an overload that takes a process ID. The process ID overload does the OpenProcess work to convert it into a handle and the CloseHandle work to clean it up.
After the refactoring, you'll have two methods:
void GetProcessName(HANDLE hProcess, PTSTR szProcessName, size_t cchSize);
void GetProcessName(DWORD PID, PTSTR szProcessName, size_t cchSize);

Related

Why does SymInitialize() invoke CreateFile()?

Firstly, I want to hook CreateFile() and rewrite it. Then I want to recode the callstack of my new CreateFile() function. But when I use SymInitialize() to Initialize a handle, it falls into an endless loop. Through my debug, the reason is SymInitialize() invokes CreateFile(). So why does SymInitialize() involve CreateFile()? How to avoid this loop? Is there any alternative method to record callstack information to avoid this loop?
#include <windows.h>
#include <stdio.h>
#include "detours.h"
#include <fstream>
#include <io.h>
#pragma comment(lib, "detours.lib")
#include <DbgHelp.h> //SymInitialize
#pragma comment(lib,"dbghelp.lib")
#define STACK_INFO_LEN 200
struct stackInfo {
PDWORD hashValue; // hash value to identify same stack
char* szBriefInfo; // callstack info
};
stackInfo ShowTraceStack(char* szBriefInfo)
{
static const int MAX_STACK_FRAMES = 12;
void* pStack[MAX_STACK_FRAMES];
static char szStackInfo[STACK_INFO_LEN * MAX_STACK_FRAMES];
static char szFrameInfo[STACK_INFO_LEN];
HANDLE process = GetCurrentProcess(); // The handle used must be unique to avoid sharing a session with another component,
SymInitialize(process, NULL, TRUE);
PDWORD hashValue = (PDWORD)malloc(sizeof(DWORD)); // allow memory for hashVavlue, it will be rewrited in function CaptureStackBackTrace
WORD frames = CaptureStackBackTrace(0, MAX_STACK_FRAMES, pStack, hashValue);
//printf("hash value is: %ud \n", &hashValue);
if (szBriefInfo == NULL) {
strcpy_s(szStackInfo, "stack traceback:\n");
}
else {
strcpy_s(szStackInfo, szBriefInfo);
}
for (WORD i = 0; i < frames; ++i) {
DWORD64 address = (DWORD64)(pStack[i]);
DWORD64 displacementSym = 0;
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
DWORD displacementLine = 0;
IMAGEHLP_LINE64 line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymFromAddr(process, address, &displacementSym, pSymbol) &&
SymGetLineFromAddr64(process, address, &displacementLine, &line))
{
_snprintf_s(szFrameInfo, sizeof(szFrameInfo), "\t%s() at %s:%d(0x%x)\n",
pSymbol->Name, line.FileName, line.LineNumber, pSymbol->Address);
}
else
{
_snprintf_s(szFrameInfo, sizeof(szFrameInfo), "\terror: %d\n", GetLastError());
}
strcat_s(szStackInfo, szFrameInfo);
}
stackInfo traceStackInfo;
traceStackInfo.hashValue = hashValue;
traceStackInfo.szBriefInfo = szStackInfo;
return traceStackInfo;
//printf("%s", szStackInfo);
}
HANDLE (*__stdcall oldCreateFile)(LPCWSTR,
DWORD,
DWORD,
LPSECURITY_ATTRIBUTES,
DWORD,
DWORD,
HANDLE) = CreateFileW;
HANDLE WINAPI newCreateFile(
_In_ LPCWSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
) {
ShowTraceStack((char*)"trace information.\n");
return oldCreateFile(
L".\\newFiles.txt", // L".\\NewFile.txt", // Filename
//lpFileName,
dwDesiredAccess, // Desired access
dwShareMode, // Share mode
lpSecurityAttributes, // Security attributes
dwCreationDisposition, // Creates a new file, only if it doesn't already exist
dwFlagsAndAttributes, // Flags and attributes
NULL);
}
void hook() {
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)oldCreateFile, newCreateFile);
DetourTransactionCommit();
}
void unhook()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)oldCreateFile, newCreateFile);
DetourTransactionCommit();
}
void myProcess() {
HANDLE hFile = CreateFile(TEXT(".\\CreateFileDemo.txt"),
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
OutputDebugString(TEXT("CreateFile fail!\r\n"));
}
// write to file
const int BUFSIZE = 4096;
char chBuffer[BUFSIZE];
memcpy(chBuffer, "Test", 4);
DWORD dwWritenSize = 0;
BOOL bRet = WriteFile(hFile, chBuffer, 4, &dwWritenSize, NULL);
if (bRet) {
OutputDebugString(TEXT("WriteFile success!\r\n"));
}
}
int main(){
hook();
myProcess();
unhook();
}
The main problem is the call to SymInitialize where you pass through "TRUE" for fInvadeProcess parameter. This is causing it to SymLoadModuleEx to be called for each loaded module. This will cause a lot of file access to download / create / open PDB files for each loaded module. This is the reason for your infinite loop.
The "quick" fix for this sample is to move the call to SymInitialize into your main before the hook call as it only needs to be called once. This means all the PDB modules are loaded before the hooking / call to ShowTraceStack.
The other problems are:
dbghelp API is NOT thread safe - so this example will not work in a multi-threaded application
SymFromAddr may call CreateFile as well for the same reason to load a newly loaded module PDB information - so your hook not passing through the filename will cause PDB information to not work
If you are trying to make someone more useful I would:
Move SymInitialize to main before the hooking (called only once)
Only call CaptureStackBackTrace in the hook and queue the thread stack information to be processed at a later time
Create a separate thread the takes the CaptureStackBackTrace stack information output and convert it to a stack trace - this would is the only thread calling the dbghlp API making calls to dbghlp API thread safe
In your hook detect when being called from the dbghlp API usage thread and don't do the stack trace and don't modify the CreateFile parameters so you don't get into a infinite loop

CreateRemoteThread MessageBoxA causes remote process to crash

I made a simple program that calculates the RVA of the function MessaegBoxA in user32.dll and then adds that offset to the base loading address of the dll in the remote process's memory to get the address of the function MessageBoxA. I made a dummy program that outputs the address of the function in its memory using GetProcAddress and then implement my own function in my program to display the address it calculated for the same function in the remote process. They always match so I'm certain my function for finding the address of MessageBoxA in remote process's is not the problem.
I made a struct that contains all the necessary information and parameters needed for ThreadProc to execute MessageBoxA in the remote process once I load it using WriteProcessMemory.
typedef struct
{
typedef int (WINAPI* _MessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
_MessageBoxA MessageBoxA;
//These are the four parameters passed to MessageBoxA
HWND hwnd;
LPCSTR msg;
LPCSTR caption;
UINT mb;
}MB_DATA, *PMB_DATA;
When I try this on my own dummy program, the message box shows up but with weird text contrary to the strings I specified in the msg and caption members of MB_DATA. It says the following for the caption asic_string::erase and for the message it says u). And when I try to do this in any other process than my dummy process it crashes the remote process. I made a function to iterate through the modules that have been loaded in the process with tlhelp32 functions to make sure user32.dll is present and it is and my function for finding the address of the function in the process doesn't return NULL like it would if the dll were not present.
Here all relevant functions and my main function:
dependencies.hpp
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <iostream>
using namespace std;
typedef struct
{
typedef int (WINAPI* _MessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
_MessageBoxA MessageBoxA;
HWND hwnd;
LPCSTR msg;
LPCSTR caption;
UINT mb;
}MB_DATA, *PMB_DATA;
//Map the dll into memory
void* GetFileImage(char path[])
{
HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if(hFile == INVALID_HANDLE_VALUE){printf("Error getting file handle: %d", (int)GetLastError());return NULL;}
HANDLE file_map = CreateFileMapping(hFile, NULL, PAGE_READONLY|SEC_IMAGE, 0, 0, "KernelMap");
if(file_map == INVALID_HANDLE_VALUE){printf("Error mapping file: %d", (int)GetLastError());return NULL;}
LPVOID file_image = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 0);
if(file_image == 0){printf("Error getting mapped view: %d", (int)GetLastError());return NULL;}
return file_image;
}
//Get to the function export directory and find the offset for the specified function from the
//address in memory the dll was loaded at
DWORD_PTR RVAddress(char* image, const char* proc_name)
{
PIMAGE_DOS_HEADER pDos_hdr = (PIMAGE_DOS_HEADER)image;
PIMAGE_NT_HEADERS pNt_hdr = (PIMAGE_NT_HEADERS)(image+pDos_hdr->e_lfanew);
IMAGE_OPTIONAL_HEADER opt_hdr = pNt_hdr->OptionalHeader;
IMAGE_DATA_DIRECTORY exp_entry = opt_hdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
PIMAGE_EXPORT_DIRECTORY pExp_dir = (PIMAGE_EXPORT_DIRECTORY)(image+exp_entry.VirtualAddress);
DWORD* func_table = (DWORD*)(image+pExp_dir->AddressOfFunctions);
WORD* ord_table = (WORD*)(image+pExp_dir->AddressOfNameOrdinals);
DWORD* name_table = (DWORD*)(image+pExp_dir->AddressOfNames);
for(u_int i=0;i<pExp_dir->NumberOfNames;i++)
{
char* name = (char*)(image+name_table[i]);
if(strcmp(proc_name, name) == 0)
{
return (DWORD_PTR)func_table[ord_table[i]];
}
}
return (DWORD_PTR)0;
}
//Add the RVA returned from RVAddress to the address of the dll to find the function in the
//process memory
LPVOID GetProcAddressEx(DWORD dwPid, char* mod_path, char* function_name, char* mod_name)
{
HANDLE hSnapshot = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
me32.dwSize = sizeof(MODULEENTRY32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32, dwPid);
if(hSnapshot == INVALID_HANDLE_VALUE){printf("Snapshot failed");return 0;}
if(!(Module32First(hSnapshot, &me32)))
{
printf("Mod32First failed");
return 0;
}
BOOL found = FALSE;
while(Module32Next(hSnapshot, &me32))
{
if(stricmp(me32.szModule, mod_name) == 0)
{
CloseHandle(hSnapshot);
found = TRUE;
break;
}
}
if(found == FALSE){return 0;}
DWORD_PTR RVA = (DWORD_PTR)RVAddress((char*)GetFileImage(mod_path), function_name);
LPVOID func_addr = me32.modBaseAddr+RVA;
return func_addr;
}
main.cpp
#include "dependencies.hpp"
#define FUNC_SIZE 1024
typedef int (WINAPI* _MessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
int main()
{
MB_DATA mb_data;
mb_data.hwnd = NULL;
mb_data.msg = "Hey";
mb_data.caption = "Yo";
mb_data.mb = MB_OK;
SIZE_T nBytes = 0;
char proc_path[MAX_PATH];
char kernel_path[MAX_PATH];
char user32_path[MAX_PATH];
//get full path to the current process and store it in proc_path
GetModuleFileName(GetModuleHandle(NULL), proc_path, MAX_PATH);
//get full path to kernel32.dll and store it in kernel_path
GetModuleFileName(GetModuleHandle("kernel32.dll"), kernel_path, MAX_PATH);
//get full path to user3.dll and store it in user32_path
GetModuleFileName(GetModuleHandle("user32.dll"), user32_path, MAX_PATH);
//show all processes running and their PID's
system("tasklist");
DWORD dwPid = 0;
printf("PID: ");
scanf("%lu", &dwPid);
//if dwPid is 0 assign it the pid of the current process
if(dwPid == 0)
{
dwPid = GetCurrentProcessId();
}
//Get a handle to the process with all access rights
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
//make sure the handle is valid
if(hProc == NULL){printf("Error obtaining handle to process: %lu", GetLastError());return 1;}
//Get the address of the function in the remote process
LPVOID _MessageBoxA1 = GetProcAddressEx(dwPid, user32_path, (char*)"MessageBoxA", (char*)"user32.dll");
//assign the pointer to the address to the member MessageBoxA of the MB_DATA structure
mb_data.MessageBoxA = (_MessageBoxA)_MessageBoxA1;
//allocate 2mb for our the ThreadProc callback function and the MB_DATA structure
LPVOID lpBase = VirtualAllocEx(hProc, NULL, 2048, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
//did the allocation work
if(lpBase == NULL){printf("Error allocating space: %lu", GetLastError());return 1;}
//so I can check what was written with CheatEngine
cout << "Base address of memory allocated in remote process: " << lpBase << endl;
//Write the function into memory
if(WriteProcessMemory(hProc, lpBase, (LPVOID)ThreadProc, FUNC_SIZE, &nBytes) == 0)
{
printf("Error writing function to process");
return 1;
}
//the address the space left after having written ThreadProc into memory
LPVOID lpBuffer = lpBase+FUNC_SIZE;
//Write the MB_DATA structure into the memory of the remote process
if(WriteProcessMemory(hProc, lpBuffer, &mb_data, sizeof(MB_DATA), &nBytes) == 0)
{
printf("Error writing buffer to process");
}
//Run the ThreadProc function passing the MB_DATA structure to it as its lpParam parameter
if(CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpBase, lpBuffer, 0, NULL) == NULL)
{
printf("Error creating remote thread: %lu", GetLastError());
return 1;
}
//print a list of all the dll's being used by the process
EnumerateModules(dwPid);
system("pause");
return 0;
}
Any help would be greatly appreciated. Thank you very much! :)
mb_data.msg and mb_data.caption point to what in the another process ?? this is already enough for crash error. what is in ThreadProc not visible, but i not sure that it have no relocs. really ThreadProc must be member function of MB_DATA and access only it members. from you post obviously that you not debug remote process at injection time. also obviously that task is over your current level

Detours: Prevent task kill of my software via another software

I have found a code that promises to intercept and detour calls to the TerminateProcess function and thus prevent my software from being killed directly from other program.
But this code is not working and I am still able to kill my process via other program.
Here is the last my attempt with a code I have found in this YouTube video:
PS: victim.exe is the killer program.
DLL
// DllRedirectAPI.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include <Windows.h>
BYTE MOV[10] = { 0x48, 0xB8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
BYTE JMP_RAX[2] = { 0xFF, 0xE0 };
#define BuffSizeX64 (sizeof(MOV) + sizeof(JMP_RAX))
BOOL Hook_Det_x64(char LibName[], char API_Name[], LPVOID NewFun) {
DWORD OldProtect;
DWORD64 OrgAddress = (DWORD64)GetProcAddress(LoadLibraryA(LibName), API_Name);
if (OrgAddress == NULL) return 0;
memcpy(&MOV[2], &NewFun, 8);
VirtualProtect((LPVOID)OrgAddress, BuffSizeX64, PAGE_EXECUTE_READWRITE, &OldProtect);
memcpy((LPVOID)OrgAddress, MOV, sizeof(MOV));
memcpy((LPVOID)(OrgAddress + sizeof(MOV)), JMP_RAX, sizeof(JMP_RAX));
VirtualProtect((LPVOID)OrgAddress, BuffSizeX64, OldProtect, &OldProtect);
return 1;
}
int WINAPI MessageBoxAX(
HWND hWnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType) {
MessageBoxExA(0, "Hooked ...", "Mahmoud", 0, 0);
return 999;
}
BOOL WINAPI DllMain(HMODULE hModule, DWORD Call_Reason, LPVOID lpReserved) {
switch (Call_Reason) {
case DLL_PROCESS_ATTACH:
Hook_Det_x64("Kernel32.dll", "TerminateProcess", MessageBoxAX);
}
return 1;
}
INJECTOR
// Injector.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#include <conio.h>
#include <stdio.h>
#include <comdef.h>
#define WIN32_LEAN_AND_MEAN
#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)
BOOL Inject(DWORD pID, const char * DLL_NAME);
DWORD GetTargetThreadIDFromProcName(const char * ProcName);
int main(int argc, char * argv[])
{
//############### CHANGE HERE ONLY ###################
char *Target_Process = "victim.exe"; //###
//#######################################################
char *buf;
DWORD pID = GetTargetThreadIDFromProcName(Target_Process);
buf = "DllRedirectAPI.dll";
if (!Inject(pID, buf))
{
printf("DLL Not Loaded!");
}
else{
printf("DLL is Injected in torget Process");
}
_getch();
return 0;
}
BOOL Inject(DWORD pID, const char * DLL_NAME)
{
HANDLE Proc;
char buf[50] = { 0 };
LPVOID RemoteString, LoadLibAddy;
if (!pID)
return false;
Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
if (!Proc)
{
sprintf_s(buf, "OpenProcess() failed: %d", GetLastError());
printf(buf);
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "LoadLibraryA");
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME, strlen(DLL_NAME), NULL);
CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
CloseHandle(Proc);
return true;
}
DWORD GetTargetThreadIDFromProcName(const char * ProcName)
{
PROCESSENTRY32 pe;
HANDLE thSnapShot;
BOOL retval, ProcFound = false;
thSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (thSnapShot == INVALID_HANDLE_VALUE)
{
printf("Error: Unable create toolhelp snapshot!");
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapShot, &pe);
while (retval)
{
if (_bstr_t(pe.szExeFile) == _bstr_t(ProcName))
{
return pe.th32ProcessID;
}
retval = Process32Next(thSnapShot, &pe);
}
return 0;
}
Can someone help me, telling me where I'm making a mistake?
My system is Windows 7 Ultimate 64 Bits.
Thanks in advance.
(Wanted to write a comment, but it got quite long...)
As #AndrewMedico says in the comment: You need to hook the TerminateProcess of the Task Manager process to prevent the Task Manager from terminating anything.
I suggest you the following approach:
Try a simple DLL injection
a/ Make a DLL which prints some text in its DllMain, e.g. printf("I am here\n"); fflush(stdout);
b/ Try to inject it into some other command line process using the process hacker's Miscellaneous>Inject DLL...
c/ Verify your DLL was executed inside the target process by checking it's standard output
Try a simple API hook:
a/ Make a command line application which waits for a key and then terminates itself using some variant of TerminateProcess(GetCurrentProcess(), 1);. Add code to print some text after the TerminateProcess call.
b/ Run this application to verify the text after calling the TerminateProcess is not printed.
c/ Hook the TerminateProcess before waiting for the key using, e.g. mhook. Print some text in the replacement function and then return. Do not call the original TerminateProcess here.
d/ Run this application to verify the text inside the hook is printed and the text after the TerminateProcess call is printed as well (i.e. verify the process termination was suppressed).
Combine the results of previous steps to reach your goal:
a/ Put the hooking code from from step 2 into the DLL from step 1
b/ Inject it into the application from step 2b (i.e. the one without the hook) while it is waiting for the key and verify the text after TerminateProcess is printed.
c/ Enjoy (or debug/blame me)
Good luck!
EDIT>
OK, here is my view of what we have here:
Code in the question:
(Is an application very similar to what I suggest in "2b")
Hooks the TerminateProcess and shows a message box instead.
Should display a message box when executed
(Looks like it is a 32-bit only version)
YouTube video
Shows an application "Terminate process.exe" which terminates process given by name
After the "Injector.exe" is executed the application ceases to terminate the process and displays a message box instead (IMHO the "Injector.exe" injects a "DllFile.dll" into the running "Terminate process.exe")
Source code for the injector in the YouTube comments
This code injects DLL "C:\DllRedirectAPI.dll" into the first process with name "victim.exe" it finds
(It does not inject into "Terminate process.exe", it does not use "DllFile.dll")
Source code for the DLL in the YouTube comments
This code hooks function MessageBoxA that it shows a different message box instead. It is worth noting that the hook code itself calls the original MessageBoxA and takes the approach that it reverts the modification it did during the hooking, calls the original function and then re-applies the hook.
(It does not hook 'TerminateProcess' at all)
(Looks like it is a 32-bit only version)
64-bit version excerpts
Destructive hook of MessageBoxA (i.e. does not backup the original code)
The hook uses MessageBoxExA (which is intact) to display a different message box instead (i.e. it does not use the overwritten MessageBoxA)
(It does not hook 'TerminateProcess' at all)
(It is a 64-bit version)
Disclaimer: I am not that proficient with the topic to be 100% sure, feel free to correct/clarify me.
For the actual hooking I personally recommend to use the mhook library, which worked for me. It's documentation is worth reading as well.
See e.g. this for some alternatives (I have not tried any of them)...
EDIT>
This one works for me on Win XP inside VirtualBox:
#include <windows.h>
#include <stdio.h>
#include <mhook.h>
static BOOL WINAPI
(*_TerminateProcess)(
_In_ HANDLE hProcess,
_In_ UINT uExitCode
) = NULL;
BOOL WINAPI
TerminateProcessImpl(
_In_ HANDLE hProcess,
_In_ UINT uExitCode) {
printf("\nBlocked\n"); fflush(stdout);
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID Reserved) {
if(Reason==DLL_PROCESS_ATTACH) {
printf("\nDLL attached!\n"); fflush(stdout);
HMODULE h = LoadLibrary("Kernel32");
if(h!=NULL) {
printf("\nGot Kernel32!\n"); fflush(stdout);
_TerminateProcess=(void*)GetProcAddress(h,"TerminateProcess");
if(_TerminateProcess!=NULL) {
printf("\nAbout to hook...\n"); fflush(stdout);
if(Mhook_SetHook((void*)&_TerminateProcess, &TerminateProcessImpl)) {
printf("\nHooked OK!\n"); fflush(stdout);
} else {
printf("\nHook failed!\n"); fflush(stdout);
}
}
}
}
return TRUE;
}

Injected DLL and calling a function using CreateRemoteThread causes "has stopped working", what happens?

I`m trying to inject a DLL in a process and call a exported function in my DLL.
The DLL is injected alright with that code:
HANDLE Proc;
char buf[50] = { 0 };
LPVOID RemoteString, LoadLibAddy;
if (!pID)
return false;
Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
if (!Proc)
{
sprintf_s(buf, "OpenProcess() failed: %d", GetLastError());
printf(buf);
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
// Allocate space in the process for our DLL
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
// Write the string name of our DLL in the memory allocated
WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME, strlen(DLL_NAME), NULL);
// Load our DLL
HANDLE hThread = CreateRemoteThread(Proc, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
The module of my DLL is created OK, like you see in that image of Process Hacker (BootstrapDLL.exe):
My exported functions is ok too, like you see in the list of functions exported on Process Hacker (ImplantDotNetAssembly):
The problems, I think, happens on the offset calculation to get the address of the "ImplantDotNetAssembly", because everything above is alright and when I do the calculation I get the address of the "ImplantDotNetAssembly", but when I call CreateRemoteThread again to call it, the window "Has stopped working..." of the windows is showed and the process stoped. What`s happening?
Here is the code of the calculation of the offset:
DWORD_PTR hBootstrap = GetRemoteModuleHandle(ProcId, L"BootstrapDLL.exe");
DWORD_PTR offset = GetFunctionOffset(L"C:\\Users\\Acaz\\Documents\\Visual Studio 2013\\Projects\\Contoso\\Debug\\BootstrapDLL.exe", "ImplantDotNetAssembly");
DWORD_PTR fnImplant = hBootstrap + offset;
HANDLE hThread2 = CreateRemoteThread(Proc, NULL, 0, (LPTHREAD_START_ROUTINE)fnImplant, NULL, 0, NULL);
Here are the functions GetRemoteModuleHandle and GetFunctionOffset:
DWORD_PTR GetFunctionOffset(const wstring& library, const char* functionName)
{
// load library into this process
HMODULE hLoaded = LoadLibrary(library.c_str());
// get address of function to invoke
void* lpInject = GetProcAddress(hLoaded, functionName);
// compute the distance between the base address and the function to invoke
DWORD_PTR offset = (DWORD_PTR)lpInject - (DWORD_PTR)hLoaded;
// unload library from this process
FreeLibrary(hLoaded);
// return the offset to the function
return offset;
}
DWORD_PTR GetRemoteModuleHandle(const int processId, const wchar_t* moduleName)
{
MODULEENTRY32 me32;
HANDLE hSnapshot = INVALID_HANDLE_VALUE;
// get snapshot of all modules in the remote process
me32.dwSize = sizeof(MODULEENTRY32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processId);
// can we start looking?
if (!Module32First(hSnapshot, &me32))
{
CloseHandle(hSnapshot);
return 0;
}
// enumerate all modules till we find the one we are looking for or until every one of them is checked
while (wcscmp(me32.szModule, moduleName) != 0 && Module32Next(hSnapshot, &me32));
// close the handle
CloseHandle(hSnapshot);
// check if module handle was found and return it
if (wcscmp(me32.szModule, moduleName) == 0)
return (DWORD_PTR)me32.modBaseAddr;
return 0;
}
If someone know what is happening, I'll be very grateful!
I cant`t even debug the "has stopped work.." error. When I clik in the DEBUG button on the window, the error throw again and everything stop.
Thank you.
NEVER inject managed assemblies. If for some reason you must inject code into another process, use native code with either NO C library or a STATIC C library.

How to inject a DLL into a Delphi program

I have a legacy application, which contains a grid with data I need to extract.
I don't have the code for that application and it is impossible to get the data out of it with normal means (like programmatically selecting all cells and copying them into clipboard).
So I decided to use DLL injection as described in section "II. The CreateRemoteThread & LoadLibrary Technique" at
http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces
My plan is
To load a DLL into the address space of the legacy application.
Make the DLL read the data from the grid and write them out (e. g. via a named pipe).
The first step is to inject the DLL into the address space of the legacy application (step a) above).
I've written following code for that:
int InjectDll (HANDLE hProcess);
int _tmain(int argc, _TCHAR* argv[])
{
printf("DllInjector\n");
/**
* Find out PID of the legacy application (START)
*/
HWND windowHandle = FindWindowW(NULL, L"FORMSSSSS");
DWORD* processID = new DWORD;
GetWindowThreadProcessId(windowHandle, processID);
DWORD delphiAppProcessId = *processID;
/**
* Find out PID of the legacy application (END)
*/
printf("Process ID of legacy app: %lu\n", delphiAppProcessId);
// Now we need the handle of the legacy app
HANDLE hProcess = OpenProcess(
PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
FALSE, delphiAppProcessId);
if (hProcess != NULL)
{
printf("Found handle, ready for injection\n");
int result = InjectDll(hProcess);
CloseHandle( hProcess );
printf("Injection complete, result=%d\n", result);
}
else
{
printf("Handle not found\n");
}
system("pause");
return 0;
}
int InjectDll( HANDLE hProcess )
{
HANDLE hThread;
const char* const szLibPath = "D:\\mycompany\\SampleDll\\Debug\\SampleDll.dll";
void* pLibRemote = 0; // the address (in the remote process) where
// szLibPath will be copied to;
DWORD hLibModule = 0; // base adress of loaded module (==HMODULE);
HMODULE hKernel32 = ::GetModuleHandle(L"Kernel32");
// 1. Allocate memory in the remote process for szLibPath
// 2. Write szLibPath to the allocated memory
pLibRemote = ::VirtualAllocEx( hProcess, NULL, sizeof(szLibPath), MEM_COMMIT, PAGE_READWRITE );
if( pLibRemote == NULL )
return false;
::WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath,sizeof(szLibPath),NULL);
// Load "LibSpy.dll" into the remote process
// (via CreateRemoteThread & LoadLibrary)
hThread = ::CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"LoadLibraryA"),
pLibRemote, 0, NULL );
if( hThread == NULL )
goto JUMP;
::WaitForSingleObject( hThread, INFINITE );
// Get handle of loaded module
::GetExitCodeThread( hThread, &hLibModule );
::CloseHandle( hThread );
JUMP:
::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );
if( hLibModule == NULL ) // (1)
return false;
// Unload "LibSpy.dll" from the remote process
// (via CreateRemoteThread & FreeLibrary)
hThread = ::CreateRemoteThread( hProcess,
NULL, 0,
(LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"FreeLibrary"),
(void*)hLibModule,
0, NULL );
if( hThread == NULL ) // failed to unload
return false;
::WaitForSingleObject( hThread, INFINITE );
::GetExitCodeThread( hThread, &hLibModule );
::CloseHandle( hThread );
// return value of remote FreeLibrary (=nonzero on success)
return hLibModule;
}
Some comments:
The legacy program has the title "FORMSSSSS".
The sample DLL has following DllMain method:
-
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
{
OutputDebugStringA("DllMain called: ");
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
OutputDebugStringA("DLL_PROCESS_ATTACH\n");
case DLL_THREAD_ATTACH:
OutputDebugStringA("DLL_THREAD_ATTACH\n");
case DLL_THREAD_DETACH:
OutputDebugStringA("DLL_THREAD_DETACH\n");
case DLL_PROCESS_DETACH:
OutputDebugStringA("DLL_PROCESS_DETACH\n");
break;
}
return TRUE;
}
When it is called, a text is written into the standard output of the application.
When I run the program above (the one with _tmain method), I expect to see the text
DllMain called: DLL_PROCESS_ATTACH
in the console output (it means that the DLL injection was successful).
But it doesn't happen.
One potential cause is that the PID of the legacy application is determined incorrectly:
HWND windowHandle = FindWindowW(NULL, L"FORMSSSSS");
DWORD* processID = new DWORD;
GetWindowThreadProcessId(windowHandle, processID);
DWORD delphiAppProcessId = *processID;
But the value delphiAppProcessId is the same as the PID displayed in the task manager, so I can exclude this potential bug.
Using the debugger I found out that the execution stops at the line with comment (1):
JUMP:
::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );
if( hLibModule == NULL ) // (1)
return false;
What do I need to change in order for the sample DLL to be injected into the address space of the application with title "FORMSSSSS" ?
Update, 16.09.2012:
I replaced all occurrences of
sizeof(szLibPath)
by pathLength, where
const int pathLength = strlen(szLibPath)+1;
Now, in
::WaitForSingleObject( hThread, INFINITE );
::GetExitCodeThread( hThread, &hLibModule );
::CloseHandle( hThread );
// return value of remote FreeLibrary (=nonzero on success)
return hLibModule;
}
hLibModule is nonzero, which means that the injection was successful.
But I still can't see the log output of the sample DLL in the output of the program.
Update, 16.09.2012 (2):
When I
a) add a call to AllocConsole() in DllMain of the sample DLL,
b) rebuild it and
c) execute the injecting program,
then a console window appears, which has the same icon as the Delphi application.
When I remove AllocConsole from the DllMain function, and execute the injecting application, the console window does not appear.
So the injection might actually work.
The biggest problem that I can see is that sizeof(szLibPath) evaluates to the size of a pointer. Use strlen(szLibPath)+1 instead.
For sure that means that your injection will fail because the path that LoadLibraryA receives will be truncated. There may be other problems, but that's the place to start.