Error while reading other process memory - windows

I'm using ReadProcessMemory to read a single byte out of a process i've created.
Since i'm attaching as a debugger, i'm reading addresses that are being executed now (or in the near past).
but i get a 299 error for ReadProcessMemory via GetLastError() on some addresses only (some works fine..)
On the cases i get an error, i call VirtualQueryEx, and the memInfo protect is 0x1, while the type & baseAddress are 0x0 (but the region size is some normal number), also VirtualQueryEx isn't failing..
if i call VirtualProtectEx for those cases, i get error 487 (Attempt to access invalid address).
i thought maybe the address i'm trying to read is paged out, thus all the errors, but it doesn't seem right since, as i've already mentioned, its an address that was executed recently.
ideas anyone?

You want to loop through all the memory, calling VirtualQueryEx() to make sure the memory is valid before calling ReadProcessMemory()
You need to make sure that MEMORY_BASIC_INFORMATION.State is MEM_COMMIT in most cases.
This whole operation can be easy to screw up, because you didn't supply any code I will provide a working solution that should work in 95% of situations. It's ok for bytesRead to be different than regionSize, you just need to handle that situation correctly. You don't need to take permissions in most cases using VirtualProtect because all valid memory should have read access.
int main()
{
DWORD procid = GetProcId("notepad.exe");
unsigned char* addr = 0;
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procid);
MEMORY_BASIC_INFORMATION mbi;
while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)))
{
if (mbi.State == MEM_COMMIT && mbi.Protect != PAGE_NOACCESS)
{
char* buffer = new char[mbi.RegionSize]{ 0 };
SIZE_T bytesRead = 0;
if (ReadProcessMemory(hProc, addr, buffer, mbi.RegionSize, &bytesRead))
{
if (bytesRead)
{
//scan from buffer[0] to buffer[bytesRead]
}
else
{
//scan from buffer[0] to buffer[mbi.RegionSize]
}
}
delete[] buffer;
}
addr += mbi.RegionSize;
}
CloseHandle(hProc);
}
Reminder: This is just a PoC to teach you the concept.

Related

Using IRPs for I/O on device object returned by IoGetDeviceObjectPointer()

Can one use IoCallDriver() with an IRP created by IoBuildAsynchronousFsdRequest() on a device object returned by IoGetDeviceObjectPointer()? What I have currently fails with blue screen (BSOD) 0x7E (unhandled exception), which when caught shows an Access Violation (0xc0000005). Same code worked when the device was stacked (using the device object returned by IoAttachDeviceToDeviceStack()).
So what I have is about the following:
status = IoGetDeviceObjectPointer(&device_name, FILE_ALL_ACCESS, &FileObject, &windows_device);
if (!NT_SUCCESS(status)) {
return -1;
}
offset.QuadPart = 0;
newIrp = IoBuildAsynchronousFsdRequest(io, windows_device, buffer, 4096, &offset, &io_stat);
if (newIrp == NULL) {
return -1;
}
IoSetCompletionRoutine(newIrp, DrbdIoCompletion, bio, TRUE, TRUE, TRUE);
status = ObReferenceObjectByPointer(newIrp->Tail.Overlay.Thread, THREAD_ALL_ACCESS, NULL, KernelMode);
if (!NT_SUCCESS(status)) {
return -1;
}
status = IoCallDriver(bio->bi_bdev->windows_device, newIrp);
if (!NT_SUCCESS(status)) {
return -1;
}
return 0;
device_name is \Device\HarddiskVolume7 which exists according to WinObj.exe .
buffer has enough space and is read/writable. offset and io_stat are on stack (also tried with heap, didn't help). When catching the exception (SEH exception) it doesn't blue screen but shows an access violation as reason for the exception. io is IRP_MJ_READ.
Do I miss something obvious? Is it in general better to use IRPs than the ZwCreateFile / ZwReadFile / ZwWriteFile API (which would be an option, but isn't that slower?)? I also tried a ZwCreateFile to have an extra reference, but this also didn't help.
Thanks for any insights.
you make in this code how minimum 2 critical errors.
can I ask - from which file you try read (or write) data ? from
FileObject you say ? but how file system driver, which will handle
this request know this ? you not pass any file object to newIrp.
look for IoBuildAsynchronousFsdRequest - it have no file object
parameter (and impossible get file object from device object - only
visa versa - because on device can be multiple files open). so it
and can not be filled by this api in newIrp. you must setup it
yourself:
PIO_STACK_LOCATION irpSp = IoGetNextIrpStackLocation( newIrp );
irpSp->FileObject = FileObject;
I guess bug was exactly when file system try access FileObject
from irp which is 0 in your case. also read docs for
IRP_MJ_READ - IrpSp->FileObject -
Pointer to the file object that is associated with DeviceObject
you pass I guess local variables io_stat (and offset) to
IoBuildAsynchronousFsdRequest. as result io_stat must be valid
until newIrp is completed - I/O subsystem write final result to it
when operation completed. but you not wait in function until request
will be completed (in case STATUS_PENDING returned) but just exit
from function. as result later I/O subsystem, if operation completed
asynchronous, write data to arbitrary address &io_stat (it became
arbitrary just after you exit from function). so you need or check
for STATUS_PENDING returned and wait in this case (have actually
synchronous io request). but more logical use
IoBuildSynchronousFsdRequest in this case. or allocate io_stat
not from stack, but say in your object which correspond to file. in
this case you can not have more than single io request with this
object at time. or if you want exactly asynchronous I/O - you can do
next trick - newIrp->UserIosb = &newIrp->IoStatus. as result you
iosb always will be valid for newIrp. and actual operation status
you check/use in DrbdIoCompletion
also can you explain (not for me - for self) next code line ?:
status = ObReferenceObjectByPointer(newIrp->Tail.Overlay.Thread, THREAD_ALL_ACCESS, NULL, KernelMode);
who and where dereference thread and what sense in this ?
Can one use ...
we can use all, but with condition - we understand what we doing and deep understand system internally.
Is it in general better to use IRPs than the ZwCreateFile / ZwReadFile
/ ZwWriteFile API
for performance - yes, better. but this require more code and more complex code compare api calls. and require more knowledge. also if you know that previous mode is kernel mode - you can use NtCreateFile, NtWriteFile, NtReadFile - this of course will be bit slow (need every time reference file object by handle) but more faster compare Zw version
Just wanted to add that the ObReferenceObjectByPointer is needed
because the IRP references the current thread which may exit before
the request is completed. It is dereferenced in the Completion
Routine. Also as a hint the completion routine must return
STATUS_MORE_PROCESSING_REQUIRED if it frees the IRP (took me several
days to figure that out).
here you make again several mistakes. how i understand you in completion routine do next:
IoFreeIrp(Irp);
return StopCompletion;
but call simply call IoFreeIrp here is error - resource leak. i advice you check (DbgPrint) Irp->MdlAddress at this point. if you read data from file system object and request completed asynchronous - file system always allocate Mdl for access user buffer in arbitrary context. now question - who free this Mdl ? IoFreeIrp - simply free Irp memory - nothing more. you do this yourself ? doubt. but Irp is complex object, which internally hold many resources. as result need not only free it memory but call "destructor" for it. this "destructor" is IofCompleteRequest. when you return StopCompletion (=STATUS_MORE_PROCESSING_REQUIRED) you break this destructor at very begin. but you must latter again call IofCompleteRequest for continue Irp (and it resources) correct destroy.
about referencing Tail.Overlay.Thread - what you doing - have no sense:
It is dereferenced in the Completion Routine.
but IofCompleteRequest access Tail.Overlay.Thread after it
call your completion routine (and if you not return
StopCompletion). as result your reference/dereference thread lost
sense - because you deference it too early, before system
actually access it.
also if you return StopCompletion and not more call
IofCompleteRequest for this Irp - system not access
Tail.Overlay.Thread at all. and you not need reference it in this
case.
and exist else one reason, why reference thread is senseless. system
access Tail.Overlay.Thread only for insert Apc to him - for call
final part (IopCompleteRequest) of Irp destruction in original
thread context. really this need only for user mode Irp's requests,
where buffers and iosb located in user mode and valid only in
context of process (original thread ). but if thread is terminated -
call of KeInsertQueueApc fail - system not let insert apc to
died thread. as result IopCompleteRequest will be not called and
resources not freed.
so you or dereference Tail.Overlay.Thread too early or you not need do this at all. and reference for died thread anyway not help. in all case what you doing is error.
you can try do next here:
PETHREAD Thread = Irp->Tail.Overlay.Thread;
IofCompleteRequest(Irp, IO_NO_INCREMENT);// here Thread will be referenced
ObfDereferenceObject(Thread);
return StopCompletion;
A second call to IofCompleteRequest causes the I/O manager to resume calling the IRP's completion. here io manager and access Tail.Overlay.Thread insert Apc to him. and finally you call ObfDereferenceObject(Thread); already after system access it and return StopCompletion for break first call to IofCompleteRequest. look like correct but.. if thread already terminated, how i explain in 3 this will be error, because KeInsertQueueApc fail. for extended test - call IofCallDriver from separate thread and just exit from it. and in completion run next code:
PETHREAD Thread = Irp->Tail.Overlay.Thread;
if (PsIsThreadTerminating(Thread))
{
DbgPrint("ThreadTerminating\n");
if (PKAPC Apc = (PKAPC)ExAllocatePool(NonPagedPool, sizeof(KAPC)))
{
KeInitializeApc(Apc, Thread, 0, KernelRoutine, 0, 0, KernelMode, 0);
if (!KeInsertQueueApc(Apc, 0, 0, IO_NO_INCREMENT))
{
DbgPrint("!KeInsertQueueApc\n");
ExFreePool(Apc);
}
}
}
PMDL MdlAddress = Irp->MdlAddress;
IofCompleteRequest(Irp, IO_NO_INCREMENT);
ObfDereferenceObject(Thread);
if (MdlAddress == Irp->MdlAddress)
{
// IopCompleteRequest not called due KeInsertQueueApc fail
DbgPrint("!!!!!!!!!!!\n");
IoFreeMdl(MdlAddress);
IoFreeIrp(Irp);
}
return StopCompletion;
//---------------
VOID KernelRoutine (PKAPC Apc,PKNORMAL_ROUTINE *,PVOID *,PVOID *,PVOID *)
{
DbgPrint("KernelRoutine(%p)\n", Apc);
ExFreePool(Apc);
}
and you must got next debug output:
ThreadTerminating
!KeInsertQueueApc
!!!!!!!!!!!
and KernelRoutine will be not called (like and IopCompleteRequest) - no print from it.
so what is correct solution ? this of course not documented anywhere, but based on deep internal understand. you not need reference original thread. you need do next:
Irp->Tail.Overlay.Thread = KeGetCurrentThread();
return ContinueCompletion;
you can safe change Tail.Overlay.Thread - if you have no any pointers valid only in original process context. this is true for kernel mode requests - all your buffers in kernel mode and valid in any context. and of course you not need break Irp destruction but continue it. for correct free mdl and all irp resources. and finally system call IoFreeIrp for you.
and again for iosb pointer. how i say pass local variable address, if you exit from function before irp completed (and this iosb accessed) is error. if you break Irp destruction, iosb will be not accessed of course, but in this case much better pass 0 pointer as iosb. (if you latter something change and iosb pointer will be accessed - will be the worst error - arbitrary memory corrupted - with unpredictable effect. and research crash of this will be very-very hard). but if you completion routine - you not need separate iosb at all - you have irp in completion and can direct access it internal iosb - for what you need else one ? so the best solution will be do next:
Irp->UserIosb = &Irp->IoStatus;
full correct example how read file asynchronous:
NTSTATUS DemoCompletion (PDEVICE_OBJECT /*DeviceObject*/, PIRP Irp, BIO* bio)
{
DbgPrint("DemoCompletion(p=%x mdl=%p)\n", Irp->PendingReturned, Irp->MdlAddress);
bio->CheckResult(Irp->IoStatus.Status, Irp->IoStatus.Information);
bio->Release();
Irp->Tail.Overlay.Thread = KeGetCurrentThread();
return ContinueCompletion;
}
VOID DoTest (PVOID buf)
{
PFILE_OBJECT FileObject;
NTSTATUS status;
UNICODE_STRING ObjectName = RTL_CONSTANT_STRING(L"\\Device\\HarddiskVolume2");
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };
if (0 <= (status = GetDeviceObjectPointer(&oa, &FileObject)))
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (BIO* bio = new BIO(FileObject))
{
if (buf = bio->AllocBuffer(PAGE_SIZE))
{
LARGE_INTEGER ByteOffset = {};
PDEVICE_OBJECT DeviceObject = IoGetRelatedDeviceObject(FileObject);
if (PIRP Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ, DeviceObject, buf, PAGE_SIZE, &ByteOffset, 0))
{
Irp->UserIosb = &Irp->IoStatus;
Irp->Tail.Overlay.Thread = 0;
PIO_STACK_LOCATION IrpSp = IoGetNextIrpStackLocation(Irp);
IrpSp->FileObject = FileObject;
bio->AddRef();
IrpSp->CompletionRoutine = (PIO_COMPLETION_ROUTINE)DemoCompletion;
IrpSp->Context = bio;
IrpSp->Control = SL_INVOKE_ON_CANCEL|SL_INVOKE_ON_ERROR|SL_INVOKE_ON_SUCCESS;
status = IofCallDriver(DeviceObject, Irp);
}
}
bio->Release();
}
ObfDereferenceObject(FileObject);
}
DbgPrint("DoTest=%x\n", status);
}
struct BIO
{
PVOID Buffer;
PFILE_OBJECT FileObject;
LONG dwRef;
void AddRef()
{
InterlockedIncrement(&dwRef);
}
void Release()
{
if (!InterlockedDecrement(&dwRef))
{
delete this;
}
}
void* operator new(size_t cb)
{
return ExAllocatePool(PagedPool, cb);
}
void operator delete(void* p)
{
ExFreePool(p);
}
BIO(PFILE_OBJECT FileObject) : FileObject(FileObject), Buffer(0), dwRef(1)
{
DbgPrint("%s<%p>(%p)\n", __FUNCTION__, this, FileObject);
ObfReferenceObject(FileObject);
}
~BIO()
{
if (Buffer)
{
ExFreePool(Buffer);
}
ObfDereferenceObject(FileObject);
DbgPrint("%s<%p>(%p)\n", __FUNCTION__, this, FileObject);
}
PVOID AllocBuffer(ULONG NumberOfBytes)
{
return Buffer = ExAllocatePool(PagedPool, NumberOfBytes);
}
void CheckResult(NTSTATUS status, ULONG_PTR Information)
{
DbgPrint("CheckResult:status = %x, info = %p\n", status, Information);
if (0 <= status)
{
if (ULONG_PTR cb = min(16, Information))
{
char buf[64], *sz = buf;
PBYTE pb = (PBYTE)Buffer;
do sz += sprintf(sz, "%02x ", *pb++); while (--cb); sz[-1]= '\n';
DbgPrint(buf);
}
}
}
};
NTSTATUS GetDeviceObjectPointer(POBJECT_ATTRIBUTES poa, PFILE_OBJECT *FileObject )
{
HANDLE hFile;
IO_STATUS_BLOCK iosb;
NTSTATUS status = IoCreateFile(&hFile, FILE_READ_DATA, poa, &iosb, 0, 0,
FILE_SHARE_VALID_FLAGS, FILE_OPEN, FILE_NO_INTERMEDIATE_BUFFERING, 0, 0, CreateFileTypeNone, 0, 0);
if (0 <= (status))
{
status = ObReferenceObjectByHandle(hFile, 0, *IoFileObjectType, KernelMode, (void**)FileObject, 0);
NtClose(hFile);
}
return status;
}
and output:
BIO::BIO<FFFFC000024D4870>(FFFFE00001BAAB70)
DoTest=103
DemoCompletion(p=1 mdl=FFFFE0000200EE70)
CheckResult:status = 0, info = 0000000000001000
eb 52 90 4e 54 46 53 20 20 20 20 00 02 08 00 00
BIO::~BIO<FFFFC000024D4870>(FFFFE00001BAAB70)
the eb 52 90 4e 54 46 53 read ok

How to use mmap for devmemon MT7620n

I`m trying to access the GPIOs of a MT7620n via register settings. So far I can access them by using /sys/class/gpio/... but that is not fast enough for me.
In the Programming guide of the MT7620 page 84 you can see that the GPIO base address is at 0x10000600 and the single registers have an offset of 4 Bytes.
MT7620 Programming Guide
Something like:
devmem 0x10000600
from the shell works absolutely fine but I cannot access it from inside of a c Programm.
Here is my code:
#define GPIOCHIP_0_ADDDRESS 0x10000600 // base address
#define GPIO_BLOCK 4
volatile unsigned long *gpiochip_0_Address;
int gpioSetup()
{
int m_mfd;
if ((m_mfd = open("/dev/mem", O_RDWR)) < 0)
{
printf("ERROR open\n");
return -1;
}
gpiochip_0_Address = (unsigned long*)mmap(NULL, GPIO_BLOCK, PROT_READ|PROT_WRITE, MAP_SHARED, m_mfd, GPIOCHIP_0_ADDDRESS);
close(m_mfd);
if(gpiochip_0_Address == MAP_FAILED)
{
printf("mmap() failed at phsical address:%d %s\n", GPIOCHIP_0_ADDDRESS, strerror(errno));
return -2;
}
return 0;
}
The Output I get is:
mmap() failed at phsical address:268436992 Invalid argument
What do I have to take care of? Do I have to make the memory accessable before? I´m running as root.
Thanks
EDIT
Peter Cordes is right, thank you so much.
Here is my final solution, if somebody finds a bug, please tell me ;)
#define GPIOCHIP_0_ADDDRESS 0x10000600 // base address
volatile unsigned long *gpiochip_0_Address;
int gpioSetup()
{
const size_t pagesize = sysconf(_SC_PAGE_SIZE);
unsigned long gpiochip_pageAddress = GPIOCHIP_0_ADDDRESS & ~(pagesize-1); //get the closest page-sized-address
const unsigned long gpiochip_0_offset = GPIOCHIP_0_ADDDRESS - gpiochip_pageAddress; //calculate the offset between the physical address and the page-sized-address
int m_mfd;
if ((m_mfd = open("/dev/mem", O_RDWR)) < 0)
{
printf("ERROR open\n");
return -1;
}
page_virtual_start_Address = (unsigned long*)mmap(NULL, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, m_mfd, gpiochip_pageAddress);
close(m_mfd);
if(page_virtual_start_Address == MAP_FAILED)
{
printf("ERROR mmap\n");
printf("mmap() failed at phsical address:%d %d\n", GPIOCHIP_0_ADDDRESS, strerror(errno));
return -2;
}
gpiochip_0_Address = page_virtual_start_Address + (gpiochip_0_offset/sizeof(long));
return 0;
}
mmap's file offset argument has to be page-aligned, and that's one of the documented reasons for mmap to fail with EINVAL.
0x10000600 is not a multiple of 4k, or even 1k, so that's almost certainly your problem. I don't think any systems have pages as small as 512B.
mmap a whole page that includes the address you want, and access the MMIO registers at an offset within that page.
Either hard-code it, or maybe do something like GPIOCHIP_0_ADDDRESS & ~(page_size-1) to round down an address to a page-aligned boundary. You should be able to do something that gets the page size as a compile-time constant so it still compiles efficiently.

why it was failed SetFilePointer()?

BOOL SetDeviceID(HANDLE device,char *id){//
char data[2];
data[0]=0x02;
data[1]=0x27;
DWORD dwPtr=SetFilePointer(device,0x33,//distance
NULL,//
FILE_BEGIN);
if(dwPtr==INVALID_SET_FILE_POINTER) cout<<GetLastError()<<endl;
BOOL result=WriteFile(device,data,2,NULL,NULL);
//cout<<GetLastError()<<endl;
if(result==false)cout<<"Fail WRITE "<<endl;
return TRUE;
}
HANDLE GetDeviceHandle(char *path){
HANDLE handle= CreateFile(LPCSTR(path),
GENERIC_ALL,//
0,
NULL,
OPEN_EXISTING,
NULL,
NULL);
if(handle==INVALID_HANDLE_VALUE){
cout<<"fail to createfile()"<<endl;
exit(1);
}
else return handle;
}
this is some code of my works.
I am going to read/write directly device(usb)
on ReadFile() case, It was successful.
But, I have tried to call SetFilePointer
But GetLastError returned 87. it means invalid input
What is the problem? on my code
shortly, CreateFile,ReadFile is ok but SetFilePointer and WriteFile failed
When you are directly accessing a disk device you cannot seek to positions in the middle of a sector. The position must always be a multiple of the sector length. And 0x33 is not a mutiple of your sector length.
What you will need to do is read an entire sector. Modify the bytes that need to be modified. And finally write back the entire sector.

WriteProcessMemory in debugged process

I try to write simple debugger. For simplicity, assume the debugger runs under Windows XP.
At first I create new process as follows:
CreateProcess(processName,
NULL,
NULL,
NULL,
false,
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS,
NULL,
NULL,
&startInfo,
&openedProcessInfo);
And when I try to read or write something in memory of debugging process there are some problems. For example:
DWORD oldProtect;
if(!VirtualProtectEx(hProcess, breakpointAddr, 1, PAGE_EXECUTE_READWRITE, &oldProtect)) {
printf("Error: %d\n", GetLastError());
}
SIZE_T bytesRead = 0;
SIZE_T bytesWritten = 0;
BYTE instruction;
BOOL isOk = ReadProcessMemory(hProcess, breakpointAddr, &instruction, 1, &bytesRead);
BYTE originalByte = instruction;
instruction = 0xCC;
if(isOk && bytesRead == 1) {
isOk = WriteProcessMemory(hProcess, breakpointAddr, &instruction, 1, &bytesWritten);
if(isOk) {
isOk = FlushInstructionCache(hProcess, breakpointAddr, 1);
}
}
if(!isOk) {
printf("Error: %d\n", GetLastError());
}
It works, but not everywhere. It works when the address to which I want to write(read) something, is located within executable module (.exe).
But when I try to write(read) something within DLL library (for example, read at address of function VirtualAlloc) VirtualProtectEx returns false and GetLastError = 487 (Attempt to access invalid address) and ReadProcessMemory also returns false and GetLastError = 299 (Only part of a ReadProcessMemory or WriteProcessMemory request was completed.)
Debug privileges are enabled but it has no effect.
Your code looks fine, if you're running as administrator than the most likely cause of the problem is that breakpointAddr is an invalid address. VirtualProtectEx giving you the "Attempt to access invalid address" error supports this conclusion.

WriteProcessMemory/ReadProcessMemory fail

I tried using both ReadProcessMemory() and WriteProcessMemory() in my application,but in both cases I get one result - Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
Has anyone met that error code before? I'm using Vista SP2,I tried to run as admistrator,but I till get that erorcode.
Make sure you call VirtualProtectEx to set the correct protection level on the memory you want to read/write.
After thinking about it, it's probably not the problem since most memory has read access enabled, but to set the protection level do something like this (in C++)
(no error checking and just using a random memory address, but you should get the idea)
char buffer[256];
DWORD oldProtect = 0;
DWORD numRead = 0;
VirtualProtectEx( hProc, (LPVOID)0x77810F34, 256, PAGE_EXECUTE_READWRITE, &oldProtect );
ReadProcessMemory( hProc, (LPVOID)0x77810F34, buffer, 256, &numRead );
VirtualProtectEx( hProc, (LPVOID)0x77810F34, 256, oldProtect, NULL ); //restore the original protection when you're done

Resources