DarthTon / Blackbone

Windows memory hacking library
MIT License
4.68k stars 1.32k forks source link

CreateThread/QueueAPC block on Windows 10 #216

Open TopoIogist opened 6 years ago

TopoIogist commented 6 years ago

Hi DarthTon, this is not really an issue with Blackbone itself but I hope you can help me nevertheless.

I am using a variant of the Blackbone driver for Manual-Mapping my stuff but recently on Windows 10 (even before Win10FC) the injection was "blocked" by a ring-0 ac for both APC based and CreateThread based execution (BBCallRoutine I guess). The same code still works on Win 7 and works flawlessly on regular processes. Of course I remove the CreateThread notify routines so my calls should go through.

I already did the following to debug the issue:

At this point I am highly confused to why the exeuction does not work (I assume somehow the first instruction of the routine triggers an exception which is then caught). Can you provide any ideas of which mechanisms could further block injection or hint me to anything I can still try?

DarthTon commented 6 years ago

Hard to tell. Does the thread simply die after first instruction? What's the memory protection of payload region before and after execution?

TopoIogist commented 6 years ago

I am quite sure that the thread simply dies (at least the execution does not hang even though these BBCallRoutine calls use the parm to wait for the thread to finish - the functions immediately return). I will look up the memory protection of the payload in the evening and report back.

TopoIogist commented 6 years ago

@DarthTon Unfortunately this did not bring up anything spectacular I think:

BlackBone: BBQueryMemoryProtection: ZwQueryVirtualMemory(0x1C821470000): AllocationBase=0x1C821470000 AllocationProt=PAGE_EXECUTE_READWRITE RegionSize=0x2000 State=MEM_COMMIT Protect=PAGE_EXECUTE_READWRITE Type=MEM_PRIVATE
BlackBone: DummyCreateThreadCallback: (0000000000001088, 0000000000001070, 1) <--- Dummy PsSetThreadCreateNotify callback is triggered (creation).
BlackBone: BBQueryMemoryProtection: ZwQueryVirtualMemory(0x1C821470000): AllocationBase=0x1C821470000 AllocationProt=PAGE_EXECUTE_READWRITE RegionSize=0x2000 State=MEM_COMMIT Protect=PAGE_EXECUTE_READWRITE Type=MEM_PRIVATE
BlackBone: DummyCreateThreadCallback: (0000000000001088, 0000000000001070, 0) <--- Dummy PsSetThreadCreateNotify callback is triggered (creation, thread end).

According to ZwQueryVirtualMemory the memory region of the thread entry point is perfectly executable, the thread immediately returns with exit code of 0. ZwCreateThreadEx does not fail... It is a mystery to me how they prevent the memory access to that page.

Interestingly if I change the entry point of the thread to something like 0x1234 (inaccessible) the game crashes. If i change it to my memory region with the first instruction being something like 0xCC the game does not crash! (Instruction is not executed). I cannot really find an explaination how they prevent that code to trigger without setting some kind of guard to it or using a hardware breakpoint which is impossible as they do not know about the fresh thread (hwbps need to be set per thread base afaik).

TopoIogist commented 6 years ago

I also tried a third method of allocating the memory with ZwCreateSection and ZwMapViewOfSection to make it look more legitimate. Unfortunately also without success.

DarthTon commented 6 years ago

Can I test it myself somehow?

TopoIogist commented 6 years ago

Yes, the protected game is DeadByDaylight (AC=EAC). Unfortunately you would need a way to load your driver without enabling test-signing (i.e. using some kernel exploit or having a certificate). Besides you need to change the pool-tag and disable ThreadCreation notify routines (otherwise the thread gets directly blocked) and preferably also unregister ObsCallbacks (Creating threads opens up a handle afaik this could be directly used to stop the thread). Also you should use Thread flags that skip out on dll thread-attach calls (not sure if they use this). Still then you would not be able to attach a debugger.

I can provide you with the game and give further help if needed. On the other hand I found a workaround in the meantime. When I (instead of allocating the memory with BlackBone) simply "hijack" some memory of an existing module, changing the protection and wiping it all my calls go through. Of course this can induce crashes if you choose a bad spot for this memory. Still I would be very curious about how they achieve this protection.

jackqk commented 6 years ago

好人,哥哥