Skip to content
MPGHThe Dark Arts
/
RegisterLog in
Forum
Community
What's NewLatest posts across the boardTrendingHottest threads right nowSubscribedThreads you follow
Discussion
GeneralIntroductionsEntertainmentDebate FortFlaming & Rage
Board
News & AnnouncementsMPGH TimesSuggestions & HelpGiveaways
More Sections
Art & Graphic DesignProgrammingHackingCryptocurrency
Hacks & Cheats
Games
ValorantCS2 / CS:GOCall of Duty / WarzoneFortniteApex LegendsEscape From Tarkov
+14 moreLeague of LegendsGTA VMinecraftRustROTMGBattlefieldTroveBattleOnCombat ArmsCrossFireBlackshotRuneScapeDayZDead by Daylight
Resources
Game Hacking TutorialsReverse EngineeringGeneral Game HackingAnti-CheatConsole Game Hacking
Tools
Game Hacking ToolsTrainers & CheatsHack/Release NewsNew
Submit a release →Share your cheat, tool, or config with the community.
AINEW
AI Tools
General & DiscussionPrompt EngineeringLLM JailbreaksHotAI Agents & AutomationLocal / Open Models
AI × Gaming
AI Aimbots & VisionML Anti-CheatGame Bots & Automation
Create
AI Coding / Vibe CodingAI Art & MediaAI Voice & TTS
The AI frontier →Where game hacking meets modern machine learning. Jump in.
Marketplace
Buy & Sell
SellingBuyingTradingUser Services
Trust & Safety
Middleman LoungeMarketplace TalkVouch Copy Profiles
Money
Cryptocurrency TalkCurrency ExchangeWork & Job Offers
Start selling →List accounts, services, and goods. Use the middleman to trade safe.
MPGH The Dark Arts

A community for offensive security research, reverse engineering, and AI.

Community

ForumMarketplaceSearch

Account

RegisterLog in

Legal

Privacy PolicyForum RulesHelp & FAQ
© 2026 MPGH · All rights reserved.Built by the community, for the community. For educational purposes onlyContent is shared for security research and education — we don't condone illegal use. You're responsible for complying with applicable laws. Use at your own risk.
Home › Forum › Programming › C++/C Programming › C++ Code Caving (Injecting a function into another process) | video tutorial

PostC++ Code Caving (Injecting a function into another process) | video tutorial

Posts 1–15 of 20 · Page 1 of 2
ZE
ZER0MEM0RY
C++ Code Caving (Injecting a function into another process) | video tutorial
Code Caving is basically executing YOUR code in the address space of another process.

Firstly, you will need to allocate for some space in the remote target process (VirtualAllocEx), after that
write your function to the allocated space in the process' heap (WriteProcessMemory).
After that, creating a new thread to the process and placing the function in it's stack
(CreateRemoteThread) Lastly, free the allocated space used to execute your code
(VirtualFree)

Video Tutorial:



source code:

Code:
/* NOTE!!! 32bit process can't interfere with 64bit process or vice versa! */
/* You must be using the same architecture as your target process uses!*/


#define _CRT_SECURE_NO_WARNINGS //let's us use "unsafe" functions in the crt

#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>

typedef int(__stdcall *__MessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);

class cavedata // store all of our remote data to one object
{
public:
	char chMessage[256]; //here we store it's message!
	char chTitle[256]; //here we will store our messagebox's title

	DWORD paMessageBoxA; //pa = Procedure address in memory

};

DWORD GetProcId(char* procname)
{
	PROCESSENTRY32 pe;
	HANDLE hSnap;

	pe.dwSize = sizeof(PROCESSENTRY32);
	hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
	if (Process32First(hSnap, &pe)) {
		do {
			if (strcmp(pe.szExeFile, procname) == 0)
				break;
		} while (Process32Next(hSnap, &pe));
	}
	return pe.th32ProcessID;
}

DWORD __stdcall RemoteThread(cavedata *cData) //thread that will be spawned in our target process
{
	__MessageBoxA MsgBox = (__MessageBoxA)cData->paMessageBoxA; //initialize our function
	MsgBox(NULL, cData->chMessage, cData->chTitle, MB_ICONINFORMATION); //call it
	return EXIT_SUCCESS;
}

int main()
{
	cavedata CaveData; //declare cave data object
	ZeroMemory(&CaveData, sizeof(cavedata)); // fill it with zeros
	strcpy(CaveData.chMessage, "Hi, I was called from remote process!"); //set the variables inside it
	strcpy(CaveData.chTitle, "Hello from code cave!");

	HINSTANCE hUserModule = LoadLibrary("user32.dll"); //load the user32.dll
	CaveData.paMessageBoxA = (DWORD)GetProcAddress(hUserModule, "MessageBoxA"); //find MessageBox procedure from it
	// and pass it to paMessageBox.
	FreeLibrary(hUserModule);

	//open our target process for writing
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetProcId("calc.exe"));
	//allocate memory for our procedure in the remote process' address space
	LPVOID pRemoteThread = VirtualAllocEx(hProcess, NULL, sizeof(cavedata), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	//write our thread to the target process
	WriteProcessMemory(hProcess, pRemoteThread, (LPVOID)RemoteThread, sizeof(cavedata), 0);
	//allocate memory for our cavedata object in the remote process
	cavedata *pData = (cavedata*)VirtualAllocEx(hProcess, NULL, sizeof(cavedata), MEM_COMMIT, PAGE_READWRITE);
	//Write it to the target process
	WriteProcessMemory(hProcess, pData, &CaveData, sizeof(cavedata), NULL);
	//spawn/create our procedure/thread in the remote process
	HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)pRemoteThread, pData, 0, 0);
	//close thread handle
	CloseHandle(hThread);
	//free the now un-used memory from the remote process' heap
	VirtualFreeEx(hProcess, pRemoteThread, sizeof(cavedata), MEM_RELEASE);
	//close process' handle
	CloseHandle(hProcess);
	/*...*/
	getchar();
	return 0;
}
#1 · 11y ago
InunoTaishou
InunoTaishou
Pretty good, I liked it! Contributing to the C/C++ community.

And we write our scopes the same way. I thought I was one of the few that started the curly brace on the same line for statements but curly brace on the next line for everything else.
#2 · 11y ago
ZE
ZER0MEM0RY
Quote Originally Posted by InunoTaishou View Post
Pretty good, I liked it! Contributing to the C/C++ community.

And we write our scopes the same way. I thought I was one of the few that started the curly brace on the same line for statements but curly brace on the next line for everything else.
Thanks! Feels good to hear I've not just been wasting my time to write useless code (y) !
That's actually my youtube channel, if you're interested in malware, reverse-engineering or general "hacking (lol)"
please go check it out! There is more to come!
#3 · 11y ago
Hitokiri~
Hitokiri~
One thing I don't quite understand:
Code:
DWORD __stdcall RemoteThread(cavedata *cData) //thread that will be spawned in our target process
{
	__MessageBoxA MsgBox = (__MessageBoxA)cData->paMessageBoxA; //initialize our function
	MsgBox(NULL, cData->chMessage, cData->chTitle, MB_ICONINFORMATION); //call it
	return EXIT_SUCCESS;
}
Code:
WriteProcessMemory(hProcess, pRemoteThread, (LPVOID)RemoteThread, sizeof(cavedata), 0);
Basically, you're writing the pointer to the function defined locally to the remote process, ok but how are you determining the size of the function "RemoteThread" ?
If i'm not mistaken, you're assuming the size of the compiled function "RemoteThread" is <= sizeof( CodeCave ) structure?
#4 · 11y ago
Hitokiri~
Hitokiri~
No response @ZER0MEM0RY ?
#5 · 11y ago
ZE
ZER0MEM0RY
Quote Originally Posted by Hitokiri~ View Post
One thing I don't quite understand:
Code:
DWORD __stdcall RemoteThread(cavedata *cData) //thread that will be spawned in our target process
{
	__MessageBoxA MsgBox = (__MessageBoxA)cData->paMessageBoxA; //initialize our function
	MsgBox(NULL, cData->chMessage, cData->chTitle, MB_ICONINFORMATION); //call it
	return EXIT_SUCCESS;
}
Code:
WriteProcessMemory(hProcess, pRemoteThread, (LPVOID)RemoteThread, sizeof(cavedata), 0);
Basically, you're writing the pointer to the function defined locally to the remote process, ok but how are you determining the size of the function "RemoteThread" ?
If i'm not mistaken, you're assuming the size of the compiled function "RemoteThread" is <= sizeof( CodeCave ) structure?
Yes, that's what I am assuming.
#6 · 11y ago
Hitokiri~
Hitokiri~
Quote Originally Posted by ZER0MEM0RY View Post
Yes, that's what I am assuming.
Code:
size_t len = 0;
char* code = (char*)RemoteThread;
while( *code++ != 0xc3 ) len++;
Since it's a simple process such as that with no conditions, you can do that instead to determine the size. I say this because the procedure might be located at the end of the page and if you happen to exceed the page ( Which might sometimes happen when reading a large block using RPM ) and stumble across another page boundary without the necessary read access, you'll crash. That way is at least far more reliable.

Optionally, you can inject pure assembly.

Code:
push 40h ; MB_ICONINFORMATION
lea eax, [ esp + 4 ] ; title
push eax
lea eax, [ esp + 264 ] ; msg
push eax
mov eax, [ esp + 524 ] ; paMessageBoxA
call eax
mov eax, 0
retn
#7 · edited 11y ago · 11y ago
ZE
zerobyte0101
Few people share their knowledge as you , thank you friend
#8 · 11y ago
ZE
ZER0MEM0RY
Quote Originally Posted by Hitokiri~ View Post

Code:
size_t len = 0;
char* code = (char*)RemoteThread;
while( *code++ != 0xc3 ) len++;
Since it's a simple process such as that with no conditions, you can do that instead to determine the size. I say this because the procedure might be located at the end of the page and if you happen to exceed the page ( Which might sometimes happen when reading a large block using RPM ) and stumble across another page boundary without the necessary read access, you'll crash. That way is at least far more reliable.

Optionally, you can inject pure assembly.

Code:
push 40h ; MB_ICONINFORMATION
lea eax, [ esp + 4 ] ; title
push eax
lea eax, [ esp + 264 ] ; msg
push eax
mov eax, [ esp + 524 ] ; paMessageBoxA
call eax
mov eax, 0
retn
Won't actually do the trick (atleast for x64 intel & 64bit windows 7)
0xC3 is the equivalent of ret, right? Yes, but some functions could have multiple ret instructions in them, so you would only get a part of the size of a function.
Just crashes the injector process.
#9 · 11y ago
Hitokiri~
Hitokiri~
Quote Originally Posted by ZER0MEM0RY View Post
Won't actually do the trick (atleast for x64 intel & 64bit windows 7)
0xC3 is the equivalent of ret, right? Yes, but some functions could have multiple ret instructions in them, so you would only get a part of the size of a function.
Just crashes the injector process.
I
Said
For
A
Simple
Process
Such
As
This.
Not
A
Complex
Function.
#10 · 11y ago
R3
R3DDOT
Quote Originally Posted by ZER0MEM0RY View Post
Yes, that's what I am assuming.

You can also use this trick when calculating size of functions:

Code:
DWORD __stdcall RemoteThread(cavedata *cData) //thread that will be spawned in our target process
{
	__MessageBoxA MsgBox = (__MessageBoxA)cData->paMessageBoxA; //initialize our function
	MsgBox(NULL, cData->chMessage, cData->chTitle, MB_ICONINFORMATION); //call it
	return EXIT_SUCCESS;
}
void __stdcall RemoteThread_end(){} 


Calculating the size:

sizeof(RemoteThread) = (DWORD_PTR)RemoteThread_end - (DWORD_PTR)RemoteThread;
Because these functions are defined consecutively, you can get the difference from the two function pointers and see the size of the first function.
#11 · 11y ago
Hitokiri~
Hitokiri~
Quote Originally Posted by R3DDOT View Post
these functions are defined consecutively
It doesn't always especially with optimization.
#12 · 11y ago
~B
~BlackMaster~
Or you could use a disassembly framework to implement your own GetFunctionSize.
#13 · 11y ago
Hitokiri~
Hitokiri~
Quote Originally Posted by ~BlackMaster~ View Post
Or you could use a disassembly framework to implement your own GetFunctionSize.
Personally I use a method that works because of how functions are aligned against each other.

Just use some sort of length disassembler and check if opcode length == 1 and opcode byte = 0xCC ( padding byte )
#14 · 11y ago
MarkHC
MarkHC
I'd much rather do syscalls directly instead of calling wrappers which are most of the time hooked by Anti-Cheats. If you look at the exported Nt_____ functions on ntdll.dll it should be pretty obvious what you should do.

Example: Instead of calling VirtualAlloc(Ex) you can do this and call it instead:

Code:
__declspec( naked )
NTSTATUS NtAllocateVirtualMemory( HANDLE ProcessHandle, PVOID *BaseAddress, ULONG ZeroBits, PULONG AllocationSize, ULONG AllocationType, ULONG Protect ) {
	__asm
	{
		MOV EAX, 0x17;
		CALL fs : [0xC0];
		RETN 0x18;
	}
}


//somewhere...
if( NT_ERROR( NtAllocateVirtualMemory( 
			GetCurrentProcess(), 
			&m_pBuffer, 
			NULL,
			&dwSize,
			MEM_COMMIT | MEM_RESERVE,
			PAGE_READWRITE ) ) ) {
	throw Exceptions::MemoryAllocationException( "Unable to alocate memory for the image" );
}
#15 · edited 11y ago · 11y ago
Posts 1–15 of 20 · Page 1 of 2

Post a Reply

Similar Threads

  • [Tutorial(C++)]How to call functions within another processBy radnomguywfq3 in Programming Tutorials
    4Last post 18y ago
  • How to do OPK + Code Cave with a debugger and C++By radnomguywfq3 in C++/C Programming
    4Last post 16y ago
  • Code for Injector; Importing DLL into ListboxBy Invidus in Visual Basic Programming
    5Last post 16y ago
  • [REQUEST] Code Cave TutBy HeXel in WarRock - International Hacks
    10Last post 18y ago
  • [HELP] How do I inject(???) the mods into CA?By ripper639 in Combat Arms Mods & Rez Modding
    11Last post 16y ago

Tags for this Thread

#c++#code cave#executing#heap#inject#injecting#stack