Debugger and process memory
For example, IDA might claim that EIP points to an address without a segment, or none of exported names of a loaded DLL are available.
This happens because of the database synchronization. When you query IDA about a segment or a name, the information from the database is returned. The database is not (and can not be) always in sync with the process memory. The debugged process might allocate or free memory chunks thousands of times per second. The synchronization operation is very expensive: it requires enumerating all memory regions and collecting information about their types, permissions, etc. That’s why IDA tries to perform it as rarely as possible.
We tried to save the end user from this problem: the database gets synchronized as soon as the process is suspended. This is the expected behavior, so far so good.
Alas, we can not provide plugin writers with the same virtual reality: there are two distinct entities, the process memory and the program segmentation. The latter is stored in the database and it can go out of sync with the former. As a plugin writer, you have the following choices:
- Bypass the database and talk directly to the debugger module using the
dbg->read_memory() and dbg->write_memory() functions.
Advantages: no synchronization issues
Disadvantages: only memory read/write functions are available, names, functions, and other high level abstractions are not; also, direct calls are not cached.
- Explicitly synchronize the database with the process memory.
Advantages: all high level abstractions are available, repetitive “read memory” requests will be cached by the kernel (especially useful for remote debugging); breakpoints in the process memory are hidden
- Do not synchronize.
Disadvantages: occasionally a call to an IDA function might fail (e.g. getseg() might return NULL for a valid address); nevertheless, this approach can be used if you know in advance that the memory config won’t change or the changes are irrelevant to your analysis