i am student studying reverse engineering.
These days, I am learning API Hook using DLL Injector
I made personal DLL Injector using C# WPF and C++/CLI
also i have created a DLL that hooks the send
function of ws2_32.dll
to call OutputDebugString
and log messages in DebugView whenever the send
function is called.
Below is the source code for the DLL used for hooking.
i used MinHook Library
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <tchar.h>
#include "MinHook.h"
#include "pch.h"
#pragma comment(lib, "ws2_32.lib")
// Define the original send function pointer
typedef int (WINAPI* send_t)(SOCKET, const char*, int, int);
send_t fpSend = NULL;
// Hooked send function
int WINAPI HookedSend(SOCKET s, const char* buf, int len, int flags)
{
// Buffer for the log message
TCHAR logMessage[2048]; // Set to a sufficient size
// No need to convert ANSI string to Unicode string
// But convert the ANSI string used for formatting to Unicode string
WCHAR wideBuf[2048];
int wideCharCount = MultiByteToWideChar(CP_ACP, 0, buf, len, NULL, 0);
MultiByteToWideChar(CP_ACP, 0, buf, len, wideBuf, wideCharCount);
wideBuf[wideCharCount] = L''; // Null-terminate
// Format the Unicode string into the log message
_stprintf_s(logMessage, _T("send function is called! 【Buffer: %s】"), wideBuf);
OutputDebugString(logMessage);
return fpSend(s, buf, len, flags); // Call the original send function
}
void InitHooking1()
{
// Initialize MinHook
if (MH_Initialize() != MH_OK)
{
return;
}
// Get the handle to ws2_32.dll
HMODULE hWs2_32 = GetModuleHandle(_T("ws2_32.dll"));
if (hWs2_32 == NULL)
{
return;
}
// Get the address of the send function
void* pSend = (void*)GetProcAddress(hWs2_32, "send");
if (pSend == NULL)
{
return;
}
// Create the hook for the send function
if (MH_CreateHook(pSend, &HookedSend, reinterpret_cast<LPVOID*>(&fpSend)) != MH_OK)
{
return;
}
// Enable the hook for the send function
if (MH_EnableHook(pSend) != MH_OK)
{
return;
}
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
OutputDebugString(L"DLL injection successful");
DisableThreadLibraryCalls((HMODULE)hinstDLL);
InitHooking1();
}
else if (fdwReason == DLL_PROCESS_DETACH)
{
MH_Uninitialize(); // Cleanup MinHook
}
return TRUE;
}
so i want hook in my personal chat program made with C# WPF
my chat program initially displays a login screen
login_window
enter image description here
and i used my custom DLL injector to inject the DLL into the chat program
when logging in, the send
function of ws2_32.dll
is used to send the username and password to the server, so logs appear correctly in DebugView
enter image description here
However, here’s where the problem begins. After a successful login, when the chat window is created, the functionality of the hooked DLL no longer works correctly
I continue to send messages in the chat, but OutputDebugString is not being called
enter image description here
enter image description here
It seems that the newly created window is unable to utilize the hooked DLL properly.
Below is the source code for transitioning from the login screen to the chat screen after a successful login in the chat program.
if(serverMessage == "Success")
{
ChattingRoomWindow chattingRomm = new ChattingRoomWindow(usernameBox.Text, client, stream);
Close();
chattingRomm.ShowDialog();
}
Below is the code used for sending messages in the ChattingRoomWindow. I know that this code internally uses the send function from ws2_32.dll.
private async void sendMessage()
{
byte[] byteData = Encoding.Default.GetBytes(message.Text);
await client.GetStream().WriteAsync(byteData, 0, byteData.Length);
message.Text = "";
}
Below is the code used for DLL Injector
The injector is a C# WPF GUI application, but its internal logic operates in C++/CLI.
#include "pch.h"
#include "DllInjectorLib.h"
namespace DllInjectorLib {
bool Injector::Inject(String^ processName, String^ dllPath)
{
pin_ptr<const wchar_t> wProcessName = PtrToStringChars(processName);
pin_ptr<const wchar_t> wDllPath = PtrToStringChars(dllPath);
DWORD dwPID = 0;
// Wait until the process ID is obtained
while ((dwPID = GetPIDByName(wProcessName)) == 0)
{
System::Threading::Thread::Sleep(1000); // Sleep for 1 second before retrying
}
return Inject(dwPID, wDllPath);
}
bool Injector::Inject(DWORD PID, LPCWSTR DllPath)
{
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
LPVOID pRemoteBuf = NULL;
HMODULE hMod = NULL;
LPTHREAD_START_ROUTINE pThreadProc = NULL;
// Open the target process
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
if (hProcess == NULL)
{
return false;
}
// Allocate memory in the target process for the DLL path
SIZE_T dwBufSize = (wcslen(DllPath) + 1) * sizeof(wchar_t);
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
if (pRemoteBuf == NULL)
{
CloseHandle(hProcess);
return false;
}
// Write the DLL path into the allocated memory
if (!WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)DllPath, dwBufSize, NULL))
{
VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
CloseHandle(hProcess);
return false;
}
// Get the address of LoadLibraryW function from kernel32.dll
hMod = GetModuleHandle(L"kernel32.dll");
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");
// Create a remote thread in the target process to load the DLL
hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
if (hThread == NULL)
{
VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
CloseHandle(hProcess);
return false;
}
WaitForSingleObject(hThread, INFINITE); // Wait for the thread to finish
// Clean up
CloseHandle(hThread);
VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
CloseHandle(hProcess);
return true;
}
DWORD Injector::GetPIDByName(LPCWSTR processName)
{
DWORD dwPID = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
// Iterate through the process list to find the process ID
if (Process32First(hSnapshot, &pe))
{
do
{
if (wcscmp(pe.szExeFile, processName) == 0)
{
dwPID = pe.th32ProcessID;
break;
}
} while (Process32Next(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
return dwPID;
}
}
I am aware that my injector and the DLL used for hooking work correctly when injected into various programs.
enter image description here
However, as shown in the screenshot above, when the process creates a new window, the DLL does not work properly in that new window
My native language is not English, and this is my first time using Stack Overflow. I hope my intentions are conveyed clearly, and I apologize for any awkward English or unintended rudeness
jeong is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.