Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I know Windows doesn't get too much love here. But we have to admit that Win32 has already this kind of feature since ages: Process access routines such as OpenProcess() [1] coupled with ReadProcessMemory() [2] will do the job in a clean way.

Taking a snapshot of other processes is also a basic use case of this family of functions [3].

[1] https://docs.microsoft.com/en-us/windows/win32/api/processth...

[2] https://docs.microsoft.com/en-us/windows/win32/api/memoryapi...

[3] https://docs.microsoft.com/en-us/windows/win32/toolhelp/taki...



I appreciate win32 much more than a typical HN user. But let's not fall into the trap of seeing it as the only way or that certain features haven't also been on Unix for decades.

> that Win32 has already this kind of feature since ages: Process access routines such as OpenProcess() [1] coupled with ReadProcessMemory() [2]

And Unix has had ptrace(2) for a very long time too, which will accomplish the same thing. Also you can read another process's memory through /proc. So there are multiple paths.

Also keep in mind, the most "legit" use case for this stuff is for writing a debugger. If you have used a debugger you are already relying on this functionality being there.

Edit: I am not aware of a win32 equivalent of this thing that lets you easily handle another thread's page faults in user mode though. That seems a little wacky. You can use debugger APIs to handle "STATUS_IN_PAGE_ERROR" and "STATUS_ACCESS_VIOLATION", which might get you there.


> And Unix has had ptrace(2) for a very long time too

A flaw in the Linux implementation, though, prevents one to run ptrace on a process that is using ptrace itself.

As more programs use ptrace, this flaw is becoming quite annoying.


The APIs are broadly equivalent, see https://nullprogram.com/blog/2016/09/03/

What unfork does is more complicated than a mere read, though. I'm still not entirely clear on its use case, but it does all sorts of tampering that the code comments describe as "cursed." It also seems to be specifically targeting applications which have anti-debug measures.


"Debuggers" implemented mostly through ReadProcessMemory / mach_vm_read / process_vm_read/pread are all intended to defeat anti-debug mechanisms, though; I'm not clear how unfork is meant to make the process simpler, but it looks intriguing.


process_vm_read and its equivalents allow you to read data whose layout you already know. unfork allows you to read data whose layout you don't know or that is partially generated by calling the accessors that the application already has for that data instead of reverse-engineering them and doing the transformation yourself.


unfork appears to be unique in that it creates the illusion of mapping the target process's memory into the source. This is achieved through the use of userfaultfd, which allows a Linux process to mark memory as missing, to receive notifications when other threads attempt to access missing memory, and to provide the contents of that memory in response to such faults. This mechanism is quite powerful and flexible, and Windows does not have a direct equivalent of this.

The closest equivalent I can think of in Windows would be to mark pages as no-access and use vectored exception handling to trap access faults. During a fault, the exception handler would fill in the page (e.g. via ReadProcessMemory) and flip the page protection to read or read/write.

Since you wouldn't want to flip the page protection until after the memory had been updated, you would probably have to used a pagefile-backed section to update the memory at a separate virtual address with independent page protections. And unlike the userfaultfd approach, this mechanism would not help for cases where the mirrored memory was being passed to a syscall.

I think Linux could do this too, via a signal handler, but AFAIK the Linux memory manager does not efficiently support per-page access protection (unlike Windows). In the worst case, each page would get its own vma structure in the kernel, which would be quite expensive. So absent userfaultfd, the Windows memory manager probably has the edge.


I mean, /proc/foo/mem has also exposed that feature for forever on Linux.


How clean is it? Can you simply exec the result?

Glibc used to have unexec(), which is fairly old, but it was removed because nobody used it (except Emacs, and there were better solutions to the problem it was solving).


> How clean is it?

It's as clean as any official Win32 API which uses their privilege system to restrict/allow accesses to each and any bit of information on the process state and/or memory.

> Can you simply exec the result?

This is possible using CreateThread() [1] which creates a remote thread inside another process execution context.

[1] https://docs.microsoft.com/en-us/windows/win32/api/processth...

> Glibc used to have unexec()

My understanding is that unexec() was more about making a snapshot of the whole process state to an executable on disk.


That is my understanding too. Solaris had a flag for dldump (https://docs.oracle.com/cd/E19455-01/806-0627/6j9vhfmop/inde...). Emacs moved to a portable dumper (maybe inspired from XEmacs)


Emacs had its own unexec().




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: