I think this is what you need, set the target address to Read, Write and Execute (if you even want to change code).
VirtualProtect((LPVOID)targetaddress,5,PAGE_EXECUTE_READWRITE,&oldp);
This is a full scenario:
Write a DLL with a shared memory section. The DLL should be linked to your main application to enable receiving notifications or data (the string), and to enable sending commands from your main app if you need to control the remote process.
Your main application should create the remote thread, the code in that thread would be to Load the DLL into the remote process, and then the DLL should take over from there.
Using the inter-process communication mechanism of your choice, start sending/receiving data between the remote process and your main application.
Here's a DLL injection function (in your main app) to inject your DLL into the remote process:
int Inject(char *fname,char *dllname,int NewProcess,DWORD PID) // 1=new process, 2= PID, 3=current process
{
STARTUPINFOA si;
PROCESS_INFORMATION pi;
BOOL rv;
void *pr;
HANDLE hh;
SIZE_T bwrit;
DWORD par,tid;HANDLE th;
FARPROC LoadLibProc = GetProcAddress(GetModuleHandleA("KERNEL32.dll"), "LoadLibraryA");
FARPROC ExitThreadProc = GetProcAddress(GetModuleHandleA("KERNEL32.dll"), "ExitThread");
char InjectedCode[500] =
{// 0xcc,
0x60, // pushad
0xB8, 00, 00, 00, 00, // mov EAX, 0h | Pointer to LoadLibraryA() (DWORD)
0xBB, 00, 00, 00, 00, // mov EBX, 0h | DLLName to inject (DWORD)
0x53, // push EBX
0xFF, 0xD0, // call EAX
0x5b, // pop EBX
0xB8, 00, 00, 00, 00, // EAX 2 mov EAX, 0h | Pointer to ExitThreadProc() (DWORD)
0x6a,00, // Push 00
0xFF, 0xD0, // call EAX
//0xcc // INT 3h
0x61, // popad
//0xcc
// 0xc3 // ret
};
int nob=30;
char *DLLName;
DWORD *EAX, *EBX, *EAX2;
DLLName = (char*)((DWORD)InjectedCode + nob);
strcpy( DLLName, dllname );
EAX = (DWORD*)( InjectedCode + 2);
EBX = (DWORD*) ( InjectedCode + 7);
EAX2 = (DWORD*)( InjectedCode + 16);
*EAX=(DWORD)LoadLibProc;
*EAX2=(DWORD)ExitThreadProc;
*EBX=nob;
ZeroMemory((VOID*)&si, sizeof(si));
si.dwFlags=STARTF_USESHOWWINDOW;//1
si.wShowWindow=SW_HIDE;//0
if (NewProcess==1) {
rv=CreateProcessA(fname,0,0,0,FALSE,CREATE_SUSPENDED,0,0,&si,&pi);
if (rv==FALSE) {return -1;}
hh=pi.hProcess;
}
TCHAR bb[200];
if (NewProcess==2) {////PROCESS_ALL_ACCESS
hh=OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_WRITE|PROCESS_VM_OPERATION ,0,PID);
if (hh==NULL) return -6;
}
if (NewProcess==3) {
hh=GetCurrentProcess();
}
//if (hh==INVALID_HANDLE_VALUE) {printf("\nError Opening Process...");return;}
pr=VirtualAllocEx(hh,0,500,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if (pr==NULL) return -7;
Sleep(100);
//printf("\nAddress Allocated=%x",pr);
*EBX+=(DWORD)pr;
rv=WriteProcessMemory(hh,pr,InjectedCode,500,&bwrit);
if (rv==0) return -8;
th=CreateRemoteThread(hh,NULL,0,(LPTHREAD_START_ROUTINE)pr,&par,0,&tid);
if (th==NULL) return -9;
return 0;
}
Now for the DLL, in your DLL CPP, add the shared memory section to hold data for inter-process communication:
#pragma data_seg("shared")
char whateverdatatoshare[16384]={0};
// you can also define events or variables to use to signal the remote process or the main app of any incoming data
#pragma data_seg()
#pragma comment(linker, "/section:shared,rws") // This instructs the linker to make this section readable,writable and shared
In your APIENTRY dllmain function, create a thread to do whatever you want, like reading your string or data every second to send it back to the main app.
BOOL APIENTRY DllMain1( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
DWORD par,tid;
HANDLE thandle;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
thandle= CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&MsgThread,&par,0,&tid);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
The your thread code should do the actual work of sniffing the string you want.
Very Important: To make sure you can read/write in memory, use this:
First set the page to PAGE_EXECUTE_READWRITE
**VirtualProtect((LPVOID)targetaddress,5,PAGE_EXECUTE_READWRITE,&oldp);**
Second: IsBadWritePtr or IsBadReadPtr, to make sure you can write or read.