Page 1 of 2 12 LastLast
Results 1 to 15 of 20
  1. #1
    ZER0MEM0RY's Avatar
    Join Date
    Feb 2015
    Gender
    male
    Location
    \\\\.\\PhysicalDrive0
    Posts
    94
    Reputation
    10
    Thanks
    4,195
    My Mood
    Cold

    Post 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;
    }

  2. The Following 4 Users Say Thank You to ZER0MEM0RY For This Useful Post:

    Anton Troskie (10-28-2016),Cosmo_ (07-02-2015),InunoTaishou (07-01-2015),RoPMadM (07-07-2015)

  3. #2
    InunoTaishou's Avatar
    Join Date
    Jan 2009
    Gender
    male
    Location
    The Internet
    Posts
    446
    Reputation
    20
    Thanks
    938
    My Mood
    Relaxed
    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.
    https://www.mpgh.net/forum/signaturepics/sigpic210976_1.gif

  4. #3
    ZER0MEM0RY's Avatar
    Join Date
    Feb 2015
    Gender
    male
    Location
    \\\\.\\PhysicalDrive0
    Posts
    94
    Reputation
    10
    Thanks
    4,195
    My Mood
    Cold
    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!

  5. #4
    殺す必要がある唯一のものは殺されるために準備され人 々である。
    Premium Member
    Hitokiri~'s Avatar
    Join Date
    Oct 2012
    Gender
    female
    Location
    Cancer.
    Posts
    1,203
    Reputation
    24
    Thanks
    936
    My Mood
    Bitchy
    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?

  6. #5
    殺す必要がある唯一のものは殺されるために準備され人 々である。
    Premium Member
    Hitokiri~'s Avatar
    Join Date
    Oct 2012
    Gender
    female
    Location
    Cancer.
    Posts
    1,203
    Reputation
    24
    Thanks
    936
    My Mood
    Bitchy
    No response @ZER0MEM0RY ?

  7. #6
    ZER0MEM0RY's Avatar
    Join Date
    Feb 2015
    Gender
    male
    Location
    \\\\.\\PhysicalDrive0
    Posts
    94
    Reputation
    10
    Thanks
    4,195
    My Mood
    Cold
    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.

  8. #7
    殺す必要がある唯一のものは殺されるために準備され人 々である。
    Premium Member
    Hitokiri~'s Avatar
    Join Date
    Oct 2012
    Gender
    female
    Location
    Cancer.
    Posts
    1,203
    Reputation
    24
    Thanks
    936
    My Mood
    Bitchy
    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
    Last edited by Hitokiri~; 07-05-2015 at 08:32 AM.

  9. #8
    zerobyte0101's Avatar
    Join Date
    Jul 2015
    Gender
    male
    Posts
    4
    Reputation
    10
    Thanks
    0
    Few people share their knowledge as you , thank you friend

  10. #9
    ZER0MEM0RY's Avatar
    Join Date
    Feb 2015
    Gender
    male
    Location
    \\\\.\\PhysicalDrive0
    Posts
    94
    Reputation
    10
    Thanks
    4,195
    My Mood
    Cold
    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.

  11. #10
    殺す必要がある唯一のものは殺されるために準備され人 々である。
    Premium Member
    Hitokiri~'s Avatar
    Join Date
    Oct 2012
    Gender
    female
    Location
    Cancer.
    Posts
    1,203
    Reputation
    24
    Thanks
    936
    My Mood
    Bitchy
    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.

  12. #11
    R3DDOT's Avatar
    Join Date
    Dec 2013
    Gender
    male
    Location
    C://Windows/system32
    Posts
    347
    Reputation
    38
    Thanks
    2,363
    My Mood
    Cheerful
    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.

  13. #12
    殺す必要がある唯一のものは殺されるために準備され人 々である。
    Premium Member
    Hitokiri~'s Avatar
    Join Date
    Oct 2012
    Gender
    female
    Location
    Cancer.
    Posts
    1,203
    Reputation
    24
    Thanks
    936
    My Mood
    Bitchy
    Quote Originally Posted by R3DDOT View Post
    these functions are defined consecutively
    It doesn't always especially with optimization.

  14. #13
    ~BlackMaster~'s Avatar
    Join Date
    May 2014
    Gender
    male
    Location
    ummm... :B
    Posts
    48
    Reputation
    10
    Thanks
    4
    My Mood
    Amused
    Or you could use a disassembly framework to implement your own GetFunctionSize.

  15. #14
    殺す必要がある唯一のものは殺されるために準備され人 々である。
    Premium Member
    Hitokiri~'s Avatar
    Join Date
    Oct 2012
    Gender
    female
    Location
    Cancer.
    Posts
    1,203
    Reputation
    24
    Thanks
    936
    My Mood
    Bitchy
    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 )

  16. #15
          ( ° ͜ʖ͡°)╭∩╮
    Former Staff
    MarkHC's Avatar
    Join Date
    Nov 2011
    Gender
    male
    Location
    127.0.0.1
    Posts
    2,750
    Reputation
    66
    Thanks
    14,519
    My Mood
    Angelic
    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" );
    }
    Last edited by MarkHC; 07-19-2015 at 10:35 PM.


    CoD Minion from 09/19/2012 to 01/10/2013

Page 1 of 2 12 LastLast

Similar Threads

  1. [HELP] How do I inject(???) the mods into CA?
    By ripper639 in forum Combat Arms Mods & Rez Modding
    Replies: 11
    Last Post: 04-10-2010, 06:58 PM
  2. Code for Injector; Importing DLL into Listbox
    By Invidus in forum Visual Basic Programming
    Replies: 5
    Last Post: 02-20-2010, 02:43 PM
  3. How to do OPK + Code Cave with a debugger and C++
    By radnomguywfq3 in forum C++/C Programming
    Replies: 4
    Last Post: 12-08-2009, 01:00 PM
  4. [Tutorial(C++)]How to call functions within another process
    By radnomguywfq3 in forum Programming Tutorials
    Replies: 4
    Last Post: 07-08-2008, 08:33 PM
  5. [REQUEST] Code Cave Tut
    By HeXel in forum WarRock - International Hacks
    Replies: 10
    Last Post: 02-16-2008, 02:36 AM

Tags for this Thread