Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dolphin ASLR #23

Closed
Henrik0x7F opened this issue Feb 22, 2018 · 4 comments
Closed

Dolphin ASLR #23

Henrik0x7F opened this issue Feb 22, 2018 · 4 comments
Labels

Comments

@Henrik0x7F
Copy link

Hey, I'm working on a similar project and I have some questions about dolphin's ASLR. Is only the begin of the emulated memory at a random location in dolphin's process memory or is the emulated ram itself randomized? When I found the start, is it valid until the emulation is stopped? I did a bit of research but found inconsistent information, so I would appreciate the help of someone who has a program dealing with exactly that.

@aldelaro5
Copy link
Owner

Hi.

I haven't tested too much, but there's one thing I know for sure: 5.0-3981 is the first version of Dolphin where no matter the platoform, you CANNOT guess the base address of the RAM and also, this base is only good for the duration of the emulation, pressiong stop and play immediately after has a great chance to have the base address change. It can happen that it would be the same as the previous run, but it's unlikely.

This version's PR text says: "Allow (but don't force) ASLR" https://dolphin-emu.org/download/dev/3443454ba279811a6e10a840d8c21af3e24dd614/

Most importantly, this version completely changes the way the base address is determined. Before this version, you could actaully either be 100% sure of the base every single time or be fairly sure depending on the platoform. On Windows, the emulator tries to find a large conriguous space of free virtual memory of I think it's 4GB which is very large, but it's still the OS that decides here. Well for unknown reasons, it seemed very likely that the base address ended up being 0x7FFF0000, even today I have no idea why it tends to be this, most user could actually use Cheat Engine assuming this as the base, Some users however, couldn't the base could change between emulations, or be consistent, but different. As for non Windows platoform (such as Linux), the base is hardcoded to be 0x2580000000, they did this because of other circumstantial reasons, but they kept the end of the address at 0x80000000 as it makes it very easy to convert Dolphin address to console address 75% of the time (you just remove the 25 at the beginning).

This PR however, no matter the platofrm, it's random, I got multiple base address on my Linux system and none of them seemed to make much sense as far as pattern goes, the only thing it seems to guarantee is the address will end with 4 zeros, my guess is it has to do with alignement or base allocation size, but I can't really tell here. Maybe other stuff are randomnised as far as the RAM layout goes, but this is the only one I really care and am aware of. Keep in mind however that it's only the LOCATION of the emulated RAM that is random, the RAM itself isn't, for example, say you have a base, the location of MEM2 (the region of memory only used by the Wii as usable RAM) is still the base + 0x10000000, this will never change so once you have the base address, you can pretty much get to any addresses in RAM for the duration of this emulation only.

There is a way for each emulation start to be aware of the start address which might be usefull for debugging (keep in mind though, this is a revision that is further than stable 5.0 which had a ton of log changes by me). To see it, open Dolphin with the -d argument which enables debugging features. Make sure the log and log configuration panel are visible by checking in the view menu. Go to the log configuration panel, put the verbosity level to info and as for the log types, uncheck all except MI & memmap. Go to the log panel and boot a game, it will tell you that the RAM initialised sucessfully with an address, this address is your base address. You can test to stop and play the emulator and see that it indeed seems to change at random.

Now, when people was using Cheat Engine, multiple solutions were proposed such as using scans with the ID of the game (because it seems the RAM starts with that ID), but that method is wrong as many games do not have an ID (such as virtual console titles). There's also the pointer method which involves finding an internal pointer of the RAM inside Dolphin's process and add any addresses in relation to that pointer. This works, but has many caveats such as only working on the current version of Dolphin and nothing else, the annoyance of having to do hex math just to add an address permanently and finally, if you desire to change the version of Dolphin, you need to recalculate the entire table and some of these can go hundreds of entries.....not nice.

The solution I do in this project is not 100% sure to get the right address, but the chances of failling are VERY low (as if, so far, in the lattest version, no one had any problems with it). Basically, I checked the source code of Dolphin to figure out how does it map the memory such as its size and flags (like MEM_MAPPED under Windows or a filename under Linux). I use as much heuristics as I can about the mapping and I basically go through all the virtual mapping of the process and I attempt to find one with the same heuristics. This has been pretty reliable so far and it is very possible to adapt this in case there's changes in the way Dolphin maps its memory, but the heuristics I use tends to be very essential for an emulator such as Dolphin, the only change I had to do so far was to accept 2 different filenames for the mapping under Linux as one version changed it.

For more details, check the DolphinProcess folder, this is where I manage all the low level communication with Dolphin and also the "hook" process.

I kept this answer as exhaustive as possible as this is not something I told for the first time, but if you still found conflicting informations, it would mean that you haven't found a place where I was saying the whole story so I am keeping exhaustive here in case others have the same question.

@Henrik0x7F
Copy link
Author

Thanks for the detailed answer! Since I just care about 1 game, scanning the process memory for the game id (and maybe some other bytes to avoid false positives) should be fine. However factoring in the region size could reduce the size of the scanned memory and improve speed. The thing I wasn't sure about was if the ram itself is randomized but since your editor displays the memory correctly I think that's not the case.

@Henrik0x7F
Copy link
Author

Ok, seems like the person who said the ram is random was using cheat engine. He was probably looking at completely different memory.

@aldelaro5
Copy link
Owner

For CE, after the ASLR update, you HAVE to use the pointer method to make it work reliably, which sucks, but I mean, it is why this project exists :)

cristian64 added a commit to cristian64/dolphin-memory-engine that referenced this issue Aug 11, 2024
…group node is right-clicked.

This was a regression in aldelaro5#167.

Group nodes do not have a watch entry associated with them. When a group
node was right-clicked, a null pointer would be fatally dereferenced:

```
#0  MemWatchEntry::isBoundToPointer() const (this=this@entry=0x0) at /w/dolphin-memory-engine/Source/MemoryWatch/MemWatchEntry.cpp:77
aldelaro5#1  0x0000561a4ab96c94 in MemWatchWidget::onMemWatchContextMenuRequested(QPoint const&) (this=0x561a4c28c580, pos=...) at /w/dolphin-memory-engine/Source/GUI/MemWatcher/MemWatchWidget.cpp:280
aldelaro5#2  0x00007f56ac7be023 in  () at /lib/x86_64-linux-gnu/libQt6Core.so.6
aldelaro5#3  0x00007f56ad489889 in QWidget::customContextMenuRequested(QPoint const&) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
aldelaro5#4  0x00007f56ad4a6020 in QWidget::event(QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
aldelaro5#5  0x00007f56ad541406 in QFrame::event(QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
aldelaro5#6  0x00007f56ac765818 in QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
aldelaro5#7  0x00007f56ad44bd25 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
aldelaro5#8  0x00007f56ad454c5e in QApplication::notify(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
aldelaro5#9  0x00007f56ac765a58 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
aldelaro5#10 0x00007f56ad4b796c in  () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
aldelaro5#11 0x00007f56ad4ba635 in  () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
aldelaro5#12 0x00007f56ad44bd36 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
aldelaro5#13 0x00007f56ac765a58 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
aldelaro5#14 0x00007f56acd0a6bf in QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) () at /lib/x86_64-linux-gnu/libQt6Gui.so.6
aldelaro5#15 0x00007f56acd52c8c in QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt6Gui.so.6
aldelaro5#16 0x00007f56a8c7686e in  () at /usr/lib/x86_64-linux-gnu/qt6/plugins/platforms/../../../libQt6XcbQpa.so.6
aldelaro5#17 0x00007f56abe32d3b in g_main_context_dispatch () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
aldelaro5#18 0x00007f56abe882b8 in  () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
aldelaro5#19 0x00007f56abe303e3 in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
aldelaro5#20 0x00007f56ac98deae in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
aldelaro5#21 0x00007f56ac772adb in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
aldelaro5#22 0x00007f56ac76e0f3 in QCoreApplication::exec() () at /lib/x86_64-linux-gnu/libQt6Core.so.6
aldelaro5#23 0x0000561a4ab66e8c in main(int, char**) (argc=<optimised out>, argv=<optimised out>) at /w/dolphin-memory-engine/Source/main.cpp:54
```

Fixes aldelaro5#170.
dreamsyntax pushed a commit that referenced this issue Aug 11, 2024
…group node is right-clicked.

This was a regression in #167.

Group nodes do not have a watch entry associated with them. When a group
node was right-clicked, a null pointer would be fatally dereferenced:

```
#0  MemWatchEntry::isBoundToPointer() const (this=this@entry=0x0) at /w/dolphin-memory-engine/Source/MemoryWatch/MemWatchEntry.cpp:77
#1  0x0000561a4ab96c94 in MemWatchWidget::onMemWatchContextMenuRequested(QPoint const&) (this=0x561a4c28c580, pos=...) at /w/dolphin-memory-engine/Source/GUI/MemWatcher/MemWatchWidget.cpp:280
#2  0x00007f56ac7be023 in  () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#3  0x00007f56ad489889 in QWidget::customContextMenuRequested(QPoint const&) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#4  0x00007f56ad4a6020 in QWidget::event(QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#5  0x00007f56ad541406 in QFrame::event(QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#6  0x00007f56ac765818 in QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#7  0x00007f56ad44bd25 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#8  0x00007f56ad454c5e in QApplication::notify(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#9  0x00007f56ac765a58 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#10 0x00007f56ad4b796c in  () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#11 0x00007f56ad4ba635 in  () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#12 0x00007f56ad44bd36 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#13 0x00007f56ac765a58 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#14 0x00007f56acd0a6bf in QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) () at /lib/x86_64-linux-gnu/libQt6Gui.so.6
#15 0x00007f56acd52c8c in QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt6Gui.so.6
#16 0x00007f56a8c7686e in  () at /usr/lib/x86_64-linux-gnu/qt6/plugins/platforms/../../../libQt6XcbQpa.so.6
#17 0x00007f56abe32d3b in g_main_context_dispatch () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#18 0x00007f56abe882b8 in  () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#19 0x00007f56abe303e3 in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#20 0x00007f56ac98deae in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#21 0x00007f56ac772adb in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#22 0x00007f56ac76e0f3 in QCoreApplication::exec() () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#23 0x0000561a4ab66e8c in main(int, char**) (argc=<optimised out>, argv=<optimised out>) at /w/dolphin-memory-engine/Source/main.cpp:54
```

Fixes #170.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants