jpxue / Overwatch-Aim-Assist

C++ Overwatch aim assist tool and triggerbot!
GNU General Public License v3.0
169 stars 69 forks source link

Question about switching between game modes-关于切换快速模式之后失效的问题 #30

Open ghost opened 6 years ago

ghost commented 6 years ago

This issue has been solved, please read the answer from the owner. I hope you love the answer as I do!

HI,thank you for provide such an interesting assist tool! I have successfully run it on my desktop. But with just some confusions: When I switched from one mode to another, for example, training ->quick game, the tool would be failed and I have to restart the Overwatch to re-use this tool again. I tried to debug, and it seems that after I switch to quick game, the pixel color match (pixel.isHealth) does NOT return a "true". As a result, all following parts cannot be executed (such as "foundAnyRedsBefore"). The next step should check if there is something wrong about the "Capture", but I am not familiar with it and I have no idea about how to solve it. Update: if you make a screenshot using the official method (key PrtSc as default), it will be saved into username/document/overwatch. But if you paste onto photoshop, it is just a totally black picture. Maybe about image dumping?

jpxue commented 6 years ago

Sorry for the super late reply.

Yes, Blizzard implemented a way of detecting 'injected' mouse input (mouse_event, sendinput etc...). On detecting this they screenlock to prevent screen capturing using GDI.

They use SetWindowDisplayAffinity which is found on all Windows 8 + 10 machines as part of Microsoft's DRM update. On Windows 7 it can be turned off.

How do they detect 'injected' mouse input:

By means of GetRawInputData and monitoring WM_INPUT. If the cursor's position/movement simply does not tally with the WM_INPUT coming from HID driver stack then they can easily tell that input is being 'injected'.

Contrary to popular belief they do not do this by means of mouse hooks i.e. by scanning for LLMHF_INJECTED as hypothesized by many (has drawbacks + would be too easy). If you had to enumerate through all the SetWindowsHookEx calls you'd find that they only hook WH_KEYBOARD and WH_KEYBOARD_LL.

How do I bypass this:

There are various methods, I've listed 3 of them below:

1) Go internal and capture from the backbuffer. Advantages: much faster than GDI, you can capture almost every frame with minimal overhead, you can still use mouse_event or sendinput. Inject a DLL -> Present Hook -> obtain a copy from the BackBuffer. You can process that screenshot internally or you can share it between processes (IPC) by means of a shared memory space and process it through another app (involves some work but is the preferred way).

2) You can implement a Mouse Input Driver and generate input directly from the HID stack. Windows Driver Samples. I never really bothered with this because the process of installing drivers for testing is an abysmal headache (even on VMs using various exploits/driver loaders which never seem to work because of Windows updates 😠).

3) Inject and call SetWindowDisplayAffinity from the Overwatch processes. Example

ghost commented 6 years ago

Thank you very much for such a wonderful response !! Although I am not a senior developer, and it can be too hard for me to realize the bypass methods, your response is really excellent and helpful. I yielded to curiosity, and thank you for leading me to such a deep view about how it works! It seems that the Blizzard does two things at the same time: 1. prevent screen capturing(if using GDI) and 2. compare the cursor's position with WM_INPUT Therefore, I need to: 1. choose a method to get the screenshot (ie. from backbuffer or inject SetWindowDisplayAffinity). 2. make mouse inject undetected (make a Mouse Driver), and you do NOT recommend it. So, if possible , please tell me if I was utterly misconstruing the logic. Or, even we got the screenshot, we are still unable to inject the mouse (i.e to make the cursor's position tally with the WM_INPUT). Thank you in advance!!

jpxue commented 6 years ago

Yep, as you roughly said, they monitor raw input from your mouse directly (through it's driver) and have an idea where the cursor should be; if the cursor is consistently not in this position (because of injected mouse events) then they screenlock and thus any screenshot obtained through BitBlt will be black as you said. You can write a driver that generates mouse input from the HID stack to bypass this and thus 'trick' Overwatch into thinking that the input is directly coming from a mouse.

Yes, method 1 is simply another means of obtaining a screenshot that bypasses the screenlock. Method 2 prevents screenlock from happening and method 3 undoes the screenlock. Method 1 is exactly how nearly all game video recording software work (example: FRAPS, OBS, Xsplit etc...) hence why I'd recommended this + capturing from the backbuffer is blazing fast.

Method 2 is used by some but as I said, if you do not have any experience developing kernel mode drivers then you will find the setting up of a test environment + deployment a headache. There are a lot of samples online but you will still need to familiarize yourself with the basics of driver development so it's not like you can instantly jump into driver development and immediately produce results.

Method 3 should be the easiest but I do not know if they patch this or detect it.

Hope I answered your questions.

ghost commented 6 years ago

Thanks!! This is the best answer I have seen in Github!!