Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


PFN_LIST_CORRUPTwhen doing MmUnlockPages + IoFreeMdl[SOLVED]

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming
View previous topic :: View next topic  
Author Message
FerrisBuellerYourMyHero
Master Cheater
Reputation: 0

Joined: 14 Feb 2007
Posts: 401
Location: Inside your <kernel>

PostPosted: Thu Jan 08, 2009 9:18 pm    Post subject: PFN_LIST_CORRUPTwhen doing MmUnlockPages + IoFreeMdl[SOLVED] Reply with quote

Alright well previously I was using trampolines to bypass native api's (kinda like MxBot, except with NT api's instead of GDI/USER)

Well I was looking at CE's driver source again and see there's a better way which doesn't require creating a bunch of trampolines.

there's a function called "makeKernelCopy" which takes two parameters the kernel base, and kernel size.

I've already worked out how to get the base address and size of the kernel using ZwQuerySystemInformation... the kernel is called ntkrnlpa.exe for me, but can also be called ntoskrnl.exe (I read somewhere that multi-cpu machines use ntkrnlpa.exe, while a single cpu machine uses ntoskrnl.exe as its kernel! But I'm not sure if that's the case, and is there anything else it could be called?)

Ok so I noticed in ce's driver code in the makeKernelCopy function, that after using IoAllocateMdl() and MmProbeAndLockPages() and making the copy of the kernel, it never calls MmUnlockPages() or IoFreeMdl()?

Is there any reason why it doesn't? or shouldn't?

Code:

NTSTATUS makeKernelCopy(ULONG KernelBase, ULONG KernelSize)
{
   NTSTATUS ntStatus=STATUS_UNSUCCESSFUL;

   __try
   {
      PMDL mdl=NULL;
      char *buffer=NULL;

      mdl = IoAllocateMdl((PVOID)KernelBase, KernelSize, FALSE, TRUE, NULL);
      if (!mdl)
      {
         DbgPrint("Not enough memory dude!!!!\n");
         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
         return ntStatus;
      }

      try
      {
         MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
         buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority );
         if (buffer)
         {
            DbgPrint("mapped the kernel at %p\n",buffer);
            //allocate memory for the copy
            KernelCopy=ExAllocatePool(NonPagedPool, KernelSize);
            RtlCopyMemory(KernelCopy,buffer,KernelSize);
            DbgPrint("KernelCopy allocated at %p",KernelCopy);

            //change the functions to make use of the copy

         }

      }
      __except(1)
      {
         DbgPrint("Exception during copy\n");
      }
   }
   __except(0)
   {
      DbgPrint("Failed to map the kernel\n");
   }

   return ntStatus;
};


If I understand correctly IoAllocateMdl() just allocates a mdl structure which describes the memory buffer. Then MmProbeAndLockPages() locks the pages of the actual buffer (in this case the entire ntoskrnl) in memory so that when your doing the copy nothing bad will happen as all memory will be readable (well, since were specifying IoReadAccess) MmGetSystemAddressForMdlSafe just gives you a safe address you can use to access the buffer.

I was looking at msdn and they say that

msdn wrote:

MmProbeAndLockPages can be called multiple times for the same page. Each successful call to MmProbeAndLockPages for an MDL must be matched by a call to MmUnlockPages for the same MDL.


So I was thinking I should go along with it and call MmUnlockPages() after making the copy. It says "must", is that an exaggeration? ce's driver doesn't do it so maybe so?

also

msdn wrote:

The highest-level driver in a chain of layered drivers that use direct I/O calls this routine. Drivers that use buffered I/O never call MmProbeAndLockPages.


Do they mean that drivers that use buffered I/O 'SHOULD' never call MmProbeAndLockPages? Surely they can't know for certain that every single driver in existence has never once called it when using buffered I/O!!

Well ce's driver and my driver both use buffered I/O (if that means when you define your IOCTL's you use METHOD_BUFFERED) anyway the locking the pages seems to work even when you call it through DeviceIoControl, so maybe msdn is bluffing?

when I checked out IoFreeMdl

msdn wrote:

If a driver allocates an MDL to describe a buffer, it must explicitly release the MDL when operations on the buffer are done.


Again with the must! So going along with msdn again, I thought it shouldn't be problem unlocking the pages, and freeing the mdl after the copy is made. I'm trying to go along with what it says to do...

But when I use the MmUnlockPages(mdl); and IoFreeMdl(mdl); my system crashes with a blue screen of death. PFN_LIST_CORRUPT is the message. PFN meaning Page Frame Number... But I don't understand why its happening? (I'm not sure which is actually doing it the unlocking or the freeing as I haven't tried them seperately [I don't like blue screens])

If I follow suit like ce's driver however and don't unlock the pages or free the mdl after making the copy everything seems fine. But when my driver unloads I think I should free the kernel copy so if it loads again it isn't hogging up the memory making a bunch of kernel copies...

Then I just point my function pointers to the copy of the function in the kernel copy instead of the real function which will soon be hooked, and it works nicely...

So basically is there anything wrong with not unlocking the pages or freeing the mdl? Will anything bad happen if that mdl stays allocated and the pages stay locked when the driver is unloaded?

I just want to make sure I'm doing the right thing as to not cause future blue screens of death!!

Thanks,

Ferris Very Happy

UPDATE:

So no one knows why that causes a BSOD?

Well I found a solution I think. Only make the copy of the kernel once per boot and don't free it when the driver is unloaded. Save the address of the kernel copy to a volatile registry key after the copy is made. Just don't do MmUnlockPages or IoFreeMdl to avoid blue screen. So if the registry key exists next time the driver is loaded use the address stored instead of making a new copy. If you reboot your machine the registry key wont exist anymore. So it will have to make the copy for that session the first time the driver is loaded since the reboot. So far I haven't gotten a blue screen since having it setup this way! Actually scratch that I spoke to soon. After having the driver unloaded for a while, I suddenly just blue screened with the same message! How can I make the copy without getting a bsod somewhere down the line? Maybe I should try without the allocating the mdl or locking the pages, Shouldn't the kernel never be paged out anyway? It should always be in physical memory shouldn't it?

_________________
You know, life moves pretty fast. If you don't stop and look around once in a while, You could miss it!



Last edited by FerrisBuellerYourMyHero on Fri Jan 16, 2009 2:29 am; edited 1 time in total
Back to top
View user's profile Send private message MSN Messenger
Dark Byte
Site Admin
Reputation: 471

Joined: 09 May 2003
Posts: 25828
Location: The netherlands

PostPosted: Tue Jan 13, 2009 8:33 pm    Post subject: Reply with quote

That is old code, just allocate 4 to 8MB of nonpaged memory and dump a copy of the memory in there. No need to mess with mdl's

And yes, you do not have to worry about pagefaults, as the first 4MB (probably 8MB as well) is mapped in using 2 MB pages (in PAE, 4MB non pae)

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
FerrisBuellerYourMyHero
Master Cheater
Reputation: 0

Joined: 14 Feb 2007
Posts: 401
Location: Inside your <kernel>

PostPosted: Fri Jan 16, 2009 2:21 am    Post subject: Reply with quote

Dark Byte wrote:
That is old code, just allocate 4 to 8MB of nonpaged memory and dump a copy of the memory in there. No need to mess with mdl's

And yes, you do not have to worry about pagefaults, as the first 4MB (probably 8MB as well) is mapped in using 2 MB pages (in PAE, 4MB non pae)



Thank you Dark Byte!!! I followed your advice and removed the code that deals with a mdl!

The new kernel copy function looks like this now:

Code:

PVOID CopyKernel(PVOID KernelBase, ULONG KernelSize)
{
   PVOID KernelCopy = 0;

   __try
   {
      KernelCopy = ExAllocatePool(NonPagedPool, KernelSize);
      RtlCopyMemory(KernelCopy, KernelBase, KernelSize);
   }
   __except(1)
   {
      DbgPrint("Failed making the copy!\n");
   }

   return KernelCopy;
}


Nothing bad happens when making the copy like you said nothing would happen, and I see no more blue screens even after having the driver unloaded forever!

I still am using the volatile registry key though, as its best to just leave it once the copy is made! why mess around freeing it and then making the copy again! Just make it once and store the address!

Goodbye Hooks! Very Happy

_________________
You know, life moves pretty fast. If you don't stop and look around once in a while, You could miss it!

Back to top
View user's profile Send private message MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites