Page protection in another process

I am working on an NT 5 (2128) machine and cannot seem to get VirtualProtectEx/WriteProcessMemory working correctly.  I need to make some changes in ntdll.dll in a process that I have called CreateProcess(... SUSUPENDED...) on.

This is what I am doing:

MEMORY_BASIC_INFORMATION mbi_thunk ;
VirtualQueryEx ( ppi->hProcess,
                 (LPVOID)pvLoc,
                 &mbi_thunk,
                 sizeof ( MEMORY_BASIC_INFORMATION )  );

VirtualProtectEx( ppi->hProcess,
                  mbi_thunk.BaseAddress,
                  mbi_thunk.RegionSize,
                  PAGE_READWRITE,
                  &mbi_thunk.Protect );

   if ( !WriteProcessMemory( ppi->hProcess, (LPVOID)pvLoc,
                             (LPVOID)pvBuffer, sizeof(DWORD), &dwWritten ) )
   {
      printf("WriteProcessMemory failed: 0x%X\n", GetLastError() );
      return false;
   }

The WriteProcessMemory always fails with: 0x3E6 - "Invalid access to memory location."

Even though I didn't show it above, the VirtualQueryEx and VirtualProtectCalls both succeed.

Any clues as to what I am doint wrong here?

TIA
rmanginoAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

rmanginoAuthor Commented:
Edited text of question.
0
NickRepinCommented:
Your call to VirtualQueryEx is incorrect.
Second parameter is rounded down to the next page boundary, so you change protection not for pvLoc.
Details few minutes later.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
NickRepinCommented:
Use the following (call to VirtualQueryEx is not necessary):

VirtualProtectEx( ppi->hProcess,
                  pvLoc,
                  sizeof(DWORD),
                  PAGE_READWRITE,
                  &oldProtect );

WriteProcessMemory ...
0
Starting with Angular 5

Learn the essential features and functions of the popular JavaScript framework for building mobile, desktop and web applications.

NickRepinCommented:
May be, I'm wrong regarding VirtualQueryEx, but anyway this call is not necessary, so please try the code above.
0
NickRepinCommented:
Actually, it should work with VirtualQueryEx also. Check again that calls to Virtual..() are successful.
Here is the test program, it works fine on my NT.

#include <windows.h>
#include <iostream.h>

void main(void)
{
   STARTUPINFO si;
   memset(&si,0,sizeof(si));
   si.cb=sizeof(si);
   PROCESS_INFORMATION pi;
   if(CreateProcess(0,"a.exe",0,0,FALSE,CREATE_SUSPENDED,0,0,&si,&pi)) {
      char buf[16];
      LPVOID p=LPVOID(0x400001); // I know that 0x400000 is the base addr of process a.exe
      DWORD written;
      cout<<VirtualProtectEx(pi.hProcess,p,sizeof(DWORD),PAGE_READWRITE,
         &written)<<endl;
      // This call fails w/o previous one
      cout<<WriteProcessMemory(pi.hProcess,p,&buf,4,&written)<<endl;
   }
}
0
rmanginoAuthor Commented:
Thanks for all the work so far Nick.  Could you try your test again, but this time try to write to an area that ntdll.dll is mapped to?  

Thanks!
0
NickRepinCommented:
Unfortunately, I have no NT5 installed at the moment. I make the test on NT4. I don't think that behaviours of NT4 and NT5 are dirrefent - in this case it means application incompatibility.

Of course, you can reject my answer.

I tested writting to ntdll.dll - it also works fine.

As far as I can guess from your code,  'mbi_thunk' is the pointer to something like import thunk. ntdll on NT4 has no import section, I suppose that it is true for NT5 also. May be, the problem with your code is not near the WriteProcessMemory, but in the code which assigns value to mbi_thunk?

You can run my test program yourself. But you have to compile a.exe first. Make it simple, just like void main(void) { }. Then run a.exe under debugger and write down the base address of ntdll.dll. Then hard-code it in my test code.

Also I can suggest to print the contents of mbi_thunk and check whether it really lies inside ntdll.
0
rmanginoAuthor Commented:
Thanks again for the info Nick.  The mbi_thunk variable is the structure that gets passed to VirtualQueryEx - MEMORY_BASIC_INFORMATION.  Post your little test - as that would prove that my problem is based upon NT5.0.

As an aside, I checked out your profile and I thought it was cool that you are interested in Windows internals - I work for NuMega Labs - on the BoundsChecker team - so I am REALLY into this stuff!

Post the test and I'll accept your answer.

Thanks!
0
NickRepinCommented:
>>The mbi_thunk variable is the
>>structure that gets passed to

Sorry, it is my mistake. Really I told about pvLoc. Sure, mbi_thunk is just a Windows structure.

It was not necessary to accept my answer if it doesn't answer anything.

-----
Test programs:
Just compile both and run parent.exe.
The output on my NT:

Child: NTDLL base=0x77F60000
Child: signature=MZ
Parent: got message, NTDLL base 0x77F60000
Parent: signature=MZ
Parent: Test write failed - OK
Parent: Write success - OK

---------
// Child.cpp
#include <windows.h>
#include <iostream.h>

void main(int argc,char* argv[])
{
   // Get address of NTDLL
   DWORD ntdllBase=DWORD(GetModuleHandle("NTDLL"));
   if(!ntdllBase) {
      cout<<"Child: NTDLL is not loaded!"<<endl;
      return;
   }
   cout<<"Child: NTDLL base="<<LPVOID(ntdllBase)<<endl;
   
   // Just to make sure, following lines must print 'MZ' signature
   char sign[3];
   *LPWORD(sign)=*LPWORD(ntdllBase);
   sign[2]=0;
   cout<<"Child: signature="<<sign<<endl;

   // Extract parent's thread id
   if(argc<2) {  
      cout<<"Child: no parameter passed!"<<endl;
      return;
   }
   DWORD parent=strtoul(argv[1],0,10);

   // Pass address of NTDLL to the parent
   PostThreadMessage(parent,WM_USER+10,ntdllBase,0);

   // Allow parent to do its job
   Sleep(INFINITE);
}

--------

// Parent.cpp
#include <windows.h>
#include <iostream.h>

void main(void)
{
   // Create message queue
   MSG msg;
   PeekMessage(&msg,0,WM_USER,WM_USER,PM_NOREMOVE);

   // Run child process, pass as parameter our thread id.
   char cmdLine[120];
   wsprintf(cmdLine,"child.exe %u",GetCurrentThreadId());

   STARTUPINFO si;
   memset(&si,0,sizeof(si));
   si.cb=sizeof(si);
   PROCESS_INFORMATION pi;
   if(!CreateProcess(0,cmdLine,0,0,FALSE,0,0,0,&si,&pi)) {
      cout<<"Parent: unable to run child.exe!"<<endl;
      return;
   }
   CloseHandle(pi.hThread);

   // Wait for message from the child
   GetMessage(&msg,0,WM_USER+10,WM_USER+10);
   LPVOID ntdllBase=LPVOID(msg.wParam);
   cout<<"Parent: got message, NTDLL base "<<ntdllBase<<endl;

   DWORD n;

   __try {
      // Just to make sure, following lines must print 'MZ' signature
      char sign[3];
      if(!ReadProcessMemory(pi.hProcess,ntdllBase,&sign,2,&n)) {
         cout<<"Parent: unable to read memory!"<<endl;
         return;
      }
      sign[2]=0;
      cout<<"Parent: signature="<<sign<<endl;

      // Test - following call must fail
      if(WriteProcessMemory(pi.hProcess,ntdllBase,&sign,3,&n))
         cout<<"Parent: Test write success - VERY STRANGE!"<<endl;
      else
         cout<<"Parent: Test write failed - OK"<<endl;

      // Now change protection
      if(!VirtualProtectEx(pi.hProcess,ntdllBase,3,PAGE_READWRITE,&n)) {
         cout<<"Parent: VirtualProtect failed!"<<endl;
         return;
      }

      if(WriteProcessMemory(pi.hProcess,ntdllBase,&sign,3,&n))
         cout<<"Parent: Write success - OK"<<endl;
      else
         cout<<"Parent: Write failed, err="<<GetLastError()<<endl;

   }
   __finally {
      TerminateProcess(pi.hProcess,0);
      CloseHandle(pi.hProcess);
   }
}

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.