Originally Posted by
brewbuck
1. Use ptrace() to attach to the process and wait for it to suspend.
2. Parse the /proc/XXX/maps file to get a memory map of the process
3. Find a small page with execute permissions and inject a stub function into it. This stub function will call mmap() to allocate another page of code memory, then suspend itself with a kill( SIGSTOP )
4. Twiddle the registers to cause the stub to execute, then restart the process.
5. Wait for the process to stop again.
6. Into the newly mapped memory page, write another stub which allows you to invoke mprotect(). Also, restore the data that was previously in the code page which you overwrote.
7. Call this stub repeatedly (by register fiddling), to mprotect() the entire process address space to be unreadable/unwritable/unexecutable
8. Restart the process where it left off.
9. Wait for the process to access memory, at which time it will receive a SIGSEGV
10. Examine the address which caused the fault. Log it somewhere.
11. Invoke the mprotect() stub in the process to cause the faulting page to become readable.
12. Use ptrace() to single step the process by one instruction.
13. Wait for suspension again, then invoke the mprotect() stub to set the page back to no permissions.
14. Go to step 8.
This involves multiple system calls and page table manipulations for every single memory access. It's going to be ludicrously slow, but it should work in theory. You'd be better off learning about libVEX from Valgrind and trying to extend it to do what you want. There are mailing lists where people discuss such Valgrind extensions.